diff options
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/podman/cliconfig/config.go | 4 | ||||
-rw-r--r-- | cmd/podman/cp.go | 97 | ||||
-rw-r--r-- | cmd/podman/exec.go | 7 | ||||
-rw-r--r-- | cmd/podman/generate_kube.go | 19 | ||||
-rw-r--r-- | cmd/podman/main.go | 3 | ||||
-rw-r--r-- | cmd/podman/main_local.go | 2 | ||||
-rw-r--r-- | cmd/podman/main_remote.go | 8 | ||||
-rw-r--r-- | cmd/podman/restore.go | 18 | ||||
-rw-r--r-- | cmd/podman/rm.go | 9 | ||||
-rw-r--r-- | cmd/podman/varlink/io.podman.varlink | 10 |
10 files changed, 162 insertions, 15 deletions
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go index b8b1648b8..4a4c839cc 100644 --- a/cmd/podman/cliconfig/config.go +++ b/cmd/podman/cliconfig/config.go @@ -145,7 +145,8 @@ type ExportValues struct { } type GenerateKubeValues struct { PodmanCommand - Service bool + Service bool + Filename string } type GenerateSystemdValues struct { @@ -438,6 +439,7 @@ type RmValues struct { All bool Force bool Latest bool + Storage bool Volumes bool } diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go index 7679ebcf1..a9418e6e0 100644 --- a/cmd/podman/cp.go +++ b/cmd/podman/cp.go @@ -145,7 +145,19 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin var glob []string if isFromHostToCtr { - if filepath.IsAbs(destPath) { + if isVol, volDestName, volName := isVolumeDestName(destPath, ctr); isVol { + path, err := pathWithVolumeMount(ctr, runtime, volDestName, volName, destPath) + if err != nil { + return errors.Wrapf(err, "error getting destination path from volume %s", volDestName) + } + destPath = path + } else if isBindMount, mount := isBindMountDestName(destPath, ctr); isBindMount { + path, err := pathWithBindMountSource(mount, destPath) + if err != nil { + return errors.Wrapf(err, "error getting destination path from bind mount %s", mount.Destination) + } + destPath = path + } else if filepath.IsAbs(destPath) { cleanedPath, err := securejoin.SecureJoin(mountPoint, destPath) if err != nil { return err @@ -166,7 +178,19 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin destPath = cleanedPath } } else { - if filepath.IsAbs(srcPath) { + if isVol, volDestName, volName := isVolumeDestName(srcPath, ctr); isVol { + path, err := pathWithVolumeMount(ctr, runtime, volDestName, volName, srcPath) + if err != nil { + return errors.Wrapf(err, "error getting source path from volume %s", volDestName) + } + srcPath = path + } else if isBindMount, mount := isBindMountDestName(srcPath, ctr); isBindMount { + path, err := pathWithBindMountSource(mount, srcPath) + if err != nil { + return errors.Wrapf(err, "error getting source path from bind moutn %s", mount.Destination) + } + srcPath = path + } else if filepath.IsAbs(srcPath) { cleanedPath, err := securejoin.SecureJoin(mountPoint, srcPath) if err != nil { return err @@ -407,3 +431,72 @@ func streamFileToStdout(srcPath string, srcfi os.FileInfo) error { } return nil } + +func isVolumeDestName(path string, ctr *libpod.Container) (bool, string, string) { + separator := string(os.PathSeparator) + if filepath.IsAbs(path) { + path = strings.TrimPrefix(path, separator) + } + if path == "" { + return false, "", "" + } + for _, vol := range ctr.Config().NamedVolumes { + volNamePath := strings.TrimPrefix(vol.Dest, separator) + if matchVolumePath(path, volNamePath) { + return true, vol.Dest, vol.Name + } + } + return false, "", "" +} + +// if SRCPATH or DESTPATH is from volume mount's destination -v or --mount type=volume, generates the path with volume mount point +func pathWithVolumeMount(ctr *libpod.Container, runtime *libpod.Runtime, volDestName, volName, path string) (string, error) { + destVolume, err := runtime.GetVolume(volName) + if err != nil { + return "", errors.Wrapf(err, "error getting volume destination %s", volName) + } + if !filepath.IsAbs(path) { + path = filepath.Join(string(os.PathSeparator), path) + } + path, err = securejoin.SecureJoin(destVolume.MountPoint(), strings.TrimPrefix(path, volDestName)) + return path, err +} + +func isBindMountDestName(path string, ctr *libpod.Container) (bool, specs.Mount) { + separator := string(os.PathSeparator) + if filepath.IsAbs(path) { + path = strings.TrimPrefix(path, string(os.PathSeparator)) + } + if path == "" { + return false, specs.Mount{} + } + for _, m := range ctr.Config().Spec.Mounts { + if m.Type != "bind" { + continue + } + mDest := strings.TrimPrefix(m.Destination, separator) + if matchVolumePath(path, mDest) { + return true, m + } + } + return false, specs.Mount{} +} + +func matchVolumePath(path, target string) bool { + pathStr := filepath.Clean(path) + target = filepath.Clean(target) + for len(pathStr) > len(target) && strings.Contains(pathStr, string(os.PathSeparator)) { + pathStr = pathStr[:strings.LastIndex(pathStr, string(os.PathSeparator))] + } + if pathStr == target { + return true + } + return false +} + +func pathWithBindMountSource(m specs.Mount, path string) (string, error) { + if !filepath.IsAbs(path) { + path = filepath.Join(string(os.PathSeparator), path) + } + return securejoin.SecureJoin(m.Source, strings.TrimPrefix(path, m.Destination)) +} diff --git a/cmd/podman/exec.go b/cmd/podman/exec.go index deff44a92..0684da842 100644 --- a/cmd/podman/exec.go +++ b/cmd/podman/exec.go @@ -125,5 +125,10 @@ func execCmd(c *cliconfig.ExecValues) error { streams.AttachError = true streams.AttachInput = true - return ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs) + err = ctr.Exec(c.Tty, c.Privileged, envs, cmd, c.User, c.Workdir, streams, c.PreserveFDs) + if errors.Cause(err) == libpod.ErrCtrStateInvalid { + exitCode = 126 + } + + return err } diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go index 318dd0771..3969e3132 100644 --- a/cmd/podman/generate_kube.go +++ b/cmd/podman/generate_kube.go @@ -2,6 +2,9 @@ package main import ( "fmt" + "io/ioutil" + "os" + "github.com/containers/libpod/cmd/podman/cliconfig" "github.com/containers/libpod/pkg/adapter" podmanVersion "github.com/containers/libpod/version" @@ -37,6 +40,7 @@ func init() { containerKubeCommand.SetUsageTemplate(UsageTemplate()) flags := containerKubeCommand.Flags() flags.BoolVarP(&containerKubeCommand.Service, "service", "s", false, "Generate YAML for kubernetes service object") + flags.StringVarP(&containerKubeCommand.Filename, "filename", "f", "", "Filename to output to") } func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error { @@ -88,8 +92,19 @@ func generateKubeYAMLCmd(c *cliconfig.GenerateKubeValues) error { output = append(output, []byte("---\n")...) output = append(output, marshalledService...) } - // Output the v1.Pod with the v1.Container - fmt.Println(string(output)) + + if c.Filename != "" { + if _, err := os.Stat(c.Filename); err == nil { + return errors.Errorf("cannot write to %q - file exists", c.Filename) + } + + if err := ioutil.WriteFile(c.Filename, output, 0644); err != nil { + return err + } + } else { + // Output the v1.Pod with the v1.Container + fmt.Println(string(output)) + } return nil } diff --git a/cmd/podman/main.go b/cmd/podman/main.go index a149a47f9..cbca32cc8 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -104,6 +104,9 @@ func before(cmd *cobra.Command, args []string) error { logrus.Errorf(err.Error()) os.Exit(1) } + if err := setSyslog(); err != nil { + return err + } if err := setupRootless(cmd, args); err != nil { return err } diff --git a/cmd/podman/main_local.go b/cmd/podman/main_local.go index b4f21bd0c..132f35ab5 100644 --- a/cmd/podman/main_local.go +++ b/cmd/podman/main_local.go @@ -48,7 +48,7 @@ func init() { rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.Runtime, "runtime", "", "Path to the OCI-compatible binary used to run containers, default is /usr/bin/runc") // -s is depracated due to conflict with -s on subcommands rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.StorageDriver, "storage-driver", "", "Select which storage driver is used to manage storage of images and containers (default is overlay)") - rootCmd.PersistentFlags().StringSliceVar(&MainGlobalOpts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver") + rootCmd.PersistentFlags().StringArrayVar(&MainGlobalOpts.StorageOpts, "storage-opt", []string{}, "Used to pass an option to the storage driver") rootCmd.PersistentFlags().BoolVar(&MainGlobalOpts.Syslog, "syslog", false, "Output logging information to syslog as well as the console") rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.TmpDir, "tmpdir", "", "Path to the tmp directory") diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go index de6c2c760..1b9430e92 100644 --- a/cmd/podman/main_remote.go +++ b/cmd/podman/main_remote.go @@ -3,15 +3,21 @@ package main import ( + "os/user" + "github.com/spf13/cobra" ) const remote = true func init() { + var username string + if curruser, err := user.Current(); err == nil { + username = curruser.Username + } rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.ConnectionName, "connection", "", "remote connection name") rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteConfigFilePath, "remote-config-path", "", "alternate path for configuration file") - rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", "", "username on the remote host") + rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", username, "username on the remote host") rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", "", "remote host") // TODO maybe we allow the altering of this for bridge connections? //rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket") diff --git a/cmd/podman/restore.go b/cmd/podman/restore.go index 9c77d4a5e..6e445e5df 100644 --- a/cmd/podman/restore.go +++ b/cmd/podman/restore.go @@ -76,8 +76,22 @@ func restoreCmd(c *cliconfig.RestoreValues, cmd *cobra.Command) error { return errors.Errorf("--tcp-established cannot be used with --name") } - if (c.Import != "") && (c.All || c.Latest) { - return errors.Errorf("Cannot use --import and --all or --latest at the same time") + argLen := len(c.InputArgs) + if c.Import != "" { + if c.All || c.Latest { + return errors.Errorf("Cannot use --import with --all or --latest") + } + if argLen > 0 { + return errors.Errorf("Cannot use --import with positional arguments") + } } + + if (c.All || c.Latest) && argLen > 0 { + return errors.Errorf("no arguments are needed with --all or --latest") + } + if argLen < 1 && !c.All && !c.Latest && c.Import == "" { + return errors.Errorf("you must provide at least one name or id") + } + return runtime.Restore(getContext(), c, options) } diff --git a/cmd/podman/rm.go b/cmd/podman/rm.go index 1bf56b782..2710a8194 100644 --- a/cmd/podman/rm.go +++ b/cmd/podman/rm.go @@ -42,7 +42,9 @@ func init() { flags.BoolVarP(&rmCommand.All, "all", "a", false, "Remove all containers") flags.BoolVarP(&rmCommand.Force, "force", "f", false, "Force removal of a running container. The default is false") flags.BoolVarP(&rmCommand.Latest, "latest", "l", false, "Act on the latest container podman is aware of") + flags.BoolVar(&rmCommand.Storage, "storage", false, "Remove container from storage library") flags.BoolVarP(&rmCommand.Volumes, "volumes", "v", false, "Remove the volumes associated with the container") + markFlagHiddenForRemoteClient("storage", flags) markFlagHiddenForRemoteClient("latest", flags) } @@ -54,6 +56,13 @@ func rmCmd(c *cliconfig.RmValues) error { } defer runtime.Shutdown(false) + // Storage conflicts with --all/--latest/--volumes + if c.Storage { + if c.All || c.Latest || c.Volumes { + return errors.Errorf("--storage conflicts with --volumes, --all, and --latest") + } + } + ok, failures, err := runtime.RemoveContainers(getContext(), c) if err != nil { if errors.Cause(err) == libpod.ErrNoSuchCtr { diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink index 5b3d5ae4c..9410b9459 100644 --- a/cmd/podman/varlink/io.podman.varlink +++ b/cmd/podman/varlink/io.podman.varlink @@ -207,7 +207,7 @@ type ContainerNameSpace ( ipc: string ) -# InfoDistribution describes the the host's distribution +# InfoDistribution describes the host's distribution type InfoDistribution ( distribution: string, version: string @@ -671,7 +671,7 @@ method PauseContainer(name: string) -> (container: string) # See also [PauseContainer](#PauseContainer). method UnpauseContainer(name: string) -> (container: string) -# Attach takes the name or ID of a container and sets up a the ability to remotely attach to its console. The start +# Attach takes the name or ID of a container and sets up the ability to remotely attach to its console. The start # bool is whether you wish to start the container in question first. method Attach(name: string, detachKeys: string, start: bool) -> () @@ -744,7 +744,7 @@ method BuildImage(build: BuildInfo) -> (image: MoreResponse) # This function is not implemented yet. # method CreateImage() -> (notimplemented: NotImplemented) -# InspectImage takes the name or ID of an image and returns a string respresentation of data associated with the +# InspectImage takes the name or ID of an image and returns a string representation of data associated with the #image. You must serialize the string into JSON to use it further. An [ImageNotFound](#ImageNotFound) error will # be returned if the image cannot be found. method InspectImage(name: string) -> (image: string) @@ -810,7 +810,7 @@ method Commit(name: string, image_name: string, changes: []string, author: strin method ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) -> (image: string) # ExportImage takes the name or ID of an image and exports it to a destination like a tarball. There is also -# a booleon option to force compression. It also takes in a string array of tags to be able to save multiple +# a boolean option to force compression. It also takes in a string array of tags to be able to save multiple # tags of the same image to a tarball (each tag should be of the form <image>:<tag>). Upon completion, the ID # of the image is returned. If the image cannot be found in local storage, an [ImageNotFound](#ImageNotFound) # error will be returned. See also [ImportImage](ImportImage). @@ -915,7 +915,7 @@ method ListPods() -> (pods: []ListPodData) # ~~~ method GetPod(name: string) -> (pod: ListPodData) -# InspectPod takes the name or ID of an image and returns a string respresentation of data associated with the +# InspectPod takes the name or ID of an image and returns a string representation of data associated with the # pod. You must serialize the string into JSON to use it further. A [PodNotFound](#PodNotFound) error will # be returned if the pod cannot be found. method InspectPod(name: string) -> (pod: string) |