Multiple commands for app command; (workaround for "watchPath" daemon )

Hi guys, I’m having a really hard time packaging a script that I assumed would have been extremely simple.

Here’s my snapcraft.yml:

 name: visshous
base: core18
 version: '0.1'
summary: magically transport your vim config to remote servers
description: |
  ViSSHous is a simple tool which helps you carry your vim profile everywhere across SSH sessions, by embedding your vim configuration within SSH itself.
grade: devel
confinement: devmode
 
apps:
 visshous:
   command: inotifywait -e modify -e create $HOME/.vimrc; sh vissh
   daemon: simple
   restart-condition: always
 
 parts:
   visshous:
      stage-packages:
         - inotify-tools
      source: https://github.com/gWOLF3/viSSHous/archive/v0.0.3.tar.gz
      plugin: dump

Can snap commands not access the $HOME directory?

My vissh commands wants to access the $HOME directory as well.

I am trying to distribute a simple shell script that should be executed any time the .vimrc file changes. This is very explicitly simple with systemd unit file, as well as homebrew, but I cannot find a way to make it work here.

The command listed in the yaml is not interpreted by /bin/sh, which is why the multiple commands are not handled here.

At present it would probably be easiest to create a shell script containing what you want to execute, and use that in the command: attribute.

thanks - do you know any other way I can possibly implement a “watch file for changes” functionality other than build it myself into the executable?

It’s not hard to do, but it would be great if there was some way to just define this as one does with systemd unit file or launchd.

I don’t think we have any alternatives at the moment.

One of the difficulties in exposing PathChanged and friends to snaps is answering the question “can the snap read the given path?”. At present, systemd unit files are generated on package install, and not influenced by plug/slot connections.

It would be pretty easy to allow watching paths under e.g. $SNAP_DATA and $SNAP_COMMON since they are always accessible to the snap. Watching paths whose access is granted by interfaces like home, removable-media, etc is more problematic.

Your inotifywait work around is easier to reason about because the watch is being performed from within the sandbox: by definition you’ll only be able to watch files you can see from there.

So I’ve been trying all your suggestions and did my best to create a workaround but I’m pulling my hair out now because I just can’t figure out what I’m doing wrong.

My updated snapcraft.yml:

name: visshous
base: core18
version: '0.1'
summary: magically transport your vim config to remote servers
description: |
  ViSSHous is a simple tool which helps you carry your vim profile everywhere across SSH sessions, by embedding your vim configuration within SSH itself.
grade: devel
confinement: devmode

plugs:
  vim-files:
    interface: personal-files
    read:
    - $HOME/.vimrc
    - $HOME/.vim
    - $HOME/.ssh/viSSHous
    write:
    - $HOME/.vimrc
    - $HOME/.vim
    - $HOME/.bashrc
    - $HOME/.zshrc
    - $HOME/.ssh/viSSHous

apps:
  visshous:
    plugs:
    - vim-files
    command: sh $SNAP/vissh_snap
    daemon: simple
    restart-condition: always

parts:
  visshous:
    stage-packages:
      - inotify-tools
    source: https://github.com/gWOLF3/viSSHous/archive/v0.0.4.tar.gz
    plugin: dump

As you can see, I’ve tried to give it all the permissions that it needs to work, as well as changed the command to a single command which runs inotify inside the shell script.

My shell script that I run looks like this:

if [ ! -f $HOME/.vimrc ]; then touch $HOME/.vimrc; fi;
inotifywait -e modify $HOME/.vimrc;
  
if ([ -f ~/.bashrc ] && ( ! grep -qR 'alias ssh="ssh -F ~/.ssh/viSSHous"' ~/.bashrc ));
  then echo 'alias ssh="ssh -F ~/.ssh/viSSHous"' >> ~/.bashrc && bash
fi

if ([ -f ~/.zshrc ] && ( ! grep -qR 'alias ssh="ssh -F ~/.ssh/viSSHous"' ~/.zshrc ));
  then echo 'alias ssh="ssh -F ~/.ssh/viSSHous"' >> ~/.zshrc && zsh
fi 

