loading...

How I played with golang to impeach sshfs failures

malikbenkirane profile image Malik Benkirane Updated on ・5 min read

Last day, while reading the docker reference, I spotted an sshfs container. Finally, I ended up finding this repo. I said, well, but the repo has not been updated since 3 years and roughly linked with dockers’ api. Finally I just gave up and this is how I spent one day having fun with golang without messing with the docker api.

It begins with...

Last day, as it happens occasionally, I was reading the docker cli reference. While trying to understand an example, my mind just stopped on sshfs. At this moment, I was like : "Really ? all this time rsyncing !".

Excited to learn more about this container image, I found myself dealing with this repositiry that sadly has not been updated since 3 years. Fortunately, the sshfs project is still living pretty well. And I still was excited enough to try it out.

From that moment — and I swear this is not coronavirus fever — I wanted to write a small piece of code that will run on the host from where I want to access some directory from a remote ssh server that will suits my needs and do all the preflight checks for my needs.

Some may say let’s write a python script or a bash script. Well, no, but this is how I spent one day having fun with Golang.

Finally the small piece of code ended up with 250 A+ go lines.

Also, that was my first experience and short experience with .travis.yml.

If you’re a go enthusiast like me, go to the github repository and just read the code.

With next section, I expose what kind of tool I wanted.

A tool ? What for ?

My idea was to have a small binary to copy wherever I often need to mount
remote directory accessible from a remote ssh server. And this is how I unfortunately find out about sshfs. The hypothetical binary I will carry will either read options from cli or a yaml file and it will check

  • if I have the credentials for connecting to the remote host
  • if the remote directory I will mount exists
  • if the mount point exists

If so, I will be able to run something like the following shell script
without being stopped by a trivial error

host=#...
local_dir=#...
mnt_dir=#...
docker_uid=#...
docker_gid=#...
# sudo mkdir ${mnt_dir} # not necessarily
sudo sshfs \
  -o idmap=user,uid=${docker_uid},gid=${docker_gid} \
  -o allow_other \
  ${host}:${remote_dir} \
  ${mnt_dir}

My host, where I want to port the said binary, is running latest ubuntu server and there is also docker daemon running. I want to remap uid and gid to have read and write permissions on the remote directory. For instance I may have to use this directory inside docker

docker_mnt_dir=#...
docker run --rm -ti -v ${mnt_dir}:${docker_mnt_dir} # ...

Now, it’s time for a demo.

Action!

We start with removing the leading # in /etc/fuse.conf

https://serverfault.com/questions/947182/mount-a-sshfs-volume-into-a-docker-instance
uncomment user_allow_other in /etc/fuse.conf

I start with getting the uid and gid for the user logged in the container

docker run --rm <some-image> id

Then I write an sshfs.yml yaml configuration for mount_sshfs

uid: 1001
gid: 1001
docker: true
remote: myuser@myhost:/my/remote/dir
mount: /mount/point/dir

For the moment, I didn't decided yet, if mount_sshfs will make the mount point directory. Actually, if you had already read mount_sshfs README, you may have noticed that nothing is actually done by the tool except for checking that everything is alright before actually calling sshfs.

That is, that firs, you’ll run

mount_sshfs -config sshfs.yml

And then, only if it looks alright

mount_sshfs -config sshfs.yml 2>/dev/null | sh

In case mount_sshfs exits at step 1 with

... invalid mount dir path

make sure the directory exists. For example, I can type

grep mount sshfs.yml | sed -n '/mount/s/mount:/sudo mkdir/p'

Then, I will check if output is ok and I will type on the shell prompt (<up>, or <esc>kA followed with | sh)

grep mount sshfs.yml | sed -n '/mount/s/mount:/sudo mkdir -p/p' | sh

Although, it's not my priority right now to work on a smart tool that will both check and assist shell level error resolution. I would be very happy to use a tool of this kind which actually hooks errors and redirect me to an nice assistant able to solve that kind of error in someway like I just showed.

Although, I suspect this to be programmatically nicely feasible, this is again not my priority right now. But you may either be interested or not thinking it's nicely feasible. In both cases I'll be very happy you let me know.

Back now with the demo. And let say mount_sshfs exits with

... key is uknown

you may need therefore to

ssh-copy-id {user}@{host}

And if this may not be ok in your case but I'm sure you will find the right way to do it.

If all tests pass, mount_sshfs only prints on standard output the prefilled shell command we wanted so far

sudo sshfs \
  -o idmap=user,uid=<yaml:uid>,gid=<yaml:gid>\
  -o allow_other \
  <yaml:remote> \
  <yaml:mount>

This means step 1 is okay but as any good system adminstrator, you will double check the command before running

mount_sshfs -config sshfs.yml 2>/dev/null | sh

And hopefully

$ ls -ln <yaml:mount>
total 112
drwxr-xr-x 1 1001 1001  7904 Apr  3 09:55 node_modules
-rw-r--r-- 1 1001 1001   543 Apr  3 09:55 package.json
drwxrwxr-x 1 1001 1001   160 Apr  3 09:03 public
-rw-r--r-- 1 1001 1001  2424 Feb  2 17:44 README.md
-rw-r--r-- 1 1001 1001  1709 Feb  2 17:44 rollup.config.js
drwxrwxr-x 1 1001 1001   128 Apr  3 09:15 src
-rw-r--r-- 1 1001 1001 83399 Apr  3 09:55 yarn.lock

This is the end of this story.

Now, I'll be really happy to answer your questions and I'm truly excited for all the amazing improvement or ideas you have.

References

Discussion

markdown guide