diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/adapter/containers.go | 2 | ||||
-rw-r--r-- | pkg/adapter/network.go | 147 | ||||
-rw-r--r-- | pkg/adapter/pods.go | 2 | ||||
-rw-r--r-- | pkg/adapter/runtime.go | 5 | ||||
-rw-r--r-- | pkg/adapter/runtime_remote.go | 7 | ||||
-rw-r--r-- | pkg/cgroups/cgroups.go | 73 | ||||
-rw-r--r-- | pkg/cgroups/systemd.go | 23 | ||||
-rw-r--r-- | pkg/hooks/hooks.go | 3 | ||||
-rw-r--r-- | pkg/network/config.go | 4 | ||||
-rw-r--r-- | pkg/network/network.go | 26 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.c | 14 | ||||
-rw-r--r-- | pkg/spec/storage.go | 9 | ||||
-rw-r--r-- | pkg/util/mountOpts.go | 3 | ||||
-rw-r--r-- | pkg/util/utils_windows.go | 12 | ||||
-rw-r--r-- | pkg/varlinkapi/containers.go | 9 |
15 files changed, 297 insertions, 42 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go index b712bd9aa..45a9a54a3 100644 --- a/pkg/adapter/containers.go +++ b/pkg/adapter/containers.go @@ -342,7 +342,7 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode if err := ctr.Start(ctx, c.IsSet("pod")); err != nil { // This means the command did not exist exitCode = 127 - if strings.Contains(err.Error(), "permission denied") { + if strings.Contains(err.Error(), "permission denied") || strings.Contains(err.Error(), "file not found") { exitCode = 126 } return exitCode, err diff --git a/pkg/adapter/network.go b/pkg/adapter/network.go new file mode 100644 index 000000000..cf3a1dfdd --- /dev/null +++ b/pkg/adapter/network.go @@ -0,0 +1,147 @@ +// +build !remoteclient + +package adapter + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "strings" + "text/tabwriter" + + "github.com/containernetworking/cni/libcni" + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/pkg/network" + "github.com/pkg/errors" +) + +func getCNIConfDir(r *LocalRuntime) (string, error) { + config, err := r.GetConfig() + if err != nil { + return "", err + } + configPath := config.CNIConfigDir + + if len(config.CNIConfigDir) < 1 { + configPath = network.CNIConfigDir + } + return configPath, nil +} + +// NetworkList displays summary information about CNI networks +func (r *LocalRuntime) NetworkList(cli *cliconfig.NetworkListValues) error { + cniConfigPath, err := getCNIConfDir(r) + if err != nil { + return err + } + networks, err := network.LoadCNIConfsFromDir(cniConfigPath) + if err != nil { + return err + } + // quiet means we only print the network names + if cli.Quiet { + for _, cniNetwork := range networks { + fmt.Println(cniNetwork.Name) + } + return nil + } + w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) + if _, err := fmt.Fprintln(w, "NAME\tVERSION\tPLUGINS"); err != nil { + return err + } + for _, cniNetwork := range networks { + if _, err := fmt.Fprintf(w, "%s\t%s\t%s\n", cniNetwork.Name, cniNetwork.CNIVersion, getCNIPlugins(cniNetwork)); err != nil { + return err + } + } + return w.Flush() +} + +// NetworkInspect displays the raw CNI configuration for one +// or more CNI networks +func (r *LocalRuntime) NetworkInspect(cli *cliconfig.NetworkInspectValues) error { + var ( + rawCNINetworks []map[string]interface{} + ) + cniConfigPath, err := getCNIConfDir(r) + if err != nil { + return err + } + for _, name := range cli.InputArgs { + b, err := readRawCNIConfByName(name, cniConfigPath) + if err != nil { + return err + } + rawList := make(map[string]interface{}) + if err := json.Unmarshal(b, &rawList); err != nil { + return fmt.Errorf("error parsing configuration list: %s", err) + } + rawCNINetworks = append(rawCNINetworks, rawList) + } + out, err := json.MarshalIndent(rawCNINetworks, "", "\t") + if err != nil { + return err + } + fmt.Printf("%s\n", out) + return nil +} + +// NetworkRemove deletes one or more CNI networks +func (r *LocalRuntime) NetworkRemove(cli *cliconfig.NetworkRmValues) error { + cniConfigPath, err := getCNIConfDir(r) + if err != nil { + return err + } + for _, name := range cli.InputArgs { + cniPath, err := getCNIConfigPathByName(name, cniConfigPath) + if err != nil { + return err + } + if err := os.Remove(cniPath); err != nil { + return err + } + fmt.Printf("Deleted: %s\n", name) + } + return nil +} + +// getCNIConfigPathByName finds a CNI network by name and +// returns its configuration file path +func getCNIConfigPathByName(name, cniConfigPath string) (string, error) { + files, err := libcni.ConfFiles(cniConfigPath, []string{".conflist"}) + if err != nil { + return "", err + } + for _, confFile := range files { + conf, err := libcni.ConfListFromFile(confFile) + if err != nil { + return "", err + } + if conf.Name == name { + return confFile, nil + } + } + return "", errors.Errorf("unable to find network configuration for %s", name) +} + +// readRawCNIConfByName reads the raw CNI configuration for a CNI +// network by name +func readRawCNIConfByName(name, cniConfigPath string) ([]byte, error) { + confFile, err := getCNIConfigPathByName(name, cniConfigPath) + if err != nil { + return nil, err + } + b, err := ioutil.ReadFile(confFile) + return b, err +} + +// getCNIPlugins returns a list of plugins that a given network +// has in the form of a string +func getCNIPlugins(list *libcni.NetworkConfigList) string { + var plugins []string + for _, plug := range list.Plugins { + plugins = append(plugins, plug.Network.Type) + } + return strings.Join(plugins, ",") +} diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 66588ce26..1dd72babf 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -708,6 +708,8 @@ func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name) } + containerConfig.UserCommand = containerConfig.Command + containerConfig.StopSignal = 15 // If the user does not pass in ID mappings, just set to basics diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 61db65a9d..ba988aaf7 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -289,9 +289,12 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti options.CommonBuildOpts = commonOpts options.SystemContext = systemContext - if c.Flag("runtime").Changed { + if c.GlobalFlags.Runtime != "" { + options.Runtime = c.GlobalFlags.Runtime + } else { options.Runtime = r.GetOCIRuntimePath() } + if c.Quiet { options.ReportWriter = ioutil.Discard } diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index 39ea88131..420c9d0bb 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -10,6 +10,7 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "strings" "text/template" "time" @@ -69,6 +70,12 @@ func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, cmd: c.GlobalFlags, } configPath := remoteclientconfig.GetConfigFilePath() + // Check if the basedir for configPath exists and if not, create it. + if _, err := os.Stat(filepath.Dir(configPath)); os.IsNotExist(err) { + if mkdirErr := os.MkdirAll(filepath.Dir(configPath), 0750); mkdirErr != nil { + return nil, mkdirErr + } + } if len(c.GlobalFlags.RemoteConfigFilePath) > 0 { configPath = c.GlobalFlags.RemoteConfigFilePath customConfig = true diff --git a/pkg/cgroups/cgroups.go b/pkg/cgroups/cgroups.go index f2c6b548e..085718855 100644 --- a/pkg/cgroups/cgroups.go +++ b/pkg/cgroups/cgroups.go @@ -10,6 +10,8 @@ import ( "strconv" "strings" + systemdDbus "github.com/coreos/go-systemd/dbus" + "github.com/godbus/dbus" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -352,7 +354,56 @@ func (c *CgroupControl) CreateSystemdUnit(path string) error { if !c.systemd { return fmt.Errorf("the cgroup controller is not using systemd") } - return systemdCreate(path) + + conn, err := systemdDbus.New() + if err != nil { + return err + } + defer conn.Close() + + return systemdCreate(path, conn) +} + +// GetUserConnection returns an user connection to D-BUS +func GetUserConnection(uid int) (*systemdDbus.Conn, error) { + return systemdDbus.NewConnection(func() (*dbus.Conn, error) { + return dbusAuthConnection(uid, dbus.SessionBusPrivate) + }) +} + +// CreateSystemdUserUnit creates the systemd cgroup for the specified user +func (c *CgroupControl) CreateSystemdUserUnit(path string, uid int) error { + if !c.systemd { + return fmt.Errorf("the cgroup controller is not using systemd") + } + + conn, err := GetUserConnection(uid) + if err != nil { + return err + } + defer conn.Close() + + return systemdCreate(path, conn) +} + +func dbusAuthConnection(uid int, createBus func(opts ...dbus.ConnOption) (*dbus.Conn, error)) (*dbus.Conn, error) { + conn, err := createBus() + if err != nil { + return nil, err + } + + methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))} + + err = conn.Auth(methods) + if err != nil { + conn.Close() + return nil, err + } + if err := conn.Hello(); err != nil { + return nil, err + } + + return conn, nil } // Delete cleans a cgroup @@ -386,10 +437,11 @@ func rmDirRecursively(path string) error { return nil } -// DeleteByPath deletes the specified cgroup path -func (c *CgroupControl) DeleteByPath(path string) error { +// DeleteByPathConn deletes the specified cgroup path using the specified +// dbus connection if needed. +func (c *CgroupControl) DeleteByPathConn(path string, conn *systemdDbus.Conn) error { if c.systemd { - return systemdDestroy(path) + return systemdDestroyConn(path, conn) } if c.cgroup2 { return rmDirRecursively(filepath.Join(cgroupRoot, c.path)) @@ -413,6 +465,19 @@ func (c *CgroupControl) DeleteByPath(path string) error { return lastError } +// DeleteByPath deletes the specified cgroup path +func (c *CgroupControl) DeleteByPath(path string) error { + if c.systemd { + conn, err := systemdDbus.New() + if err != nil { + return err + } + defer conn.Close() + return c.DeleteByPathConn(path, conn) + } + return c.DeleteByPathConn(path, nil) +} + // Update updates the cgroups func (c *CgroupControl) Update(resources *spec.LinuxResources) error { for _, h := range handlers { diff --git a/pkg/cgroups/systemd.go b/pkg/cgroups/systemd.go index e72e456bc..b8e6db156 100644 --- a/pkg/cgroups/systemd.go +++ b/pkg/cgroups/systemd.go @@ -9,13 +9,7 @@ import ( "github.com/godbus/dbus" ) -func systemdCreate(path string) error { - c, err := systemdDbus.New() - if err != nil { - return err - } - defer c.Close() - +func systemdCreate(path string, c *systemdDbus.Conn) error { slice, name := filepath.Split(path) slice = strings.TrimSuffix(slice, "/") @@ -43,7 +37,7 @@ func systemdCreate(path string) error { } ch := make(chan string) - _, err = c.StartTransientUnit(name, "replace", properties, ch) + _, err := c.StartTransientUnit(name, "replace", properties, ch) if err != nil { lastError = err continue @@ -55,7 +49,7 @@ func systemdCreate(path string) error { } /* - systemdDestroy is copied from containerd/cgroups/systemd.go file, that + systemdDestroyConn is copied from containerd/cgroups/systemd.go file, that has the following license: Copyright The containerd Authors. @@ -72,18 +66,11 @@ func systemdCreate(path string) error { See the License for the specific language governing permissions and limitations under the License. */ - -func systemdDestroy(path string) error { - c, err := systemdDbus.New() - if err != nil { - return err - } - defer c.Close() - +func systemdDestroyConn(path string, c *systemdDbus.Conn) error { name := filepath.Base(path) ch := make(chan string) - _, err = c.StopUnit(name, "replace", ch) + _, err := c.StopUnit(name, "replace", ch) if err != nil { return err } diff --git a/pkg/hooks/hooks.go b/pkg/hooks/hooks.go index b962ffa5c..0d26bf4af 100644 --- a/pkg/hooks/hooks.go +++ b/pkg/hooks/hooks.go @@ -4,6 +4,7 @@ package hooks import ( "context" "fmt" + "os" "sort" "strings" "sync" @@ -56,7 +57,7 @@ func New(ctx context.Context, directories []string, extensionStages []string) (m for _, dir := range directories { err = ReadDir(dir, manager.extensionStages, manager.hooks) - if err != nil { + if err != nil && !os.IsNotExist(err) { return nil, err } } diff --git a/pkg/network/config.go b/pkg/network/config.go new file mode 100644 index 000000000..d282f66b6 --- /dev/null +++ b/pkg/network/config.go @@ -0,0 +1,4 @@ +package network + +// CNIConfigDir is the path where CNI config files exist +const CNIConfigDir = "/etc/cni/net.d" diff --git a/pkg/network/network.go b/pkg/network/network.go new file mode 100644 index 000000000..9d04340a3 --- /dev/null +++ b/pkg/network/network.go @@ -0,0 +1,26 @@ +package network + +import ( + "sort" + + "github.com/containernetworking/cni/libcni" +) + +// LoadCNIConfsFromDir loads all the CNI configurations from a dir +func LoadCNIConfsFromDir(dir string) ([]*libcni.NetworkConfigList, error) { + var configs []*libcni.NetworkConfigList + files, err := libcni.ConfFiles(dir, []string{".conflist"}) + if err != nil { + return nil, err + } + sort.Strings(files) + + for _, confFile := range files { + conf, err := libcni.ConfListFromFile(confFile) + if err != nil { + return nil, err + } + configs = append(configs, conf) + } + return configs, nil +} diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 19b76f387..94933ddd0 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -137,7 +137,7 @@ get_cmd_line_args (pid_t pid) { allocated += 512; char *tmp = realloc (buffer, allocated); - if (buffer == NULL) + if (tmp == NULL) { free (buffer); return NULL; @@ -276,7 +276,7 @@ static void __attribute__((constructor)) init() return; } - r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf))); + r = TEMP_FAILURE_RETRY (read (fd, buf, sizeof (buf) - 1)); close (fd); if (r < 0) { @@ -457,6 +457,11 @@ create_pause_process (const char *pause_pid_file_path, char **argv) } r = TEMP_FAILURE_RETRY (write (p[1], "0", 1)); + if (r < 0) + { + fprintf (stderr, "cannot write to pipe: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } close (p[1]); _exit (EXIT_SUCCESS); @@ -811,6 +816,11 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re } ret = TEMP_FAILURE_RETRY (write (ready, "0", 1)); + if (ret < 0) + { + fprintf (stderr, "cannot write to ready pipe: %s\n", strerror (errno)); + _exit (EXIT_FAILURE); + } close (ready); if (sigprocmask (SIG_SETMASK, &oldsigset, NULL) < 0) diff --git a/pkg/spec/storage.go b/pkg/spec/storage.go index e0bb48a9c..b634f4cac 100644 --- a/pkg/spec/storage.go +++ b/pkg/spec/storage.go @@ -168,14 +168,14 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount, "/run": false, } if config.ReadOnlyRootfs && config.ReadOnlyTmpfs { - options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup", "size=65536k"} + options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"} for dest := range readonlyTmpfs { if _, ok := baseMounts[dest]; ok { continue } localOpts := options if dest == "/run" { - localOpts = append(localOpts, "noexec") + localOpts = append(localOpts, "noexec", "size=65536k") } baseMounts[dest] = spec.Mount{ Destination: dest, @@ -238,11 +238,6 @@ func (config *CreateConfig) parseVolumes(runtime *libpod.Runtime) ([]spec.Mount, // Conflicts are resolved simply - the last container specified wins. // Container names may be suffixed by mount options after a colon. func (config *CreateConfig) getVolumesFrom(runtime *libpod.Runtime) (map[string]spec.Mount, map[string]*libpod.ContainerNamedVolume, error) { - // TODO: This can probably be disabled now - if os.Geteuid() != 0 { - return nil, nil, nil - } - // Both of these are maps of mount destination to mount type. // We ensure that each destination is only mounted to once in this way. finalMounts := make(map[string]spec.Mount) diff --git a/pkg/util/mountOpts.go b/pkg/util/mountOpts.go index 40c99384d..9b2c734c0 100644 --- a/pkg/util/mountOpts.go +++ b/pkg/util/mountOpts.go @@ -92,9 +92,6 @@ func ProcessTmpfsOptions(options []string) ([]string, error) { if !foundWrite { baseOpts = append(baseOpts, "rw") } - if !foundSize { - baseOpts = append(baseOpts, "size=65536k") - } if !foundProp { baseOpts = append(baseOpts, "rprivate") } diff --git a/pkg/util/utils_windows.go b/pkg/util/utils_windows.go index e7b2a272e..e781e6717 100644 --- a/pkg/util/utils_windows.go +++ b/pkg/util/utils_windows.go @@ -6,29 +6,31 @@ import ( "github.com/pkg/errors" ) +var errNotImplemented = errors.New("not yet implemented") + // IsCgroup2UnifiedMode returns whether we are running in cgroup 2 unified mode. func IsCgroup2UnifiedMode() (bool, error) { - return false, errors.New("this function is not implemented for windows") + return false, errors.Wrap(errNotImplemented, "IsCgroup2Unified") } // GetContainerPidInformationDescriptors returns a string slice of all supported // format descriptors of GetContainerPidInformation. func GetContainerPidInformationDescriptors() ([]string, error) { - return nil, errors.New("this function is not implemented for windows") + return nil, errors.Wrap(errNotImplemented, "GetContainerPidInformationDescriptors") } // GetRootlessPauseProcessPidPath returns the path to the file that holds the pid for // the pause process func GetRootlessPauseProcessPidPath() (string, error) { - return "", errors.New("this function is not implemented for windows") + return "", errors.Wrap(errNotImplemented, "GetRootlessPauseProcessPidPath") } // GetRootlessRuntimeDir returns the runtime directory when running as non root func GetRootlessRuntimeDir() (string, error) { - return "", errors.New("this function is not implemented for windows") + return "", errors.Wrap(errNotImplemented, "GetRootlessRuntimeDir") } // GetRootlessConfigHomeDir returns the config home directory when running as non root func GetRootlessConfigHomeDir() (string, error) { - return "", errors.New("this function is not implemented for windows") + return "", errors.Wrap(errNotImplemented, "GetRootlessConfigHomeDir") } diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go index bb66ff962..c7aa5233f 100644 --- a/pkg/varlinkapi/containers.go +++ b/pkg/varlinkapi/containers.go @@ -19,6 +19,8 @@ import ( "github.com/containers/libpod/libpod/define" "github.com/containers/libpod/libpod/logs" "github.com/containers/libpod/pkg/adapter/shortcuts" + "github.com/containers/libpod/pkg/cgroups" + "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/varlinkapi/virtwriter" "github.com/containers/storage/pkg/archive" "github.com/pkg/errors" @@ -317,6 +319,13 @@ func (i *LibpodAPI) ExportContainer(call iopodman.VarlinkCall, name, outPath str // GetContainerStats ... func (i *LibpodAPI) GetContainerStats(call iopodman.VarlinkCall, name string) error { + cgroupv2, err := cgroups.IsCgroup2UnifiedMode() + if err != nil { + return call.ReplyErrorOccurred(err.Error()) + } + if rootless.IsRootless() && !cgroupv2 { + return call.ReplyErrRequiresCgroupsV2ForRootless("rootless containers cannot report container stats") + } ctr, err := i.Runtime.LookupContainer(name) if err != nil { return call.ReplyContainerNotFound(name, err.Error()) |