aboutsummaryrefslogtreecommitdiff
path: root/cmd/podman/system/service.go
blob: 78062d135584323fd8b73ad537d154c74931424a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
// +build linux,!remote

package system

import (
	"net/url"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"github.com/containers/common/pkg/completion"
	"github.com/containers/podman/v2/cmd/podman/registry"
	"github.com/containers/podman/v2/pkg/domain/entities"
	"github.com/containers/podman/v2/pkg/rootless"
	"github.com/containers/podman/v2/pkg/systemd"
	"github.com/containers/podman/v2/pkg/util"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
)

var (
	srvDescription = `Run an API service

Enable a listening service for API access to Podman commands.
`

	srvCmd = &cobra.Command{
		Use:               "service [options] [URI]",
		Args:              cobra.MaximumNArgs(1),
		Short:             "Run API service",
		Long:              srvDescription,
		RunE:              service,
		ValidArgsFunction: completion.AutocompleteDefault,
		Example:           `podman system service --time=0 unix:///tmp/podman.sock`,
	}

	srvArgs = struct {
		Timeout int64
		Varlink bool
	}{}
)

func init() {
	registry.Commands = append(registry.Commands, registry.CliCommand{
		Mode:    []entities.EngineMode{entities.ABIMode},
		Command: srvCmd,
		Parent:  systemCmd,
	})

	flags := srvCmd.Flags()

	timeFlagName := "time"
	flags.Int64VarP(&srvArgs.Timeout, timeFlagName, "t", 5, "Time until the service session expires in seconds.  Use 0 to disable the timeout")
	_ = srvCmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone)

	flags.BoolVar(&srvArgs.Varlink, "varlink", false, "Use legacy varlink service instead of REST. Unit of --time changes from seconds to milliseconds.")

	_ = flags.MarkDeprecated("varlink", "valink API is deprecated.")
	flags.SetNormalizeFunc(aliasTimeoutFlag)
}

func aliasTimeoutFlag(_ *pflag.FlagSet, name string) pflag.NormalizedName {
	if name == "timeout" {
		name = "time"
	}
	return pflag.NormalizedName(name)
}

func service(cmd *cobra.Command, args []string) error {
	apiURI, err := resolveAPIURI(args)
	if err != nil {
		return err
	}
	logrus.Infof("using API endpoint: '%s'", apiURI)

	// Clean up any old existing unix domain socket
	if len(apiURI) > 0 {
		uri, err := url.Parse(apiURI)
		if err != nil {
			return err
		}

		// socket activation uses a unix:// socket in the shipped unit files but apiURI is coded as "" at this layer.
		if "unix" == uri.Scheme && !registry.IsRemote() {
			if err := syscall.Unlink(uri.Path); err != nil && !os.IsNotExist(err) {
				return err
			}
			mask := syscall.Umask(0177)
			defer syscall.Umask(mask)
		}
	}

	opts := entities.ServiceOptions{
		URI:     apiURI,
		Command: cmd,
	}

	if srvArgs.Varlink {
		opts.Timeout = time.Duration(srvArgs.Timeout) * time.Millisecond
		return registry.ContainerEngine().VarlinkService(registry.GetContext(), opts)
	}

	opts.Timeout = time.Duration(srvArgs.Timeout) * time.Second
	return restService(opts, cmd.Flags(), registry.PodmanConfig())
}

func resolveAPIURI(_url []string) (string, error) {
	// When determining _*THE*_ listening endpoint --
	// 1) User input wins always
	// 2) systemd socket activation
	// 3) rootless honors XDG_RUNTIME_DIR
	// 4) if varlink -- adapter.DefaultVarlinkAddress
	// 5) lastly adapter.DefaultAPIAddress

	if len(_url) == 0 {
		if v, found := os.LookupEnv("PODMAN_SOCKET"); found {
			logrus.Debugf("PODMAN_SOCKET='%s' used to determine API endpoint", v)
			_url = []string{v}
		}
	}

	switch {
	case len(_url) > 0 && _url[0] != "":
		return _url[0], nil
	case systemd.SocketActivated():
		logrus.Info("using systemd socket activation to determine API endpoint")
		return "", nil
	case rootless.IsRootless():
		xdg, err := util.GetRuntimeDir()
		if err != nil {
			return "", err
		}

		socketName := "podman.sock"
		if srvArgs.Varlink {
			socketName = "io.podman"
		}
		socketPath := filepath.Join(xdg, "podman", socketName)
		if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil {
			return "", err
		}
		return "unix:" + socketPath, nil
	case srvArgs.Varlink:
		return registry.DefaultVarlinkAddress, nil
	default:
		if err := os.MkdirAll(filepath.Dir(registry.DefaultRootAPIPath), 0700); err != nil {
			return "", err
		}
		return registry.DefaultRootAPIAddress, nil
	}
}