=== sadmac_ is now known as sadmac === magnetic is now known as foolano [18:23] notting: read my blog? [18:24] saw it. have not looked at the code. [18:24] cool [19:08] ion_: I wrote a new allocator over the weekend ;) [19:09] Ooo [19:09] Keybuk: get my email? [19:09] sadmac2: yes. I still think your state machine is crazy [19:10] ion_: nih_alloc and nih_free still work as before (alloc with parent, free anyway) [19:10] but now you have nih_alloc_ref (add a new parent), nih_alloc_unref (drop a parent) and nih_discard (throw away only if there are no parents) [19:10] Keybuk: and I still haven't seen you propose a mechanism behind that pretty syntax of yours [19:10] keybuk: Alright [19:10] keybuk: Does unref automatically discard? [19:11] ion_: yes [19:11] sadmac2: err, I've told you exactly what I'm going to do - it hasn't changed since plumbers [19:12] Keybuk: really? because I haven't read about it the same way twice [19:12] depsolving keeps disappearing and reappearing... [19:12] "depsolving" ? [19:12] if you start foo, which depends on bar, does it start both or just error and tell the user "Fix it?" I've heard you tell it both ways [19:13] no you haven't [19:14] there was an auto keyword at plumbers [19:14] that vanished last time we spoke [19:16] err, that vanished after a lengthy debate both on the mailing list and on here [19:17] must've missed it here. Dunno where it was on the mailing list [19:17] "upstart configuration", Nov 2008 [19:18] ah, so its add a manual now [19:18] no [19:18] the functionality is still there then [19:19] it's treat disabling jobs as a separate thing to their definition [19:19] a sysadmin can flag a job as disabled [19:19] bit more like SMF [19:19] I ran it by our server team here, their eyes lit up with joy, so it's a keeper [19:21] ok, so the fundamental difference is in your system states/jobs are first class objects [19:21] where my system essentially doesn't have a first class object [19:23] can you solve all the use cases with yours? mounting? (dbus I know you've done) [19:23] I suspect that leads to a lot of differences, both fundamental and trivial [19:23] I'm fairly certain yours could be implemented on top of mine (not that we should, but its very significant that we can). [19:23] stateless mounting still can't be solved in yours, so I don't see that to be a useful example [19:24] can you mount at all? [19:24] can you manage the state for stateful mounting? [19:24] yes, of course [19:24] 0.5 can't do /either/ that's the importance of the case [19:25] I can manage the state for stateful mounting without Upstart at all [19:25] just by using udev and some shell scripts [19:25] so I'm not sure that's a useful example either [19:25] I don't know that you can easily express virtual states either (explanation follows): [19:26] so my usecase would be SELinux [19:26] its damn useful to know if the system is enforcing or not and act based on this. [19:26] you can check if the system is enforcing by running getenforce [19:27] but its hard to get an event stream from which you can derive it [19:27] in my model its not hard to describe states coming from anywhere. so you could define: [19:27] selinux: test-by /usr/bin/getenforce [19:28] and it would run that how many times a second? [19:28] Keybuk: it would run it when it needed to know. When the user lists states or when dependency checking is interested in the selinux state [19:28] the rest of the time selinux would be neither up nor down [19:29] its "quantum." neither running nor not running until observed [19:29] it needs to know continually [19:29] otherwise how would it know when to stop a service because selinux is no longer being enforced? [19:30] also would it only check that if a sysadmin issues a start command? [19:30] otherwise when would it check that for other reasons? [19:30] when the service came up [19:30] Keybuk: and this can be used in combination with regular ons and when (event1..event2) [19:31] how can the service come up if it's waiting on a dependency using test-by? [19:32] Keybuk: if there's an exec stanza, then it goes by the usual method (it can verify the test after execing, or not, that's a bit more of a philisophical question) [19:33] sorry [19:33] but it sounds like you really haven't thought this through [19:33] since you're not bothering to answer the question [19:34] Keybuk: on setenforce(1)..until setenforce(0) [19:35] Keybuk: the events can still stop it [19:35] ok, let's do a worked example [19:35] Keybuk: /but/ we don't get the initial setenforce, because its done in initrd (and there be pjones) [19:35] give me a real example of a service that would depend on selinux in this fashion [19:35] so the additional test-by is necessary [19:36] Keybuk: setroubleshootd [19:36] no, that runs in permissive too. If we had one for "disabled" then that works [19:36] ok, let's use setroubleshootd for a moment [19:37] how would its definition be expressed? [19:37] setroubleshootd when selinux [19:37] no : s ? [19:37] no paths or arguments ? [19:38] that's just the setroubleshootd ->selinux dep [19:38] setroubleshootd has no other dependencies (not even filesystem writable or mounted?) [19:38] please don't shorthand [19:38] give the full example [19:38] use pastebin if you like [19:38] setroubleshootd [19:38] when selinux [19:39] when can-exec("/usr/bin/selinux") [19:39] exec /usr/bin/selinux [19:40] can-exec test-by [ -x %1 ] [19:40] selinux [19:40] test-by getenforce [19:40] when (setenforce(1)..setenforce(0)) [19:40] #eof [19:40] ok [19:40] now give me a worked example of a system boot [19:40] it's just come up [19:40] Upstart has started [19:40] now what happens? [19:41] well, assumedly it parses the job definitions [19:41] so let's say it's done that [19:41] now what? [19:41] shit. missing a line [19:42] can-exec when mounted [19:42] ^^for efficiency. not mandatory [19:42] you haven't defined mounted in the above, so please do that [19:42] (feel free to just claim it's a state that comes up at some useful point) [19:43] Keybuk: its a state that comes up whenever a filesystem is mounted. [19:43] what brings that state up? [19:43] I think if you're going to rely on such a thing right now, you need to define it ;) [19:43] it might be easier for your example just to assume that there's only one filesystem and no such state [19:44] yeah, ignore that. there's some particulars to this stage of boot I'm not thinking of [19:44] ok, so we're up [19:45] ok [19:45] so we're up [19:45] what happens now? [19:47] we trip an initial event, say startup. [19:47] this triggers a whole bunch of states not relevant to this example. [19:47] perhaps [19:47] though that event is not referenced in your above example [19:47] so let's ignore it [19:48] ok. [19:48] upstart has started, it has parsed its configuration, what happens next? [19:49] it triggers some state which wants setroubleshootd [19:49] setroubleshootd in turn wants selinux [19:49] selinux was enabled with setenforce, but this happened in initrd, so we don't know [19:49] this being a fresh boot, the state is indeterminate, so we run test-by [19:50] getenforce tells us selinux is up. we clear that dependency for selinux' [19:50] can-exec is never triggered by anything but the test-by. [19:50] so we run the test stanza there [19:51] it tells us we are allowed to execute /usr/sbin/selinux. [19:51] */usr/bin/setroubleshoot [19:52] we bring the state tentatively up, and tell the service manager to run /usr/bin/setroubleshoot [19:52] it returns a service handle, which we add to our parameters, and come all the way up [19:54] this triggers a netsplit [20:11] wb [20:11] this triggers a whole bunch of states not relevant to this example. [20:11] so let's ignore them [20:11] your example is all that interests me [20:11] and it is self-contained [20:11] it makes no reference to other events, or other states [20:11] upstart has started, it has parsed its configuration, what happens next? [20:11] -- [20:11] that's as far as things got before the split [20:16] Keybuk: ok, what'd we collectively miss? === sadmac_ is now known as sadmac [20:18] wb [20:18] this triggers a whole bunch of states not relevant to this example. [20:18] so let's ignore them [20:18] your example is all that interests me [20:18] and it is self-contained [20:18] it makes no reference to other events, or other states [20:18] upstart has started, it has parsed its configuration, what happens next? [20:18] -- [20:18] that's as far as things got before the split [20:18] --> sadmac_ (n=sadmac@nat/redhat/x-6753e36432a1150f) has joined #upstart [20:20] Keybuk: ok, well, we need one more state: running_normal [20:20] Keybuk: it has lots and lots and lots of deps. one of them is setroubleshoot [20:21] a goal state [20:21] if you so please [20:21] one that lists the services that should be running in normal configuration? [20:21] yes [20:21] I consider this a failure [20:22] if we're going to have goals, let's just use initng [20:22] umm, what? [20:22] why? [20:23] the reasons I wrote Upstart, instead of just modifying something that already exists, is that I expressly did not want goals, runlevels, or anything similar [20:23] it's the _only_ difference between Upstart and those other systems [20:23] Keybuk: and its the _most_ requested feature I get from people [20:23] then those people should use initng or launchd or smf [20:23] Keybuk: the advantage here is 1) goals aren't mutualy exclusive [20:23] they aren't mutually exclusive in initng either [20:24] 2) goals are named, and there are infinitely many [20:24] they are named in initng [20:24] 3) they can be expressed in terms of each other [20:24] goals in initng can depend on each other [20:24] Keybuk: ok, how do I start a predefined subset of my usual services from the command line? [20:24] in initng? ngc start wibble I think [20:25] it's been a while since I played with it [20:25] in upstart [20:26] in my plan for Upstart ? [20:26] yes [20:26] start my-predefined-subset-of-my-usual-services [20:26] which is a file that looks something like: [20:26] while service1 and service2 and service3 [20:26] a goal state [20:26] you can also just do: [20:26] start service1 [20:26] start service2 [20:26] start service3 [20:26] and that has the same effect [20:26] no, it's not a goal [20:26] a set of goal states [20:27] yes it is [20:27] no, it really isn't [20:27] why not? [20:28] let's put this discussion on abeyance for a moment [20:28] and go back to your example [20:28] setroubleshootd [20:28] when selinux [20:28] when can-exec("/usr/bin/selinux") [20:28] exec /usr/bin/selinux [20:28] can-exec test-by [ -x %1 ] [20:28] selinux [20:28] test-by getenforce [20:28] when (setenforce(1)..setenforce(0)) [20:28] that is what you defined [20:28] and upstart has started, has parsed its configuration, and is now waiting [20:28] what happens next? [20:29] it knows its supposed to start running_normal (from other configuration, kernel cmdline, your pick) [20:29] and so it does, and it depsolves it as it starts it [20:29] running_normal isn't defined above [20:29] so please, again, do not reference anything outside your example [20:29] I defined it as I came in [20:29] in syntax.. [20:30] running_normal: [20:30] when setroubleshoot [20:30] ok [20:30] when [20:30] upstart is waiting [20:30] what tells it to start "running_normal"? [20:30] what tells it to start "setroubleshootd"? [20:30] what tells it to start "selinux?" [20:31] upstart's first action on running is always to start some kind of "strap state" which in our case is configured (one way or another) as running_normal [20:31] ok [20:31] that is what I call a "goal" [20:31] it does a solve-and-start on the strap state [20:31] goal, strap state, runlevel, etc. [20:31] ok [20:31] upstart has a predefined state it tries to reach [20:31] I'm not disputing its a goal [20:31] this state is defined as a series of dependencies [20:32] to reach it, it solves the dependency set, starting each service in term [20:32] perhaps applying some kind of ordering to that [20:32] congratulations, you've designed a dependency-based init daemon [20:32] http://initng.org/ - enjoy ;P [20:32] Keybuk: what of this strategy are you escaping with upstart? [20:33] Upstart, in its very original definition, is an event-based system [20:33] not a dependency-based system [20:33] which is broken [20:33] from the very first document I wrote on the subject, I outlined this as the distinction between Upstart and what else exists out there today [20:34] if that is broken, then Upstart is a failed project and should be abandoned [20:34] our efforts would be better spent on the pre-existing dependency based init daemons [20:34] what are we changing then? [20:34] (if you consider that not broken) [20:34] what does your plan do that is not a goal? [20:35] if you truly believe that Upstart, as an event-based init daemon, is broken [20:35] and you believe that a dependency-based init daemon works, then you should look into one of the dependency-based daemons [20:35] initng is the prime example here [20:35] if the licence isn't a problem, SMF might be appealing - though it isn't as flexible [20:35] ok [20:36] but how is an event based init daemon /that solves the problems in 0.5/ still different? [20:38] the difference between the two can be defined quite simply [20:38] a dependency-based init daemon knows where it's going, and figures out how to get there [20:38] an event-based init daemon has no idea, and just does whatever it can [20:39] ok, I see your problem. let me adjust my example [20:39] to setroubleshoot add: [20:39] when running_normal [20:39] auto [20:40] (the auto is an artifact of the present syntax. It can be massaged out) [20:40] and delete running_normal's definition altogether [20:40] same result [20:40] actually, that's better [20:40] now there's no depsolving in standard boot [20:40] so let's go back to the same worked example [20:41] upstart has parsed its configuration [20:41] what does it do next? [20:41] well, it marks running_normal as up, by config. This is now just a marker though. It has no deps [20:42] a ground state? [20:42] ie. replace startup with a state? [20:42] yes [20:42] (would just "on startup" not be a valid example there?) [20:43] ok. I think in the long run this way is better for a few reasons, but sure. [20:43] running_normal on startup [20:43] that fulfills one of setroubleshootd's when clauses [20:43] but not the other [20:43] sorry, not the other TWO [20:44] it has a dep on the can-exec("/usr/sbin/selinux") state [20:44] and the selinux state itself [20:44] and it doesn't /trigger/ it, let's go into that for a second and then we'll look at those [20:44] so running normal comes up. [20:45] as upstart finishes doing this, it adds an event to the event queue: trigger-auto-services [20:45] this causes setroubleshootd to be brought into question [20:46] upstart iterates through setroubleshootd's deps. theres running_normal. that's satisfied. [20:46] there's can_exec. upstart looks at the can_exec state and sees that it is undetermined and has a test_by [20:47] it runs the test by and finds that /usr/bin/setroubleshootd is accessible [20:47] so can_exec is up [20:47] note that it does not /come/ up [20:47] it /is/ up [20:47] upstart just didn't know it before :) [20:47] selinux is much the same way. its test_by is run and it is determined to be up. [20:48] for the sake of argument [20:48] setroubleshootd's when's now satisfied, it leaps upward [20:48] let's say that selinux is not up [20:48] the test-by fails [20:48] test-by fails, selinux remains undetermined, and no setroubleshootd [20:49] /now/ [20:49] suppose we added this line to our config [20:49] no [20:49] no changing things [20:49] setroubleshootd didn't come up on boot [20:49] fine [20:50] the sysadmin notices that, and realises that selinux wasn't enabled [20:50] and enables selinux [20:50] what happens now? [20:50] nothing [20:50] no [20:51] selinux had 2 lines of config [20:51] nothing tells your system to re-evaluate its test-by clauses [20:51] look at number 2 [20:51] and let me elaborate [20:51] when (setenforce(1)..setenforce(0)) [20:51] the sysadmin brings up selinux [20:51] you didn't define setenforce in your example, so I ignored it [20:53] you didn't mention this hypothetical appendix in your example [20:53] err [20:53] so I didn't elaborate on the mechanisms that would make that case work [20:53] the whole point of working an example is to find out what happens ;) [20:53] no, I /know/ what happens [20:53] that means working through all the cases [20:53] the point is to tell you [20:54] ok, we'll define setenforce [20:54] setenforce, through whatever syntax is defined on inotify noticing a change in /selinux/enforcing [20:54] (yes, said file supports inotify) [20:55] it is emitted with one argument: the contents of that file. [20:56] * sadmac needs selinux auto [20:56] yeah, I'll work on getting the auto thing out of the syntax [20:56] its kinda a pain [20:57] so the sysadmin changes enforcing, and this satisfies selinux's one and only when clause [20:58] from here there's a couple things it could do, and I'm flexible as to which: [20:58] we could re-run the test-by to be sure (not certain I like that) [20:58] this is my fundamental issue with test-by [20:59] you have to re-run it periodically [20:59] or, and this is my assumption, we simply jump right up. once up, if we are configured with a debug flag, we run the test clause, and if it disagrees with what we just did, we through -EDUMBASS [20:59] Keybuk: but we've run it exactly 2 times now, both times deterministically [21:00] no interval timer yet [21:00] Keybuk: the other thing is even if its unreliable it can still be useful in some form. for example [21:00] mount(type: nfs, host: *) [21:00] when network-up(%host) [21:01] network-up test-by ping %host [21:01] even the ingrained unreliabilities there are better than we could do otherwise. [21:02] when it fails due to insufficient repitition the mount just takes longer to timeout [21:02] when it works though we have a bit more verification and probably a quicker abort, [21:08] to be fair, I should give how I'd do it [21:08] I'm not familar with selinux, but judging above the above [21:08] selinux would look like: [21:08] pre-start exec getenforce || setenforce [21:08] post-stop exec setenforce 0 [21:09] -- [21:09] setroubleshootd would look like: [21:09] while selinux [21:09] exec /usr/sbin/selinux [21:09] the worked example would be [21:09] upstart parses its configuration [21:09] the selinux job has no while condition, so can be immediately started [21:09] if selinux was enabled already, getenforce would succeed so the state would be up [21:10] if selinux was not enabled already, getenforce would fail, so setenforce is run and the state would be up [21:10] (it setenforce failed, then selinux would be down) [21:10] selinux coming up fulfills the while condition for setroubleshootd [21:10] so that would exec /usr/sbin/selinux and come up [21:10] what if sbin isn't mounted [21:11] no need for any startup event or ground state, etc. [21:11] you mean /usr ;-) [21:11] Keybuk: you've known saner storage admins than me I gues [21:11] s [21:11] :P [21:11] /sbin cannot be on a separate filesystem [21:11] it contains init [21:12] anyway [21:12] now, the above has a slight disadvantage in that it requires you to not use setenforce directly, but instead use "stop selinux" or "start selinux" as the commands [21:12] that in of itself isn't insane, but it's maybe annoying to experienced sysadmins [21:12] I'd solve that the same way you would [21:12] redefine selinux in terms of the contents of /selinux/enforcing [21:13] that might be something like [21:13] while file-contains /selinux/enforcing 1 [21:13] where file-contains was a built-in that used inotify [21:13] you've mostly talked me out of test-by [21:15] barring that then, what else is different between the mechanisms? [21:16] syntax is somewhat an artifact and somewhat not. I don't care about the syntax but the differences in mine are an artifact of it doing things yours doesn't [21:16] the fact that everything my way is first class [21:16] and it's massively simpler to understand [21:17] not really [21:17] I'll go back to what I said months ago [21:17] when I figured it out [21:17] foo(bar: baz) == all foos with bar = baz have these properties: [21:17] yours can be summed up as [21:17] : [21:17] ie. when the state on the left is true, the actions on the right are performed [21:18] no [21:18] that's very wrong [21:18] because there are no actions [21:18] that's how you defined it yourself not so long ago ;) [21:18] its declarative, and its backward [21:18] oh, no [21:18] sorry [21:18] : [21:18] the state on the left is true, while all of the tests on the right are true [21:18] I wouldn't go with that either [21:18] confusing it with something else I was thinking of [21:18] : [21:19] the state[s!] on the left behave in the manner described on the right [21:20] my model never talks about one state [21:20] it always talks about sets of them [21:21] mounted(type: nfs, mountpoint: /) is a subset of mounted(type: nfs) is a subset of mounted() [21:22] if you want a model for it, its awk [21:22] pattern: transformation [21:38] Keybuk: if you put filename: at the top of all your files, how does yours behave differently than mine? [21:38] serious question. [21:38] probably in terms of such things as instancing [21:39] yeah. that is it [21:40] not to mention arguments, which your system fundamentally relies on [21:47] Keybuk: what'd I miss? last thing I saw was last thing I said to you [21:47] not to mention arguments, which your system fundamentally relies on === sadmac_ is now known as sadmac [21:47] Keybuk: you don't have any arguments at all? [21:51] let me describe things as I see them [21:52] you define in files, or over D-Bus, services, tasks, states and other objects you would like Upstart to control [21:52] as far as Upstart is concerned, these are all just different names for the same thing [21:52] ok [21:52] let's call them Objects for now [21:53] (to avoid any inference of behaviour from previous versions) [21:53] same so far. except I don't give them different names [21:53] Objects have three basic attributes [21:53] - the condition in which they may be running [21:53] - an activation which starts them [21:53] - and what to do [21:54] a fun fictional example that uses all three [21:54] while apache2 [21:54] on control-alt-delete [21:54] exec echo "don't kill my web server" | wall [21:54] ok [21:55] if an object has no condition, then it may be running at all times [21:55] if an object has no activation, it will be activated as soon as the condition is true [21:55] if an object has nothing to do, it is simply a state [21:55] while apache2 [21:55] is valid, except exceedingly pointless [21:55] on control-alt-delete [21:55] exec shutdown -r now [21:56] is valid, it may be run at any time when control-alt-delete is pressed [21:56] exec /sbin/udevd [21:56] is valid, it defines a service that should always be running [21:57] ok so far? [21:57] yes [21:57] ok, great [21:57] Objects are just definitions [21:58] Instances are the important thing [21:58] when an Object is running, what we really mean is "there is an Instance of Object" [21:58] when an Object is not running, what we really mean is "there are no Instances of Object" [21:59] when I start apache2, I am not starting the apache2 Object, I am creating an Instance of the apache2 Object and starting that instance [21:59] (not quite true actually, but the definition suffices for now) [22:00] ok [22:00] it would be more truthful to say that you start and stop an Instance of the apache2 Object - you don't create it [22:01] Objects reference each other in their matches [22:02] if an Instance of an Object is created, then an Instance of all Objects that reference it are created as well [22:03] that's a very complicated way of saying something very simple [22:03] you can have as many copies of apache2 running as you like [22:03] and for each copy of apache2 that you run, you will get a second copy of everything that depends on apache2 as well [22:03] what if you try to run something that depends on apache2 after that? [22:04] Upstart only exposes *Instances* [22:04] if there is something defined that depends on apache2, you will see two copies of it in the list [22:04] so you'd inherently be picking which one you want to run (or probably both) [22:05] and Upstart knows which apache2 instance each is linked to [22:05] Instances have two additional attributes over Objects [22:06] - state (up or down) [22:06] - environment/properties (FOO=BAR) [22:06] an Instance's environment is taken from the exported list of environment of Instances that created it - and optionally the sysadmin's own start command [22:07] how do you prevent the rooting problem? [22:07] "the rooting problem" ? [22:07] ok, so you have fooservice which depends on barservice [22:07] err [22:08] no I don't [22:08] I can have fooservice which includes barservice in its condition [22:08] ok then [22:08] I *very* explicitly avoided the term "depends on" [22:08] fooservice is conditional on barservice? :p [22:08] 17:03 < Keybuk> and for each copy of apache2 that you run, you will get a second copy of everything that depends on apache2 as well [22:08] depends on [22:08] gotcha! [22:08] oh, damn [22:08] :p [22:08] got me [22:09] I'm trying very hard not to call them jobs :p [22:09] anyway [22:09] the rooting problem [22:09] fooservice has while barservice in it [22:09] ok, so you have 2 copies of fooservice, and 2 copies of barservice (instances rather [22:10] right [22:10] now bazservice comes along, and it has when fooservice, and when barservice [22:10] how come you don't get 4 copies of it? [22:10] ok [22:11] I'll talk this one through forwards [22:11] we have a barservice Object [22:11] we have a fooservice Object [22:11] we have a bazservice Object [22:11] fooservice links to barservice [22:11] bazservice links to fooservice and barservice [22:12] right? [22:12] we create an instance of barservice [22:12] k [22:12] let's call it bar1 [22:12] this tracks back its links [22:12] fooservice has a link, so we get a new instance "foo1" that links to bar1 [22:13] bazservice has a link to fooservice, so we get a new instance "baz1" that links to "foo1" that links to "bar1" [22:13] bazservice has a link to barservice, but there's already the baz1->bar1 instance [22:13] so no instance needs to be created [22:13] what ensures that order [22:13] let's create the second instance the other way [22:13] we create an instance of barservice "bar2" [22:14] suppose we evaluate "bazservice has a link to barservice" first? [22:14] bazservice has a link to barservice, but its condition on fooservice is not yet met, so no instance is created [22:15] fooservice has a link, so we get a new instance "foo2" that links to "bar2" [22:15] bazservice has a link to fooservice, so we get a new instance "baz2" that links to "foo2" that links to "bar2" [22:15] ok, swap those last two: [22:15] you can't swap the last two [22:15] it's a tree [22:16] a -> b -> c [22:16] we have foo1, bar1, foo2, bar2 [22:16] -> c [22:16] we go to evaluate bazservice: [22:16] we don't "go to" do anything, we follow trees [22:16] what's to keep bazservice from grabbing bar1, then foo2 [22:16] we have a tree [22:16] oh, I get it now [22:17] a -> b -> c [22:17] -> c [22:17] but the deps aren't necessarily a tree [22:17] in fact they aren't now [22:17] there are two valid ways to iterate that [22:17] a, b, c, c [22:17] or a, c, b, c [22:17] either way, c always ends up last ;) [22:17] they damned well are trees [22:17] ok, so consider only one foo1 and one bar1 [22:17] cut the 2s [22:17] ok [22:18] you have [22:18] so we have foo1->bar1, baz1->foo1, baz1->bar1 [22:18] bar1 [22:18] triangle [22:18] foo1->bar1 [22:18] baz1->foo1,bar1 [22:18] that's triangular [22:18] thats not a tree [22:18] no it's not? [22:19] draw it [22:19] a -> b -> c [22:19] -> c [22:19] that's a tree [22:19] I can do it the other way too [22:19] those 2 cs are the same node [22:19] c -> b -> a [22:19] b -> a [22:19] a [22:19] that's still a tree [22:19] just a baobab ;P [22:19] no, it has a cycle [22:20] sure [22:20] it's a bit of a twisty tree ;) [22:20] but it's still a tree [22:20] its not a tree [22:20] its a directed graph [22:21] (actually it is a digraph because foo could depend on baz) [22:21] but we're not considering that case here :p [22:21] digraph is short for directed [22:21] I know [22:21] if you can start at any node and get to another by more than one route without backtracking its not a tree [22:22] exxxxcept [22:22] that the only way to iterate it is as a tree [22:22] it's self-breaking [22:22] so while the mesh of objects is a digraph [22:22] the mesh of instances is a tree [22:22] actually, it's more of a bag than anything else, but hey :p [22:22] so it has an MST [22:22] that just makes it a graph [22:22] and well connected [22:23] so now we're finished arguing about terminology, you can see that it works? :p [22:23] more or less [22:23] go on [22:23] well, that's it really [22:24] ok [22:24] mine actually doesn't have states the more I think about it. [22:24] I keep wanting to call them that, but they're not [22:24] you can never end up with four copies of baz because the instances ref-count each other [22:24] you'd have two instances ref-counting the same instance [22:24] and that's not allowed by model [22:25] oh, one more thing [22:25] you can avoid inheriting instances [22:25] so you only get one instance no matter how many instances of your parent there are [22:25] but in that case, you don't get any environment from them [22:26] any [22:27] a good example to all of the above is a D-Bus interface to Bind9 (replacing rndc?) [22:27] right [22:27] while dbus and bind9 [22:27] exec /usr/sbin/bind9dbd [22:27] you get a copy for each dbus bus daemon you run and each bind9 bus daemon you run [22:27] interconnecting each of them [22:28] (dbus exports the session bus address, assumedly bind9 exports the socket address) [22:28] if you had another service that depended on that and dbus [22:28] while bind9dbd and dbus [22:29] you get a copy for each bind9dbd [22:29] connected to that dbus daemon [22:29] it doesn't multiply [22:29] in fact, in many cases, it gives you fewer than you might actually expect, but usually the number you need [22:30] err, sorry, you get a copy for each dbus connected to a bind9dbd on that dbus daemon [22:30] had that backwards [22:30] sounds ok [22:31] its actually more complicated than mine XD [22:31] it's far simpler to describe though [22:31] without technical terms [22:32] Keybuk: most of the difficulty is I've been insistent on calling them states and dealing with it in this way [22:32] To define your DNS service, create a file /etc/init/bind9 and in that put "exec /usr/sbin/bind9" [22:32] Keybuk: I think I can explain it now [22:32] if that DNS service may only be running during certain times, add "while blah and blah or blah" to that file [22:34] Keybuk: so you have a computer on/under your desk, right? [22:34] yes [22:35] now, there's a lot of things you could say about this computer. "Its fast" (kind of subjective) "Its purple" (maybe maybe not) etc. [22:35] my "state machine" manages statements like this [22:35] when you configure it, you tell it what can and cannot be true. It then reads events and works out what is true. [22:36] "Apache is running" implies that "The harddisk is mounted" [22:36] how do I run apache when the harddisk isn't mounted? [22:37] "Apache is running" implies that "The harddisk is not mounted" [22:37] now obviously this is too verbose, so we allow shorthand [22:37] no [22:37] I mean [22:38] I'm a sysadmin [22:38] apache when not disk [22:38] I have booted, and the hard disk failed to mount [22:38] but I need to start apache [22:38] the example is contrived [22:38] hardly [22:38] no I mean perhaps the rule is bad [22:38] replace apache with any other service that might normally be only running in a full multi-user condition but for which I might need [22:38] here's a good one [22:39] syslog [22:39] I often need to start that one when debugging [22:39] your system *only* permits you to do the things the daemon allows [22:39] there's no separation [22:39] Keybuk: my system is necessarily equivalent to yours [22:39] its second order logic. you can define all of computing with it [22:40] unless yours isn't a piece of software... [22:40] well, use my example then [22:40] unless I'm mistaken, in order to have two dbus daemons, I would need to define two different dbus daemons [22:40] no [22:41] well, that's getting ahead actually [22:41] well, dbus with two different possible arguments [22:41] ok, that's true [22:41] the point being, the person who wrote the dbus service has to allow, up front, the sysadmin to have multiple copies of it [22:42] it's kinda like the 0.5 instance model [22:42] the service has to define the limits of instantiation [22:42] why do you need 2 identical copies of the same service? [22:42] chroot [22:42] namespace [22:42] 2 /identical/ copies [22:42] no, you're missing my point [22:43] your system requires that the service define the ways in which they may be different [22:43] yes [22:43] with the exception that they propagate their arguments [22:43] if you want to allow dbus to be run on different bus addresses, the service has to, up-front, accept an argument to allow that [22:43] (this is a recent change) [22:43] so different deps yields a different service [22:43] if you want to allow dbus to be run in different chroots, the service has to, up-front, accept an argument to allow that [22:44] it all has to be up-front designed [22:44] Keybuk: watch closely. this isn't far from possible: [22:44] *(*): when namespace [22:45] use the chroot example? [22:45] dbus: exec /usr/bin/dbus-daemon | us_set %bus_id [22:45] *(%chroot): chroot %chroot ? [22:45] everything takes a chroot argument that specifies its chroot? [22:45] Keybuk: propagation has been made automatic now [22:45] so no %s [22:46] ok [22:46] so the dbus example [22:46] the bus_id is actually set by starting dbus [22:46] right [22:47] you can see in the script how it works [22:47] 17:45 < sadmac> dbus: exec /usr/bin/dbus-daemon | us_set %bus_id [22:47] how do you create a second one? [22:47] Keybuk: if you say start dbus, you get dbus(bus_id: deadbeef) [22:48] if you say it again you get dbus(bus_id: feedface) [22:48] so if I say start bind9, but there's a bind9 running [22:48] how does that *not* create another bind9? [22:48] because bind9's script doesn't set any variables inside of it [22:49] so it has to parse its own exec/script stuff to figure out whether it might set any variables? [22:49] what happens if that just looks like: [22:49] script [22:49] Keybuk: it doesn't have to know ahead of time [22:49] echo < FOO [22:49] you might want to use us_set %bus_id [22:49] FOO [22:49] end script [22:49] yes it does [22:49] nope [22:49] it has to know *before* it starts bind9! [22:49] no it doesn't [22:49] it doesn't know that it shouldn't start another dbus-daemon until it's started it [22:49] because it doesn't know what the value of that variable is until it's read the output [22:50] therefore it cannot know *not* to start bind9 either [22:50] Keybuk: but it knows the first time a variable was set [22:50] no it doesn't [22:50] yes it does [22:50] Keybuk: it attempted to start dbus(*) [22:50] Keybuk: only dbus(bus_id: deadbeef) came up [22:51] Keybuk: another (infinity-1) services didn't launch [22:51] its worth trying again to launch one of them [22:54] foo(bar: baz) is a statement. A sentence [22:55] It reads "any thing foo such that bar = baz is true" [22:55] if you also say foo [22:55] it reads "any thing foo is true" [22:55] if the second is true, the first must be by definition [22:55] so if foo() is up, then foo(bar: baz) is up by definition, but the converse is /not/ true [22:58] so for your bind9 example [22:58] the first one starts bind9() [22:59] the second one can't hope to start bind9(foo: bar), bind9(chicken: never), bind9(wibble: wobble) because these are /already true conditions/ [22:59] Keybuk: with me? [23:13] yeah [23:13] I still say your state machine is insanely complicated [23:13] I prefer mine [23:22] its logic [23:22] its not hard [23:23] plus the last 3 ways you got it wrong all would have yielded correct configuration files in most situations :D [23:23] In a way I agree that its complicated, but I think the user has to understand it less completely [23:23] most guesses will result in you operating it correctly [23:24] plus implementing it is really nice