In CrOS, we do something similar. We have three "boot phase" jobs that most other jobs are started and stopped by. They are:<div><br></div><div> startup (distinct from the event)</div><div> boot-services</div><div>
system-services</div><div><br></div><div>They are chained together thus:</div><div><br></div><div> startup: start on startup (this has a main process that carries out jobs similar to mountall)</div><div> boot-services: start on stopped startup</div>
<div> system-services: start on started boot-services</div><div><br></div><div>boot-services and system-services stay running until shutdown.</div><div><br></div><div>Other jobs then use:</div><div><br></div><div> start on starting startup</div>
<div><br></div><div> start on starting boot-services</div><div> stop on stopping boot-services</div><div><br></div><div> start on starting system-services</div><div> stop on stopping system-services</div><div><br></div>
<div>The use of "ing" here is important; it means that "started boot-services" means that all boot-services have started (since the starting event blocks for them). So system-services happen entirely after boot-services (UI is a boot service for us).</div>
<div><br></div><div>Scott<br><br><div class="gmail_quote">On Tue, Jun 7, 2011 at 7:00 AM, James Hunt <span dir="ltr"><<a href="mailto:james.hunt@ubuntu.com">james.hunt@ubuntu.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Hi All,<br>
<br>
This mail turned into rather an epic in the writing. The summary is I'm<br>
interested in thoughts on the two implementation options for "Proposal 2".<br>
<br>
Regards,<br>
<br>
James.<br>
<br>
<br>
= Overview =<br>
<br>
For a while Clint and I have thought it would make sense to introduce<br>
some "helper" events and jobs. The idea here being to:<br>
<br>
- Simplify existing .conf files.<br>
- Make it easier / speed up writing new .conf files.<br>
- Aid in understanding .conf files.<br>
<br>
The idea was discussed at UDS-O ([1]+[2]) and there were no fundamental issues<br>
raised so the plan is to introduce them for Oneiric.<br>
<br>
This mail explains the problem we're trying to address along with 2<br>
possible implementations.<br>
<br>
Let's start by describing the problem...<br>
<br>
= Problem Examples =<br>
<br>
== Example 1: plymouth.conf ==<br>
<br>
The first example is taken from /etc/init/plymouth.conf:<br>
<br>
start on (starting mountall<br>
or (runlevel [016]<br>
and (stopped gdm<br>
or stopped kdm<br>
or stopped xdm<br>
or stopped lxdm<br>
or stopped lightdm<br>
or stopped uxlaunch)))<br>
<br>
=== Observations ===<br>
<br>
1) Overly complex "start on" condition.<br>
- Indicative of refactoring requirement.<br>
(since a rule of thumb is that most jobs should only<br>
require ~3-4 events).<br>
- Difficult to understand.<br>
- Difficult to modify without breaking behaviour.<br>
<br>
2) Cryptic runlevel condition.<br>
<br>
3) Hard-coded list of Display Managers.<br>
<br>
Bad since:<br>
<br>
- Results in inability to handle new Display Managers efficiently.<br>
- Promotes "cut-and-paste hell" (where the same bugs are pasted into<br>
other .conf files and the problem is propagated, thus making it<br>
more time-consuming to fix).<br>
<br>
== Example 2: gdm.conf ==<br>
<br>
Here is the upcoming /etc/init/gdm.conf:<br>
<br>
start on ((filesystem<br>
and (runlevel [!06]<br>
and (started dbus<br>
and (drm-device-added card0 PRIMARY_DEVICE_FOR_DISPLAY=1<br>
or (graphics-device-added PRIMARY_DEVICE_FOR_DISPLAY=1<br>
or stopped udevtrigger)))))<br>
or runlevel PREVLEVEL=S)<br>
<br>
=== Observations ===<br>
<br>
1) WT^H^H Errr... what?<br>
<br>
You may be forgiven for dropping your Rich Tea biscuit into your cuppa<br>
on seeing this for the first time (YMMV of course :)<br>
<br>
2) Why are there two lines which appear to represent the same thing<br>
(graphics device)?<br>
<br>
3) Thought: surely there must be a simpler way to represent this condition?<br>
<br>
4) Fragile.<br>
<br>
= The Problem(s) defined =<br>
<br>
- Too many job configuration files hard-code required *applications* for<br>
which there are multiple alternatives.<br>
<br>
What if you don't have that application installed? The Ubuntu archive<br>
is huge and there are often many alternatives for system components.<br>
So, by hard-coding applications, you risk breaking users who deviate<br>
from the defaults, resulting potentially in a bad experience.<br>
<br>
A level of abstraction would protect us from this problem.<br>
<br>
Job Configuration Files should instead specify the *services* they<br>
require.<br>
<br>
- Quite a few core Job Configuration Files have overly complex<br>
conditions which can be abstracted.<br>
<br>
- Cut-and-pasting of complex conditions has led to problems.<br>
We need to provide a way to avoid this sort of problem proliferating.<br>
<br>
= Proposals =<br>
<br>
== Proposal 1: Provide Event Aliases for Common Scenarios ==<br>
<br>
Create event aliases as shown below:<br>
<br>
|----------------+------------------|<br>
| Existing Event | Event Alias |<br>
|----------------+------------------|<br>
| runlevel 0 | halt |<br>
| runlevel 1 | single-user-mode |<br>
| runlevel S | single-user-mode |<br>
| runlevel 2 | multi-user-mode |<br>
| runlevel 6 | reboot |<br>
| runlevel [016] | shutdown |<br>
|----------------+------------------|<br>
<br>
== Proposal 2: Provide Abstract Jobs for Common Services ==<br>
<br>
|-----------------+-------------------------------------------------------------------|<br>
| Abstract Job | Description |<br>
|-----------------+-------------------------------------------------------------------|<br>
| display-manager | gdm, kdm, lightm, etc. |<br>
| network-manager | NetworkManager, wicd, connman, etc |<br>
| firewall | ufw alias. |<br>
| network | started when *all* configured network interfaces and bridges "up" |<br>
| graphics-card | starts when first graphics card added to system. |<br>
|-----------------+-------------------------------------------------------------------|<br>
<br>
=== Implementation ===<br>
<br>
There are two simple methods here we're considering.<br>
<br>
==== Option 1 ====<br>
<br>
Update every package that provides a service such that its Job<br>
Configuration File sets and exports a "well-known" variable. The<br>
proposed list of environment variables which represent these services<br>
is:<br>
<br>
DISPLAY_MANAGER<br>
FIREWALL<br>
GRAPHICS_CARD<br>
NETWORK<br>
NETWORK_MANAGER<br>
<br>
For example, each display manager package would be updated such that its<br>
.conf file specified:<br>
<br>
env DISPLAY_MANAGER=y<br>
export DISPLAY_MANAGER<br>
<br>
Then, any job that requires a display manager could say:<br>
<br>
start on starting DISPLAY_MANAGER=y<br>
<br>
===== Observations =====<br>
<br>
- This might *appear* to be inefficient in that Upstart must check every<br>
time *any* job starts to determine if DISPLAY_MANAGER=y is set in that<br>
jobs environment. However, there is no additional overhead beyond how<br>
Upstart currently works. Consider that...<br>
<br>
start on starting gdm<br>
<br>
... is actually an alias for:<br>
<br>
start on stating JOB=gdm<br>
<br>
- This would require *every* package that provides a service to be<br>
updated. Admittedly this would only need to be done once though.<br>
<br>
- Might be confusing since users you *must* specify "=y" exactly<br>
(dropping the "=y" won't work, and nor will specifying "=Y" (or "=1")).<br>
<br>
==== Option 2 ====<br>
<br>
Create a Job Configuration File that hard-codes the list of known<br>
service providers. For example for "display-manger", we could have:<br>
<br>
start on (starting gdm<br>
or (starting kdm<br>
or (starting lightdm<br>
or (starting lxdm<br>
or (starting slim<br>
or (starting wdm<br>
or starting xdm))))))<br>
<br>
stop on (stopping gdm<br>
or (stopping kdm<br>
or (stopping lightdm<br>
or (stopping lxdm<br>
or (stopping slim<br>
or (stopping wdm<br>
or stopping xdm))))))<br>
<br>
env ABSTRACT_JOB=y<br>
export ABSTRACT_JOB<br>
<br>
===== Observations =====<br>
<br>
- Since this is an Abstract Job, it will have no PID, but this job will<br>
"run" for the duration of the first display manager to be invoked.<br>
<br>
- We appear to have simply "moved the problem" since although we are no<br>
longer hard-coding the list of display managers in "plymouth.conf", we<br>
are hard-coding the list now in "display-manager.conf". However, we<br>
have gained by doing this since:<br>
<br>
- We have still created the level of abstraction desired.<br>
- We have contained the problem into a single file: we define the list<br>
of display managers *once*.<br>
- We don't need to update every Ubuntu (and potentially every Debian)<br>
package as would be required for "Option 1".<br>
- We *could* conceivably auto-generate "display-manager.conf" from the<br>
archive with a simple script which munged the output of:<br>
<br>
apt-cache search x-display-manager|awk '{print $1}'|sort<br>
<br>
- The "ABSTRACT_JOB" variable would allow other jobs to detect that a<br>
job was abstract (they shouldn't need to care, but just in case...)<br>
This also avoids the unwieldliness of "abstract-display-manager" (or<br>
even "abstract/display-manager" (were we to put the abstract jobs in<br>
/etc/init/abstract/ say).<br>
<br>
==== Personal Preference ====<br>
<br>
Although it looks rather ugly, my preference is currently for Option 2<br>
primarily since it would be quick and easy to modify the single source<br>
for each service. However, I could be persuaded otherwise :)<br>
<br>
= Rationale =<br>
<br>
By introducing Abstract Jobs and Event Alias "helpers", we can simplify<br>
the existing Job Configuration Files and make them more understandable.<br>
For example, the "start on" condition for "plymouth.conf" could become:<br>
<br>
start on (starting mountall<br>
or (shutdown and stopped display-manager))<br>
<br>
Similarly, "gdm.conf" could become the much simpler / easier to comprehend:<br>
<br>
start on (filesystem and (started dbus and graphics-device-available)<br>
stop on shutdown<br>
<br>
These changes may also incidentally minimise changes required by Ubuntu<br>
derivatives once the helpers become pervasive.<br>
<br>
= Documentation =<br>
<br>
We will of course ensure that all these helpers are documented appropriately and we plan to make<br>
maximum use of them to ease the work required for [2].<br>
<br>
-----<br>
<br>
[1] - <a href="https://blueprints.launchpad.net/ubuntu/+spec/foundations-o-upstart-convert-main-initd-to-jobs" target="_blank">https://blueprints.launchpad.net/ubuntu/+spec/foundations-o-upstart-convert-main-initd-to-jobs</a><br>
[2] - <a href="http://summit.ubuntu.com/uds-o/meeting/foundations-o-upstart-convert-main-initd-to-jobs/" target="_blank">http://summit.ubuntu.com/uds-o/meeting/foundations-o-upstart-convert-main-initd-to-jobs/</a><br>
<br>
<br>
--<br>
James Hunt<br>
<font color="#888888"><br>
--<br>
upstart-devel mailing list<br>
<a href="mailto:upstart-devel@lists.ubuntu.com">upstart-devel@lists.ubuntu.com</a><br>
Modify settings or unsubscribe at: <a href="https://lists.ubuntu.com/mailman/listinfo/upstart-devel" target="_blank">https://lists.ubuntu.com/mailman/listinfo/upstart-devel</a><br>
</font></blockquote></div><br></div>