Difference between snap command and service

Hi all,

I am working with snaps on Ubuntu Core 18.
I have created a snap that, if run as a command, works fine.
Now, I need to make its application autostart after boot, so I defined it as a service, as shown in the snapcraft.yaml:

base: core18
grade: devel
confinement: devmode

apps:
  app-name:
    command: bin/app-name
    daemon: simple
    restart-condition: on-abnormal

Although, after autostarting, the app is now no more able to find a library file that it needs for its correct execution.
Do you have any hints about how to solve the issue? I guess that for snaps there is a difference between running a command and a service, which makes the snap unable to find the needed file.
I have also tried to keep defining this app as a command and adding another app as a service within the same snap, with the latter starting the command, but I get the same problem.

Not really, both are started via snap run. The difference is that a command is started by the user, while a service is started by systemd.

Sounds like a build problem. What is the exact error message? Are you using snapcraft to build the snap?

Hi

Yes I am.

By using the command sudo journalctl -r I can see the following error:

Jun 09 09:08:54 localhost <snap-name>.<service-name>[6580]: [2021-06-09 09:08:54][root][ERROR] File libstgentl.cti not found.

To give you a complete view, I put here my whole snapcraft.yaml. I defined two service apps (I would like service2 to be able to start/stop service1 when needed through snapctl start/stop snap-name.service2) and an additional part (extra-libs) containing some libraries needed by service1:

name: snap-name
version: xxxxx

base: core18
grade: devel
confinement: devmode

apps:
  service1:
    command: bin/service1
    daemon: simple
    restart-condition: on-abnormal
    before: [service2]
    plugs:
      - camera
      - home
      - display-control
      - desktop
      - x11
      - io-ports-control
      - network
      - process-control
      - raw-usb
  service2:
    command: bin/service2
    daemon: simple
    restart-condition: on-abnormal
    start-timeout: 10s
    plugs:
      - home
      - display-control
      - desktop
      - x11
      - io-ports-control
      - network
      - process-control
      - raw-usb

parts:
  service1:
    plugin: python
    python-version: python3
    source: .
    after: [extra-libs]
    requirements: [./yyyyyy/requirements.txt]
    stage-packages:
      - x11-utils
      - python3-tk
      - python3-distutils
      - libturbojpeg
      - qt5-default
      - qtchooser
      - libpng16-16
      - libdouble-conversion1
      - libgles1
      - libopengl0
      - libqt5concurrent5
      - libqt5core5a
      - libqt5dbus5
      - libqt5gui5
      - libqt5network5
      - libqt5opengl5
      - libqt5printsupport5
      - libqt5sql5
      - libqt5sql5-sqlite
      - libqt5svg5
      - libqt5test5
      - libqt5widgets5
      - libqt5xml5
      - libwayland-bin
      - libx11-doc
      - libxcb-xinerama0
      - qt5-gtk-platformtheme
      - qt5-qmake
      - qt5-qmake-bin
      - qtbase5-dev-tools
      - qttranslations5-l10n
      - xorg-sgml-doctools
  extra-libs:
    plugin: nil
    source: extra-libs
    override-build: |
      mkdir -p $SNAPCRAFT_PART_INSTALL/lib
      cp -av lib* $SNAPCRAFT_PART_INSTALL/lib/
    stage-packages:
      - libturbojpeg
      - qt5-default
      - qtchooser
      - libpng16-16
  service2:
    plugin: python
    python-version: python3
    source: ./zzzzzz/
    after: [service1]
    requirements: [requirements.txt]

EDIT: I still see the “missing” file libstgentl.cti present in the folder /snap/snap-name/12/lib as it was when the app was defined as a command.

if you do a:

find /snap/<snap-name>/current/ -name '*libstgentl.cti*'

is the lib found anywhere inside your installed snap ?

Yes, running this command

I get the following output:

/snap/<snap-name>/current/lib/libstgentl.cti

hmm, does your app perhaps try to open it from ./ or some such via a hardcoded entry ?

EDIT: also switch it to strict confinement, install snappy-debug on the system and run snappy-debug from a second terminal while starting the service, that should give you some extra hints …

I do not think so, also because if I define the app as a command and I run from terminal <snap-name>.service1 it works. Maybe could be something related to this?

well, try that in strict mode and with snappy-debug running, it might load it form somewhere in your home dir or some such …

OK I will try and let you know.
In the meanwhile, I ask you another thing. Is there a command that an app defined as a service can use to start/stop an app defined as a command within the same snap or for another snap? This could also be enough to solve my issue.

any service can indeed spawn any app … but that app would indeed just run in the same context as the service (as root) …

i also doubt that your app will still run when spawned as user once you use proper confinement since i suspect that it finds the lib then is simply because it has access to a dir it shouldnt.

