We define the type for each config value, and validate the data when
retrieving and setting it.
Change-type: minor
Signed-off-by: Cameron Diver <cameron@balena.io>
Docker always returns ports in ascending order, so if they aren't
specified like that in the compose, a restart loop would occur. This
patch changes the port maps to be stored in ascending order, based on
an alphabetical sort of the internalStart port (not taking into account
the protocol). This is the same as how Docker returns them, so they will
match, regardless of input form.
Change-type: patch
Closes: #824
Signed-off-by: Cameron Diver <cameron@balena.io>
Also change the return format of ApplicationManager.getStatus(), which
does not conform to the above.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@balena.io>
Up to now, there was a slim but non-zero chance that an image would be downloaded between the call to `@getTarget` inside deviceState
(which gets the target state and creates Service objects using information from available images), and the call to
`@images.getAvailable` in ApplicationManager (which is used to determine whether we should keep waiting for a download or start the
service). If this race condition happened, then the ApplicationManager would infer that a service was ready to be started (because
the image appears as available), but would have incomplete information about the service because the image wasn't available when
the Service object was created. The result would be that the service would be started, and then immediately on the next applyTarget
the ApplicationManager would try to kill it and restart it to update it with the complete information from the image.
This patch changes this behavior by ensuring that all of the additional information about the current state, which includes available images,
is gathered *before* building the current and target states that we compare. This means that if the image is downloaded after the call to getAvailable, the Service might be constructed with all the information about the image, but it won't be started until the next pass, because ApplicationManager will treat it as still downloading.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
We also replace a createTableIfNotExists in the migrations with hasTable then createTable, to
avoid a warning message about it being not recommended.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
The move from pure CoffeeScript to TypeScript has brought a
few changes to the way transpiling happens. Previously, through
serendipity, the way `startIPAddressUpdate` was called worked
because of the binding convention pre-transpiling.
However, with the move to TypeScript, this has altered and
the assumption that a lack of parentheses would call the
method before supplying a callback into the returned function
is incorrect. The method must be specifically called first.
Connects-to: #836
Change-type: patch
Signed-off-by: Heds Simons <heds@balena.io>
When updating from old supervisors (<7.0.0), we've been so far using a fake id 1 for serviceId, imageId
and releaseId since these were not available in the old supervisor. This causes problems when the supervisor
tries to report these values to the API. Moreover, the app from the legacy supervisor has an image URL
that doesn't include the content hash - this causes the supervisor to believe the image is not really downloaded
and try to fetch it again.
To fix these issues, we add a request to the API when the supervisor starts up and detects that there's a legacy
app that needs to be normalised. We fetch the appropriate release, and use it to populate the resource ids
and the updated image URL.
This should avoid the unnecessary image download, and errors reporting target state after an update.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
Now you can either pass a serviceName or imageId to restart a specific
service, which is much easier from a device container.
Change-type: minor
Signed-off-by: Cameron Diver <cameron@balena.io>
The supervisor has been doing regular pulls instead of deltas
from scratch for a while now. We remove remaining references to
resin/scratch, and add a handler in docker-utils to fall back
to a regular pull with a null deltaSource (which should never be
called anyways, but is left as a precaution).
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
getAndSetTargetState in the APIBinder had a check for whether the target state has changed.
When triggering an update from the API, we want to *always* call triggerApplyTarget, especially
when the update is forced. Otherwise the API endpoint doesn't work for forced updates (and in general,
will rarely trigger an update unless a change in the API's target state has happened)
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
In commit 19cd310da3 this line was deleted,
probably to avoid deleting local mode apps when setting the API target and
viceversa but we need to delete old apps to avoid problems when moving
the device between apps.
We now filter by source to avoid the problem with local mode too.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
Otherwise we may skip saving a target image to the db when updating from legacy supervisors,
which in turn prevents from deleting the legacy image entry (with imageId = 1), leaving the
supervisor in a state where it can't report its current state to the API.
While we're at it, we also remove an unused variable in _getStatus.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
We do this by formatting the keys from the target state before comparing them
with the ones from the current state (that are already formatted to strip the namespace
prefix).
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
This avoids issues on provisioning where the current state
(esp. config.txt) that we want to save is retrieved without
a RESIN_ or BALENA_ prefix, causing those values to be lost.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
Otherwise old releases (where applications expected tty to be true)
would break.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
i.e. if we're not provisioned or if the target state is empty (of apps), then we
read apps.json to preload. We then mark that the target state has been set to avoid
trying to preload again if we ever get an empty target state from the API.
Change-type: patch
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
They will take precedence over any existing RESIN_ variables. We strip both namespaces now
whenever we get the target values.
This also fixes preloading with a legacy config (the interface to get the config keys from
the legacy apps.json was broken).
Change-type: minor
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
Instead of hardcoding balena.sock we use this variable since the path changes
with the balena -> balenaEngine rename.
We keep also mounting into balena.sock for backwards compatibility (even though
most tools should transparently use the DOCKER_HOST env var).
Change-type: minor
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
But we keep backwards compatibility by normalizing existing io.resin labels
into io.balena ones, and adding both RESIN_ and BALENA_ env vars for these features.
Change-Type: minor
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
We update the supervisor API docs to reflect the new `BALENA_` injected env vars.
We also add the new sensitive env vars to the list of vars not sent by the API.
And we remove the unused RESIN_DATA_PATH and RESIN_PROXYVISOR_HOOK_RECEIVER from the
vars the supervisor parses from its own environment.
Signed-off-by: Pablo Carranza Velez <pablo@balena.io>
Also fixes the handover wait (since the service interface for it was missing).
We add some logging to this process too.
Change-type: minor
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
We change the lockfile to /tmp/balena/updates.lock, and the resin-kill-me file to /tmp/balena/handover-complete.
In the host, we change to use /tmp/balena-supervisor instead of /tmp/resin-supervisor.
We add BALENA_ env vars in addition to the RESIN_ env vars.
We keep backwards compatibility by using both paths for the lockfile and handover, and keeping the RESIN_ env vars.
Changelog-entry: Move the handover and lock files to /tmp/balena, rename them, and add BALENA_ env vars
Change-type: minor
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This commit changes a bug where the compose healthcheck would always
overwrite the healthcheck set by the image - even if no compose
healthcheck exists.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
These options were discussed in an arch call and the conclusion was
that they don't need to be in the blacklist.
Change-type: patch
Changelog-entry: Remove a few blacklisted config.txt options
Signed-off-by: Zubair Lutfullah Kakakhel <zubair@resin.io>
We were joining every network on container creation, which is currently
bugged in Docker. We were also joining networks afterwards, so the
non-default networks are joined post-creation, and only the networkMode
container is joined on creation.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
This enables the switch to be added to the compose, and the handling of
docker messages has been changed to ensure that the multiplexed logs
which result are handled properly.
Change-type: minor
Signed-off-by: Cameron Diver <cameron@resin.io>
Stability improvements;
* Printing of unsupported compose fields
* Added a lot of tests
* All compose configuration has a default value, enabling better
comparison
Change-type: minor
Signed-off-by: Cameron Diver <cameron@resin.io>
When using the predicate functions in bluebird `.catch`es from
typescript, the compiler would complain that the predicates do not
accept a function which takes an error. Because these are specific
errors, I've extended the base `Error` class, and added the extra fields
we expect.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
Debounce will mean that in certain cases, the events will never be sent,
whereas with throttle we can be sure that it will be sent a minimum
amount per time slice.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
This was causing a bug where the applications were cloned when
restarting all of them. These clones did not carry over the binds, so
when starting the containers back up, two different versions of `this`
were being used.
Change-type: patch
Closes: #736
Signed-off-by: Cameron Diver <cameron@resin.io>
Device names with newlines cause reboot loops, due to newlines not being
supported by docker. This PR will warn when a device name contains a
newline.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
Currently the service has the device name applied after the docker
config is generated. This means that is has no effect until the next
restart.
This commit ensures that the device name is applied before the docker
config is generated, meaning that the env var gets applied to the
upcoming container.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
The previous approach had the bad side effect of resending tons of logs
in the case of a supervisor restart.
The approach can be improved by storing the last timestamp per container
and re-attaching at the correct point.
Change-type: minor
Signed-off-by: Petros Angelatos <petrosagg@gmail.com>
The resinApiEndpoint config option existed for legacy reasons, where the
apiEndpoint was passed in via env vars, but this is no longer the case,
and the current supervisor wouldn't run on these older versions of
resinOS anymore anyway, so I've removed the references to this legacy
endpoint, as it made reasoning about offline mode weird.
Change-type: minor
Signed-off-by: Cameron Diver <cameron@resin.io>
During the conversion to typescript, the behaviour of the database
handle changed slightly, meaning storing a reference to the models
function also requires a bind to be applied too.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
Also change logsChannelSecret value to be queried with the api backend,
so that logs are not shared between instances. This has been implemented
as the first config function provider with mutability.
Change-type: minor
Closes: #675
Signed-off-by: Cameron Diver <cameron@resin.io>
This function takes the docker output representing ports, and generates
the port map values from them. This means that services can accurately
be compared and next steps can be inferred.
The normalization function ensures that regardless of source, PortMaps
that represent the same port setup will be represented correctly
internally.
Change-type: patch
Closes: #644
Signed-off-by: Cameron Diver <cameron@resin.io>
Before this change, port ranges were iterated and stored as an object
per port mapping. Now the port ranges are stored as ranges until they
need to be converted to objects. The need to convert to objects still
exists as this is the format which the docker remote API expects, but
hopefully this should alleviate bugs like #644 by making the memory more
shorter-lived.
Also added more tests.
Change-type: patch
Closes: #644
Signed-of-by: Cameron Diver <cameron@resin.io>
Also had to change config module to bind `.this` value, due to
differences in setup.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
This commit abstracts all of the boot config code out of the
device-config module, ready to extend with different config backends.
Change-type: patch
Signed-off-by: Cameron Diver <cameron@resin.io>
Resin’s delta server supports Balena deltas as version 3 deltas. This commit adds support for triggering delta generation for Balena deltas, and applying them locally to the device via a simple pull.
The delta version to use when updating has been abstracted away as an env var that is user-defined. The default value is still instructing use of rsync deltas (v2).
Change-Type: minor
The supervisor will now check that a source of an application matches
the current source, and only start it if so.
Change-type: patch
Closes: #658
Signed-off-by: Cameron Diver <cameron@resin.io>
This field will represent the apiEndpoint that the application came
from, (or an empty string for local apps). This means that when
configuring an application to work on a different environment, as long
as the endpoint is different, the supervisor can know not to start the
old application.
Change-type: minor
Connects-to: #658
Signed-off-by: Cameron Diver <cameron@resin.io>
This api endpoint is the endpoint which the intial config was reported.
Also changed the code to detect if the api endpoint has changed, and
therefore whether we need to re-report the initial config, to avoid
losing hardware specific information.
Change-type: minor
Closes: #649
Signed-off-by: Cameron Diver <cameron@resin.io>
We add a bunch of additional unit tests, and also a coverage report using istanbul.
The tests are not meant to cover everything, but they're a first attempt at having *some* unit testing
on the supervisor. There's much to improve but hopefully it helps catch obvious errors.
Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This is to combat when a working directory is in the compose file for a
service with a trailing slash. Docker will strip this slash and that
means service comparisons will fail going forward - even if they are the
same.
Change-type: patch
Closes: #635
Signed-off-by: Cameron Diver <cameron@resin.io>
Add webpack config and dependencies to have typescript built, and also
convert src/lib/validation.coffee to typescript.
In this conversion I also added a lot of debugging which should help the
upcoming local mode development.
Change-type: minor
Signed-off-by: Cameron Diver <cameron@resin.io>
It now allows a trailing `b`, as the docker-compose docs specify.
In addition the regex now specifies a case-insensitive flag, to catch
both upper and lower case memory numbers (the rest of the function
supported these already).
Change-type: patch
Closes: #603
Signed-off-by: Cameron Diver <cameron@resin.io>
Otherwise if the hostname on the supervisor container differs from the hostname on the host, the current and target
services will never match.
Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
We were getting the correct working dir from the compose or image config, but not really using it.
Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
This should fix an issue where, on an update that only changes container metadata, the image install for the old image
is kept around on the API.
Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
We migrate to a default composition because we need to avoid deleting existing docker images, but
we need to use the legacy-container label to avoid potentially creating a duplicated container when a target state comes in.
(Just like we do for preloaded apps)
Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
In some cases we were using early `return res.status(...).send(...)` to send 400 errors
but this happened inside a promise chain that later sent another status and response.
We fix this with the correct indentation of the success response so that an early return doesn't fall there.
Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>
We weren't passing a "target" to serviceAction, which made the start action fail.
Plus we need to get the container again after starting to get the latest containerId.
Change-Type: patch
Signed-off-by: Pablo Carranza Velez <pablo@resin.io>