|
47 | 47 | - `Castle.unpack/1` and `Castle.install/1` now refuse a system that cannot be |
48 | 48 | upgraded from, and refuse it in the same call that would otherwise have done |
49 | 49 | the work. `:release_handler` reads `releases/RELEASES` once, as it starts, and |
50 | | - when the file is not there it makes a release record up out of the boot |
51 | | - script's name and version — a record that names no applications at all. |
| 50 | + when it cannot — the file absent, or there but not consultable — it makes a |
| 51 | + release record up out of the boot script's name and version — a record that |
| 52 | + names no applications at all. |
52 | 53 | Upgrading a system in that state is worse than being stopped: the install |
53 | 54 | reports success, and every application whose version changed but whose code the |
54 | 55 | upgrade does not explicitly load goes on running its old code out of the |
55 | 56 | directory of the release that was just replaced, until a later `remove` deletes |
56 | 57 | it. Nothing can repair the running system afterwards, because creating the file |
57 | | - changes no record the node holds — so what the refusal says is to restart, |
58 | | - which is the one thing that does: the release creates the file before it |
59 | | - starts. |
| 58 | + changes no record the node holds — so what the refusal says is to restart, with |
| 59 | + the file either absent or consultable first. See *Fixed* below for what that |
| 60 | + condition is and why a bare restart is not always enough. |
60 | 61 |
|
61 | 62 | The question is asked of the node's own records rather than of the filesystem, |
62 | 63 | which is the only way to see the case where the file exists but the boot that |
|
70 | 71 | operation that *writes* release records: an unpack on such a node would put the |
71 | 72 | made-up record into `releases/RELEASES`, where the next boot would read it back |
72 | 73 | as though it belonged there — which takes away the restart that is the way out, |
73 | | - since the file is only created when it is missing. Committing and removing are |
| 74 | + since the file is only created when it is absent. Committing and removing are |
74 | 75 | unaffected: neither can write that record back, and refusing them could strand |
75 | 76 | a version that was already installed. |
76 | 77 | - `Castle.upgradable/0`, which answers the same question on its own, for an |
|
152 | 153 |
|
153 | 154 | - The refusal for a system running from a synthesised release record now names a |
154 | 155 | remedy that works. It said to restart, and a restart alone is enough only when |
155 | | - the `RELEASES` file `:release_handler` reads is absent or readable: the release |
156 | | - creates that file when it is missing, so one that is present but unreadable is |
157 | | - stepped over on every start and the system comes back on another synthesised |
158 | | - record. An operator following the old message would have restarted |
| 156 | + the `RELEASES` file `:release_handler` reads is absent or consultable: it reads |
| 157 | + that file with `file:consult/1`, so a malformed one fails just as an unreadable |
| 158 | + one does, and the release creates the file only when it is *absent* — so |
| 159 | + anything left in place that cannot be consulted is stepped over on every start |
| 160 | + and the system comes back on another synthesised record. An operator following the old message would have restarted |
159 | 161 | indefinitely. |
160 | 162 |
|
161 | | - The refusal now asks for that file to be absent or readable before the restart, |
| 163 | + The refusal now asks for that file to be absent or consultable before the restart, |
162 | 164 | and identifies it rather than assuming: `releases/RELEASES` under the release |
163 | 165 | root, unless `RELDIR` or the `sasl` `releases_dir` parameter points elsewhere. |
164 | 166 | Where one of those does, the two are different files and a restart cannot fix it |
|
0 commit comments