/srv/irclogs.ubuntu.com/2012/09/24/#maas.txt

lifelessbigjools: hey03:39
lifelessbigjools: we basically run the installer on every machine today, right ?03:39
bigjoolswotcha lifeless03:39
bigjoolslifeless: yes03:39
lifelesscool, thanks.03:39
lifelessJust checking my facts.03:39
bigjoolsI think Daviey was looking at using an image instead, don't know how far he got03:40
lifelessnova bare metal does images03:46
lifelessit writes them using iscsi straight to the bare metal host03:46
lifelesswhich is an interesting approach03:46
bigjoolslifeless: can iscsi be proxied?03:50
lifelessyes03:51
lifelessthere are proxy initiators around according to a quick google03:51
lifelessbut failing that, its routable03:51
lifelessproxying would be useful if you need to support action at a distance or handle 3rd party actor scenarios03:52
SpamapSI thought we were doing images by now03:54
SpamapSonly difficulty there is storage configuration.03:55
bigjoolslifeless: well I am thinking whether to send it via the clusters or just get everything to download from the region03:56
bigjoolswill need to do the latter eventually03:56
bigjoolserr former I mean03:56
jtv"make test" broken on quantal: buildout complains about selecting amqplib 1.0.2.  :(05:38
jtvbigjools: are you getting that?05:38
bigjoolsjtv: I use "make check" successfully05:38
jtvBroken for me, in trunk.  :(05:39
* bigjools tries again05:39
bigjoolsdeleting all my eggs first05:39
jtvLooks as if it's that don't-pick-your-own-version setting05:39
bigjoolswell amqp is not in buildout any more05:40
bigjoolswe're using system packages05:40
bigjoolsbut I just cleaned everything out, building from scratch now05:41
jtvFWIW it's for building maas-test.05:42
bigjoolsseems ok here05:42
bigjoolshave you got latest trunk and installed all package deps?05:43
jtvAh, I hadn't installed dependencies!05:43
* bigjools rolls eyes05:43
* jtv cowers05:43
jtvStill no luck with the dependencies updated though.05:50
jtvAh, _also_ had to delete the egg.05:53
SpamapSyou forgot one thing...05:56
SpamapShttp://www.youtube.com/watch?v=25q3hxlgvw405:56
SpamapSyou forgot.. to hook up.. the doll05:56
jtvI'll try that, but better if I do it on Friday afternoon, right?05:59
SpamapScertainly better for attendance at the party06:09
jtvGood morning rvba07:25
bigjools"do-release-upgrade -d" on precise is telling me there's no upgrade ...07:26
rvba\o jtv.07:27
jtvjam: question about your tag-list-api branch.  Why is "nodes" a POST and not a GET?08:02
jamjtv: because if I make it a GET, it overrides the default GET, and I can't get the regular tag back08:11
jamjtv: if you know of how to add a GET with an op and preserve the get without an op08:11
jamI would love to hear it.08:11
jamMaybe rvba knows?08:12
jamjtv: I agree it should be a plain GET08:12
jamI suppose I could make it "/tags/<tag-name>/nodes" or some other URL08:12
jtvjam: I forgot about that problem.  I know of no solution.08:15
rvbajam: you're right, that's not possible with what we have in place right now.08:15
jamrvba: k, do you know of a reasonable compromise? POST/nodes path/something else?08:16
jam(I went with POST)08:16
rvbajam: I think this can be properly fixed by improving how the api_operation thing works.  otp right now, let me think about it some more.08:18
jamk08:18
rvbajam: the problem you're having is related to bug 1049933 (perform_api_operation() should always use the default CRUD method if op is not defined.)09:15
ubot5Launchpad bug 1049933 in MAAS "The public-facing API code confusingly conflates CRUD, HTTP methods, and piggybacked operations" [Medium,Triaged] https://launchpad.net/bugs/104993309:15
rvbajam: I suggest you XXX that code (and keep it a POST method for now).  I think the fix can be simple, I'll look into it.09:15
jamrvba: thanks for the heads up. Will do.09:16
=== jam2 is now known as jam
jtvbigjools: I guess we don't have the bit of packaging yet that asks the cluster admin where the region controller is?09:44
bigjoolsjtv: we don't09:45
bigjoolsthat will come last when the upstream code is finished09:45
jtvI'll have to use some kind of placeholder and file a bug/card.09:45
bigjoolsyou just need to look in a config09:45
bigjoolsyeah we need to decide on a common config09:45
bigjoolsI think I did /etc/maas/maas_api.conf09:46
bigjoolsMAAS_URL=<thing>09:46
bigjoolsinside it09:46
bigjoolsand I'll make the package write thjat09:46
bigjoolsI already did some code to do that if you look in my WIP branch09:46
bigjoolsjtv: why do you want another card?09:47
jtvIf I understand you correctly, it's something I can't finish with the rest of the work.  In which case we need one card to track the work I'm doing now, and another to track that capstone piece of config.09:48
bigjoolsjtv: I think it's ok to work with this minimal spec as above09:48
bigjoolsjust read the file and use that config format09:49
jtvOK.  I didn't know you were already working on that packaging change.09:49
bigjoolsyeah I had forgotten I had started it :)09:49
jtvIf you're reading that file, ideally I'd reuse your code for doing so.09:51
bigjoolsI am just writing it09:51
bigjoolshere's my code09:51
bigjoolsecho "MAAS_URL=$RET" > /etc/maas/maas_api.conf09:52
bigjools:)09:52
jtvI sometimes get my technical terms confused, but I could have sworn that was called "writing" the file.  :)09:53
jtvI know -- I'll make the URL a command-line parameter.09:53
bigjools[19:51:31] <jtv> If you're reading that file, ideally I'd reuse your code for doing so.09:53
bigjools"reading"09:54
bigjools:)09:54
jtvYes, and what you showed me was "writing" the file.09:54
bigjoolslike I said!09:54
bigjoolsI was being facaetious09:54
jtvI'm still confused.  I said I'd like to reuse your code for reading the file, and you showed me the code for writing the file...09:55
jtvBut never mind.09:55
jtvI'll make this a command-line parameter and that's an easy way out of the temporary problem.09:55
bigjoolsjtv: my point was that I am not reading it09:56
bigjoolsjust writing09:56
jtvAh.09:57
bigjoolsjtv: make it default to that file name, with an optional override to another09:57
jtvWouldn't it be easier and cleaner to source that file in the shell?09:57
jtvAnd pass it explicitly to the maas-provision command I'm writing?09:58
jtvThen the python code doesn't need to know about the file as an extra level of indirection.09:58
bigjoolswhat shell?09:58
bigjoolsyou're not writing any shell09:59
rvbaallenap: that might be the problem, because 0.6.1 is not mentioned anywhere explicitely.10:00
rvbaexplicitly*10:00
bigjoolsjtv: your new command will need to be started from an upstart conf10:00
bigjoolsjtv: there's no shell as such, it needs to read the config10:01
bigjoolsmaking sense?10:01
bigjoolsok it's 8pm here, I am ducking out10:01
bigjoolsgood night all10:01
jtvThe upstart conf is where you normally run shell code.10:01
allenapCheerio bigjools.10:01
rvbaallenap: 'make check' works on the jenkins box so I'm a bit confused…10:02
rvba\o bigjools.10:02
bigjoolsjtv: not at all, you just tell it what executable to run10:02
jtvCan do, I guess.  I'm used to it running script.10:02
jtvOkay, I'll read that file.10:02
bigjoolsjtv: look at the files in /etc/init/10:02
bigjoolsthey are config files10:03
bigjoolsyou're thinking of /etc/init.d10:03
jtvNo10:03
bigjoolsthey are shell10:03
jtvI'm thinking of upstart scripts.10:03
jtvThey can have script sections.10:03
allenaprvba: rabbitfixture depends on amqplib >= 0.6.1.10:03
allenaprvba: Maybe we can turn off allow-picked-versions...10:03
allenapOr on even.10:03
bigjoolsjtv: ok I'll leave it to you to decide how best to do it10:04
jtvbigjools: I just picked one at random, for resolvconf, and it contains a script section that runs the daemon.10:04
jtvOK.  Good night!10:04
bigjoolsjtv: it does, can't say I like it, but it does :)10:04
jtv:-P10:04
bigjoolsjtv: but open(file,"r").splitlines().split("=") is not too complicated :)10:05
* jtv reels10:05
bigjoolswith a read() somewhere in there10:05
* bigjools exits, bye!10:06
jtvbye10:06
jtvI'm stepping out for a bite too.10:06
rvbaallenap: changing allow-picked-versions seems to fix the problem indeed.  At least locally on my machine :)10:07
allenaprvba: Cool. Can you check that it's using the local lxml rather than something from a random egg?10:15
allenaprvba: And, if so, are you happy to propose those changes, and I'll review?10:17
rvbaallenap: it's still downloading lxml (lxml-2.3.5-py2.7-linux-x86_64.egg) and amqplib-1.0.2-py2.7.egg :/10:17
allenapBalls.10:17
allenapAt this point we may need to ditch buildout and just use virtualenv+pip.10:17
rvbaallenap: are you sure it's a good idea to do this right now.  Yo're the buildout expert here so I really rely on your expertise for all this ;)10:19
allenaprvba: I'm not sure it's a good idea to do this right now, but unless we can coax buildout to stop being an idiot, we may have to do it. Can you try one more thing:10:20
allenapmake distclean && rm -rf ~/.buildout/eggs && make10:20
allenapthen see where lxml and co. are coming from?10:20
rvbaallenap: you're not seeing the problem I'm having?10:21
rvbaallenap: running it right now…10:21
allenaprvba: My machine is still on precise and I've been too busy/lazy to fire up my laptop ;)10:21
rvbaallenap: I'm still on precise too :).  I use canonistack to get quantal machines.10:22
allenaprvba: I've been to busy/lazy to fire up any canonistack instances ;)10:22
rvbaallenap: ok :).  But all of this is on precise.10:23
rvbaallenap: and the jenkins box is on precise too.10:23
allenaprvba: Gah, we've got to get that fixed then.10:24
allenaprvba: With just http://paste.ubuntu.com/1224227/ against trunk, trunk builds with the packaged amqplib and lxml.10:28
allenapOn precise.10:28
rvbaallenap: I just realized that for some reason, buildout added amqplib = 1.0.2 in versions.cfg :/10:30
allenaprvba: Huh? Is that the auto stuff kicking in?10:30
allenapI've never seen that before.10:30
rvbaallenap: I guess it's the auto stuff. http://paste.ubuntu.com/1224232/10:31
allenaprvba: How annoying :-/ Anyway, with that earlier patch to remove lxml from buildout.cfg, I'm getting a clean and, I think, correct build on both precise and quantal.10:33
rvbaallenap: if that's enough then that's great. Now we're back with our Jenkins problem.10:34
allenaprvba: And the Jenkins machine that keeps kicking me out every 30 seconds.10:36
allenaprvba: Shall I propose that patch then?10:36
rvbaallenap: please do.  I'll investigate the Jenkins problem.  So far, I've been unable to reproduce but I'll try again…10:37
allenaprvba: https://code.launchpad.net/~allenap/maas/lxml-not-a-test-dep/+merge/12596910:50
rvbaallenap: approved.  The test suite runs fine on the Jenkins box when I run it manually.  I think I'll wait for Diogo to come online and ask him to help me out with this.  This seems to be Jenkins-related somehow.11:00
allenaprvba: Ta. How &^%$%^& frustrating.11:01
allenaprvba: Which is the DNS card you were thinking of?11:15
allenaprvba: Also, do we land to 12.04-nocobbler (precise trunk) by hand?11:17
rvbaallenap: the high priority card in story 2.11:18
rvbaallenap: yes.11:18
allenaprvba: Okay, I'm going to get some lunch now then I'll ping you about a pre-imp.11:19
rvbaallenap: cool.11:19
jamallenap: so, I'm trying to land some of mgz's code because he has poor access, but lp.net is currently taking about 30+s for every action I do. Is it terrible to just land on trunk directly? (given that tarmac doesn't run the test suite anyway.)11:27
allenapjam: I'll land them if you want, LP's working fine for me.11:30
jamallenap: that is very strange. https://code.launchpad.net/~jameinel/maas/arch_constraint/+merge/125979 needs to be marked approved11:31
allenapjam: But I don't think it's terrible to land directly either.11:31
jambut my 'review' vote hasn't happened in 2 min11:31
jamI don't know why I'm not getting timeouts, it is possible it is on my end, but a simple HTTPS request shouldn't be particularly slow.11:31
allenapjam: The Great Firewall Of $Location?11:32
jamallenap: well, it is strange, as 'bzr up' happens quickly over ssh, but https submit is being slow. I really wonder what is happening.11:32
allenapjam: I've approved that mp. I'm going for lunch now, but I'll be back in ~1h.11:34
jamallenap: enjoy your food. catch you later.11:34
jamallenap: +1 on your lxml change11:37
jamwe want to use it, too11:38
jtvallenap: time for a call?13:03
jtvjam: by the way don't forget my comments on your tag-list-api MP13:04
jtvallenap: need to discuss a technicality of starting celeryd with you.13:05
jamjtv: well, since nobody has approved it, I don't have a choice :). But I'm stil working through the prereqs. I will certainly address them.13:05
jtvOK13:05
jtvjam: Once those notes are addressed I think the branch should be good to land -- I just didn't want to jump the gun before you'd had a chance to discuss the GET/POST issue with Raphael.13:06
jtvAny outcome for that?13:06
jamjtv: it is a current limitation of the infrastructure, and we should just land it with POST until we can update things.13:07
jtvOK13:07
jtvThen I'm ready to approve, as long as you address those notes before landing.13:07
allenapjtv: Yeah, in 5; I'm defuckerating buildout with rbasak right now.13:13
jtvok13:13
allenapjtv: Sorry for the delay. Hangout?13:31
jtvYup.  I'll set one up.13:31
jtvDone.13:32
jtvrvba: do you happen to know what (if anything) we need to pass to celeryd besides the broker URL?  Doesn't it also need to know its queue name?14:13
rvbajtv: yes, we need to pass the queue names.  But if we don't, it defaults to using 'celery'.14:14
rvbajtv: I'm currently working on adding proper routing for the tasks.14:14
jtvI'm working on starting up celeryd from a maas-provision command.14:15
jtvThe queue name is the cluster's uuid, right?14:15
rvbayes14:15
rvbaFor a cluster, the param should be: -Q $uuid,common14:15
rvba(because there is also a 'common' queue for broadcast messages)14:16
rvbaFor the master, the param should: -Q celery,common14:16
jtvThanks!  Do we store the uuid anywhere on the cluster controller yet?14:16
rvba(We could s/celery/master but since 'celery' is currently used to route tasks, this will allow you (and I) to land stuff without breaking anything)14:17
rvbajtv: not yet, that needs to be done by the packaging I guess: generate the UUID and store it somewhere in a config file.14:17
jtvI guess I'll have to use "celery" for now then.14:18
jtvAnd file an XXX for the follow-up.14:18
rvbaYes, sounds good to me.14:19
jtvThanks.14:20
rvbanp14:20
rvbajtv: I just noticed that src/provisioningserver/tasks.py:remove_dhcp_host_map isn't used anywhere (but in tests).  Do we still want to keep that task?14:31
jtvI've been assuming that we would still want it.14:31
jtvI think Julian wrote it.14:31
jtvWhen we decommission a node, we ought to free up the host map so that dhcpd can reclaim the address eventually, if appropriate.14:32
rvbaallenap: I'm afraid the recent changes made to buildout.cfg et al are causing lots of timeouts :/ https://jenkins.qa.ubuntu.com/job/maas-trunk/836/console14:50
allenaprvba: Why on earth is it pulling those things? buildout has about as much common sense as a bag full of hungry squirrels.14:53
allenapI need a cup of tea before I wage war with this again.14:53
rbasakallenap: can you see why https://twitter.com/lmukadam/statuses/249471182510882816? hasn't landed?14:54
rbasaker14:54
rbasakhttps://code.launchpad.net/~allenap/maas/buildfallout/+merge/12600914:54
=== dpb_ is now known as Guest75974
allenapjam: I suspect you have a lock in lp:maas.15:05
allenapjam: I also suspect you no longer have it.15:07
allenapjam: I now suspect that you've been a victim of a vicious slur.15:09
matsubararvba, build passed15:10
allenaprbasak: Tarmac is falling over when getting a lock on lp:~maas-maintainers/maas/packaging and not proceeding any further.15:10
allenaprbasak: Seems to be working again now.15:11
rbasakthanks!15:11
allenapmatsubara: What did you do?15:11
matsubaraallenap, I just forced the build, rvba fixed it :-)15:11
rvbaallenap: I… well… installed python-django-piston :)15:12
allenaprvba: I thought it was installed!?15:13
allenapHow was it passing beforehand?15:13
rvbaIt was not, for some reason.  I was on the wrong machine earlier.15:13
matsubaraallenap, we have two VMs running tests now, one for quantal and one for precise15:13
allenapmatsubara: Ah ha!15:14
rvbaallenap: my guess is that it was using an egg.  Then the change to the buildout broke that.15:14
rvbabuildout config*15:14
rvbaallenap: yep, there is django_piston-0.2.3-py2.7.egg in the cache.15:15
smoserallenap, ping.15:52
allenapsmoser: Hi.15:53
smosera while ago, when trying to do ipmi setting/gathering....15:53
smoserwe came across the issue that the commissioning envirionment did not have access to credentials that could modify the node that it was running on15:53
smoserhas this been resolved in any way?15:53
allenapsmoser: Not that I'm aware of. roaksoax and I were just talking about similar things. We'll just provide an anonymous API method for now. There's no good way of getting credentials on a machine right now that's less likely to leak than a chocolate teapot.15:56
smoserallenap, sure there is15:57
smoserthe provisioing network is assumed safe15:57
smoserif its not, you're hosed.15:58
roaksoaxsmoser: what I was suggesting was simply ensure that the commissioning node updating the power settings should send all the MAC addresses of its NIC's and verify that are the same with the ones stored in MAAS during enlistment15:58
roaksoaxsimply to make sure that the node what's updating itself15:58
allenapsmoser: Which provisioning network? There is no separate provisioning network.15:59
smoserthere is a provisioing network.16:01
smoserits the one that is utilized for pxeboot and such.16:01
smoserand installation.16:01
smoserthat may happen to be another network also.16:01
smoserbut we are assuming it is secure.16:01
smoserotherwise, we're hosed already.16:01
smoseri thikn you should just assume that if you passed credentials via commissioning user-data, that they are safe.16:02
smoserafaik, it has been accepted that http is good enough for that.16:03
allenapsmoser: It was made explicit in the IoM that there is no separate provisioning network at all.16:03
smoserallenap, i'm not suggesting that it is separate. i'm suggesting that if you have 1 network, and you're doing pxeboot and http and dhcp on that network, then it has to be secure.16:04
smoserand if that network is not secured some way, then you cannot solve your problem.16:04
* roaksoax brb16:04
allenapsmoser: What do you mean by secure in that sense?16:05
smosernon-hostile i guess.16:05
allenapsmoser: Okay, but there's nothing in maas that helps ensure that.16:06
smoseras if a deployed node has a hostile agent inside it, and that node can listen to traffic due for other nodes, you're kind of screwed.16:06
smoserallenap, you're right.16:06
smoseranwyay...16:06
allenapsmoser: We have to assume that everyone on the network is nice. But, if we assume that, we don't need to pass credentials to the node.16:06
smoserwe're using http for metadata16:06
smoserand we accepted that16:06
smoserbecause we accepted that the network was secure16:07
smoserhm..16:07
smoserjust pass credentials.16:07
smoserassume they're not intercepted.16:07
smoserthen you only need to ensure that the transmission is safe.16:08
smosernot that everyone is nice.16:08
smoser(niether is ensurable at this point, but ensuring safe transmission is easier than ensuring that all people are good)16:08
allenapsmoser: How can we do that? Can we do something on the switch/router to prevent eavesdropping?16:08
smoserallenap, we cannot, really.16:08
smoserbut high end switches would be able to do that.16:09
smoseri really dont have a lot of experience here. but i've been told that basically people virtually plug a provisioning network in (via switch apis), then provision a node, then un-plug the provisioning netowrk.16:09
allenapsmoser: Okay, we could pass a token on the kernel command line. Does that sound about right?16:10
smoserso that when the node is deployed it is not "physically" connected to the provisioning network.16:10
smoserallenap, dont pass it on the command line.16:10
smoserpass it in the user-data16:10
smoserfor the commssioning.16:10
smoserthe user-data is general purpose, and could easily be made to be done over https16:11
allenapsmoser: That sounds fine. It can even be encoded in the API URL that might already be in there. http://token@...16:11
smoserwell yo'ure already passing to the commissioning environment a set of metadata tokens16:11
smoserthose tokens then get the user-data16:11
smoserand the user-data says "here are some maas api tokesn"16:12
smoserdoes that make sense?16:12
smoserits a little less direct, but it uses infrastructure we already have in place.16:12
smoserand is intended to be general purpose.16:12
allenapsmoser: Yeah, makes sense, sounds good. I don't know enough to see all the plumbing, but I guess you do.16:13
allenapmatsubara: Can you review https://code.launchpad.net/~allenap/maas/offline-more/+merge/126045 please?16:18
matsubaraallenap, so we won't have the make build-offline target anymore?16:24
matsubaraallenap, you change looks good. I just need to update the target to run 'make offline=true build' then?16:25
allenapmatsubara: Nope, instead you can `export offline=true` or call `make offline=true {build,...}`16:25
matsubaracool16:25
allenapmatsubara: I personally prefer the latter; it's more explicit when reading the log.16:26
matsubaraok16:26
matsubaraallenap, are you going to backport that to the precise branch?16:26
allenapmatsubara: Thanks for the review. Erm, yes, I guess I will.16:26
matsubaralet me know when it's done so I can update the jenkins job16:27
allenapmatsubara: Done.16:29
matsubaraallenap, ok, job updated, a build kicked16:32
matsubaraallenap, hmm it still tried to contact pypi16:32
allenapmatsubara: !*^£ buildout's days are numbered. Small numbers.16:34
allenapmatsubara: I'm off now. Speak to you tomorrow, have a good evening!16:35
matsubaraallenap, you too!16:35
roaksoaxallenap:  bug #105566217:37
ubot5Launchpad bug 1055662 in MAAS "Anonymous API access to update power_type, power_settings" [Critical,Confirmed] https://launchpad.net/bugs/105566217:37
roaksoax.wub 1817:37
smoserhmmm https://launchpad.net/~maas-maintainers17:55
smoserhow can i get an archive created there.17:55
smosermaybe i need to be an admin?17:55
smoseror maybe rvba or allenap or matsubara  could do i tfo rme ?17:56
smoserdo it for me17:56
smoseror let me be an admin i suppose.17:56
smoserallenap, ^17:57
matsubarasmoser, I can create a new one, what's the name of the ppa?17:57
smosermaas-ephemeral-images17:57
matsubarasmoser, https://launchpad.net/~maas-maintainers/+archive/maas-ephemeral-images17:58
smoserthanks17:58
matsubaranp17:58
roaksoaxsmoser: what did you change to get SOL of the ephemeral images to tty0?18:00
Davieyroaksoax: wget http://ttys0.daviey.com/ > /etc/init/ttyS0.conf18:02
Davieyugh, that upstart job can be cleaned up now.18:02
smoserroaksoax, provisioningserver/kernel_opts.py18:04
smoserlook for console= there18:04
smoserroaksoax, https://bugs.launchpad.net/maas/+bug/104450318:05
ubot5Ubuntu bug 1044503 in MAAS "kernel command line is not easily customizable" [High,Triaged]18:05
Davieysmoser: we should probably put a getty on ttyS0 and ttyS1 in ephemeral18:05
smoseri think thats a generic (very generic) ubuntu bug18:13
roaksoaxandresrodriguieza18:16
roaksoaxerr18:16
roaksoaxsmoser: thanks18:16
roaksoaxDaviey: so you were doing the wget http://ttys0.daviey.com/ > /etc/init/ttyS0.conf to get ttyS0 output?18:20
Davieyroaksoax_: that is how you create a tty on a serial device19:03
Davieywell -O rather than > i guess19:04
roaksoax_Daviey: heh ok. anyways, SOL is working again19:04
=== roaksoax_ is now known as roaksoax
roaksoaxDaviey: just had to do this: http://paste.ubuntu.com/1225168/19:05
Davieyroaksoax: that doesn't give you shell access, tho does it?19:09
Daviey(or grub access)19:10
Daviey[SOL session stolen]  :)19:11
roaksoaxDaviey: Daviey hehe, waiting for it to finish installing19:12
roaksoaxi'll see the rest after it finished19:12
=== matsubara__ is now known as matsubara
=== wgrant_ is now known as wgrant
=== hazmat` is now known as 5JTAACNC2
=== 5JTAACNC2 is now known as hazmat
=== dannf` is now known as dannf

Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!