<br><span style>forgot to cc' the list ml, added.</span><div><font color="#222222" face="arial, sans-serif"><br></font><div class="gmail_quote">On Mon, Jun 11, 2012 at 3:26 AM, roger peppe <span dir="ltr"><<a href="mailto:roger.peppe@canonical.com" target="_blank">roger.peppe@canonical.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">On 11 June 2012 01:11, Kapil Thangavelu <<a href="mailto:kapil.thangavelu@canonical.com">kapil.thangavelu@canonical.com</a>> wrote:<br>

><br>
> Looks good, a few questions on details embedded.<br>
<br>
</div>Thanks for the useful response.<br>
<div class="im"><br>
> On Fri, Jun 8, 2012 at 1:07 PM, roger peppe <<a href="mailto:roger.peppe@canonical.com">roger.peppe@canonical.com</a>><br>
> wrote:<br>
>><br>
>> We'd like to be able to upgrade a running juju with new software.<br>
>> This is a scheme I originally came up with for upgrading<br>
>> minor (database-compatible) versions, somewhat modifed after<br>
>> discussion with Gustavo:<br>
>><br>
>> Client:<br>
>>        - Push new version of tools.<br>
>>        - Set new global version number in state.<br>
>><br>
><br>
> what's the state path here of the version node?<br>
<br>
</div>/version ?<br></blockquote><div><br></div><div style>sounds reasonable.. i was thinking /environment/version </div><div class="im" style><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
</blockquote></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
>> Machine agent:<br>
>>        - Wait for global version to change.<br>
>>        - Download new version.<br>
>>        - Copy version to where the local agents can see it<br>
>><br>
>>        - Set new version in local agents' state.<br>
>>        - Point "current" symlink to new version<br>
>>        - Exit and let upstart start new version<br>
><br>
><br>
><br>
> Not all agents on a machine maybe running on the same fs, a unit agent in a<br>
> container may need to download its own release.<br>
<br>
</div>That's an interesting point. I had assumed that an outer container always<br>
has access to the fs of the contained items (LXC is essentially chroot<br>
+ sugar, right?)<br>
<br></blockquote><div><br></div><div><div style>your right, the machine agent should have access. some things to keep in mind though, it might be another volume though and its possible for a container to be a different architecture (albeit the latter is a minor concern).</div>
<div class="im" style></div></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
An alternative model would be to have all agents download the new<br>
tools independently<br>
(if that's the case, perhaps we shouldn't bundle them together, but have<br>
a separate URL for each agent/tool).<br>
<div class="im"><br>
> could you clarify what you mean by symlink?<br>
<br>
</div>The idea is that there's a symlink for each tool which points to the current<br>
version of the tool. A tool upgrades itself by atomically redirecting that<br>
symlink to the new version of itself (that way we don't need to rewrite<br>
the upstart file each time the version is changed).<br>
<div class="im"><br></div></blockquote><div><br></div><div><div style>so a failure on the new release, would also entail reverting this symlink?</div><div class="im" style></div></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">
> Which states are being recorded<br>
> in zk. ISTM, that we should have running versions, and proposed versions<br>
<br>
</div>+1. I sketched over this bit, but that was part of the plan.<br>
Then you can see in the state when agents have successfully<br>
upgraded.<br>
<div class="im"><br>
> and<br>
> proposed timestamp recorded for all agents, so we can detect deltas from<br>
> outside the context of a given agent.<br>
<br>
</div>I'm not sure what you mean by "proposed timestamp" here.<br></blockquote><div><br></div><div style>its hard to distinguish error from op in progress without explicitly tracking the operation state or failing that a timestamp to differentiate persistent errors.</div>
<div class="im" style></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
>> Other agent (provisioning or unit agent):<br>
>>        - Wait for agent's version to change.<br>
>>        - Point "current" symlink to new version<br>
>>        - Exit and let upstart start new version<br>
>><br>
>> I think we should be able to do better than this. The problem is with<br>
>> the "exit and let upstart start new version" step - that means that if<br>
>> we happen to upload a broken version, then everything instantly breaks<br>
>> and needs manually restoring.<br>
>> </div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
>> Here are some desirable features for an upgrade facility:<br>
>><br>
>>        1. Uploading a broken tool shouldn't break anything.<br>
>>        2. ... even for a short while.<br>
>>        3. We shouldn't rely too heavily on upstart, given the possiblity<br>
>>        of ports to systems without upstart.<br>
>><br>
><br>
> re 3. its better to classify the functional property of such a system.. it<br>
> sounds like your saying<br>
> that such other init systems might not have process management enough to<br>
> relaunch the agents if they die?<br>
<br>
</div>No, I assume that we'll have something that can automatically start<br>
an executable on reboot, and if the agent crashes unexpectedly.<br></blockquote><div><br></div><div style><br class="Apple-interchange-newline">old school init.d systems don't nesc restart automatically, their originial intention was boot. as a quick example.</div>
<div style><br></div><div style>$ sudo apt-get install redis-server</div><div style>$ sudo kill redis-server</div><div style>$ ps aux | grep redis-server</div><div style><br></div><div style>afaik, as far as auto restart, the common init like tools that support are upstart, daemontools, systemd, and inittab.</div>
<div class="im" style></div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
But I think it *might* be possible to use upstart events to do all<br>
the coordination between new and old versions - leveraging<br>
upstart in a deep way - and I think that would not be a good idea.<br></blockquote><div><br></div><div><div style>yeah, staying away from upstart implementation details for the high level design sounds good.</div><div style>
<div class="adm" style="margin:5px 0px"><div id="q_137dbf924182d44a_13" class="ajR h4" style="color:rgb(80,0,80);font-size:11px;background-color:rgb(241,241,241);border:1px solid rgb(221,221,221);clear:both;line-height:6px;outline:none;width:20px">
</div></div></div></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
>> Obviously point 1 is not entirely attainable - a tool can be broken in<br>
>> any number of subtle ways that are not quickly detectable.<br>
>><br>
>> However, if we each tool does a set of checks at startup time (checking<br>
>> the version in the zk database and other dependencies) then I think that<br>
>> the likelyhood of breakage can be drastically reduced.<br>
>><br>
><br>
> and it would then proceed with an upgrade if it detected a delta between<br>
> runtime and state version?<br>
<br>
</div>The upgrade would not proceed if the version was incompatible.<br>
<div><div class="h5"><br>
>> Here is a proposal for a scheme that addresses the above three points. It<br>
>> remains the same as the original scheme, with the exception instead of<br>
>> letting upstart start the agents directly, we interpose a intermediary,<br>
>> say "upgrader". This tool would be designed to be small, well verified<br>
>> and with minimal dependencies - designed to need upgrading very seldom.<br>
>><br>
>><br>
>> The final "exit and let upstart start new version" step is replaced with<br>
>> the following upgrade path.<br>
>><br>
>>        - The agent asks the upgrader to run a new version of the agent<br>
>>        by passing it the name of an executable and arguments.<br>
>><br>
>>        - The upgrader starts the new agent.<br>
>><br>
>>        - The new agent connects to the state, does whatever verification<br>
>>        is necessary, and notifies the upgrader that it has successfully<br>
>>        started (but doesn't actually *do* anything yet).<br>
>><br>
>>        - The upgrader notifies the original agent that the upgrade has<br>
>>        been successful.<br>
>><br>
>>        - The original agent shuts down, notifies the upgrader that it<br>
>>        has done so, and exits.<br>
>><br>
>>        - The upgrader notifies the new agent that it can continue,<br>
>>        picking up the work where the old agent stopped.<br>
>><br>
>> A particular advantage of this scheme is that an upgraded agent<br>
>> will cause no down time, even if the new agent hangs for a long<br>
>> time when starting.<br>
>><br>
>> If the agent exits without upgrading, then the upgrader tool<br>
>> will also exit, leaving upstart (or similar mechanism) to restart it;<br>
>> this provides a way to upgrade the upgrader itself.<br>
>><br>
>> One possible drawback is that the new and the old<br>
>> agent running side-by-side might be a problem in<br>
>> resource-constrained environments. I don't think this would<br>
>> be a problem in practice (most resources will probably be taken<br>
>> as the agent continues to run, rather than at initialisation time),<br>
>> and we can work around it if necessary, by having a way to<br>
>> tell the upgrader to run the programs sequentially, and<br>
>> back off to the previous version if the upgraded version fails.<br>
>><br>
>> I have a prototype of this proposal here (WIP, untested as yet):<br>
>><br>
>>        <a href="https://codereview.appspot.com/6307061" target="_blank">https://codereview.appspot.com/6307061</a><br>
>><br>
>> The upgrader in this implementation uses stdin and stdout to talk to<br>
>> its child processes;<br>
>> another mechanism could be substituted if desired.<br>
>><br>
>> Major Version Upgrades (sketch)<br>
>><br>
>> Major version (database) upgrades can fit into the above scheme by<br>
>> providing an additional synchronisation step. The client could give the<br>
>> global version a "pending" tag and wait for all agents to indicate that<br>
>> they are halted. Then it would upgrade the database, untag the version<br>
>> and let the upgrade proceed as usual.<br>
>><br>
><br>
> its not clear why you need a separate up-grader process, the two agent<br>
> processes can coordinate between each other so the new version can be<br>
> verified and the old one shutdown.<br>
<br>
</div></div>That was my original plan, but I realised that AFAICS that's not compatible<br>
with the way that upstart (and presumably other supervision systems) work,<br>
as when the old process exits, upstart will think that it's terminated and start<br>
a new instance, even though a new instance has already started.<br>
It was not my plan to eliminate the use of upstart completely.<br>
<br></blockquote><div><br></div><div><div style><br class="Apple-interchange-newline">its unclear how using an upgrader process gets around that. upstart/init sys still wants to track the new process pid. you could maybe go old style init with a /var/run/agent-name.pid, but then again</div>
<div style>having the new/old agents coordinating directly exactly replaces the upgrader process afaics. your introducing the third party for the purpose of coordination alone afaics.</div></div><div><br></div><div> </div>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Another potential (though currently unrealised) advantage of a separate<br>
upgrader process is that it might allow us to automatically rewind to a previous<br>
version if a new version starts failing for some reason after succeeding<br>
initially. That may well be a crackful idea however.<br>
<div class="im"><br></div></blockquote><div><br></div><div><br class="Apple-interchange-newline"><span style>the rewind should be possible till the new agent starts its activities, even after its possible even without the upgrader, (ie. i've restarted 10 times in 5m, revert to old release), that's dicey though. say you do a schema upgrade as part of the upgrade, reverting backwards is a hoser.</span></div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im">
> what happens when the new version of the agent fails to start? how is the<br>
> error handled/reported?<br>
<br>
</div>The error would be logged. It's possible we might want to store the most<br>
recent error in the state, so that a juju info can quickly see what agents have<br>
failed to upgrade.<br>
<div class="im"><br>
> you'll need a barrier and some actor(s) to take on a coordinator role for<br>
> the db upgrade.<br>
<br>
</div>I think my "pending" tagged version acts a barrier. I had indeed sketched over<br>
what component actually does the db upgrade, though I think that detail<br>
can be decided later - my aim in the "major version upgrade" section was<br>
merely to show in a hand-wavy kinda way that we can do major version<br>
upgrades without changing the basic upgrade mechanism.<br>
<br></blockquote><div><br></div><div><div style>sounds good, it should layer on top as additional coordination.</div><div style> </div><div style>cheers,</div><div style><br></div><div style>Kapil</div></div><div style><br>
</div></div></div>