summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
authorbaude <bbaude@redhat.com>2020-01-16 11:23:16 -0600
committerBrent Baude <bbaude@redhat.com>2020-01-21 16:35:45 -0600
commitd4c2aaf38ad066e742dad530535faade39dadd1a (patch)
tree062e1f1f8499375c5124487769e13b7b5fb788f1 /pkg
parentf63005e0f23ae6a71c2c910014c5e19623272f73 (diff)
downloadpodman-d4c2aaf38ad066e742dad530535faade39dadd1a.tar.gz
podman-d4c2aaf38ad066e742dad530535faade39dadd1a.tar.bz2
podman-d4c2aaf38ad066e742dad530535faade39dadd1a.zip
Add service endpoint
add service endpoint for the new API. Also supports the varlink implementation. Signed-off-by: baude <bbaude@redhat.com> Refactor to allow developer more control of API server * Add api.NewServerWithSettings() to create an API server with custom settings * Add api.ListenUnix() to create a UDS net.Listener and setup UDS Signed-off-by: Jhon Honce <jhonce@redhat.com> Signed-off-by: baude <bbaude@redhat.com> More service completion Add podman service command that allows users to run either a RESTful or varlink protocol API service. Addition of docs and RESTful listening. Signed-off-by: baude <bbaude@redhat.com> Signed-off-by: Brent Baude <bbaude@redhat.com>
Diffstat (limited to 'pkg')
-rw-r--r--pkg/adapter/client.go2
-rw-r--r--pkg/adapter/client_config.go7
-rw-r--r--pkg/api/server/listener_api.go31
-rw-r--r--pkg/api/server/server.go50
-rw-r--r--pkg/bindings/containers.go8
5 files changed, 80 insertions, 18 deletions
diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go
index da4670892..5774ebe72 100644
--- a/pkg/adapter/client.go
+++ b/pkg/adapter/client.go
@@ -57,7 +57,7 @@ func (r RemoteRuntime) RemoteEndpoint() (remoteEndpoint *Endpoint, err error) {
// last resort is to make a socket connection with the default varlink address for root user
} else {
logrus.Debug("creating a varlink address based default root address")
- remoteEndpoint, err = newSocketConnection(DefaultAddress)
+ remoteEndpoint, err = newSocketConnection(DefaultVarlinkAddress)
}
return
}
diff --git a/pkg/adapter/client_config.go b/pkg/adapter/client_config.go
index 3559b16e3..8187b03b1 100644
--- a/pkg/adapter/client_config.go
+++ b/pkg/adapter/client_config.go
@@ -1,7 +1,10 @@
package adapter
-// DefaultAddress is the default address of the varlink socket
-const DefaultAddress = "unix:/run/podman/io.podman"
+// DefaultAPIAddress is the default address of the REST socket
+const DefaultAPIAddress = "unix:/run/podman/podman.sock"
+
+// DefaultVarlinkAddress is the default address of the varlink socket
+const DefaultVarlinkAddress = "unix:/run/podman/io.podman"
// EndpointType declares the type of server connection
type EndpointType int
diff --git a/pkg/api/server/listener_api.go b/pkg/api/server/listener_api.go
new file mode 100644
index 000000000..4984216b8
--- /dev/null
+++ b/pkg/api/server/listener_api.go
@@ -0,0 +1,31 @@
+package server
+
+import (
+ "net"
+ "os"
+ "path/filepath"
+
+ "github.com/pkg/errors"
+)
+
+// ListenUnix follows stdlib net.Listen() API, providing a unix listener for given path
+// ListenUnix will delete and create files/directories as needed
+func ListenUnix(network string, path string) (net.Listener, error) {
+ // setup custom listener for API server
+ err := os.MkdirAll(filepath.Dir(path), 0770)
+ if err != nil {
+ return nil, errors.Wrapf(err, "api.ListenUnix() failed to create %s", filepath.Dir(path))
+ }
+ os.Remove(path)
+
+ listener, err := net.Listen(network, path)
+ if err != nil {
+ return nil, errors.Wrapf(err, "api.ListenUnix() failed to create net.Listen(%s, %s)", network, path)
+ }
+
+ _, err = os.Stat(path)
+ if err != nil {
+ return nil, errors.Wrapf(err, "net.Listen(%s, %s) failed to report the failure to create socket", network, path)
+ }
+ return listener, nil
+}
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index 9abedb359..f3bae0345 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -54,9 +54,9 @@ import (
)
type APIServer struct {
- http.Server // Where the HTTP work happens
+ http.Server // The HTTP work happens here
*schema.Decoder // Decoder for Query parameters to structs
- context.Context // Context for graceful server shutdown
+ context.Context // Context to carry objects to handlers
*libpod.Runtime // Where the real work happens
net.Listener // mux for routing HTTP API calls to libpod routines
context.CancelFunc // Stop APIServer
@@ -64,14 +64,37 @@ type APIServer struct {
time.Duration // Duration of client access sliding window
}
-// NewServer will create and configure a new API HTTP server
+// Number of seconds to wait for next request, if exceeded shutdown server
+const (
+ DefaultServiceDuration = 300 * time.Second
+ UnlimitedServiceDuration = 0 * time.Second
+)
+
+// NewServer will create and configure a new API server with all defaults
func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
- listeners, err := activation.Listeners()
- if err != nil {
- return nil, errors.Wrap(err, "Cannot retrieve file descriptors from systemd")
- }
- if len(listeners) != 1 {
- return nil, errors.Errorf("Wrong number of file descriptors from systemd for socket activation (%d != 1)", len(listeners))
+ return newServer(runtime, DefaultServiceDuration, nil)
+}
+
+// NewServerWithSettings will create and configure a new API server using provided settings
+func NewServerWithSettings(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
+ return newServer(runtime, duration, listener)
+}
+
+func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Listener) (*APIServer, error) {
+ // If listener not provided try socket activation protocol
+ if listener == nil {
+ if _, found := os.LookupEnv("LISTEN_FDS"); !found {
+ return nil, errors.Errorf("Cannot create Server, no listener provided and socket activation protocol is not active.")
+ }
+
+ listeners, err := activation.Listeners()
+ if err != nil {
+ return nil, errors.Wrap(err, "Cannot retrieve file descriptors from systemd")
+ }
+ if len(listeners) != 1 {
+ return nil, errors.Errorf("Wrong number of file descriptors for socket activation protocol (%d != 1)", len(listeners))
+ }
+ listener = &listeners[0]
}
router := mux.NewRouter()
@@ -86,9 +109,9 @@ func NewServer(runtime *libpod.Runtime) (*APIServer, error) {
Decoder: schema.NewDecoder(),
Context: nil,
Runtime: runtime,
- Listener: listeners[0],
+ Listener: *listener,
CancelFunc: nil,
- Duration: 300 * time.Second,
+ Duration: duration,
}
server.Timer = time.AfterFunc(server.Duration, func() {
if err := server.Shutdown(); err != nil {
@@ -182,6 +205,11 @@ func (s *APIServer) Serve() error {
// Shutdown is a clean shutdown waiting on existing clients
func (s *APIServer) Shutdown() error {
+ // Duration == 0 flags no auto-shutdown of server
+ if s.Duration == 0 {
+ return nil
+ }
+
// We're still in the sliding service window
if s.Timer.Stop() {
s.Timer.Reset(s.Duration)
diff --git a/pkg/bindings/containers.go b/pkg/bindings/containers.go
index 01f68f970..057580088 100644
--- a/pkg/bindings/containers.go
+++ b/pkg/bindings/containers.go
@@ -126,11 +126,11 @@ func (c Connection) ContainerExists(nameOrID string) (bool, error) {
return false, nil
}
-func (c Connection) StopContainer(nameOrID string, timeout int) error {
- // TODO we might need to distinguish whether a timeout is desired; a zero, the int
- // zero value is valid; what do folks want to do?
+func (c Connection) StopContainer(nameOrID string, timeout *int) error {
params := make(map[string]string)
- params["t"] = strconv.Itoa(timeout)
+ if timeout != nil {
+ params["t"] = strconv.Itoa(*timeout)
+ }
response, err := c.newRequest(http.MethodPost, fmt.Sprintf("/containers/%s/stop", nameOrID), nil, params)
if err != nil {
return err