Skip to content

http/sftp: support listening on passed FDs#7801

Merged
ncw merged 4 commits intorclone:masterfrom
flokli:socket-activation
Sep 6, 2024
Merged

http/sftp: support listening on passed FDs#7801
ncw merged 4 commits intorclone:masterfrom
flokli:socket-activation

Conversation

@flokli
Copy link
Contributor

@flokli flokli commented Apr 24, 2024

Instead of the listening addresses specified above, rclone will listen to all FDs passed by the service manager, if any (and ignore any arguments passed by --{{ .Prefix }}addr.

This allows rclone to be a socket-activated service. It can be configured as described in https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html

It's possible to test this interactively through systemd-socket-activate, firing of a request in a second terminal:

❯ systemd-socket-activate -l 8088 -l 8089 --fdname=foo:bar -- ./rclone serve webdav :local:test/
Listening on [::]:8088 as 3.
Listening on [::]:8089 as 4.
Communication attempt on fd 3.
Execing ./rclone (./rclone serve webdav :local:test/)
2024/04/24 18:14:42 NOTICE: Local file system at /home/flokli/dev/flokli/rclone/test: WebDav Server started on [sd-listen:bar-0/ sd-listen:foo-0/]

What is the purpose of this change?

Closes #7783

Was the change discussed in an issue or in the forum before?

#7783
https://forum.rclone.org/t/systemd-socket-activation-for-rclone-serve/45644

Checklist

  • I have read the contribution guidelines.
  • I have added tests for all changes in this PR if appropriate.
  • I have added documentation for the changes if appropriate.
  • All commit messages are in house style.
  • I'm done, this Pull Request is ready for review :-)

@flokli flokli marked this pull request as ready for review April 24, 2024 14:08
@flokli flokli force-pushed the socket-activation branch 2 times, most recently from 1b6a661 to caa8067 Compare April 24, 2024 15:17
@flokli
Copy link
Contributor Author

flokli commented May 2, 2024

poke @ncw :-)

@flokli
Copy link
Contributor Author

flokli commented May 3, 2024

Thanks for kicking CI! That seems to be coreos/go-systemd#440. Adding a replace directive to my go.mod gets a GOOS=plan9 go build ./cmd/serve to pass.

@flokli flokli marked this pull request as draft May 3, 2024 16:25
@ncw
Copy link
Member

ncw commented May 4, 2024

Can you stub it out on plan 9?

@flokli
Copy link
Contributor Author

flokli commented May 4, 2024

That's what I did upstream, in coreos/go-systemd#440.

If this doesn't get merged there, I could add a little wrapper package in rclone, and do the plan9 stubbing there, but it'd be more code on the rclone side.

Is this the only thing blocking this, or do you have other feedback on the code?

@ncw
Copy link
Member

ncw commented May 5, 2024

Well you could do the same thing in the rclone code with build tags - that is what I was suggesting. Though if your pr is merged that is the neatest way for rclone!

I have looked at the code which looks ok (I'll do a formal review at some point). I would like some explanation of how it works in the docs and example config of how you would use it with systemd would be very useful.

Ones thing that wasn't clear to me - does systemd start a new rclone instance for every incoming connection? Or does it keep things running for a while. I guess this might be in the systemd docs!

@flokli
Copy link
Contributor Author

flokli commented May 5, 2024

Yeah, I'm also hoping PR gets merged into go-systemd, as essentially everyone linking against the activation package and building or this arch would do stubbing on their own, and there already is a windows stub...

Regarding systemd configuration, there's a lot of different config knobs, which is why I only linked to the systemd docs. You can bind on Unix sockets, TCP ports, ...

rclone keeps running, and normally gets started lazily on the first connection. If rclone had a parameter to exit the process after a specific time of inactivity, it would also get fully shut down, but that's a bit out of scope for this PR.

@ncw
Copy link
Member

ncw commented May 13, 2024

Hmm, looks like we might have to go for build tags - not a lot of action on that PR...

@flokli
Copy link
Contributor Author

flokli commented May 13, 2024

Alright, let me take a look at that

@flokli flokli force-pushed the socket-activation branch from caa8067 to 0096111 Compare May 13, 2024 19:15
@flokli
Copy link
Contributor Author

flokli commented May 13, 2024

I rebased this, and moved the wrapping into our own wrapper package, linking to the upstream issue. also added socket activation to the serve sftp command (which only has a single listener).

@flokli flokli marked this pull request as ready for review May 13, 2024 19:16
@flokli flokli force-pushed the socket-activation branch from 0096111 to 65b9e53 Compare May 14, 2024 08:16
@flokli flokli changed the title http: support listening on passed FDs http/sftp: support listening on passed FDs May 14, 2024
@flokli flokli force-pushed the socket-activation branch from 65b9e53 to d2866f2 Compare May 14, 2024 10:39
@flokli
Copy link
Contributor Author

flokli commented May 15, 2024

@ncw sorry for the noise, but can you kick off CI once again?

@flokli flokli force-pushed the socket-activation branch from d2866f2 to cc9ddd6 Compare May 15, 2024 17:26
@flokli
Copy link
Contributor Author

flokli commented May 22, 2024

Poke - this should be ready now.

@flokli
Copy link
Contributor Author

flokli commented Jun 30, 2024

I just stubled over #7392, which tried doing the same thing. Some feedback on what'd be needed to get either of the two accepted would be appreciated.

@ncw
Copy link
Member

ncw commented Jul 15, 2024

Sorry for the delay on this @flokli

Can you rebase it on master please and fixup any problems (might not be any but there have been lots of commits to master since this started).

@flokli flokli force-pushed the socket-activation branch from cc9ddd6 to 986b828 Compare August 1, 2024 14:13
@flokli
Copy link
Contributor Author

flokli commented Aug 1, 2024

@ncw I rebased this, and successfully tested socket-activating a webdav and sftp server.

systemd-socket-activate -l 8088 -l 8089 --fdname=foo:bar -- ./rclone serve webdav :local:vfs/
systemd-socket-activate -l 2022 --fdname=foo:bar -- ./rclone serve sftp :local:vfs

… both from the root of the rclone checkout, after a go build ./rclone.go.

Copy link
Member

@ncw ncw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this code is looking nice - thank you.

I successfully tested socket-activating a webdav and sftp server.

systemd-socket-activate -l 8088 -l 8089 --fdname=foo:bar -- ./rclone serve webdav :local:vfs/
systemd-socket-activate -l 2022 --fdname=foo:bar -- ./rclone serve sftp :local:vfs

… both from the root of the rclone checkout, after a go build ./rclone.go.

Can you put these commands in the docs please? It is great to have some commands people can cut and paste to try the feature.

It would be nice also to have a test - do you think that is possible?

PS I think all the test failures are flakes so I've re-run them.

@flokli
Copy link
Contributor Author

flokli commented Aug 2, 2024

PS I think all the test failures are flakes so I've re-run them.

The windows lint is actually correct - will push a fix.

Can you put these commands in the docs please? It is great to have some commands people can cut and paste to try the feature.

It really isn't how I'd expect people to run this in production usecases - where they'll probably configure systemd .service and .socket files. I can try to find a wording that makes sure this only makes sense for testing purposes.


Auxillary question - do you think we should roll this a bit differently, essentially switch to be socket-activated if we detect to be in such an environment (and have a CLI flag to disable it), but keep the existing listener syntax mostly?

@flokli flokli force-pushed the socket-activation branch from 986b828 to 5651e45 Compare August 2, 2024 09:38
@ncw
Copy link
Member

ncw commented Aug 2, 2024

PS I think all the test failures are flakes so I've re-run them.

The windows lint is actually correct - will push a fix.

👍

Can you put these commands in the docs please? It is great to have some commands people can cut and paste to try the feature.

It really isn't how I'd expect people to run this in production usecases - where they'll probably configure systemd .service and .socket files. I can try to find a wording that makes sure this only makes sense for testing purposes.

Great.

Auxillary question - do you think we should roll this a bit differently, essentially switch to be socket-activated if we detect to be in such an environment (and have a CLI flag to disable it), but keep the existing listener syntax mostly?

How does this change the listener syntax? Do you mean where it ignores the command line args if it detects socket activation?

Not sure I understand the question (probably not enough coffee yet :-)

@aanderse
Copy link

aanderse commented Aug 2, 2024

It really isn't how I'd expect people to run this in production usecases - where they'll probably configure systemd .service and .socket files.

right, which is why an example socket and service file would probably be useful to some in documentation, right?

@flokli
Copy link
Contributor Author

flokli commented Aug 2, 2024

It really isn't how I'd expect people to run this in production usecases - where they'll probably configure systemd .service and .socket files.

right, which is why an example socket and service file would probably be useful to some in documentation, right?

The docs already link to https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html, which links to a bunch of guides:

For more extensive descriptions see the "systemd for Developers" series: Socket Activation, Socket Activation, part II, Converting inetd Services, Socket Activated Internet Services and OS Containers.

There's plenty of explanation there, and I'm fairly certain people looking for this feature are already aware of how it works, or willing to do some research on it if they want it. Duplicating a small subset of examples into an individual rclone documentation item feels like a bit too much IMHO. This is the rclone documentation, we can mention we do support it, be helpful and link to some more upstream documentation, but we shouldn't try to document every other auxillary tool rclone can interface. We also don't describe how to use an sftp or http client - I see this in a similar league.

@aanderse
Copy link

aanderse commented Aug 2, 2024

yeah i mean you and i find this topic immediately recognizable so it seems basic - i just wasn't sure this would be obvious to everyone

I'm fairly certain people looking for this feature are already aware of how it works

actually that's a great point... while this won't be obvious to everyone of course it will likely be obvious to everyone looking for it

on that note... thank you for your contribution here @flokli! i was just looking for this feature 2 days ago and found this PR... somehow i wasn't surprised to see your name 😉

@flokli
Copy link
Contributor Author

flokli commented Aug 14, 2024

Auxillary question - do you think we should roll this a bit differently, essentially switch to be socket-activated if we detect to be in such an environment (and have a CLI flag to disable it), but keep the existing listener syntax mostly?

How does this change the listener syntax? Do you mean where it ignores the command line args if it detects socket activation?

Not sure I understand the question (probably not enough coffee yet :-)

I think I confused myself too 😆

With this PR, lib/http/server.go supports both TLS and non-TLS listening (by looking at tlsConfig). It doesn't look at ListenAddr if socket-activated, and this is documented in the help.

I took another pass over the docs, mentioned .socket and .service unit files, and mentioned systemd-socket-activate for ad-hoc testing:

+It can be configured with .socket and .service unit files as described in                                                                    
+https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html                                                                  
+                                                                                                                                             
+Socket activation can be tested ad-hoc with the ` + "`systemd-socket-activate`" + `command:                                                  
+                                                                                                                                             
+       systemd-socket-activate -l 2222 -- rclone serve sftp :local:vfs/                                                                      
+                                                                                                                                             
+This will socket-activate rclone on the first connection to port 2222 over TCP.   

@flokli flokli requested a review from ncw August 14, 2024 13:47
@flokli flokli force-pushed the socket-activation branch from 5651e45 to 35d1d55 Compare August 14, 2024 13:48
flokli added 4 commits August 15, 2024 05:48
Instead of the listening addresses specified above, rclone will listen to all
FDs passed by the service manager, if any (and ignore any arguments passed by
`--{{ .Prefix }}addr`.

This allows rclone to be a socket-activated service. It can be configured as described in
https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html

It's possible to test this interactively through `systemd-socket-activate`,
firing of a request in a second terminal:

```
❯ systemd-socket-activate -l 8088 -l 8089 --fdname=foo:bar -- ./rclone serve webdav :local:test/
Listening on [::]:8088 as 3.
Listening on [::]:8089 as 4.
Communication attempt on fd 3.
Execing ./rclone (./rclone serve webdav :local:test/)
2024/04/24 18:14:42 NOTICE: Local file system at /home/flokli/dev/flokli/rclone/test: WebDav Server started on [sd-listen:bar-0/ sd-listen:foo-0/]
```
This was missing the fact rclone also supports listening on Unix Domain
Sockets.
It fails to build on plan9, which is part of the rclone CI matrix, and
the PR fixing it upstream doesn't seem to be getting traction.

Stub it on our side, we can still remove this once it gets merged.
@flokli flokli force-pushed the socket-activation branch from 35d1d55 to c0338ba Compare August 15, 2024 02:48
@flokli
Copy link
Contributor Author

flokli commented Aug 20, 2024

@ncw friendly ping :-) is there anything left you want me to change here, or can we land this?

Copy link
Member

@ncw ncw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in review - been on vacation !

Let's merge this for v1.68

Thank you :-)

@ncw ncw merged commit e3b0921 into rclone:master Sep 6, 2024
@flokli flokli deleted the socket-activation branch September 6, 2024 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rclone serve: support systemd socket activation

3 participants