Command argument from snapctl get

I’m trying to have a service start with configuration taken from the snapctl.

    command: mashnet-node --dev --ws-port "$(snapctl get mashnet-node.wsport)"
    daemon: simple

But I get this:

Failed to generate snap metadata: The specified command 'target/release/mashnet-node --dev --ws-port "$(snapctl get mashnet-node.wsport)"' defined in the app 'mashnet-node' does not match the pattern expected by snapd.
The command must consist only of alphanumeric characters, spaces, and the following special characters: / . _ # : $ -

I’ve successfully done this construction in another snap, but now I seem to do either some trivial error or I’m lost.

… and I doing this backwards?

The problem is that the command line specified via command: is not run through the shell, but instead snap-exec executes the string directly (after expanding environment variables). So it won’t be able to expand the $(...) syntax.

As for why things like this might have worked for you in the past, in some modes of operation, Snapcraft copies the command you specify in the snapcraft.yaml file into a shell script (where this kind of syntax will work), and references that shell script in the final meta/snap.yaml file. It did this to add some additional setup.

Snapcraft is less likely to do that these days, instead using the command-chain feature to add extra setup scripts. That means the command you specify in snapcraft.yaml is more likely to end up in the snap.yaml verbatim, and needs to be compatible with snapd.

You can work around this by manually adding a shell script to your snap that calls mashnet-node with the relevant snapctl command to derive one of the arguments, and then list that shell script as the command: value.

I feel that some kind of “best” practice is needed here since this must be an extremely common task:

  1. Design a custom unit-file.
  2. Populate the start parameters based on the snap config.

I have previously created mods like this: How to customize systemd service created by snapd?

But I don’t know or feel this should be the way to do this from within a snapcraft.yaml context.

I really can’t find any good docs on this method.

there is no clean way to modify systemd units, they are generated at snap install time from the info in snapcraft.yaml and no snap has access to the units to randlomly modify them (this would be a security disaster) … the options you can use for unit files are documented in:

if these do not suffice (i.e. because you want to use snapctl) you should use a shell script instead …
(and/or file a bug against snapd to get the desired additional unit option into the generator code so you can use it from snapcraft.yaml)

What I can’t get my head around here is what facility should be used with snap to control systemd.

A) Should snap control every aspect of daemons, e.g. all configs for the start command must be fully static in the snapcraft.yaml command: directive. Any custom change would need to override completely using the method described here: How to customize systemd service created by snapd?

B) Should I package a systemd “override.conf” file with the snap to complement the snap so that this unit file is statically written and subsequent changes to this file is done outside of the snap via linux commands? For example have juju control the content of it.

I think the best way ™ is to somehow query snapd for configuration and pass those to the startup of the systemd unit? (e.g. option A)

Whats your take on this?

you miss the point, this is not a valid “method” for anything, it is at most a local sysadmin hack, nothing in a snap would be able to apply these hacks described there and this is on purpose …

you do not touch, talk to or manage anything via systemctl or by manuallyl hacking unit overrides in place

my tip is to completely forget about systemd here and focus on how to do it right inside the snap … which is via a shell script if you need the command to be dynamic or via a command-chain script if you can hand it to the process via a configuration setting or environment variable …

hacking overrides into /etc/syystemd/system is really not an option in any way …

Makes sense - so this leaves me with shipping a “override.conf” file for the by-snap-installed-systemd-unit-file if I need the unit-file to look anything other than what snap is generating then?

no, again: your snap can not directly modify anything in /etc/systemd/system … so an override file would not end up where you need it, the two options you have are described above …

1 Like

Right, the path using a script seems then most legit.

1 Like