echo "# last updated: $(date)" > ~/.ssh/viSSHous
echo 'Include ~/.ssh/config' >> ~/.ssh/viSSHous
echo "SetEnv LC_MONETARY=$(cat ~/.vimrc | base64)" >> ~/.ssh/viSSHous
echo "RequestTTY yes" >> ~/.ssh/viSSHous

A few things definitely seem to be wrong:

  1. snap does not install inotify-tools, even though it is listed as a dependency in my snapcraft.yml

  2. if i run snap interfaces, i don’t see any plugs attached to personal-files:

:x11                       multipass
-                          multipass:libvirt
-                          multipass:lxd
-                          visshous:vim-files

I see my plug there, but its not attached to anything.

  1. Finally, I try to debug whats happening with journalctl, and it’s very difficult to tell.
Sep 17 05:46:14 ubuntu-xfce systemd[1]: snap.visshous.visshous.service: Failed with result 'exit-code'.
Sep 17 05:46:14 ubuntu-xfce systemd[1]: snap.visshous.visshous.service: Unit entered failed state.
Sep 17 05:46:14 ubuntu-xfce systemd[1]: snap.visshous.visshous.service: Main process exited, code=exited, status=2/INVALIDARGUMENT
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: /snap/visshous/x1/vissh_snap: 22: /snap/visshous/x1/vissh_snap: cannot create /root/snap/vi
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: /snap/visshous/x1/vissh_snap: 21: /snap/visshous/x1/vissh_snap: cannot create /root/snap/vi
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: /snap/visshous/x1/vissh_snap: 20: /snap/visshous/x1/vissh_snap: cannot create /root/snap/vi
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: cat: /root/snap/visshous/x1/.vimrc: No such file or directory
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: /snap/visshous/x1/vissh_snap: 19: /snap/visshous/x1/vissh_snap: cannot create /root/snap/vi
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: /snap/visshous/x1/vissh_snap: 18: /snap/visshous/x1/vissh_snap: cannot create /root/snap/vi
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: Couldn't watch /root/snap/visshous/x1/.vimrc: No such file or directory
Sep 17 05:46:14 ubuntu-xfce visshous.visshous[7596]: Setting up watches.

Other notes about my setup:

I have to run with sudo snap run snapcraft --use-lxd everytime. Even though I’m running Ubuntu, apparently the KVD is not supported by my CPU.

How can I get the $HOME context inside my shell script to be of the actual user?

Snap should have permissions to read it, but the problem is that snap is passing its own $HOME context to the script when it runs it, is there any way to override that?

Looks like $HOME/.vimrc is being translated to /root/snap/visshous/x1/.vimrc - even though snap should not have access to the personal-files interface and be able to see $HOME/.vimrc, as defined in my snapcraft.yml.

The current method many scripts use is getent. Something like:

REALHOME=$(getent passwd $(id -u) | cut -d ':' -f 6)

The problem that I’m having is that the snap real home is not in user space for some reason?

When I snap install .. I have to run with sudo snap install .. - this creates the problem.

If I try snap run --shell <my service>, then env | grep SNAP_REAL_HOME, i get /home/users/me - which is what I want, since my script needs to monitor the .vimrc file in user space —

However - because for somereason the snap context is always root – inside my script, the $REAL_SNAP_HOME variable is set to / .

So if i run sudo snap run --shell <my service>, and then echo $(getent passwd $(id -u) | cut -d ':' -f 6). I get /root.

Is there anyway to get the home of userspace rather than root?

perhaps because you use sudo :wink: ?

@ogra That is the point though, since my snap is a daemon process, snap by default creates it as a system service unit by default - which runs with root user context. What I really need is a user service unit, which will run out of userspace context. Is there any way to do this?

this would be very complex, but you culd have a user-session daemon (creating a .desktop file, and an autostart entry):

that talks to the system daemon (through socket or whatnot), hands over all required user related info and then your system daemon execs whatever is needed as root…

more for @ogra’s knowledge since it was just mentioned in the other thread, but we have experimental support for user daemons detailed here: How to provide systemd user service

2 Likes

my hack above would also only work in graphical desktop sessions indeed (i dont think autostart: is applying to cli sessions)