I think that this is exactly my main issue. Indeed, if I run the app defined as command by just typing on the Ubuntu Core terminal <snap-name>.service1 everything goes smooth, whereas if I try sudo <snap-name>.service1 (so as root) I get the issue about the missing library.
Moreover, that library is related to the software of a camera that first needs to be installed on the system. So, actually, there is another libstgentl.cti file in my home dir, which is likely the one that is actually used by the app… But it should not be a problem if I put the home plug in the snapcraft.yaml, right? In addition, is the fact of leaving the devmode confinement to a snap such a big issue? Because until now I thought of keeping it like that…

it will be, since the home of a service is /root (also, on ubuntu core the home plug does not auto connect) … you rather want the lib in the right place your app expects it … if that is ./ you can just put it next to the app binary inside your snap or patch your code to simply load it from $SNAP/lib (where it currently lives)

using devmode means you can not release to the stable channel and the snap will not be updated automatically … (a user will have to manually ssh into the box and expicitly update this one snap)

1 Like

Actually, I am not sure that I can do this, because of the steps that I need to perform to make the camera be correctly accessed.
In particular, my snap app runs a Python script, that uses a Python library specific for the camera I use. Before installing the snap on the target system, I need to install the camera drivers in some folder (I usually choose /home/user/Documents/cams/) through a .run file; once the installation is completed, I get some files inside this folder, among which there is libstgentl.cti
Moreover, I need to use the command source /home/user/Documents/cams/.stprofile and to append to my /home/user/.bashrc file the following lines:

export PATH="/home/user/Documents/cams/:$PATH"
STAPI_ROOT_PATH=/home/user/Documents/cams
GENICAM_GENTL64_PATH=/home/user/Documents/cams/lib:$GENICAM_GENTL64_PATH
LIBRARY_PATH=$STAPI_ROOT_PATH/lib:$STAPI_ROOT_PATH/lib/GenICam:$LIBRARY_PATH
LD_LIBRARY_PATH=$STAPI_ROOT_PATH/lib:$STAPI_ROOT_PATH/lib/GenICam:$LD_LIBRARY_PATH
export GENICAM_GENTL64_PATH STAPI_ROOT_PATH LIBRARY_PATH LD_LIBRARY_PATH

Since in my code I never specify the path of the libstgentl.cti file, I assume that the camera Python library autonomously looks for it according to the LIBRARY_PATH set in the .bashrc file.
In order to try to make my snap service find the library file, since as far as I understood it is run as root, I have used sudo su and repeated the two steps of the source command and of the appending of the previous lines to the /root/.bashrc file. In this way, if I run my snap command inside the root user I do not get the error anymore, but if I use my snap service I still get it, and the same in case I run the snap command in the local user with sudo.
I do not understand why the library file is not found, since I thought that defining LIBRARY_PATH in the .bashrc file would have been enough.
Do you have any other suggestions?

yes, dont use .bashrc but simply set everything proper in an environment: entry for the services in your snapcraft.yaml … you can not have bits and pieces outside the snap in a proper setup, make sure all bits and pieces you need are inside your snap and adjust your paths to point to the proper $SNAP/$SNAP_DATA/$SNAP_COMMON dirs …

1 Like

I have added the following lines to the part of my snapcraft.yaml related to service1:

environment:
      GENICAM_GENTL64_PATH: $SNAP/lib:$GENICAM_GENTL64_PATH
      LIBRARY_PATH: $STAPI_ROOT_PATH/lib:$STAPI_ROOT_PATH/lib/GenICam:$LIBRARY_PATH
      LD_LIBRARY_PATH: $STAPI_ROOT_PATH/lib:$STAPI_ROOT_PATH/lib/GenICam:$LD_LIBRARY_PATH

Now the snap works fine! Thank you very much!

1 Like

Just one small last thing @ogra
I have defined this snap with two app services, but I would like just one of them to start automatically at system boot, whereas I would like the other one to be started/stopped by the former (I would say through snapctl start/stop <snap-name>.service2. Can I put something in the snapcraft.yaml or somewhere else to make service2 not start at boot? Up to now my snapcraft.yaml apps section is as follows:

apps:
 service2:
   command: bin/service2
   daemon: simple
   restart-condition: on-abnormal
   before: [service1]
   environment:
     GENICAM_GENTL64_PATH: $SNAP/lib:$GENICAM_GENTL64_PATH
     LIBRARY_PATH: $STAPI_ROOT_PATH/lib:$STAPI_ROOT_PATH/lib/GenICam:$LIBRARY_PATH
     LD_LIBRARY_PATH: $STAPI_ROOT_PATH/lib:$STAPI_ROOT_PATH/lib/GenICam:$LD_LIBRARY_PATH
   plugs:
     - camera
     - home
     - display-control
     - desktop
     - x11
     - io-ports-control
     - network
     - process-control
     - raw-usb
     - hardware-observe
     - network-manager
     - network-manager-observe
 service1:
   command: bin/service1
   daemon: simple
   restart-condition: on-abnormal
   start-timeout: 10s
   plugs:
     - home
     - display-control
     - desktop
     - x11
     - io-ports-control
     - network
     - process-control
     - raw-usb
     - hardware-observe
     - network-manager
     - network-manager-observe

yes, see “install-mode” on:

1 Like