diff options
136 files changed, 920 insertions, 336 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 325176179..0102dcb1a 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -28,15 +28,15 @@ env: #### Cache-image names to test with ### ACTIVE_CACHE_IMAGE_NAMES: >- - fedora-28-libpod-6318419153518592 - fedora-29-libpod-6318419153518592 - ubuntu-18-libpod-6318419153518592 - rhel-7-libpod-6318419153518592 + fedora-29-libpod-548c1c05 + fedora-28-libpod-548c1c05 + ubuntu-18-libpod-548c1c05 + rhel-7-libpod-548c1c05 image-builder-image-1541772081 - FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-6318419153518592" - PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-6318419153518592" - UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-6318419153518592" - PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-6318419153518592" + FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-548c1c05" + PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-548c1c05" + UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-548c1c05" + PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-548c1c05" # RHEL_CACHE_IMAGE_NAME: "rhel-8-notready" # CENTOS_CACHE_IMAGE_NAME: "centos-7-notready" @@ -49,7 +49,7 @@ env: CNI_COMMIT: "7480240de9749f9a0a5c8614b17f1f03e0c06ab9" CRIO_COMMIT: "7a283c391abb7bd25086a8ff91dbb36ebdd24466" CRIU_COMMIT: "c74b83cd49c00589c0c0468ba5fe685b67fdbd0a" - RUNC_COMMIT: "25f3f893c86d07426df93b7aa172f33fdf093fbd" + RUNC_COMMIT: "029124da7af7360afa781a0234d1b083550f797c" # CSV of cache-image names to build (see $PACKER_BASE/libpod_images.json) PACKER_BUILDS: "ubuntu-18,fedora-29,fedora-28,rhel-7" # TODO: rhel-8,centos-7 # Version of packer to use diff --git a/Dockerfile b/Dockerfile index 83cd3fccd..767e64570 100644 --- a/Dockerfile +++ b/Dockerfile @@ -44,7 +44,7 @@ RUN apt-get update && apt-get install -y \ && apt-get clean # Install runc -ENV RUNC_COMMIT 96ec2177ae841256168fcf76954f7177af9446eb +ENV RUNC_COMMIT 029124da7af7360afa781a0234d1b083550f797c RUN set -x \ && export GOPATH="$(mktemp -d)" \ && git clone https://github.com/opencontainers/runc.git "$GOPATH/src/github.com/opencontainers/runc" \ diff --git a/cmd/podman/attach.go b/cmd/podman/attach.go index c07c0f1cf..37f8afbad 100644 --- a/cmd/podman/attach.go +++ b/cmd/podman/attach.go @@ -47,7 +47,7 @@ func attachCmd(c *cliconfig.AttachValues) error { if remoteclient && len(c.InputArgs) != 1 { return errors.Errorf("attach requires the name or id of one running container") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating runtime") } diff --git a/cmd/podman/build.go b/cmd/podman/build.go index b69ac6e84..647ff1e86 100644 --- a/cmd/podman/build.go +++ b/cmd/podman/build.go @@ -206,7 +206,7 @@ func buildCmd(c *cliconfig.BuildValues) error { dockerfiles = append(dockerfiles, filepath.Join(contextDir, "Dockerfile")) } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/checkpoint.go b/cmd/podman/checkpoint.go index f2f5d37da..234d683bb 100644 --- a/cmd/podman/checkpoint.go +++ b/cmd/podman/checkpoint.go @@ -54,7 +54,7 @@ func checkpointCmd(c *cliconfig.CheckpointValues) error { return errors.New("checkpointing a container requires root") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/cleanup.go b/cmd/podman/cleanup.go index f5b3cf55b..9434c68ba 100644 --- a/cmd/podman/cleanup.go +++ b/cmd/podman/cleanup.go @@ -49,7 +49,7 @@ func init() { } func cleanupCmd(c *cliconfig.CleanupValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index 640a4bff4..77156f47a 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -581,6 +581,10 @@ type SystemRenumberValues struct { PodmanCommand } +type SystemMigrateValues struct { + PodmanCommand +} + type SystemDfValues struct { PodmanCommand Verbose bool diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go index ef8debe42..4b0641d82 100644 --- a/cmd/podman/commands.go +++ b/cmd/podman/commands.go @@ -50,7 +50,6 @@ func getContainerSubCommands() []*cobra.Command { _restoreCommand, _runlabelCommand, _statsCommand, - _stopCommand, _umountCommand, } } @@ -75,6 +74,7 @@ func getSystemSubCommands() []*cobra.Command { return []*cobra.Command{ _renumberCommand, _dfSystemCommand, + _migrateCommand, } } diff --git a/cmd/podman/commit.go b/cmd/podman/commit.go index 8d79c1e28..2b38bab35 100644 --- a/cmd/podman/commit.go +++ b/cmd/podman/commit.go @@ -52,7 +52,7 @@ func init() { } func commitCmd(c *cliconfig.CommitValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/common.go b/cmd/podman/common.go index ba4a3f519..eac96d3ba 100644 --- a/cmd/podman/common.go +++ b/cmd/podman/common.go @@ -434,6 +434,10 @@ func getCreateFlags(c *cliconfig.PodmanCommand) { "read-only", false, "Make containers root filesystem read-only", ) + createFlags.Bool( + "read-only-tmpfs", true, + "When running containers in read-only mode mount a read-write tmpfs on /run, /tmp and /var/tmp", + ) createFlags.String( "restart", "", "Restart is not supported. Please use a systemd unit file for restart", diff --git a/cmd/podman/container.go b/cmd/podman/container.go index 9cd8229f9..b3058bf12 100644 --- a/cmd/podman/container.go +++ b/cmd/podman/container.go @@ -65,6 +65,7 @@ var ( _runCommand, _rmCommand, _startCommand, + _stopCommand, _topCommand, _unpauseCommand, _waitCommand, diff --git a/cmd/podman/containers_prune.go b/cmd/podman/containers_prune.go index 340c47e8d..b052bda36 100644 --- a/cmd/podman/containers_prune.go +++ b/cmd/podman/containers_prune.go @@ -39,7 +39,7 @@ func init() { } func pruneContainersCmd(c *cliconfig.PruneContainersValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go index 6e48b9f3b..82f2d3f20 100644 --- a/cmd/podman/cp.go +++ b/cmd/podman/cp.go @@ -58,7 +58,7 @@ func cpCmd(c *cliconfig.CpValues) error { return errors.Errorf("you must provide a source path and a destination path") } - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/create.go b/cmd/podman/create.go index cfc0fa0c3..cb3ba14c5 100644 --- a/cmd/podman/create.go +++ b/cmd/podman/create.go @@ -52,7 +52,7 @@ func createCmd(c *cliconfig.CreateValues) error { return err } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/diff.go b/cmd/podman/diff.go index 1138c48a3..9543113d8 100644 --- a/cmd/podman/diff.go +++ b/cmd/podman/diff.go @@ -87,7 +87,7 @@ func diffCmd(c *cliconfig.DiffValues) error { return errors.Errorf("container, image, or layer name must be specified: podman diff [options [...]] ID-NAME") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/events.go b/cmd/podman/events.go index 4c11fe1f3..15f5e9571 100644 --- a/cmd/podman/events.go +++ b/cmd/podman/events.go @@ -40,7 +40,7 @@ func init() { } func eventsCmd(c *cliconfig.EventValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go index d0d88ee8b..deff44a92 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -68,7 +68,7 @@ func execCmd(c *cliconfig.ExecValues) error { argStart = 0 } cmd := args[argStart:] - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go index dae48f14b..6619522b6 100644 --- a/cmd/podman/exists.go +++ b/cmd/podman/exists.go @@ -86,7 +86,7 @@ func imageExistsCmd(c *cliconfig.ImageExistsValues) error { if len(args) > 1 || len(args) < 1 { return errors.New("you may only check for the existence of one image at a time") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } @@ -107,7 +107,7 @@ func containerExistsCmd(c *cliconfig.ContainerExistsValues) error { if len(args) > 1 || len(args) < 1 { return errors.New("you may only check for the existence of one container at a time") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } @@ -126,7 +126,7 @@ func podExistsCmd(c *cliconfig.PodExistsValues) error { if len(args) > 1 || len(args) < 1 { return errors.New("you may only check for the existence of one pod at a time") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/export.go b/cmd/podman/export.go index 004c3ccde..82a4c13e7 100644 --- a/cmd/podman/export.go +++ b/cmd/podman/export.go @@ -41,7 +41,7 @@ func init() { // exportCmd saves a container to a tarball on disk func exportCmd(c *cliconfig.ExportValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go index 7963cde6e..318dd0771 100644 --- a/cmd/podman/generate_kube.go +++ b/cmd/podman/generate_kube.go @@ -54,7 +54,7 @@ func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error { return errors.Errorf("you must provide exactly one container|pod ID or name") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/healthcheck_run.go b/cmd/podman/healthcheck_run.go index 832451e0c..111318d9c 100644 --- a/cmd/podman/healthcheck_run.go +++ b/cmd/podman/healthcheck_run.go @@ -38,7 +38,7 @@ func init() { } func healthCheckCmd(c *cliconfig.HealthCheckValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrap(err, "could not get runtime") } diff --git a/cmd/podman/history.go b/cmd/podman/history.go index f96d7934c..cebf99a9f 100644 --- a/cmd/podman/history.go +++ b/cmd/podman/history.go @@ -67,7 +67,7 @@ func init() { } func historyCmd(c *cliconfig.HistoryValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/images.go b/cmd/podman/images.go index 41aa213a8..1c46571c3 100644 --- a/cmd/podman/images.go +++ b/cmd/podman/images.go @@ -134,7 +134,7 @@ func imagesCmd(c *cliconfig.ImagesValues) error { image string ) - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "Could not get runtime") } diff --git a/cmd/podman/images_prune.go b/cmd/podman/images_prune.go index c522c8b15..1ac5bc65d 100644 --- a/cmd/podman/images_prune.go +++ b/cmd/podman/images_prune.go @@ -37,7 +37,7 @@ func init() { } func pruneImagesCmd(c *cliconfig.PruneImagesValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/import.go b/cmd/podman/import.go index 2bba6cb0c..167d9f2c9 100644 --- a/cmd/podman/import.go +++ b/cmd/podman/import.go @@ -45,7 +45,7 @@ func init() { } func importCmd(c *cliconfig.ImportValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/info.go b/cmd/podman/info.go index 2b6ae1882..a6fce7fcb 100644 --- a/cmd/podman/info.go +++ b/cmd/podman/info.go @@ -50,7 +50,7 @@ func infoCmd(c *cliconfig.InfoValues) error { info := map[string]interface{}{} remoteClientInfo := map[string]interface{}{} - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go index 9491bc7c7..4303c149c 100644 --- a/cmd/podman/inspect.go +++ b/cmd/podman/inspect.go @@ -84,7 +84,7 @@ func inspectCmd(c *cliconfig.InspectValues) error { return errors.Errorf("you cannot provide additional arguments with --latest") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/kill.go b/cmd/podman/kill.go index 0513a154f..edf69ff2e 100644 --- a/cmd/podman/kill.go +++ b/cmd/podman/kill.go @@ -59,7 +59,7 @@ func killCmd(c *cliconfig.KillValues) error { return err } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/libpodruntime/runtime.go b/cmd/podman/libpodruntime/runtime.go index 78adf1252..b03846bbc 100644 --- a/cmd/podman/libpodruntime/runtime.go +++ b/cmd/podman/libpodruntime/runtime.go @@ -1,6 +1,8 @@ package libpodruntime import ( + "context" + "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/libpod" "github.com/containers/libpod/pkg/rootless" @@ -9,17 +11,22 @@ import ( "github.com/pkg/errors" ) +// GetRuntimeMigrate gets a libpod runtime that will perform a migration of existing containers +func GetRuntimeMigrate(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { + return getRuntime(ctx, c, false, true) +} + // GetRuntimeRenumber gets a libpod runtime that will perform a lock renumber -func GetRuntimeRenumber(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(c, true) +func GetRuntimeRenumber(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { + return getRuntime(ctx, c, true, false) } // GetRuntime generates a new libpod runtime configured by command line options -func GetRuntime(c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { - return getRuntime(c, false) +func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*libpod.Runtime, error) { + return getRuntime(ctx, c, false, false) } -func getRuntime(c *cliconfig.PodmanCommand, renumber bool) (*libpod.Runtime, error) { +func getRuntime(ctx context.Context, c *cliconfig.PodmanCommand, renumber bool, migrate bool) (*libpod.Runtime, error) { options := []libpod.RuntimeOption{} storageOpts := storage.StoreOptions{} storageSet := false @@ -63,11 +70,16 @@ func getRuntime(c *cliconfig.PodmanCommand, renumber bool) (*libpod.Runtime, err storageSet = true storageOpts.GraphDriverOptions = c.GlobalFlags.StorageOpts } + if migrate { + options = append(options, libpod.WithMigrate()) + } if renumber { options = append(options, libpod.WithRenumber()) } + options = append(options, libpod.WithContext(ctx)) + // Only set this if the user changes storage config on the command line if storageSet { options = append(options, libpod.WithStorageConfig(storageOpts)) diff --git a/cmd/podman/load.go b/cmd/podman/load.go index 3cc5e67c7..f3bbed48f 100644 --- a/cmd/podman/load.go +++ b/cmd/podman/load.go @@ -58,7 +58,7 @@ func loadCmd(c *cliconfig.LoadValues) error { return errors.New("too many arguments. Requires exactly 1") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/login.go b/cmd/podman/login.go index 589255683..6bf148cca 100644 --- a/cmd/podman/login.go +++ b/cmd/podman/login.go @@ -11,6 +11,7 @@ import ( "github.com/containers/image/types" "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/libpod/image" + "github.com/docker/docker-credential-helpers/credentials" "github.com/pkg/errors" "github.com/spf13/cobra" "golang.org/x/crypto/ssh/terminal" @@ -90,7 +91,8 @@ func loginCmd(c *cliconfig.LoginValues) error { // username of user logged in to server (if one exists) userFromAuthFile, passFromAuthFile, err := config.GetAuthentication(sc, server) - if err != nil { + // Do not return error if no credentials found in credHelpers, new credentials will be stored by config.SetAuthentication + if err != nil && err != credentials.NewErrCredentialsNotFound() { return errors.Wrapf(err, "error reading auth file") } diff --git a/cmd/podman/logs.go b/cmd/podman/logs.go index 6f24dc8fb..a1ec9f4ee 100644 --- a/cmd/podman/logs.go +++ b/cmd/podman/logs.go @@ -64,7 +64,7 @@ func init() { func logsCmd(c *cliconfig.LogsValues) error { var err error - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go index 91ad42630..5afd51e28 100644 --- a/cmd/podman/main_local.go +++ b/cmd/podman/main_local.go @@ -103,7 +103,7 @@ func profileOff(cmd *cobra.Command) error { } func setupRootless(cmd *cobra.Command, args []string) error { - if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || strings.HasPrefix(cmd.Use, "help") { + if os.Geteuid() == 0 || cmd == _searchCommand || cmd == _versionCommand || cmd == _mountCommand || cmd == _migrateCommand || strings.HasPrefix(cmd.Use, "help") { return nil } podmanCmd := cliconfig.PodmanCommand{ @@ -112,7 +112,7 @@ func setupRootless(cmd *cobra.Command, args []string) error { MainGlobalOpts, remoteclient, } - runtime, err := libpodruntime.GetRuntime(&podmanCmd) + runtime, err := libpodruntime.GetRuntime(getContext(), &podmanCmd) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go index 2ade8949a..7c9150d1b 100644 --- a/cmd/podman/mount.go +++ b/cmd/podman/mount.go @@ -61,7 +61,7 @@ type jsonMountPoint struct { } func mountCmd(c *cliconfig.MountValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go index ca137150a..cd8370082 100644 --- a/cmd/podman/pause.go +++ b/cmd/podman/pause.go @@ -43,7 +43,7 @@ func pauseCmd(c *cliconfig.PauseValues) error { return errors.New("pause is not supported for rootless containers") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/play_kube.go b/cmd/podman/play_kube.go index d1008e615..967798399 100644 --- a/cmd/podman/play_kube.go +++ b/cmd/podman/play_kube.go @@ -75,7 +75,7 @@ func playKubeCmd(c *cliconfig.KubePlayValues) error { } ctx := getContext() - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(ctx, &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_create.go b/cmd/podman/pod_create.go index 551010dce..c891f2c7b 100644 --- a/cmd/podman/pod_create.go +++ b/cmd/podman/pod_create.go @@ -62,7 +62,7 @@ func podCreateCmd(c *cliconfig.PodCreateValues) error { podIdFile *os.File ) - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/pod_inspect.go b/cmd/podman/pod_inspect.go index eb2366031..a22624078 100644 --- a/cmd/podman/pod_inspect.go +++ b/cmd/podman/pod_inspect.go @@ -49,7 +49,7 @@ func podInspectCmd(c *cliconfig.PodInspectValues) error { return errors.Errorf("you must provide the name or id of a pod") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_kill.go b/cmd/podman/pod_kill.go index 145d0492f..c1ea66126 100644 --- a/cmd/podman/pod_kill.go +++ b/cmd/podman/pod_kill.go @@ -49,7 +49,7 @@ func init() { // podKillCmd kills one or more pods with a signal func podKillCmd(c *cliconfig.PodKillValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_pause.go b/cmd/podman/pod_pause.go index 1c6611ebc..e8574bfdc 100644 --- a/cmd/podman/pod_pause.go +++ b/cmd/podman/pod_pause.go @@ -45,7 +45,7 @@ func init() { func podPauseCmd(c *cliconfig.PodPauseValues) error { var lastError error - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/pod_ps.go b/cmd/podman/pod_ps.go index f4b7437eb..b9dcbc05d 100644 --- a/cmd/podman/pod_ps.go +++ b/cmd/podman/pod_ps.go @@ -157,7 +157,7 @@ func podPsCmd(c *cliconfig.PodPsValues) error { return errors.Wrapf(err, "error with flags passed") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/pod_restart.go b/cmd/podman/pod_restart.go index 519568974..a1f4c8359 100644 --- a/cmd/podman/pod_restart.go +++ b/cmd/podman/pod_restart.go @@ -47,7 +47,7 @@ func init() { func podRestartCmd(c *cliconfig.PodRestartValues) error { var lastError error - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_rm.go b/cmd/podman/pod_rm.go index dd67bb0e0..218ed8154 100644 --- a/cmd/podman/pod_rm.go +++ b/cmd/podman/pod_rm.go @@ -47,7 +47,7 @@ func init() { // podRmCmd deletes pods func podRmCmd(c *cliconfig.PodRmValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_start.go b/cmd/podman/pod_start.go index 104f9ad73..5c9225428 100644 --- a/cmd/podman/pod_start.go +++ b/cmd/podman/pod_start.go @@ -45,7 +45,7 @@ func init() { } func podStartCmd(c *cliconfig.PodStartValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_stats.go b/cmd/podman/pod_stats.go index ed59d9a61..e0e5ca24e 100644 --- a/cmd/podman/pod_stats.go +++ b/cmd/podman/pod_stats.go @@ -78,7 +78,7 @@ func podStatsCmd(c *cliconfig.PodStatsValues) error { all = true } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_stop.go b/cmd/podman/pod_stop.go index 9cd425c29..b4b1718d9 100644 --- a/cmd/podman/pod_stop.go +++ b/cmd/podman/pod_stop.go @@ -47,7 +47,7 @@ func init() { } func podStopCmd(c *cliconfig.PodStopValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/pod_top.go b/cmd/podman/pod_top.go index e997d1456..64e32318e 100644 --- a/cmd/podman/pod_top.go +++ b/cmd/podman/pod_top.go @@ -67,7 +67,7 @@ func podTopCmd(c *cliconfig.PodTopValues) error { return errors.Errorf("you must provide the name or id of a running pod") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/pod_unpause.go b/cmd/podman/pod_unpause.go index 15375bee9..c5b7e6a18 100644 --- a/cmd/podman/pod_unpause.go +++ b/cmd/podman/pod_unpause.go @@ -46,7 +46,7 @@ func init() { func podUnpauseCmd(c *cliconfig.PodUnpauseValues) error { var lastError error - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/pods_prune.go b/cmd/podman/pods_prune.go index e6946f068..bdd75f9de 100644 --- a/cmd/podman/pods_prune.go +++ b/cmd/podman/pods_prune.go @@ -36,7 +36,7 @@ func init() { } func podPruneCmd(c *cliconfig.PodPruneValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/port.go b/cmd/podman/port.go index d63ae4aa9..7a9f01fe6 100644 --- a/cmd/podman/port.go +++ b/cmd/podman/port.go @@ -98,7 +98,7 @@ func portCmd(c *cliconfig.PortValues) error { } } - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go index df1ea2765..623f17050 100644 --- a/cmd/podman/ps.go +++ b/cmd/podman/ps.go @@ -211,7 +211,7 @@ func psCmd(c *cliconfig.PsValues) error { return errors.Wrapf(err, "error with flags passed") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go index 521419e7a..f6a5beb17 100644 --- a/cmd/podman/pull.go +++ b/cmd/podman/pull.go @@ -73,7 +73,7 @@ func pullCmd(c *cliconfig.PullValues) (retError error) { defer span.Finish() } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") diff --git a/cmd/podman/push.go b/cmd/podman/push.go index e6beaaeb4..ee14b15e2 100644 --- a/cmd/podman/push.go +++ b/cmd/podman/push.go @@ -100,7 +100,7 @@ func pushCmd(c *cliconfig.PushValues) error { registryCreds = creds } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not create runtime") } diff --git a/cmd/podman/refresh.go b/cmd/podman/refresh.go index 6640d9954..9f9cbf908 100644 --- a/cmd/podman/refresh.go +++ b/cmd/podman/refresh.go @@ -38,7 +38,7 @@ func init() { } func refreshCmd(c *cliconfig.RefreshValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/restart.go b/cmd/podman/restart.go index 9ab2dd528..437676eef 100644 --- a/cmd/podman/restart.go +++ b/cmd/podman/restart.go @@ -51,7 +51,7 @@ func restartCmd(c *cliconfig.RestartValues) error { return errors.Wrapf(libpod.ErrInvalidArg, "you must provide at least one container name or ID") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go index d9e85c267..8cfd5ca0d 100644 --- a/cmd/podman/restore.go +++ b/cmd/podman/restore.go @@ -54,7 +54,7 @@ func restoreCmd(c *cliconfig.RestoreValues) error { return errors.New("restoring a container requires root") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index e3ee186ce..1bf56b782 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -48,7 +48,7 @@ func init() { // rmCmd removes one or more containers func rmCmd(c *cliconfig.RmValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go index be7c81dab..4c41a3ad5 100644 --- a/cmd/podman/rmi.go +++ b/cmd/podman/rmi.go @@ -51,7 +51,7 @@ func rmiCmd(c *cliconfig.RmiValues) error { ctx := getContext() removeAll := c.All - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/run.go b/cmd/podman/run.go index 717a36e04..01b12d282 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -48,7 +48,7 @@ func runCmd(c *cliconfig.RunValues) error { return err } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/runlabel.go b/cmd/podman/runlabel.go index 8267e941f..f097cb693 100644 --- a/cmd/podman/runlabel.go +++ b/cmd/podman/runlabel.go @@ -85,7 +85,7 @@ func runlabelCmd(c *cliconfig.RunlabelValues) error { } opts := make(map[string]string) - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/save.go b/cmd/podman/save.go index a45223b6a..4d204337e 100644 --- a/cmd/podman/save.go +++ b/cmd/podman/save.go @@ -70,7 +70,7 @@ func saveCmd(c *cliconfig.SaveValues) error { return errors.Errorf("need at least 1 argument") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not create runtime") } diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go index e14276bdf..9050fd2b9 100644 --- a/cmd/podman/shared/container.go +++ b/cmd/podman/shared/container.go @@ -658,7 +658,8 @@ func GetCtrInspectInfo(config *libpod.ContainerConfig, ctrInspectData *inspect.C OomKillDisable: memDisableOOMKiller, PidsLimit: pidsLimit, Privileged: config.Privileged, - ReadonlyRootfs: spec.Root.Readonly, + ReadOnlyRootfs: spec.Root.Readonly, + ReadOnlyTmpfs: createArtifact.ReadOnlyTmpfs, Runtime: config.OCIRuntime, NetworkMode: string(createArtifact.NetMode), IpcMode: string(createArtifact.IpcMode), diff --git a/cmd/podman/shared/create.go b/cmd/podman/shared/create.go index 3f54e193f..c521f9cb6 100644 --- a/cmd/podman/shared/create.go +++ b/cmd/podman/shared/create.go @@ -650,6 +650,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod. PortBindings: portBindings, Quiet: c.Bool("quiet"), ReadOnlyRootfs: c.Bool("read-only"), + ReadOnlyTmpfs: c.Bool("read-only-tmpfs"), Resources: cc.CreateResourceConfig{ BlkioWeight: blkioWeight, BlkioWeightDevice: c.StringSlice("blkio-weight-device"), diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go index 2e1827561..9c494dec5 100644 --- a/cmd/podman/shared/intermediate.go +++ b/cmd/podman/shared/intermediate.go @@ -434,6 +434,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes m["publish-all"] = newCRBool(c, "publish-all") m["quiet"] = newCRBool(c, "quiet") m["read-only"] = newCRBool(c, "read-only") + m["read-only-tmpfs"] = newCRBool(c, "read-only-tmpfs") m["restart"] = newCRString(c, "restart") m["rm"] = newCRBool(c, "rm") m["rootfs"] = newCRBool(c, "rootfs") diff --git a/cmd/podman/shared/intermediate_varlink.go b/cmd/podman/shared/intermediate_varlink.go index d62a65955..5e21245e3 100644 --- a/cmd/podman/shared/intermediate_varlink.go +++ b/cmd/podman/shared/intermediate_varlink.go @@ -141,6 +141,7 @@ func (g GenericCLIResults) MakeVarlink() iopodman.Create { PublishAll: BoolToPtr(g.Find("publish-all")), Quiet: BoolToPtr(g.Find("quiet")), Readonly: BoolToPtr(g.Find("read-only")), + Readonlytmpfs: BoolToPtr(g.Find("read-only-tmpfs")), Restart: StringToPtr(g.Find("restart")), Rm: BoolToPtr(g.Find("rm")), Rootfs: BoolToPtr(g.Find("rootfs")), @@ -397,6 +398,7 @@ func VarlinkCreateToGeneric(opts iopodman.Create) GenericCLIResults { m["publish-all"] = boolFromVarlink(opts.PublishAll, "publish-all", false) m["quiet"] = boolFromVarlink(opts.Quiet, "quiet", false) m["read-only"] = boolFromVarlink(opts.Readonly, "read-only", false) + m["read-only-tmpfs"] = boolFromVarlink(opts.Readonlytmpfs, "read-only-tmpfs", true) m["restart"] = stringFromVarlink(opts.Restart, "restart", nil) m["rm"] = boolFromVarlink(opts.Rm, "rm", false) m["rootfs"] = boolFromVarlink(opts.Rootfs, "rootfs", false) diff --git a/cmd/podman/sign.go b/cmd/podman/sign.go index b19b6a840..0c25eec62 100644 --- a/cmd/podman/sign.go +++ b/cmd/podman/sign.go @@ -56,7 +56,7 @@ func signCmd(c *cliconfig.SignValues) error { if len(args) < 1 { return errors.Errorf("at least one image name must be specified") } - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not create runtime") } diff --git a/cmd/podman/start.go b/cmd/podman/start.go index 9f93061f9..bd34010f2 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -65,7 +65,7 @@ func startCmd(c *cliconfig.StartValues) error { return errors.Wrapf(libpod.ErrInvalidArg, "you cannot use sig-proxy without --attach") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/stats.go b/cmd/podman/stats.go index 6aa0cc10c..c2b2a688c 100644 --- a/cmd/podman/stats.go +++ b/cmd/podman/stats.go @@ -88,7 +88,7 @@ func statsCmd(c *cliconfig.StatsValues) error { return errors.Errorf("you must specify --all, --latest, or at least one container") } - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/stop.go b/cmd/podman/stop.go index f263bb166..d88c90deb 100644 --- a/cmd/podman/stop.go +++ b/cmd/podman/stop.go @@ -56,7 +56,7 @@ func stopCmd(c *cliconfig.StopValues) error { defer span.Finish() } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/system_df.go b/cmd/podman/system_df.go index aa0ead022..840916547 100644 --- a/cmd/podman/system_df.go +++ b/cmd/podman/system_df.go @@ -99,7 +99,7 @@ func init() { } func dfSystemCmd(c *cliconfig.SystemDfValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "Could not get runtime") } diff --git a/cmd/podman/system_migrate.go b/cmd/podman/system_migrate.go new file mode 100644 index 000000000..4a0afcfad --- /dev/null +++ b/cmd/podman/system_migrate.go @@ -0,0 +1,50 @@ +package main + +import ( + "github.com/containers/libpod/cmd/podman/cliconfig" + "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +var ( + migrateCommand cliconfig.SystemMigrateValues + migrateDescription = ` + podman system migrate + + Migrate existing containers to a new version of Podman. +` + + _migrateCommand = &cobra.Command{ + Use: "migrate", + Args: noSubArgs, + Short: "Migrate containers", + Long: migrateDescription, + RunE: func(cmd *cobra.Command, args []string) error { + migrateCommand.InputArgs = args + migrateCommand.GlobalFlags = MainGlobalOpts + return migrateCmd(&migrateCommand) + }, + } +) + +func init() { + migrateCommand.Command = _migrateCommand + migrateCommand.SetHelpTemplate(HelpTemplate()) + migrateCommand.SetUsageTemplate(UsageTemplate()) +} + +func migrateCmd(c *cliconfig.SystemMigrateValues) error { + // We need to pass one extra option to NewRuntime. + // This will inform the OCI runtime to start a migrate. + // That's controlled by the last argument to GetRuntime. + r, err := libpodruntime.GetRuntimeMigrate(getContext(), &c.PodmanCommand) + if err != nil { + return errors.Wrapf(err, "error migrating containers") + } + if err := r.Shutdown(false); err != nil { + return err + } + + return nil +} diff --git a/cmd/podman/system_prune.go b/cmd/podman/system_prune.go index 37b6ef95f..d5b218cd8 100644 --- a/cmd/podman/system_prune.go +++ b/cmd/podman/system_prune.go @@ -72,7 +72,7 @@ Are you sure you want to continue? [y/N] `, volumeString) } } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/system_renumber.go b/cmd/podman/system_renumber.go index 70ba706bb..81752a177 100644 --- a/cmd/podman/system_renumber.go +++ b/cmd/podman/system_renumber.go @@ -40,7 +40,7 @@ func renumberCmd(c *cliconfig.SystemRenumberValues) error { // We need to pass one extra option to NewRuntime. // This will inform the OCI runtime to start a renumber. // That's controlled by the last argument to GetRuntime. - r, err := libpodruntime.GetRuntimeRenumber(&c.PodmanCommand) + r, err := libpodruntime.GetRuntimeRenumber(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error renumbering locks") } diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go index deda4e985..58f221e26 100644 --- a/cmd/podman/tag.go +++ b/cmd/podman/tag.go @@ -38,7 +38,7 @@ func tagCmd(c *cliconfig.TagValues) error { if len(args) < 2 { return errors.Errorf("image name and at least one new name must be specified") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not create runtime") } diff --git a/cmd/podman/top.go b/cmd/podman/top.go index f1f594ebf..2e0a22d92 100644 --- a/cmd/podman/top.go +++ b/cmd/podman/top.go @@ -76,7 +76,7 @@ func topCmd(c *cliconfig.TopValues) error { return errors.Errorf("you must provide the name or id of a running container") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/tree.go b/cmd/podman/tree.go index f205c83e4..6490c609d 100644 --- a/cmd/podman/tree.go +++ b/cmd/podman/tree.go @@ -51,7 +51,7 @@ func treeCmd(c *cliconfig.TreeValues) error { return errors.Errorf("you must provide at most 1 argument") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/trust_set_show.go b/cmd/podman/trust_set_show.go index 580331673..b615f6266 100644 --- a/cmd/podman/trust_set_show.go +++ b/cmd/podman/trust_set_show.go @@ -74,7 +74,7 @@ File(s) must exist before using this command`) } func showTrustCmd(c *cliconfig.ShowTrustValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not create runtime") } @@ -131,7 +131,7 @@ func showTrustCmd(c *cliconfig.ShowTrustValues) error { } func setTrustCmd(c *cliconfig.SetTrustValues) error { - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not create runtime") } diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go index cdf8b951a..ddbd00bd5 100644 --- a/cmd/podman/umount.go +++ b/cmd/podman/umount.go @@ -48,7 +48,7 @@ func init() { } func umountCmd(c *cliconfig.UmountValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating runtime") } diff --git a/cmd/podman/unpause.go b/cmd/podman/unpause.go index fa946bfd7..2cd6846fe 100644 --- a/cmd/podman/unpause.go +++ b/cmd/podman/unpause.go @@ -42,7 +42,7 @@ func unpauseCmd(c *cliconfig.UnpauseValues) error { return errors.New("unpause is not supported for rootless containers") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "could not get runtime") } diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go index 787ad01cd..978678a84 100644 --- a/cmd/podman/varlink.go +++ b/cmd/podman/varlink.go @@ -55,7 +55,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error { timeout := time.Duration(c.Timeout) * time.Millisecond // Create a single runtime for varlink - runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand) + runtime, err := libpodruntime.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index 17179d665..309f9765a 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -346,6 +346,7 @@ type Create ( publishAll: ?bool, quiet: ?bool, readonly: ?bool, + readonlytmpfs: ?bool, restart: ?string, rm: ?bool, rootfs: ?bool, diff --git a/cmd/podman/volume_create.go b/cmd/podman/volume_create.go index 2b10adb2b..84f6bba94 100644 --- a/cmd/podman/volume_create.go +++ b/cmd/podman/volume_create.go @@ -42,7 +42,7 @@ func init() { } func volumeCreateCmd(c *cliconfig.VolumeCreateValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/volume_inspect.go b/cmd/podman/volume_inspect.go index 66d394307..e4b05f96a 100644 --- a/cmd/podman/volume_inspect.go +++ b/cmd/podman/volume_inspect.go @@ -43,7 +43,7 @@ func volumeInspectCmd(c *cliconfig.VolumeInspectValues) error { return errors.New("provide one or more volume names or use --all") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/volume_ls.go b/cmd/podman/volume_ls.go index b9ab89196..581e595cb 100644 --- a/cmd/podman/volume_ls.go +++ b/cmd/podman/volume_ls.go @@ -72,7 +72,7 @@ func init() { } func volumeLsCmd(c *cliconfig.VolumeLsValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/volume_prune.go b/cmd/podman/volume_prune.go index ad62bfc22..6dc9e2403 100644 --- a/cmd/podman/volume_prune.go +++ b/cmd/podman/volume_prune.go @@ -63,7 +63,7 @@ func volumePrune(runtime *adapter.LocalRuntime, ctx context.Context) error { } func volumePruneCmd(c *cliconfig.VolumePruneValues) error { - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/volume_rm.go b/cmd/podman/volume_rm.go index 4534019c6..77137eb7a 100644 --- a/cmd/podman/volume_rm.go +++ b/cmd/podman/volume_rm.go @@ -47,7 +47,7 @@ func volumeRmCmd(c *cliconfig.VolumeRmValues) error { return errors.New("choose either one or more volumes or all") } - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating libpod runtime") } diff --git a/cmd/podman/wait.go b/cmd/podman/wait.go index 97ec75b0c..380e861ed 100644 --- a/cmd/podman/wait.go +++ b/cmd/podman/wait.go @@ -51,7 +51,7 @@ func waitCmd(c *cliconfig.WaitValues) error { } interval := time.Duration(c.Interval) * time.Millisecond - runtime, err := adapter.GetRuntime(&c.PodmanCommand) + runtime, err := adapter.GetRuntime(getContext(), &c.PodmanCommand) if err != nil { return errors.Wrapf(err, "error creating runtime") } diff --git a/completions/bash/podman b/completions/bash/podman index dce23df2b..6acdcc05a 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -1765,6 +1765,7 @@ _podman_container_run() { --publish-all -P --quiet --read-only + --read-only-tmpfs --tty -t " diff --git a/contrib/cirrus/packer/ubuntu_setup.sh b/contrib/cirrus/packer/ubuntu_setup.sh index 24f1cce21..e84566ce3 100644 --- a/contrib/cirrus/packer/ubuntu_setup.sh +++ b/contrib/cirrus/packer/ubuntu_setup.sh @@ -49,7 +49,7 @@ ooe.sh sudo -E apt-get -qq install \ gettext \ go-md2man \ golang \ - iproute \ + iproute2 \ iptables \ libaio-dev \ libapparmor-dev \ @@ -68,6 +68,7 @@ ooe.sh sudo -E apt-get -qq install \ libprotobuf-dev \ libseccomp-dev \ libseccomp2 \ + libsystemd-dev \ libtool \ libudev-dev \ lsof \ diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 0d26f6c9a..3818abbc7 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -55,7 +55,6 @@ then # Some setup needs to vary between distros case "${OS_RELEASE_ID}-${OS_RELEASE_VER}" in ubuntu-18) - sudo apt-get -qq -y install libsystemd-dev # Always install runc on Ubuntu install_runc_from_git ;; diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md index f61deebd2..52c965293 100644 --- a/docs/podman-create.1.md +++ b/docs/podman-create.1.md @@ -542,6 +542,9 @@ By default a container will have its root filesystem writable allowing processes to write files anywhere. By specifying the `--read-only` flag the container will have its root filesystem mounted as read only prohibiting any writes. +**--read-only-tmpfs**=*true*|*false* +If container is running in --read-only mode, then mount a read-write tmpfs on /run, /tmp, and /var/tmp. The default is *true* + **--restart=""** Not implemented. diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md index 5a311980f..e54e5e691 100644 --- a/docs/podman-run.1.md +++ b/docs/podman-run.1.md @@ -534,6 +534,9 @@ By default a container will have its root filesystem writable allowing processes to write files anywhere. By specifying the `--read-only` flag the container will have its root filesystem mounted as read only prohibiting any writes. +**--read-only-tmpfs**=*true*|*false* +If container is running in --read-only mode, then mount a read-write tmpfs on /run, /tmp, and /var/tmp. The default is *true* + **--restart=""** Not implemented. @@ -905,7 +908,11 @@ still need to write temporary data. The best way to handle this is to mount tmpfs directories on /run and /tmp. ``` -$ podman run --read-only --tmpfs /run --tmpfs /tmp -i -t fedora /bin/bash +$ podman run --read-only -i -t fedora /bin/bash +``` + +``` +$ podman run --read-only --read-only-tmpfs=false --tmpfs /run -i -t fedora /bin/bash ``` ### Exposing log messages from the container to the host's log diff --git a/docs/podman-system-migrate.1.md b/docs/podman-system-migrate.1.md new file mode 100644 index 000000000..7c2d1823c --- /dev/null +++ b/docs/podman-system-migrate.1.md @@ -0,0 +1,21 @@ +% podman-system-migrate(1) podman + +## NAME +podman\-system\-migrate - Migrate container to the latest version of podman + +## SYNOPSIS +** podman system migrate** + +## DESCRIPTION +** podman system migrate** migrates containers to the latest podman version. + +**podman system migrate** takes care of migrating existing containers to the latest version of podman if any change is necessary. + +## SYNOPSIS +**podman system migrate** + +## SEE ALSO +`podman(1)`, `libpod.conf(5)` + +# HISTORY +April 2019, Originally compiled by Giuseppe Scrivano (gscrivan at redhat dot com) diff --git a/docs/podman-system.1.md b/docs/podman-system.1.md index 32b3efdd9..d36715feb 100644 --- a/docs/podman-system.1.md +++ b/docs/podman-system.1.md @@ -17,6 +17,7 @@ The system command allows you to manage the podman systems | info | [podman-system-info(1)](podman-info.1.md) | Displays Podman related system information. | | prune | [podman-system-prune(1)](podman-system-prune.1.md) | Remove all unused data | | renumber | [podman-system-renumber(1)](podman-system-renumber.1.md)| Migrate lock numbers to handle a change in maximum number of locks. | +| migrate | [podman-system-migrate(1)](podman-system-migrate.1.md)| Migrate existing containers to a new podman version. | ## SEE ALSO podman(1) diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index f352b188e..c5e404155 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -420,7 +420,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { // It also expects to be able to write to /sys/fs/cgroup/systemd and /var/log/journal func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) error { options := []string{"rw", "rprivate", "noexec", "nosuid", "nodev"} - for _, dest := range []string{"/run", "/run/lock"} { + for _, dest := range []string{"/run"} { if MountExists(mounts, dest) { continue } diff --git a/libpod/events.go b/libpod/events.go index 1b5c3bd99..13bb5bdde 100644 --- a/libpod/events.go +++ b/libpod/events.go @@ -50,6 +50,16 @@ func (p *Pod) newPodEvent(status events.Status) { } } +// newSystemEvent creates a new event for libpod as a whole. +func (r *Runtime) newSystemEvent(status events.Status) { + e := events.NewEvent(status) + e.Type = events.System + + if err := r.eventer.Write(e); err != nil { + logrus.Errorf("unable to write system event: %q", err) + } +} + // newVolumeEvent creates a new event for a libpod volume func (v *Volume) newVolumeEvent(status events.Status) { e := events.NewEvent(status) diff --git a/libpod/events/config.go b/libpod/events/config.go index d3b6d8c50..36387e835 100644 --- a/libpod/events/config.go +++ b/libpod/events/config.go @@ -84,6 +84,9 @@ const ( Image Type = "image" // Pod - event is related to pods Pod Type = "pod" + // System - event is related to Podman whole and not to any specific + // container/pod/image/volume + System Type = "system" // Volume - event is related to volumes Volume Type = "volume" @@ -123,8 +126,14 @@ const ( Pull Status = "pull" // Push ... Push Status = "push" + // Refresh indicates that the system refreshed the state after a + // reboot. + Refresh Status = "refresh" // Remove ... Remove Status = "remove" + // Renumber indicates that lock numbers were reallocated at user + // request. + Renumber Status = "renumber" // Restore ... Restore Status = "restore" // Save ... diff --git a/libpod/events/events.go b/libpod/events/events.go index e8c61faa0..202c9db4e 100644 --- a/libpod/events/events.go +++ b/libpod/events/events.go @@ -49,6 +49,8 @@ func (e *Event) ToHumanReadable() string { humanFormat = fmt.Sprintf("%s %s %s %s (image=%s, name=%s)", e.Time, e.Type, e.Status, e.ID, e.Image, e.Name) case Image: humanFormat = fmt.Sprintf("%s %s %s %s %s", e.Time, e.Type, e.Status, e.ID, e.Name) + case System: + humanFormat = fmt.Sprintf("%s %s %s", e.Time, e.Type, e.Status) case Volume: humanFormat = fmt.Sprintf("%s %s %s %s", e.Time, e.Type, e.Status, e.Name) } @@ -85,10 +87,12 @@ func StringToType(name string) (Type, error) { return Image, nil case Pod.String(): return Pod, nil + case System.String(): + return System, nil case Volume.String(): return Volume, nil } - return "", errors.Errorf("unknown event type %s", name) + return "", errors.Errorf("unknown event type %q", name) } // StringToStatus converts a string to an Event Status @@ -107,7 +111,6 @@ func StringToStatus(name string) (Status, error) { case Commit.String(): return Commit, nil case Create.String(): - return Create, nil case Exec.String(): return Exec, nil @@ -135,8 +138,14 @@ func StringToStatus(name string) (Status, error) { return Pull, nil case Push.String(): return Push, nil + case Refresh.String(): + return Refresh, nil case Remove.String(): return Remove, nil + case Renumber.String(): + return Renumber, nil + case Restore.String(): + return Restore, nil case Save.String(): return Save, nil case Start.String(): @@ -154,7 +163,7 @@ func StringToStatus(name string) (Status, error) { case Untag.String(): return Untag, nil } - return "", errors.Errorf("unknown event status %s", name) + return "", errors.Errorf("unknown event status %q", name) } func (e EventLogFile) getTail(options ReadOptions) (*tail.Tail, error) { diff --git a/libpod/events/events_linux.go b/libpod/events/events_linux.go index d6898145c..da5d7965e 100644 --- a/libpod/events/events_linux.go +++ b/libpod/events/events_linux.go @@ -1,13 +1,16 @@ package events import ( - "github.com/pkg/errors" "strings" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // NewEventer creates an eventer based on the eventer type func NewEventer(options EventerOptions) (Eventer, error) { var eventer Eventer + logrus.Debugf("Initializing event backend %s", options.EventerType) switch strings.ToUpper(options.EventerType) { case strings.ToUpper(Journald.String()): eventer = EventJournalD{options} diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go index e6b54db1d..8ba5bc2c7 100644 --- a/libpod/events/journal_linux.go +++ b/libpod/events/journal_linux.go @@ -7,6 +7,7 @@ import ( "github.com/coreos/go-systemd/journal" "github.com/coreos/go-systemd/sdjournal" "github.com/pkg/errors" + "github.com/sirupsen/logrus" ) // EventJournalD is the journald implementation of an eventer @@ -87,7 +88,11 @@ func (e EventJournalD) Read(options ReadOptions) error { } newEvent, err := newEventFromJournalEntry(entry) if err != nil { - return err + // We can't decode this event. + // Don't fail hard - that would make events unusable. + // Instead, log and continue. + logrus.Errorf("Unable to decode event: %v", err) + continue } include := true for _, filter := range eventOptions { diff --git a/libpod/events/logfile.go b/libpod/events/logfile.go index 3232b86d0..e5efc09bb 100644 --- a/libpod/events/logfile.go +++ b/libpod/events/logfile.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/containers/storage" "github.com/pkg/errors" ) @@ -15,6 +16,13 @@ type EventLogFile struct { // Writes to the log file func (e EventLogFile) Write(ee Event) error { + // We need to lock events file + lock, err := storage.GetLockfile(e.options.LogFilePath + ".lock") + if err != nil { + return err + } + lock.Lock() + defer lock.Unlock() f, err := os.OpenFile(e.options.LogFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0700) if err != nil { return err diff --git a/libpod/options.go b/libpod/options.go index 8038f1935..9932d5453 100644 --- a/libpod/options.go +++ b/libpod/options.go @@ -1,6 +1,7 @@ package libpod import ( + "context" "net" "os" "path/filepath" @@ -436,6 +437,22 @@ func WithRenumber() RuntimeOption { } } +// WithMigrate instructs libpod to perform a lock migrateing while +// initializing. This will handle migrations from early versions of libpod with +// file locks to newer versions with SHM locking, as well as changes in the +// number of configured locks. +func WithMigrate() RuntimeOption { + return func(rt *Runtime) error { + if rt.valid { + return ErrRuntimeFinalized + } + + rt.doMigrate = true + + return nil + } +} + // Container Creation Options // WithShmDir sets the directory that should be mounted on /dev/shm. @@ -450,6 +467,19 @@ func WithShmDir(dir string) CtrCreateOption { } } +// WithContext sets the context to use. +func WithContext(ctx context.Context) RuntimeOption { + return func(rt *Runtime) error { + if rt.valid { + return ErrRuntimeFinalized + } + + rt.ctx = ctx + + return nil + } +} + // WithSystemd turns on systemd mode in the container func WithSystemd() CtrCreateOption { return func(ctr *Container) error { diff --git a/libpod/runtime.go b/libpod/runtime.go index d03731284..e85242028 100644 --- a/libpod/runtime.go +++ b/libpod/runtime.go @@ -1,8 +1,8 @@ package libpod import ( + "context" "fmt" - "github.com/containers/libpod/libpod/events" "io/ioutil" "os" "path/filepath" @@ -12,6 +12,7 @@ import ( "github.com/BurntSushi/toml" is "github.com/containers/image/storage" "github.com/containers/image/types" + "github.com/containers/libpod/libpod/events" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/libpod/lock" "github.com/containers/libpod/pkg/firewall" @@ -100,6 +101,8 @@ type Runtime struct { // unused. doRenumber bool + doMigrate bool + // valid indicates whether the runtime is ready to use. // valid is set to true when a runtime is returned from GetRuntime(), // and remains true until the runtime is shut down (rendering its @@ -109,6 +112,8 @@ type Runtime struct { // mechanism to read and write even logs eventer events.Eventer + + ctx context.Context } // OCIRuntimePath contains information about an OCI runtime. @@ -754,6 +759,17 @@ func makeRuntime(runtime *Runtime) (err error) { if err != nil { return err } + + defer func() { + if err != nil && store != nil { + // Don't forcibly shut down + // We could be opening a store in use by another libpod + _, err2 := store.Shutdown(false) + if err2 != nil { + logrus.Errorf("Error removing store for partially-created runtime: %s", err2) + } + } + }() } runtime.store = store @@ -780,17 +796,6 @@ func makeRuntime(runtime *Runtime) (err error) { runtime.eventer = eventer ir.Eventer = eventer - defer func() { - if err != nil && store != nil { - // Don't forcibly shut down - // We could be opening a store in use by another libpod - _, err2 := store.Shutdown(false) - if err2 != nil { - logrus.Errorf("Error removing store for partially-created runtime: %s", err2) - } - } - }() - // Set up a storage service for creating container root filesystems from // images storageService, err := getStorageService(runtime.store) @@ -962,6 +967,24 @@ func makeRuntime(runtime *Runtime) (err error) { // further runtime.valid = true + if runtime.doMigrate { + if os.Geteuid() != 0 { + aliveLock.Unlock() + locked = false + + became, ret, err := rootless.BecomeRootInUserNS() + if err != nil { + return err + } + if became { + os.Exit(ret) + } + } + if err := runtime.migrate(); err != nil { + return err + } + } + return nil } @@ -1074,6 +1097,8 @@ func (r *Runtime) refresh(alivePath string) error { } defer file.Close() + r.newSystemEvent(events.Refresh) + return nil } diff --git a/libpod/runtime_migrate.go b/libpod/runtime_migrate.go new file mode 100644 index 000000000..a084df289 --- /dev/null +++ b/libpod/runtime_migrate.go @@ -0,0 +1,47 @@ +package libpod + +import ( + "path/filepath" + + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +func (r *Runtime) migrate() error { + runningContainers, err := r.GetRunningContainers() + if err != nil { + return err + } + + allCtrs, err := r.state.AllContainers() + if err != nil { + return err + } + + logrus.Infof("stopping all containers") + for _, ctr := range runningContainers { + logrus.Infof("stopping %s", ctr.ID()) + if err := ctr.Stop(); err != nil { + return errors.Wrapf(err, "cannot stop container %s", ctr.ID()) + } + } + + for _, ctr := range allCtrs { + oldLocation := filepath.Join(ctr.state.RunDir, "conmon.pid") + if ctr.config.ConmonPidFile == oldLocation { + logrus.Infof("changing conmon PID file for %s", ctr.ID()) + ctr.config.ConmonPidFile = filepath.Join(ctr.config.StaticDir, "conmon.pid") + if err := r.state.RewriteContainerConfig(ctr, ctr.config); err != nil { + return errors.Wrapf(err, "error rewriting config for container %s", ctr.ID()) + } + } + } + + for _, ctr := range runningContainers { + if err := ctr.Start(r.ctx, true); err != nil { + logrus.Errorf("error restarting container %s", ctr.ID()) + } + } + + return nil +} diff --git a/libpod/runtime_renumber.go b/libpod/runtime_renumber.go index 125cf0825..735ffba34 100644 --- a/libpod/runtime_renumber.go +++ b/libpod/runtime_renumber.go @@ -1,6 +1,7 @@ package libpod import ( + "github.com/containers/libpod/libpod/events" "github.com/pkg/errors" ) @@ -53,5 +54,7 @@ func (r *Runtime) renumberLocks() error { } } + r.newSystemEvent(events.Renumber) + return nil } diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go index 790ed5c89..0d840d65b 100644 --- a/pkg/adapter/runtime.go +++ b/pkg/adapter/runtime.go @@ -57,8 +57,8 @@ type Volume struct { type VolumeFilter func(*Volume) bool // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it -func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) { - runtime, err := libpodruntime.GetRuntime(c) +func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) { + runtime, err := libpodruntime.GetRuntime(ctx, c) if err != nil { return nil, err } diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go index 29ee821e0..6102daccf 100644 --- a/pkg/adapter/runtime_remote.go +++ b/pkg/adapter/runtime_remote.go @@ -46,7 +46,7 @@ type LocalRuntime struct { } // GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it -func GetRuntime(c *cliconfig.PodmanCommand) (*LocalRuntime, error) { +func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) { runtime := RemoteRuntime{} conn, err := runtime.Connect() if err != nil { diff --git a/pkg/inspect/inspect.go b/pkg/inspect/inspect.go index 270e431ad..6978370ef 100644 --- a/pkg/inspect/inspect.go +++ b/pkg/inspect/inspect.go @@ -38,7 +38,8 @@ type HostConfig struct { PidMode string `json:"PidMode"` Privileged bool `json:"Privileged"` PublishAllPorts bool `json:"PublishAllPorts"` //TODO - ReadonlyRootfs bool `json:"ReadonlyRootfs"` + ReadOnlyRootfs bool `json:"ReadonlyRootfs"` + ReadOnlyTmpfs bool `json:"ReadonlyTmpfs"` SecurityOpt []string `json:"SecurityOpt"` UTSMode string `json:"UTSMode"` UsernsMode string `json:"UsernsMode"` diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index e71d9d3db..064dedd45 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -113,6 +113,7 @@ type CreateConfig struct { PublishAll bool //publish-all Quiet bool //quiet ReadOnlyRootfs bool //read-only + ReadOnlyTmpfs bool //read-only-tmpfs Resources CreateResourceConfig Rm bool //rm StopSignal syscall.Signal // stop-signal diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go index 0371b6d4d..4cbed0ea4 100644 --- a/pkg/spec/spec.go +++ b/pkg/spec/spec.go @@ -341,6 +341,31 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint } } + if config.ReadOnlyRootfs && config.ReadOnlyTmpfs { + options := []string{"rw", "rprivate", "nosuid", "nodev", "tmpcopyup"} + for _, i := range []string{"/tmp", "/var/tmp"} { + if libpod.MountExists(g.Config.Mounts, i) { + continue + } + // Default options if nothing passed + tmpfsMnt := spec.Mount{ + Destination: i, + Type: "tmpfs", + Source: "tmpfs", + Options: options, + } + g.AddMount(tmpfsMnt) + } + if !libpod.MountExists(g.Config.Mounts, "/run") { + tmpfsMnt := spec.Mount{ + Destination: "/run", + Type: "tmpfs", + Source: "tmpfs", + Options: append(options, "noexec", "size=65536k"), + } + g.AddMount(tmpfsMnt) + } + } for name, val := range config.Env { g.AddProcessEnv(name, val) } diff --git a/vendor.conf b/vendor.conf index 572ae5fdb..02283beb9 100644 --- a/vendor.conf +++ b/vendor.conf @@ -19,7 +19,7 @@ github.com/containers/image v1.5.1 github.com/vbauerster/mpb v3.3.4 github.com/mattn/go-isatty v0.0.4 github.com/VividCortex/ewma v1.1.1 -github.com/containers/storage v1.12.3 +github.com/containers/storage v1.12.5 github.com/containers/psgo v1.2.1 github.com/coreos/go-systemd v14 github.com/coreos/pkg v4 @@ -94,7 +94,7 @@ k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apim k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7 github.com/varlink/go 3ac79db6fd6aec70924193b090962f92985fe199 -github.com/containers/buildah fcc12bdadf6a5fab77e62e1bd12663bb6fbc3eda +github.com/containers/buildah v1.8.0 # TODO: Gotty has not been updated since 2012. Can we find replacement? github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512 github.com/fsouza/go-dockerclient v1.3.0 diff --git a/vendor/github.com/containers/buildah/add.go b/vendor/github.com/containers/buildah/add.go index d42246d53..d67a481f1 100644 --- a/vendor/github.com/containers/buildah/add.go +++ b/vendor/github.com/containers/buildah/add.go @@ -292,7 +292,7 @@ func addHelper(excludes []DockerIgnore, extract bool, dest string, destfi os.Fil break } // combine the filename with the dest directory - fpath := strings.TrimPrefix(path, options.ContextDir) + fpath := strings.TrimPrefix(path, esrc) if err = copyFileWithTar(path, filepath.Join(dest, fpath)); err != nil { return errors.Wrapf(err, "error copying %q to %q", path, dest) } diff --git a/vendor/github.com/containers/buildah/buildah.go b/vendor/github.com/containers/buildah/buildah.go index 8b076630f..b6e6545ec 100644 --- a/vendor/github.com/containers/buildah/buildah.go +++ b/vendor/github.com/containers/buildah/buildah.go @@ -26,7 +26,7 @@ const ( Package = "buildah" // Version for the Package. Bump version in contrib/rpm/buildah.spec // too. - Version = "1.8-dev" + Version = "1.8.0" // The value we use to identify what type of information, currently a // serialized Builder structure, we are using as per-container state. // This should only be changed when we make incompatible changes to @@ -282,6 +282,8 @@ type CommonBuildOptions struct { CPUSetCPUs string // CPUSetMems memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems. CPUSetMems string + // HTTPProxy determines whether *_proxy env vars from the build host are passed into the container. + HTTPProxy bool // Memory is the upper limit (in bytes) on how much memory running containers can use. Memory int64 // DNSSearch is the list of DNS search domains to add to the build container's /etc/resolv.conf diff --git a/vendor/github.com/containers/buildah/chroot/run.go b/vendor/github.com/containers/buildah/chroot/run.go index ff39c2f24..1c3ac65f3 100644 --- a/vendor/github.com/containers/buildah/chroot/run.go +++ b/vendor/github.com/containers/buildah/chroot/run.go @@ -512,7 +512,7 @@ func runUsingChroot(spec *specs.Spec, bundlePath string, ctty *os.File, stdin io logNamespaceDiagnostics(spec) // If we have configured ID mappings, set them here so that they can apply to the child. - hostUidmap, hostGidmap, err := util.GetHostIDMappings("") + hostUidmap, hostGidmap, err := unshare.GetHostIDMappings("") if err != nil { return 1, err } diff --git a/vendor/github.com/containers/buildah/chroot/selinux.go b/vendor/github.com/containers/buildah/chroot/selinux.go index 3e62d743d..08e8f998b 100644 --- a/vendor/github.com/containers/buildah/chroot/selinux.go +++ b/vendor/github.com/containers/buildah/chroot/selinux.go @@ -13,7 +13,7 @@ import ( // setSelinuxLabel sets the process label for child processes that we'll start. func setSelinuxLabel(spec *specs.Spec) error { logrus.Debugf("setting selinux label") - if spec.Process.SelinuxLabel != "" && selinux.EnforceMode() != selinux.Disabled { + if spec.Process.SelinuxLabel != "" && selinux.GetEnabled() { if err := label.SetProcessLabel(spec.Process.SelinuxLabel); err != nil { return errors.Wrapf(err, "error setting process label to %q", spec.Process.SelinuxLabel) } diff --git a/vendor/github.com/containers/buildah/commit.go b/vendor/github.com/containers/buildah/commit.go index 5e73be881..05d1550b3 100644 --- a/vendor/github.com/containers/buildah/commit.go +++ b/vendor/github.com/containers/buildah/commit.go @@ -64,12 +64,9 @@ type CommitOptions struct { // manifest of the new image will reference the blobs rather than // on-disk layers. BlobDirectory string - - // OnBuild is a list of commands to be run by images based on this image - OnBuild []string - // Parent is the base image that this image was created by. - Parent string - + // EmptyLayer tells the builder to omit the diff for the working + // container. + EmptyLayer bool // OmitTimestamp forces epoch 0 as created timestamp to allow for // deterministic, content-addressable builds. OmitTimestamp bool @@ -169,7 +166,7 @@ func (b *Builder) Commit(ctx context.Context, dest types.ImageReference, options } } // Build an image reference from which we can copy the finished image. - src, err := b.makeImageRef(options.PreferredManifestType, options.Parent, exportBaseLayers, options.Squash, options.BlobDirectory, options.Compression, options.HistoryTimestamp, options.OmitTimestamp) + src, err := b.makeImageRef(options, exportBaseLayers) if err != nil { return imgID, nil, "", errors.Wrapf(err, "error computing layer digests and building metadata for container %q", b.ContainerID) } diff --git a/vendor/github.com/containers/buildah/image.go b/vendor/github.com/containers/buildah/image.go index 1cd329c85..215920cc3 100644 --- a/vendor/github.com/containers/buildah/image.go +++ b/vendor/github.com/containers/buildah/image.go @@ -56,6 +56,7 @@ type containerImageRef struct { preferredManifestType string exporting bool squash bool + emptyLayer bool tarPath func(path string) (io.ReadCloser, error) parent string blobDirectory string @@ -184,7 +185,7 @@ func (i *containerImageRef) createConfigsAndManifests() (v1.Image, v1.Manifest, if err := json.Unmarshal(i.dconfig, &dimage); err != nil { return v1.Image{}, v1.Manifest{}, docker.V2Image{}, docker.V2S2Manifest{}, err } - dimage.Parent = docker.ID(digest.FromString(i.parent)) + dimage.Parent = docker.ID(i.parent) // Always replace this value, since we're newer than our base image. dimage.Created = created // Clear the list of diffIDs, since we always repopulate it. @@ -290,6 +291,11 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, sc *types.System if err != nil { return nil, errors.Wrapf(err, "unable to locate layer %q", layerID) } + // If we're up to the final layer, but we don't want to include + // a diff for it, we're done. + if i.emptyLayer && layerID == i.layerID { + continue + } // If we're not re-exporting the data, and we're reusing layers individually, reuse // the blobsum and diff IDs. if !i.exporting && !i.squash && layerID != i.layerID { @@ -433,7 +439,7 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, sc *types.System CreatedBy: i.createdBy, Author: oimage.Author, Comment: i.historyComment, - EmptyLayer: false, + EmptyLayer: i.emptyLayer, } oimage.History = append(oimage.History, onews) dnews := docker.V2S2History{ @@ -441,11 +447,11 @@ func (i *containerImageRef) NewImageSource(ctx context.Context, sc *types.System CreatedBy: i.createdBy, Author: dimage.Author, Comment: i.historyComment, - EmptyLayer: false, + EmptyLayer: i.emptyLayer, } dimage.History = append(dimage.History, dnews) appendHistory(i.postEmptyLayers) - dimage.Parent = docker.ID(digest.FromString(i.parent)) + dimage.Parent = docker.ID(i.parent) // Sanity check that we didn't just create a mismatch between non-empty layers in the // history and the number of diffIDs. @@ -636,7 +642,7 @@ func (i *containerImageSource) GetBlob(ctx context.Context, blob types.BlobInfo, return ioutils.NewReadCloserWrapper(layerFile, closer), size, nil } -func (b *Builder) makeImageRef(manifestType, parent string, exporting bool, squash bool, blobDirectory string, compress archive.Compression, historyTimestamp *time.Time, omitTimestamp bool) (types.ImageReference, error) { +func (b *Builder) makeImageRef(options CommitOptions, exporting bool) (types.ImageReference, error) { var name reference.Named container, err := b.store.Container(b.ContainerID) if err != nil { @@ -647,6 +653,7 @@ func (b *Builder) makeImageRef(manifestType, parent string, exporting bool, squa name = parsed } } + manifestType := options.PreferredManifestType if manifestType == "" { manifestType = OCIv1ImageManifest } @@ -659,8 +666,8 @@ func (b *Builder) makeImageRef(manifestType, parent string, exporting bool, squa return nil, errors.Wrapf(err, "error encoding docker-format image configuration %#v", b.Docker) } created := time.Now().UTC() - if historyTimestamp != nil { - created = historyTimestamp.UTC() + if options.HistoryTimestamp != nil { + created = options.HistoryTimestamp.UTC() } createdBy := b.CreatedBy() if createdBy == "" { @@ -670,13 +677,21 @@ func (b *Builder) makeImageRef(manifestType, parent string, exporting bool, squa } } - if omitTimestamp { + if options.OmitTimestamp { created = time.Unix(0, 0) } + parent := "" + if b.FromImageID != "" { + parentDigest := digest.NewDigestFromEncoded(digest.Canonical, b.FromImageID) + if parentDigest.Validate() == nil { + parent = parentDigest.String() + } + } + ref := &containerImageRef{ store: b.store, - compression: compress, + compression: options.Compression, name: name, names: container.Names, containerID: container.ID, @@ -690,10 +705,11 @@ func (b *Builder) makeImageRef(manifestType, parent string, exporting bool, squa annotations: b.Annotations(), preferredManifestType: manifestType, exporting: exporting, - squash: squash, + squash: options.Squash, + emptyLayer: options.EmptyLayer, tarPath: b.tarPath(), parent: parent, - blobDirectory: blobDirectory, + blobDirectory: options.BlobDirectory, preEmptyLayers: b.PrependedEmptyLayers, postEmptyLayers: b.AppendedEmptyLayers, } diff --git a/vendor/github.com/containers/buildah/imagebuildah/build.go b/vendor/github.com/containers/buildah/imagebuildah/build.go index b692d3bcf..d9909cdc8 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/build.go +++ b/vendor/github.com/containers/buildah/imagebuildah/build.go @@ -28,7 +28,7 @@ import ( "github.com/containers/storage" "github.com/containers/storage/pkg/archive" docker "github.com/fsouza/go-dockerclient" - "github.com/opencontainers/image-spec/specs-go/v1" + v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/opencontainers/runtime-spec/specs-go" "github.com/openshift/imagebuilder" "github.com/openshift/imagebuilder/dockerfile/parser" @@ -215,9 +215,12 @@ type Executor struct { forceRmIntermediateCtrs bool imageMap map[string]string // Used to map images that we create to handle the AS construct. containerMap map[string]*buildah.Builder // Used to map from image names to only-created-for-the-rootfs containers. + baseMap map[string]bool // Holds the names of every base image, as given. + rootfsMap map[string]bool // Holds the names of every stage whose rootfs is referenced in a COPY or ADD instruction. blobDirectory string excludes []string unusedArgs map[string]struct{} + buildArgs map[string]string } // StageExecutor bundles up what we need to know when executing one stage of a @@ -480,6 +483,19 @@ func (s *StageExecutor) volumeCacheRestore() error { // imagebuilder tells us the instruction was "ADD" and not "COPY". func (s *StageExecutor) Copy(excludes []string, copies ...imagebuilder.Copy) error { for _, copy := range copies { + // If the file exists, check to see if it's a symlink. + // If it is a symlink, convert to it's target otherwise + // the symlink will be overwritten. + fileDest, _ := os.Lstat(filepath.Join(s.mountPoint, copy.Dest)) + if fileDest != nil { + if fileDest.Mode()&os.ModeSymlink != 0 { + if symLink, err := resolveSymlink(s.mountPoint, copy.Dest); err == nil { + copy.Dest = symLink + } else { + return errors.Wrapf(err, "error reading symbolic link to %q", copy.Dest) + } + } + } if copy.Download { logrus.Debugf("ADD %#v, %#v", excludes, copy) } else { @@ -590,7 +606,7 @@ func (s *StageExecutor) Run(run imagebuilder.Run, config docker.Config) error { // UnrecognizedInstruction is called when we encounter an instruction that the // imagebuilder parser didn't understand. func (s *StageExecutor) UnrecognizedInstruction(step *imagebuilder.Step) error { - errStr := fmt.Sprintf("Build error: Unknown instruction: %q ", step.Command) + errStr := fmt.Sprintf("Build error: Unknown instruction: %q ", strings.ToUpper(step.Command)) err := fmt.Sprintf(errStr+"%#v", step) if s.executor.ignoreUnrecognizedInstructions { logrus.Debugf(err) @@ -610,7 +626,7 @@ func (s *StageExecutor) UnrecognizedInstruction(step *imagebuilder.Step) error { } // NewExecutor creates a new instance of the imagebuilder.Executor interface. -func NewExecutor(store storage.Store, options BuildOptions) (*Executor, error) { +func NewExecutor(store storage.Store, options BuildOptions, mainNode *parser.Node) (*Executor, error) { excludes, err := imagebuilder.ParseDockerignore(options.ContextDirectory) if err != nil { return nil, err @@ -656,8 +672,11 @@ func NewExecutor(store storage.Store, options BuildOptions) (*Executor, error) { forceRmIntermediateCtrs: options.ForceRmIntermediateCtrs, imageMap: make(map[string]string), containerMap: make(map[string]*buildah.Builder), + baseMap: make(map[string]bool), + rootfsMap: make(map[string]bool), blobDirectory: options.BlobDirectory, unusedArgs: make(map[string]struct{}), + buildArgs: options.Args, } if exec.err == nil { exec.err = os.Stderr @@ -679,6 +698,25 @@ func NewExecutor(store storage.Store, options BuildOptions) (*Executor, error) { exec.unusedArgs[arg] = struct{}{} } } + for _, line := range mainNode.Children { + node := line + for node != nil { // tokens on this line, though we only care about the first + switch strings.ToUpper(node.Value) { // first token - instruction + case "ARG": + arg := node.Next + if arg != nil { + // We have to be careful here - it's either an argument + // and value, or just an argument, since they can be + // separated by either "=" or whitespace. + list := strings.SplitN(arg.Value, "=", 2) + if _, stillUnused := exec.unusedArgs[list[0]]; stillUnused { + delete(exec.unusedArgs, list[0]) + } + } + } + break + } + } return &exec, nil } @@ -845,9 +883,9 @@ func (b *Executor) resolveNameToImageRef(output string) (types.ImageReference, e return imageRef, nil } -// stepRequiresCommit indicates whether or not the step should be followed by -// committing the in-progress container to create an intermediate image. -func (*StageExecutor) stepRequiresCommit(step *imagebuilder.Step) bool { +// stepRequiresLayer indicates whether or not the step should be followed by +// committing a layer container when creating an intermediate image. +func (*StageExecutor) stepRequiresLayer(step *imagebuilder.Step) bool { switch strings.ToUpper(step.Command) { case "ADD", "COPY", "RUN": return true @@ -875,6 +913,10 @@ func (s *StageExecutor) getImageRootfs(ctx context.Context, stage imagebuilder.S func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, base string) (imgID string, ref reference.Canonical, err error) { ib := stage.Builder checkForLayers := s.executor.layers && s.executor.useCache + moreStages := s.index < s.stages-1 + lastStage := !moreStages + imageIsUsedLater := moreStages && (s.executor.baseMap[stage.Name] || s.executor.baseMap[fmt.Sprintf("%d", stage.Position)]) + rootfsIsUsedLater := moreStages && (s.executor.rootfsMap[stage.Name] || s.executor.rootfsMap[fmt.Sprintf("%d", stage.Position)]) // If the base image's name corresponds to the result of an earlier // stage, substitute that image's ID for the base image's name here. @@ -896,7 +938,8 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b // A helper function to only log "COMMIT" as an explicit step if it's // the very last step of a (possibly multi-stage) build. logCommit := func(output string, instruction int) { - if instruction < len(children)-1 || s.index < s.stages-1 { + moreInstructions := instruction < len(children)-1 + if moreInstructions || moreStages { return } commitMessage := "COMMIT" @@ -921,7 +964,7 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b // squash the contents of the base image. Whichever is // the case, we need to commit() to create a new image. logCommit(s.output, -1) - if imgID, ref, err = s.commit(ctx, ib, getCreatedBy(nil), s.output); err != nil { + if imgID, ref, err = s.commit(ctx, ib, s.executor.getCreatedBy(nil), false, s.output); err != nil { return "", nil, errors.Wrapf(err, "error committing base container") } } else { @@ -936,6 +979,8 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b } for i, node := range children { + moreInstructions := i < len(children)-1 + lastInstruction := !moreInstructions // Resolve any arguments in this instruction. step := ib.Step() if err := step.Resolve(node); err != nil { @@ -946,30 +991,19 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b s.executor.log("%s", step.Original) } - // If this instruction declares an argument, remove it from the - // set of arguments that we were passed but which we haven't - // yet seen used by the Dockerfile. - if step.Command == "arg" { - for _, Arg := range step.Args { - list := strings.SplitN(Arg, "=", 2) - if _, stillUnused := s.executor.unusedArgs[list[0]]; stillUnused { - delete(s.executor.unusedArgs, list[0]) - } - } - } - // Check if there's a --from if the step command is COPY or // ADD. Set copyFrom to point to either the context directory // or the root of the container from the specified stage. s.copyFrom = s.executor.contextDir for _, n := range step.Flags { - if strings.Contains(n, "--from") && (step.Command == "copy" || step.Command == "add") { + command := strings.ToUpper(step.Command) + if strings.Contains(n, "--from") && (command == "COPY" || command == "ADD") { var mountPoint string arr := strings.Split(n, "=") otherStage, ok := s.executor.stages[arr[1]] if !ok { if mountPoint, err = s.getImageRootfs(ctx, stage, arr[1]); err != nil { - return "", nil, errors.Errorf("%s --from=%s: no stage or image found with that name", step.Command, arr[1]) + return "", nil, errors.Errorf("%s --from=%s: no stage or image found with that name", command, arr[1]) } } else { mountPoint = otherStage.mountPoint @@ -984,7 +1018,7 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b // contents of any volumes declared between now and when we // finish. noRunsRemaining := false - if i < len(children)-1 { + if moreInstructions { noRunsRemaining = !ib.RequiresStart(&parser.Node{Children: children[i+1:]}) } @@ -996,24 +1030,29 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b logrus.Debugf("%v", errors.Wrapf(err, "error building at step %+v", *step)) return "", nil, errors.Wrapf(err, "error building at STEP \"%s\"", step.Message) } - if i < len(children)-1 { + if moreInstructions { // There are still more instructions to process // for this stage. Make a note of the // instruction in the history that we'll write // for the image when we eventually commit it. now := time.Now() - s.builder.AddPrependedEmptyLayer(&now, getCreatedBy(node), "", "") + s.builder.AddPrependedEmptyLayer(&now, s.executor.getCreatedBy(node), "", "") continue } else { // This is the last instruction for this stage, // so we should commit this container to create - // an image. - logCommit(s.output, i) - imgID, ref, err = s.commit(ctx, ib, getCreatedBy(node), s.output) - if err != nil { - return "", nil, errors.Wrapf(err, "error committing container for step %+v", *step) + // an image, but only if it's the last one, or + // if it's used as the basis for a later stage. + if lastStage || imageIsUsedLater { + logCommit(s.output, i) + imgID, ref, err = s.commit(ctx, ib, s.executor.getCreatedBy(node), false, s.output) + if err != nil { + return "", nil, errors.Wrapf(err, "error committing container for step %+v", *step) + } + logImageID(imgID) + } else { + imgID = "" } - logImageID(imgID) break } } @@ -1028,18 +1067,14 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b // If we have to commit for this instruction, only assign the // stage's configured output name to the last layer. - if i == len(children)-1 { + if lastInstruction { commitName = s.output } // If we're using the cache, and we've managed to stick with // cached images so far, look for one that matches what we // expect to produce for this instruction. - // Only check at steps where we commit, so that we don't - // abandon the cache at this step just because we can't find an - // image with a history entry in it that we wouldn't have - // committed. - if checkForLayers && (s.stepRequiresCommit(step) || i == len(children)-1) && !(s.executor.squash && i == len(children)-1 && s.index == s.stages-1) { + if checkForLayers && !(s.executor.squash && lastInstruction && lastStage) { cacheID, err = s.layerExists(ctx, node, children[:i]) if err != nil { return "", nil, errors.Wrap(err, "error checking if cached image exists from a previous build") @@ -1059,17 +1094,32 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b // the last step in this stage, add the name to the // image. imgID = cacheID - if commitName != "" && (s.stepRequiresCommit(step) || i == len(children)-1) { - logCommit(s.output, i) + if commitName != "" { + logCommit(commitName, i) if imgID, ref, err = s.copyExistingImage(ctx, cacheID, commitName); err != nil { return "", nil, err } logImageID(imgID) } // Update our working container to be based off of the - // cached image, in case we need to read content from - // its root filesystem. - rebase = true + // cached image, if we might need to use it as a basis + // for the next instruction, or if we need the root + // filesystem to match the image contents for the sake + // of a later stage that wants to copy content from it. + rebase = moreInstructions || rootfsIsUsedLater + // If the instruction would affect our configuration, + // process the configuration change so that, if we fall + // off the cache path, the filesystem changes from the + // last cache image will be all that we need, since we + // still don't want to restart using the image's + // configuration blob. + if !s.stepRequiresLayer(step) { + err := ib.Run(step, s, noRunsRemaining) + if err != nil { + logrus.Debugf("%v", errors.Wrapf(err, "error building at step %+v", *step)) + return "", nil, errors.Wrapf(err, "error building at STEP \"%s\"", step.Message) + } + } } else { // If we didn't find a cached image that we could just reuse, // process the instruction directly. @@ -1078,36 +1128,20 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b logrus.Debugf("%v", errors.Wrapf(err, "error building at step %+v", *step)) return "", nil, errors.Wrapf(err, "error building at STEP \"%s\"", step.Message) } - if s.stepRequiresCommit(step) || i == len(children)-1 { - // Either this is the last instruction, or - // there are more instructions and we need to - // create a layer from this one before - // continuing. - // TODO: only commit for the last instruction - // case if we need to use this stage's image as - // a base image later, or if we're the final - // stage. - logCommit(s.output, i) - imgID, ref, err = s.commit(ctx, ib, getCreatedBy(node), commitName) - if err != nil { - return "", nil, errors.Wrapf(err, "error committing container for step %+v", *step) - } - logImageID(imgID) - // We only need to build a new container rootfs - // using this image if we plan on making - // further changes to it. Subsequent stages - // that just want to use the rootfs as a source - // for COPY or ADD will be content with what we - // already have. - rebase = i < len(children)-1 - } else { - // There are still more instructions to process - // for this stage, and we don't need to commit - // here. Make a note of the instruction in the - // history for the next commit. - now := time.Now() - s.builder.AddPrependedEmptyLayer(&now, getCreatedBy(node), "", "") + // Create a new image, maybe with a new layer. + logCommit(s.output, i) + imgID, ref, err = s.commit(ctx, ib, s.executor.getCreatedBy(node), !s.stepRequiresLayer(step), commitName) + if err != nil { + return "", nil, errors.Wrapf(err, "error committing container for step %+v", *step) } + logImageID(imgID) + // We only need to build a new container rootfs + // using this image if we plan on making + // further changes to it. Subsequent stages + // that just want to use the rootfs as a source + // for COPY or ADD will be content with what we + // already have. + rebase = moreInstructions } if rebase { @@ -1122,8 +1156,6 @@ func (s *StageExecutor) Execute(ctx context.Context, stage imagebuilder.Stage, b // creating a new working container with the // just-committed or updated cached image as its new // base image. - // TODO: only create a new container if we know that - // we'll need the updated root filesystem. if _, err := s.prepare(ctx, stage, imgID, false, true); err != nil { return "", nil, errors.Wrap(err, "error preparing container for next step") } @@ -1195,13 +1227,13 @@ func (s *StageExecutor) layerExists(ctx context.Context, currNode *parser.Node, // it means that this image is potentially a cached intermediate image from a previous // build. Next we double check that the history of this image is equivalent to the previous // lines in the Dockerfile up till the point we are at in the build. - if layer.Parent == s.executor.topLayers[len(s.executor.topLayers)-1] { + if layer.Parent == s.executor.topLayers[len(s.executor.topLayers)-1] || layer.ID == s.executor.topLayers[len(s.executor.topLayers)-1] { history, err := s.executor.getImageHistory(ctx, image.ID) if err != nil { return "", errors.Wrapf(err, "error getting history of %q", image.ID) } // children + currNode is the point of the Dockerfile we are currently at. - if historyMatches(append(children, currNode), history) { + if s.executor.historyMatches(append(children, currNode), history) { // This checks if the files copied during build have been changed if the node is // a COPY or ADD command. filesMatch, err := s.copiedFilesMatch(currNode, history[len(history)-1].Created) @@ -1225,21 +1257,26 @@ func (b *Executor) getImageHistory(ctx context.Context, imageID string) ([]v1.Hi } ref, err := imageRef.NewImage(ctx, nil) if err != nil { - return nil, errors.Wrap(err, "error creating new image from reference") + return nil, errors.Wrapf(err, "error creating new image from reference to image %q", imageID) } + defer ref.Close() oci, err := ref.OCIConfig(ctx) if err != nil { - return nil, errors.Wrapf(err, "error getting oci config of image %q", imageID) + return nil, errors.Wrapf(err, "error getting possibly-converted OCI config of image %q", imageID) } return oci.History, nil } // getCreatedBy returns the command the image at node will be created by. -func getCreatedBy(node *parser.Node) string { +func (b *Executor) getCreatedBy(node *parser.Node) string { if node == nil { return "/bin/sh" } if node.Value == "run" { + buildArgs := b.getBuildArgs() + if buildArgs != "" { + return "|" + strconv.Itoa(len(strings.Split(buildArgs, " "))) + " " + buildArgs + " /bin/sh -c " + node.Original[4:] + } return "/bin/sh -c " + node.Original[4:] } return "/bin/sh -c #(nop) " + node.Original @@ -1249,12 +1286,23 @@ func getCreatedBy(node *parser.Node) string { // in the Dockerfile till the point of build we are at. // Used to verify whether a cache of the intermediate image exists and whether // to run the build again. -func historyMatches(children []*parser.Node, history []v1.History) bool { +func (b *Executor) historyMatches(children []*parser.Node, history []v1.History) bool { i := len(history) - 1 for j := len(children) - 1; j >= 0; j-- { instruction := children[j].Original if children[j].Value == "run" { instruction = instruction[4:] + buildArgs := b.getBuildArgs() + // If a previous image was built with some build-args but the new build process doesn't have any build-args + // specified, so compare the lengths of the old instruction with the current one + // 11 is the length of "/bin/sh -c " that is used to run the run commands + if buildArgs == "" && len(history[i].CreatedBy) > len(instruction)+11 { + return false + } + // There are build-args, so check if anything with the build-args has changed + if buildArgs != "" && !strings.Contains(history[i].CreatedBy, buildArgs) { + return false + } } if !strings.Contains(history[i].CreatedBy, instruction) { return false @@ -1264,6 +1312,18 @@ func historyMatches(children []*parser.Node, history []v1.History) bool { return true } +// getBuildArgs returns a string of the build-args specified during the build process +// it excludes any build-args that were not used in the build process +func (b *Executor) getBuildArgs() string { + var buildArgs []string + for k, v := range b.buildArgs { + if _, ok := b.unusedArgs[k]; !ok { + buildArgs = append(buildArgs, k+"="+v) + } + } + return strings.Join(buildArgs, " ") +} + // getFilesToCopy goes through node to get all the src files that are copied, added or downloaded. // It is possible for the Dockerfile to have src as hom*, which means all files that have hom as a prefix. // Another format is hom?.txt, which means all files that have that name format with the ? replaced by another character. @@ -1348,7 +1408,7 @@ func urlContentModified(url string, historyTime *time.Time) (bool, error) { // commit writes the container's contents to an image, using a passed-in tag as // the name if there is one, generating a unique ID-based one otherwise. -func (s *StageExecutor) commit(ctx context.Context, ib *imagebuilder.Builder, createdBy, output string) (string, reference.Canonical, error) { +func (s *StageExecutor) commit(ctx context.Context, ib *imagebuilder.Builder, createdBy string, emptyLayer bool, output string) (string, reference.Canonical, error) { var imageRef types.ImageReference if output != "" { imageRef2, err := s.executor.resolveNameToImageRef(output) @@ -1438,8 +1498,8 @@ func (s *StageExecutor) commit(ctx context.Context, ib *imagebuilder.Builder, cr PreferredManifestType: s.executor.outputFormat, SystemContext: s.executor.systemContext, Squash: s.executor.squash, + EmptyLayer: emptyLayer, BlobDirectory: s.executor.blobDirectory, - Parent: s.builder.FromImageID, } imgID, _, manifestDigest, err := s.builder.Commit(ctx, imageRef, options) if err != nil { @@ -1510,6 +1570,46 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image } defer cleanup() + // Build maps of every named base image and every referenced stage root + // filesystem. Individual stages can use them to determine whether or + // not they can skip certain steps near the end of their stages. + for _, stage := range stages { + node := stage.Node // first line + for node != nil { // each line + for _, child := range node.Children { // tokens on this line, though we only care about the first + switch strings.ToUpper(child.Value) { // first token - instruction + case "FROM": + if child.Next != nil { // second token on this line + base := child.Next.Value + if base != "scratch" { + // TODO: this didn't undergo variable and arg + // expansion, so if the AS clause in another + // FROM instruction uses argument values, + // we might not record the right value here. + b.baseMap[base] = true + logrus.Debugf("base: %q", base) + } + } + case "ADD", "COPY": + for _, flag := range child.Flags { // flags for this instruction + if strings.HasPrefix(flag, "--from=") { + // TODO: this didn't undergo variable and + // arg expansion, so if the previous stage + // was named using argument values, we might + // not record the right value here. + rootfs := flag[7:] + b.rootfsMap[rootfs] = true + logrus.Debugf("rootfs: %q", rootfs) + } + } + } + break + } + node = node.Next // next line + } + } + + // Run through the build stages, one at a time. for stageIndex, stage := range stages { var lastErr error @@ -1555,7 +1655,7 @@ func (b *Executor) Build(ctx context.Context, stages imagebuilder.Stages) (image // If this is an intermediate stage, make a note of the ID, so // that we can look it up later. - if stageIndex < len(stages)-1 { + if stageIndex < len(stages)-1 && imageID != "" { b.imageMap[stage.Name] = imageID // We're not populating the cache with intermediate // images, so add this one to the list of images that @@ -1671,7 +1771,7 @@ func BuildDockerfiles(ctx context.Context, store storage.Store, options BuildOpt } mainNode.Children = append(mainNode.Children, additionalNode.Children...) } - exec, err := NewExecutor(store, options) + exec, err := NewExecutor(store, options, mainNode) if err != nil { return "", nil, errors.Wrapf(err, "error creating build executor") } diff --git a/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink.go b/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink.go index 86bf7653b..0789c2b3c 100644 --- a/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink.go +++ b/vendor/github.com/containers/buildah/imagebuildah/chroot_symlink.go @@ -129,20 +129,20 @@ func resolveModifiedTime(rootdir, filename, historyTime string) (bool, error) { func modTimeIsGreater(rootdir, path string, historyTime string) (bool, error) { var timeIsGreater bool - // the Walk below doesn't work if rootdir and path are equal - if rootdir == path { - return false, nil - } - // Convert historyTime from string to time.Time for comparison histTime, err := time.Parse(time.RFC3339Nano, historyTime) if err != nil { return false, errors.Wrapf(err, "error converting string to time.Time %q", historyTime) } + + // Since we are chroot in rootdir, we want a relative path, i.e (path - rootdir) + relPath, err := filepath.Rel(rootdir, path) + if err != nil { + return false, errors.Wrapf(err, "error making path %q relative to %q", path, rootdir) + } + // Walk the file tree and check the time stamps. - // Since we are chroot in rootdir, only want the path of the actual filename, i.e path - rootdir. - // +1 to account for the extra "/" (e.g rootdir=/home/user/mydir, path=/home/user/mydir/myfile.json) - err = filepath.Walk(path[len(rootdir)+1:], func(path string, info os.FileInfo, err error) error { + err = filepath.Walk(relPath, func(path string, info os.FileInfo, err error) error { // If using cached images, it is possible for files that are being copied to come from // previous build stages. But if using cached images, then the copied file won't exist // since a container won't have been created for the previous build stage and info will be nil. @@ -154,6 +154,9 @@ func modTimeIsGreater(rootdir, path string, historyTime string) (bool, error) { if info.Mode()&os.ModeSymlink == os.ModeSymlink { // Evaluate any symlink that occurs to get updated modified information resolvedPath, err := filepath.EvalSymlinks(path) + if err != nil && os.IsNotExist(err) { + return errors.Wrapf(errDanglingSymlink, "%q", path) + } if err != nil { return errors.Wrapf(err, "error evaluating symlink %q", path) } @@ -169,7 +172,12 @@ func modTimeIsGreater(rootdir, path string, historyTime string) (bool, error) { } return nil }) + if err != nil { + // if error is due to dangling symlink, ignore error and return nil + if errors.Cause(err) == errDanglingSymlink { + return false, nil + } return false, errors.Wrapf(err, "error walking file tree %q", path) } return timeIsGreater, err diff --git a/vendor/github.com/containers/buildah/imagebuildah/errors.go b/vendor/github.com/containers/buildah/imagebuildah/errors.go new file mode 100644 index 000000000..cf299656b --- /dev/null +++ b/vendor/github.com/containers/buildah/imagebuildah/errors.go @@ -0,0 +1,7 @@ +package imagebuildah + +import "errors" + +var ( + errDanglingSymlink = errors.New("error evaluating dangling symlink") +) diff --git a/vendor/github.com/containers/buildah/pkg/cli/common.go b/vendor/github.com/containers/buildah/pkg/cli/common.go index 6c4d14303..7fa0a7777 100644 --- a/vendor/github.com/containers/buildah/pkg/cli/common.go +++ b/vendor/github.com/containers/buildah/pkg/cli/common.go @@ -89,6 +89,7 @@ type FromAndBudResults struct { DNSSearch []string DNSServers []string DNSOptions []string + HttpProxy bool Isolation string Memory string MemorySwap string @@ -182,6 +183,7 @@ func GetFromAndBudFlags(flags *FromAndBudResults, usernsResults *UserNSResults, fs.StringSliceVar(&flags.DNSSearch, "dns-search", []string{}, "Set custom DNS search domains") fs.StringSliceVar(&flags.DNSServers, "dns", []string{}, "Set custom DNS servers") fs.StringSliceVar(&flags.DNSOptions, "dns-option", []string{}, "Set custom DNS options") + fs.BoolVar(&flags.HttpProxy, "http-proxy", true, "pass thru HTTP Proxy environment variables") fs.StringVar(&flags.Isolation, "isolation", DefaultIsolation(), "`type` of process isolation to use. Use BUILDAH_ISOLATION environment variable to override.") fs.StringVarP(&flags.Memory, "memory", "m", "", "memory limit (format: <number>[<unit>], where unit = b, k, m or g)") fs.StringVar(&flags.MemorySwap, "memory-swap", "", "swap limit equal to memory plus swap: '-1' to enable unlimited swap") diff --git a/vendor/github.com/containers/buildah/pkg/parse/parse.go b/vendor/github.com/containers/buildah/pkg/parse/parse.go index c4e3e4264..cc85136fd 100644 --- a/vendor/github.com/containers/buildah/pkg/parse/parse.go +++ b/vendor/github.com/containers/buildah/pkg/parse/parse.go @@ -86,6 +86,7 @@ func CommonBuildOptions(c *cobra.Command) (*buildah.CommonBuildOptions, error) { cpuPeriod, _ := c.Flags().GetUint64("cpu-period") cpuQuota, _ := c.Flags().GetInt64("cpu-quota") cpuShares, _ := c.Flags().GetUint64("cpu-shared") + httpProxy, _ := c.Flags().GetBool("http-proxy") ulimit, _ := c.Flags().GetStringSlice("ulimit") commonOpts := &buildah.CommonBuildOptions{ AddHost: addHost, @@ -98,6 +99,7 @@ func CommonBuildOptions(c *cobra.Command) (*buildah.CommonBuildOptions, error) { DNSSearch: dnsSearch, DNSServers: dnsServers, DNSOptions: dnsOptions, + HTTPProxy: httpProxy, Memory: memoryLimit, MemorySwap: memorySwap, ShmSize: c.Flag("shm-size").Value.String(), diff --git a/vendor/github.com/containers/buildah/pkg/unshare/unshare.go b/vendor/github.com/containers/buildah/pkg/unshare/unshare.go index 5b2e7d7d1..33232740e 100644 --- a/vendor/github.com/containers/buildah/pkg/unshare/unshare.go +++ b/vendor/github.com/containers/buildah/pkg/unshare/unshare.go @@ -3,6 +3,7 @@ package unshare import ( + "bufio" "bytes" "fmt" "io" @@ -15,7 +16,7 @@ import ( "sync" "syscall" - "github.com/containers/buildah/util" + "github.com/containers/storage/pkg/idtools" "github.com/containers/storage/pkg/reexec" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -157,7 +158,7 @@ func (c *Cmd) Start() error { } if len(c.UidMappings) == 0 || len(c.GidMappings) == 0 { - uidmap, gidmap, err := util.GetHostIDMappings("") + uidmap, gidmap, err := GetHostIDMappings("") if err != nil { fmt.Fprintf(continueWrite, "error reading ID mappings in parent: %v", err) return errors.Wrapf(err, "error reading ID mappings in parent") @@ -352,7 +353,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { // Read the set of ID mappings that we're allowed to use. Each // range in /etc/subuid and /etc/subgid file is a starting host // ID and a range size. - uidmap, gidmap, err = util.GetSubIDMappings(me.Username, me.Username) + uidmap, gidmap, err = GetSubIDMappings(me.Username, me.Username) bailOnError(err, "error reading allowed ID mappings") if len(uidmap) == 0 { logrus.Warnf("Found no UID ranges set aside for user %q in /etc/subuid.", me.Username) @@ -384,7 +385,7 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { return } // Read the set of ID mappings that we're currently using. - uidmap, gidmap, err = util.GetHostIDMappings("") + uidmap, gidmap, err = GetHostIDMappings("") bailOnError(err, "error reading current ID mappings") // Just reuse them. for i := range uidmap { @@ -404,6 +405,16 @@ func MaybeReexecUsingUserNamespace(evenForRoot bool) { err = os.Setenv(UsernsEnvName, "1") bailOnError(err, "error setting %s=1 in environment", UsernsEnvName) + // Set the default isolation type to use the "rootless" method. + if _, present := os.LookupEnv("BUILDAH_ISOLATION"); !present { + if err = os.Setenv("BUILDAH_ISOLATION", "rootless"); err != nil { + if err := os.Setenv("BUILDAH_ISOLATION", "rootless"); err != nil { + logrus.Errorf("error setting BUILDAH_ISOLATION=rootless in environment: %v", err) + os.Exit(1) + } + } + } + // Reuse our stdio. cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout @@ -446,3 +457,89 @@ func ExecRunnable(cmd Runnable) { } os.Exit(0) } + +// getHostIDMappings reads mappings from the named node under /proc. +func getHostIDMappings(path string) ([]specs.LinuxIDMapping, error) { + var mappings []specs.LinuxIDMapping + f, err := os.Open(path) + if err != nil { + return nil, errors.Wrapf(err, "error reading ID mappings from %q", path) + } + defer f.Close() + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + fields := strings.Fields(line) + if len(fields) != 3 { + return nil, errors.Errorf("line %q from %q has %d fields, not 3", line, path, len(fields)) + } + cid, err := strconv.ParseUint(fields[0], 10, 32) + if err != nil { + return nil, errors.Wrapf(err, "error parsing container ID value %q from line %q in %q", fields[0], line, path) + } + hid, err := strconv.ParseUint(fields[1], 10, 32) + if err != nil { + return nil, errors.Wrapf(err, "error parsing host ID value %q from line %q in %q", fields[1], line, path) + } + size, err := strconv.ParseUint(fields[2], 10, 32) + if err != nil { + return nil, errors.Wrapf(err, "error parsing size value %q from line %q in %q", fields[2], line, path) + } + mappings = append(mappings, specs.LinuxIDMapping{ContainerID: uint32(cid), HostID: uint32(hid), Size: uint32(size)}) + } + return mappings, nil +} + +// GetHostIDMappings reads mappings for the specified process (or the current +// process if pid is "self" or an empty string) from the kernel. +func GetHostIDMappings(pid string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) { + if pid == "" { + pid = "self" + } + uidmap, err := getHostIDMappings(fmt.Sprintf("/proc/%s/uid_map", pid)) + if err != nil { + return nil, nil, err + } + gidmap, err := getHostIDMappings(fmt.Sprintf("/proc/%s/gid_map", pid)) + if err != nil { + return nil, nil, err + } + return uidmap, gidmap, nil +} + +// GetSubIDMappings reads mappings from /etc/subuid and /etc/subgid. +func GetSubIDMappings(user, group string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) { + mappings, err := idtools.NewIDMappings(user, group) + if err != nil { + return nil, nil, errors.Wrapf(err, "error reading subuid mappings for user %q and subgid mappings for group %q", user, group) + } + var uidmap, gidmap []specs.LinuxIDMapping + for _, m := range mappings.UIDs() { + uidmap = append(uidmap, specs.LinuxIDMapping{ + ContainerID: uint32(m.ContainerID), + HostID: uint32(m.HostID), + Size: uint32(m.Size), + }) + } + for _, m := range mappings.GIDs() { + gidmap = append(gidmap, specs.LinuxIDMapping{ + ContainerID: uint32(m.ContainerID), + HostID: uint32(m.HostID), + Size: uint32(m.Size), + }) + } + return uidmap, gidmap, nil +} + +// ParseIDMappings parses mapping triples. +func ParseIDMappings(uidmap, gidmap []string) ([]idtools.IDMap, []idtools.IDMap, error) { + uid, err := idtools.ParseIDMap(uidmap, "userns-uid-map") + if err != nil { + return nil, nil, err + } + gid, err := idtools.ParseIDMap(gidmap, "userns-gid-map") + if err != nil { + return nil, nil, err + } + return uid, gid, nil +} diff --git a/vendor/github.com/containers/buildah/pkg/unshare/unshare_unsupported.go b/vendor/github.com/containers/buildah/pkg/unshare/unshare_unsupported.go index d8d5f6f7a..bf4d567b8 100644 --- a/vendor/github.com/containers/buildah/pkg/unshare/unshare_unsupported.go +++ b/vendor/github.com/containers/buildah/pkg/unshare/unshare_unsupported.go @@ -4,6 +4,9 @@ package unshare import ( "os" + + "github.com/containers/storage/pkg/idtools" + "github.com/opencontainers/runtime-spec/specs-go" ) const ( @@ -29,3 +32,14 @@ func RootlessEnv() []string { // MaybeReexecUsingUserNamespace re-exec the process in a new namespace func MaybeReexecUsingUserNamespace(evenForRoot bool) { } + +// GetHostIDMappings reads mappings for the specified process (or the current +// process if pid is "self" or an empty string) from the kernel. +func GetHostIDMappings(pid string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) { + return nil, nil, nil +} + +// ParseIDMappings parses mapping triples. +func ParseIDMappings(uidmap, gidmap []string) ([]idtools.IDMap, []idtools.IDMap, error) { + return nil, nil, nil +} diff --git a/vendor/github.com/containers/buildah/run.go b/vendor/github.com/containers/buildah/run.go index 5d28644d7..00eac8e39 100644 --- a/vendor/github.com/containers/buildah/run.go +++ b/vendor/github.com/containers/buildah/run.go @@ -865,7 +865,7 @@ func setupNamespaces(g *generate.Generator, namespaceOptions NamespaceOptions, i if err := g.AddOrReplaceLinuxNamespace(specs.UserNamespace, ""); err != nil { return false, nil, false, errors.Wrapf(err, "error adding new %q namespace for run", string(specs.UserNamespace)) } - hostUidmap, hostGidmap, err := util.GetHostIDMappings("") + hostUidmap, hostGidmap, err := unshare.GetHostIDMappings("") if err != nil { return false, nil, false, err } @@ -983,6 +983,24 @@ func (b *Builder) configureUIDGID(g *generate.Generator, mountPoint string, opti func (b *Builder) configureEnvironment(g *generate.Generator, options RunOptions) { g.ClearProcessEnv() + if b.CommonBuildOpts.HTTPProxy { + for _, envSpec := range []string{ + "http_proxy", + "HTTP_PROXY", + "https_proxy", + "HTTPS_PROXY", + "ftp_proxy", + "FTP_PROXY", + "no_proxy", + "NO_PROXY", + } { + envVal := os.Getenv(envSpec) + if envVal != "" { + g.AddProcessEnv(envSpec, envVal) + } + } + } + for _, envSpec := range append(b.Env(), options.Env...) { env := strings.SplitN(envSpec, "=", 2) if len(env) > 1 { diff --git a/vendor/github.com/containers/buildah/selinux.go b/vendor/github.com/containers/buildah/selinux.go index 2b850cf9f..e64eb6112 100644 --- a/vendor/github.com/containers/buildah/selinux.go +++ b/vendor/github.com/containers/buildah/selinux.go @@ -4,9 +4,12 @@ package buildah import ( "github.com/opencontainers/runtime-tools/generate" + selinux "github.com/opencontainers/selinux/go-selinux" ) func setupSelinux(g *generate.Generator, processLabel, mountLabel string) { - g.SetProcessSelinuxLabel(processLabel) - g.SetLinuxMountLabel(mountLabel) + if processLabel != "" && selinux.GetEnabled() { + g.SetProcessSelinuxLabel(processLabel) + g.SetLinuxMountLabel(mountLabel) + } } diff --git a/vendor/github.com/containers/buildah/util/util.go b/vendor/github.com/containers/buildah/util/util.go index 7f3bbaef4..698d79a81 100644 --- a/vendor/github.com/containers/buildah/util/util.go +++ b/vendor/github.com/containers/buildah/util/util.go @@ -1,13 +1,11 @@ package util import ( - "bufio" "fmt" "io" "net/url" "os" "path" - "strconv" "strings" "syscall" @@ -18,7 +16,6 @@ import ( "github.com/containers/image/transports" "github.com/containers/image/types" "github.com/containers/storage" - "github.com/containers/storage/pkg/idtools" "github.com/docker/distribution/registry/api/errcode" specs "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" @@ -299,92 +296,6 @@ func GetHostRootIDs(spec *specs.Spec) (uint32, uint32, error) { return GetHostIDs(spec.Linux.UIDMappings, spec.Linux.GIDMappings, 0, 0) } -// getHostIDMappings reads mappings from the named node under /proc. -func getHostIDMappings(path string) ([]specs.LinuxIDMapping, error) { - var mappings []specs.LinuxIDMapping - f, err := os.Open(path) - if err != nil { - return nil, errors.Wrapf(err, "error reading ID mappings from %q", path) - } - defer f.Close() - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Text() - fields := strings.Fields(line) - if len(fields) != 3 { - return nil, errors.Errorf("line %q from %q has %d fields, not 3", line, path, len(fields)) - } - cid, err := strconv.ParseUint(fields[0], 10, 32) - if err != nil { - return nil, errors.Wrapf(err, "error parsing container ID value %q from line %q in %q", fields[0], line, path) - } - hid, err := strconv.ParseUint(fields[1], 10, 32) - if err != nil { - return nil, errors.Wrapf(err, "error parsing host ID value %q from line %q in %q", fields[1], line, path) - } - size, err := strconv.ParseUint(fields[2], 10, 32) - if err != nil { - return nil, errors.Wrapf(err, "error parsing size value %q from line %q in %q", fields[2], line, path) - } - mappings = append(mappings, specs.LinuxIDMapping{ContainerID: uint32(cid), HostID: uint32(hid), Size: uint32(size)}) - } - return mappings, nil -} - -// GetHostIDMappings reads mappings for the specified process (or the current -// process if pid is "self" or an empty string) from the kernel. -func GetHostIDMappings(pid string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) { - if pid == "" { - pid = "self" - } - uidmap, err := getHostIDMappings(fmt.Sprintf("/proc/%s/uid_map", pid)) - if err != nil { - return nil, nil, err - } - gidmap, err := getHostIDMappings(fmt.Sprintf("/proc/%s/gid_map", pid)) - if err != nil { - return nil, nil, err - } - return uidmap, gidmap, nil -} - -// GetSubIDMappings reads mappings from /etc/subuid and /etc/subgid. -func GetSubIDMappings(user, group string) ([]specs.LinuxIDMapping, []specs.LinuxIDMapping, error) { - mappings, err := idtools.NewIDMappings(user, group) - if err != nil { - return nil, nil, errors.Wrapf(err, "error reading subuid mappings for user %q and subgid mappings for group %q", user, group) - } - var uidmap, gidmap []specs.LinuxIDMapping - for _, m := range mappings.UIDs() { - uidmap = append(uidmap, specs.LinuxIDMapping{ - ContainerID: uint32(m.ContainerID), - HostID: uint32(m.HostID), - Size: uint32(m.Size), - }) - } - for _, m := range mappings.GIDs() { - gidmap = append(gidmap, specs.LinuxIDMapping{ - ContainerID: uint32(m.ContainerID), - HostID: uint32(m.HostID), - Size: uint32(m.Size), - }) - } - return uidmap, gidmap, nil -} - -// ParseIDMappings parses mapping triples. -func ParseIDMappings(uidmap, gidmap []string) ([]idtools.IDMap, []idtools.IDMap, error) { - uid, err := idtools.ParseIDMap(uidmap, "userns-uid-map") - if err != nil { - return nil, nil, err - } - gid, err := idtools.ParseIDMap(gidmap, "userns-gid-map") - if err != nil { - return nil, nil, err - } - return uid, gid, nil -} - // GetPolicyContext sets up, initializes and returns a new context for the specified policy func GetPolicyContext(ctx *types.SystemContext) (*signature.PolicyContext, error) { policy, err := signature.DefaultPolicy(ctx) diff --git a/vendor/github.com/containers/buildah/vendor.conf b/vendor/github.com/containers/buildah/vendor.conf index a77130acb..bec681e5c 100644 --- a/vendor/github.com/containers/buildah/vendor.conf +++ b/vendor/github.com/containers/buildah/vendor.conf @@ -8,7 +8,7 @@ github.com/vbauerster/mpb v3.3.4 github.com/mattn/go-isatty v0.0.4 github.com/VividCortex/ewma v1.1.1 github.com/boltdb/bolt v1.3.1 -github.com/containers/storage v1.12.2 +github.com/containers/storage v1.12.3 github.com/docker/distribution 5f6282db7d65e6d72ad7c2cc66310724a57be716 github.com/docker/docker 54dddadc7d5d89fe0be88f76979f6f6ab0dede83 github.com/docker/docker-credential-helpers v0.6.1 diff --git a/vendor/github.com/containers/psgo/go.mod b/vendor/github.com/containers/psgo/go.mod new file mode 100644 index 000000000..dd671bbb0 --- /dev/null +++ b/vendor/github.com/containers/psgo/go.mod @@ -0,0 +1,11 @@ +module github.com/containers/psgo + +go 1.12 + +require ( + github.com/opencontainers/runc v0.0.0-20190425234816-dae70e8efea4 + github.com/pkg/errors v0.0.0-20190227000051-27936f6d90f9 + github.com/sirupsen/logrus v0.0.0-20190403091019-9b3cdde74fbe + github.com/stretchr/testify v1.2.2 + golang.org/x/sys v0.0.0-20190425145619-16072639606e +) diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go index 69036a5c1..5d667d8c6 100644 --- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go +++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go @@ -16,7 +16,7 @@ import ( "sync" "syscall" - "github.com/containers/storage/drivers" + graphdriver "github.com/containers/storage/drivers" "github.com/containers/storage/drivers/overlayutils" "github.com/containers/storage/drivers/quota" "github.com/containers/storage/pkg/archive" @@ -320,6 +320,8 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI mergedDir := filepath.Join(layerDir, "merged") lower1Dir := filepath.Join(layerDir, "lower1") lower2Dir := filepath.Join(layerDir, "lower2") + upperDir := filepath.Join(layerDir, "upper") + workDir := filepath.Join(layerDir, "work") defer func() { // Permitted to fail, since the various subdirectories // can be empty or not even there, and the home might @@ -331,7 +333,9 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI _ = idtools.MkdirAs(mergedDir, 0700, rootUID, rootGID) _ = idtools.MkdirAs(lower1Dir, 0700, rootUID, rootGID) _ = idtools.MkdirAs(lower2Dir, 0700, rootUID, rootGID) - flags := fmt.Sprintf("lowerdir=%s:%s", lower1Dir, lower2Dir) + _ = idtools.MkdirAs(upperDir, 0700, rootUID, rootGID) + _ = idtools.MkdirAs(workDir, 0700, rootUID, rootGID) + flags := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", lower1Dir, lower2Dir, upperDir, workDir) if len(flags) < unix.Getpagesize() { err := mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags) if err == nil { @@ -341,7 +345,7 @@ func supportsOverlay(home string, homeMagic graphdriver.FsMagic, rootUID, rootGI logrus.Debugf("overlay test mount with multiple lowers failed %v", err) } } - flags = fmt.Sprintf("lowerdir=%s", lower1Dir) + flags = fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lower1Dir, upperDir, workDir) if len(flags) < unix.Getpagesize() { err := mountFrom(filepath.Dir(home), "overlay", mergedDir, "overlay", 0, flags) if err == nil { @@ -677,6 +681,40 @@ func (d *Driver) Remove(id string) error { return nil } +// recreateSymlinks goes through the driver's home directory and checks if the diff directory +// under each layer has a symlink created for it under the linkDir. If the symlink does not +// exist, it creates them +func (d *Driver) recreateSymlinks() error { + // List all the directories under the home directory + dirs, err := ioutil.ReadDir(d.home) + if err != nil { + return fmt.Errorf("error reading driver home directory %q: %v", d.home, err) + } + for _, dir := range dirs { + // Skip over the linkDir + if dir.Name() == linkDir || dir.Mode().IsRegular() { + continue + } + // Read the "link" file under each layer to get the name of the symlink + data, err := ioutil.ReadFile(path.Join(d.dir(dir.Name()), "link")) + if err != nil { + return fmt.Errorf("error reading name of symlink for %q: %v", dir, err) + } + linkPath := path.Join(d.home, linkDir, strings.Trim(string(data), "\n")) + // Check if the symlink exists, and if it doesn't create it again with the name we + // got from the "link" file + _, err = os.Stat(linkPath) + if err != nil && os.IsNotExist(err) { + if err := os.Symlink(path.Join("..", dir.Name(), "diff"), linkPath); err != nil { + return err + } + } else if err != nil { + return fmt.Errorf("error trying to stat %q: %v", linkPath, err) + } + } + return nil +} + // Get creates and mounts the required file system for the given id and returns the mount path. func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr error) { return d.get(id, false, options) @@ -732,7 +770,16 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO } lower = "" } - if lower == "" { + // if it is a "not found" error, that means the symlinks were lost in a sudden reboot + // so call the recreateSymlinks function to go through all the layer dirs and recreate + // the symlinks with the name from their respective "link" files + if lower == "" && os.IsNotExist(err) { + logrus.Warnf("Can't stat lower layer %q because it does not exist. Going through storage to recreate the missing symlinks.", newpath) + if err := d.recreateSymlinks(); err != nil { + return "", fmt.Errorf("error recreating the missing symlinks: %v", err) + } + lower = newpath + } else if lower == "" { return "", fmt.Errorf("Can't stat lower layer %q: %v", newpath, err) } } else { diff --git a/vendor/github.com/fsouza/go-dockerclient/go.mod b/vendor/github.com/fsouza/go-dockerclient/go.mod new file mode 100644 index 000000000..bcf549c21 --- /dev/null +++ b/vendor/github.com/fsouza/go-dockerclient/go.mod @@ -0,0 +1,42 @@ +module github.com/fsouza/go-dockerclient + +require ( + github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 + github.com/Microsoft/go-winio v0.4.11 + github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 + github.com/containerd/continuity v0.0.0-20180814194400-c7c5070e6f6e // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/docker v0.7.3-0.20180827131323-0c5f8d2b9b23 + github.com/docker/go-connections v0.4.0 // indirect + github.com/docker/go-units v0.3.3 + github.com/docker/libnetwork v0.8.0-dev.2.0.20180608203834-19279f049241 // indirect + github.com/fsnotify/fsnotify v1.4.7 // indirect + github.com/gogo/protobuf v1.1.1 // indirect + github.com/golang/protobuf v1.2.0 // indirect + github.com/google/go-cmp v0.2.0 + github.com/gorilla/context v1.1.1 // indirect + github.com/gorilla/mux v1.6.2 + github.com/hpcloud/tail v1.0.0 // indirect + github.com/onsi/ginkgo v1.6.0 // indirect + github.com/onsi/gomega v1.4.1 // indirect + github.com/opencontainers/go-digest v1.0.0-rc1 // indirect + github.com/opencontainers/image-spec v1.0.1 // indirect + github.com/opencontainers/runc v0.1.1 // indirect + github.com/pkg/errors v0.8.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sirupsen/logrus v1.0.6 + github.com/stretchr/testify v1.2.2 // indirect + github.com/vishvananda/netlink v1.0.0 // indirect + github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc // indirect + golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac // indirect + golang.org/x/net v0.0.0-20180826012351-8a410e7b638d // indirect + golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect + golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87 + golang.org/x/text v0.3.0 // indirect + gopkg.in/airbrake/gobrake.v2 v2.0.9 // indirect + gopkg.in/fsnotify.v1 v1.4.7 // indirect + gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2 // indirect + gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect + gopkg.in/yaml.v2 v2.2.1 // indirect + gotest.tools v2.1.0+incompatible // indirect +) diff --git a/vendor/github.com/hashicorp/errwrap/go.mod b/vendor/github.com/hashicorp/errwrap/go.mod new file mode 100644 index 000000000..c9b84022c --- /dev/null +++ b/vendor/github.com/hashicorp/errwrap/go.mod @@ -0,0 +1 @@ +module github.com/hashicorp/errwrap diff --git a/vendor/github.com/hashicorp/go-multierror/go.mod b/vendor/github.com/hashicorp/go-multierror/go.mod new file mode 100644 index 000000000..2534331d5 --- /dev/null +++ b/vendor/github.com/hashicorp/go-multierror/go.mod @@ -0,0 +1,3 @@ +module github.com/hashicorp/go-multierror + +require github.com/hashicorp/errwrap v1.0.0 diff --git a/vendor/github.com/stretchr/testify/go.mod b/vendor/github.com/stretchr/testify/go.mod new file mode 100644 index 000000000..90e5dbe25 --- /dev/null +++ b/vendor/github.com/stretchr/testify/go.mod @@ -0,0 +1,7 @@ +module github.com/stretchr/testify + +require ( + github.com/davecgh/go-spew v1.1.0 + github.com/pmezard/go-difflib v1.0.0 + github.com/stretchr/objx v0.1.0 +) diff --git a/vendor/golang.org/x/text/go.mod b/vendor/golang.org/x/text/go.mod new file mode 100644 index 000000000..5eb1e8b16 --- /dev/null +++ b/vendor/golang.org/x/text/go.mod @@ -0,0 +1,3 @@ +module golang.org/x/text + +require golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e diff --git a/vendor/gopkg.in/yaml.v2/go.mod b/vendor/gopkg.in/yaml.v2/go.mod new file mode 100644 index 000000000..1934e8769 --- /dev/null +++ b/vendor/gopkg.in/yaml.v2/go.mod @@ -0,0 +1,5 @@ +module "gopkg.in/yaml.v2" + +require ( + "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405 +) |