ipfs / ipfs-update

An updater tool for Kubo IPFS binary
https://dist.ipfs.tech/#ipfs-update
MIT License
137 stars 60 forks source link

Handle updating self on Windows #88

Closed djdv closed 5 years ago

djdv commented 6 years ago

Followup to: https://github.com/ipfs/ipfs-update/pull/87

This should fix the issue of updating ipfs.exe when launched from ipfs.exe as well as when it's in use by other processes. On Windows, we can't delete files that are in use, but we can move them. As a fallback, we try to move it to the system's temporary directory where it can be deleted eventually. There is a flag that allows us to schedule these files to be deleted on boot, but that flag requires admin rights to succeed, so we leave cleanup to the user / system services. These discarded files are renamed to contain a timestamp for pseudo-uniqueness to prevent possible conflicts. The name could be changed if desired.

Example: https://ipfs.io/ipfs/zDMZof1m1RDh2XA5Utthu41G1nLNfD5E9uPsDMinp4wmUUVKR2Nr/Desktop%202018.06.07%20-%2015.47.33.13-an.mp4

Stebalien commented 6 years ago

Can we not have ipfs exit after it starts ipfs-update?

djdv commented 6 years ago

@Stebalien We'd have to shut down any running daemons as well. Here we just replace the binary and leave old instances alive.

Stebalien commented 6 years ago

We'd have to shut down any running daemons as well. Here we just replace the binary and leave old instances alive.

That's actually what many users will expect. That is, they'd expect you to restart ipfs with the new version.

(on windows at least)

djdv commented 6 years ago

@Stebalien Do we want to explicitly shut down the daemon before upgrading on all platforms? It seems sensible to want to upgrade the instance after upgrading the binary, worst case the old binary can be relaunched after reverting.

I'm wondering if we can retrieve daemon arguments prior to shutting down the existing daemon. For example, to see if --enable-gc was set, so that we can launch the new instance with the same args.

Stebalien commented 6 years ago

Do we want to explicitly shut down the daemon before upgrading on all platforms? It seems sensible to want to upgrade the instance after upgrading the binary, worst case the old binary can be relaunched after reverting.

Not sure... on Linux, at least, I manage go-ipfs with systemd and wouldn't want some other service restarting it.

I'm wondering if we can retrieve daemon arguments prior to shutting down the existing daemon. For example, to see if --enable-gc was set, so that we can launch the new instance with the same args.

So, on Linux we can definitely do that using /proc. I'm not sure how that'd work on windows or macos. This sounds kind of hard, actually.


Instead of restarting the daemon from ipfs-update, it may be better to add a restart command to IPFS itself. That way:

  1. It'll continue running as the same user in the same execution context (environment variables, namespaces, etc.).
  2. We can start it with the same options.

So, on linux, we can simply replace the binary. On Windows, we'd move the old binary out of the way, move the new binary in place, restart, and then remove the old binary.

However, this'll still be a bit tricky. On linux, we'd want to explicitly use the exec syscall to replace the current process (otherwise, service managers like systemd will see the primary process die and may kill the entire service). If we were doing this the right way, we'd pass our state through to the new process and pick up where we left off. But, that's not going to happen.

Stebalien commented 5 years ago

I should have just merged this and discussed better solutions later.

bmwiedemann commented 5 years ago

I'm wondering if we can retrieve daemon arguments prior to shutting down the existing daemon. For example, to see if --enable-gc was set, so that we can launch the new instance with the same args.

So, on Linux we can definitely do that using /proc. I'm not sure how that'd work on windows or macos. This sounds kind of hard, actually.

It can work even without /proc from within the process that is replaced - e.g. in bash you can do exec "$0" "$@" using the args passed to your own process.

djdv commented 5 years ago

using the args passed to your own process.

Gathering and exposing os.Args from the node instance seems like a simple and portable way to implement this.

I'm wondering if it would make sense to store these in the $IPFS_PATH, deleting them at the same time the api file is deleted, except when a flag is specified to keep it. On init, the daemon could check for the existence, and use those arguments, this could even be guarded with something like ipfs daemon --resume=true (ignoring the file otherwise).

In whole, imagine:

I'm not sure how best to handle it though, there may be a simpler/saner approach.

bmwiedemann commented 5 years ago

I had thought about something simpler: