From 8362e7cc103e5f53c2b3658df646f1bbd2f65b7b Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 3 Jan 2014 18:06:34 -0800 Subject: [PATCH 1/4] Move listenfd to utility package Docker-DCO-1.1-Signed-off-by: Brandon Philips (github: philips) --- systemd/listendfd.go | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 systemd/listendfd.go diff --git a/systemd/listendfd.go b/systemd/listendfd.go new file mode 100644 index 0000000..a8fdb09 --- /dev/null +++ b/systemd/listendfd.go @@ -0,0 +1,41 @@ +package systemd + +import ( + "errors" + "fmt" + "net" + "strconv" + + "github.com/coreos/go-systemd/activation" +) + +// ListenFD returns the specified socket activated files as a slice of +// net.Listeners or all of the activated files if "*" is given. +func ListenFD(addr string) ([]net.Listener, error) { + files := activation.Files(false) + if files == nil || len(files) == 0 { + return nil, errors.New("No sockets found") + } + + fdNum, _ := strconv.Atoi(addr) + fdOffset := fdNum - 3 + if (addr != "*") && (len(files) < int(fdOffset)+1) { + return nil, errors.New("Too few socket activated files passed in") + } + + // socket activation + listeners := make([]net.Listener, len(files)) + for i, f := range files { + var err error + listeners[i], err = net.FileListener(f) + if err != nil { + return nil, fmt.Errorf("Error setting up FileListener for fd %d: %s", f.Fd(), err.Error()) + } + } + + if addr == "*" { + return listeners, nil + } + + return []net.Listener{listeners[fdOffset]}, nil +} From 56cf7be3345925fd39f0a3847172c2dda0e6ad9d Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 3 Jan 2014 18:07:43 -0800 Subject: [PATCH 2/4] Allow fd:// like unix:// and tcp:// Somthing like 20605eb310f0b57bd06eea80ec63c5022fc83bde Docker-DCO-1.1-Signed-off-by: Brandon Philips (github: philips) --- systemd/listendfd.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/systemd/listendfd.go b/systemd/listendfd.go index a8fdb09..08070b6 100644 --- a/systemd/listendfd.go +++ b/systemd/listendfd.go @@ -17,6 +17,11 @@ func ListenFD(addr string) ([]net.Listener, error) { return nil, errors.New("No sockets found") } + // default to all fds just like unix:// and tcp:// + if addr == "" { + addr = "*" + } + fdNum, _ := strconv.Atoi(addr) fdOffset := fdNum - 3 if (addr != "*") && (len(files) < int(fdOffset)+1) { From f89629467c37daf1f347e4b8b15113a58b55786d Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Fri, 17 Jan 2014 14:07:06 -0800 Subject: [PATCH 3/4] chore(systemd): use activation.Listeners instead of Files Use this Listeners() API that was exposed to save a few more lines of boiler plate code. Docker-DCO-1.1-Signed-off-by: Brandon Philips (github: philips) --- systemd/listendfd.go | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/systemd/listendfd.go b/systemd/listendfd.go index 08070b6..0fbc0a6 100644 --- a/systemd/listendfd.go +++ b/systemd/listendfd.go @@ -2,7 +2,6 @@ package systemd import ( "errors" - "fmt" "net" "strconv" @@ -12,8 +11,13 @@ import ( // ListenFD returns the specified socket activated files as a slice of // net.Listeners or all of the activated files if "*" is given. func ListenFD(addr string) ([]net.Listener, error) { - files := activation.Files(false) - if files == nil || len(files) == 0 { + // socket activation + listeners, err := activation.Listeners(false) + if err != nil { + return nil, err + } + + if listeners == nil || len(listeners) == 0 { return nil, errors.New("No sockets found") } @@ -24,20 +28,10 @@ func ListenFD(addr string) ([]net.Listener, error) { fdNum, _ := strconv.Atoi(addr) fdOffset := fdNum - 3 - if (addr != "*") && (len(files) < int(fdOffset)+1) { + if (addr != "*") && (len(listeners) < int(fdOffset)+1) { return nil, errors.New("Too few socket activated files passed in") } - // socket activation - listeners := make([]net.Listener, len(files)) - for i, f := range files { - var err error - listeners[i], err = net.FileListener(f) - if err != nil { - return nil, fmt.Errorf("Error setting up FileListener for fd %d: %s", f.Fd(), err.Error()) - } - } - if addr == "*" { return listeners, nil } From 3f799912bf7796bf2f2c75787f337f937d5806eb Mon Sep 17 00:00:00 2001 From: Brandon Philips Date: Tue, 21 Jan 2014 12:43:57 -0800 Subject: [PATCH 4/4] chore(coreos/go-systemd): copy to github.com/dotcloud/docker/systemd/pkg/activation Via https://github.com/dotcloud/docker/pull/3105#issuecomment-32807547 Docker-DCO-1.1-Signed-off-by: Brandon Philips (github: philips) --- systemd/activation/files.go | 55 +++++++++++++++++++++++++++++++++ systemd/activation/listeners.go | 37 ++++++++++++++++++++++ systemd/listendfd.go | 2 +- 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 systemd/activation/files.go create mode 100644 systemd/activation/listeners.go diff --git a/systemd/activation/files.go b/systemd/activation/files.go new file mode 100644 index 0000000..0281146 --- /dev/null +++ b/systemd/activation/files.go @@ -0,0 +1,55 @@ +/* +Copyright 2013 CoreOS Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Package activation implements primitives for systemd socket activation. +package activation + +import ( + "os" + "strconv" + "syscall" +) + +// based on: https://gist.github.com/alberts/4640792 +const ( + listenFdsStart = 3 +) + +func Files(unsetEnv bool) []*os.File { + if unsetEnv { + // there is no way to unset env in golang os package for now + // https://code.google.com/p/go/issues/detail?id=6423 + defer os.Setenv("LISTEN_PID", "") + defer os.Setenv("LISTEN_FDS", "") + } + + pid, err := strconv.Atoi(os.Getenv("LISTEN_PID")) + if err != nil || pid != os.Getpid() { + return nil + } + + nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS")) + if err != nil || nfds == 0 { + return nil + } + + var files []*os.File + for fd := listenFdsStart; fd < listenFdsStart+nfds; fd++ { + syscall.CloseOnExec(fd) + files = append(files, os.NewFile(uintptr(fd), "LISTEN_FD_"+strconv.Itoa(fd))) + } + + return files +} diff --git a/systemd/activation/listeners.go b/systemd/activation/listeners.go new file mode 100644 index 0000000..3296a08 --- /dev/null +++ b/systemd/activation/listeners.go @@ -0,0 +1,37 @@ +/* +Copyright 2014 CoreOS Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package activation + +import ( + "fmt" + "net" +) + +// Listeners returns net.Listeners for all socket activated fds passed to this process. +func Listeners(unsetEnv bool) ([]net.Listener, error) { + files := Files(unsetEnv) + listeners := make([]net.Listener, len(files)) + + for i, f := range files { + var err error + listeners[i], err = net.FileListener(f) + if err != nil { + return nil, fmt.Errorf("Error setting up FileListener for fd %d: %s", f.Fd(), err.Error()) + } + } + + return listeners, nil +} diff --git a/systemd/listendfd.go b/systemd/listendfd.go index 0fbc0a6..f604432 100644 --- a/systemd/listendfd.go +++ b/systemd/listendfd.go @@ -5,7 +5,7 @@ import ( "net" "strconv" - "github.com/coreos/go-systemd/activation" + "github.com/dotcloud/docker/pkg/systemd/activation" ) // ListenFD returns the specified socket activated files as a slice of