summaryrefslogtreecommitdiff
path: root/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'cmd')
-rw-r--r--cmd/podman/common/create_opts.go9
-rw-r--r--cmd/podman/common/specgen.go42
-rw-r--r--cmd/podman/containers/cp.go135
-rw-r--r--cmd/podman/containers/restore.go6
4 files changed, 104 insertions, 88 deletions
diff --git a/cmd/podman/common/create_opts.go b/cmd/podman/common/create_opts.go
index 66778f519..42e0efe5d 100644
--- a/cmd/podman/common/create_opts.go
+++ b/cmd/podman/common/create_opts.go
@@ -517,7 +517,14 @@ func ContainerCreateToContainerCLIOpts(cc handlers.CreateContainerConfig, rtc *c
cliOpts.OOMKillDisable = *cc.HostConfig.OomKillDisable
}
if cc.Config.Healthcheck != nil {
- cliOpts.HealthCmd = strings.Join(cc.Config.Healthcheck.Test, " ")
+ finCmd := ""
+ for _, str := range cc.Config.Healthcheck.Test {
+ finCmd = finCmd + str + " "
+ }
+ if len(finCmd) > 1 {
+ finCmd = finCmd[:len(finCmd)-1]
+ }
+ cliOpts.HealthCmd = finCmd
cliOpts.HealthInterval = cc.Config.Healthcheck.Interval.String()
cliOpts.HealthRetries = uint(cc.Config.Healthcheck.Retries)
cliOpts.HealthStartPeriod = cc.Config.Healthcheck.StartPeriod.String()
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 24b45e479..42f515ace 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -516,7 +516,6 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
if len(con) != 2 {
return fmt.Errorf("invalid --security-opt 1: %q", opt)
}
-
switch con[0] {
case "apparmor":
s.ContainerSecurityConfig.ApparmorProfile = con[1]
@@ -664,25 +663,40 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
}
func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, startPeriod string) (*manifest.Schema2HealthConfig, error) {
+ cmdArr := []string{}
+ isArr := true
+ err := json.Unmarshal([]byte(inCmd), &cmdArr) // array unmarshalling
+ if err != nil {
+ cmdArr = strings.SplitN(inCmd, " ", 2) // default for compat
+ isArr = false
+ }
// Every healthcheck requires a command
- if len(inCmd) == 0 {
+ if len(cmdArr) == 0 {
return nil, errors.New("Must define a healthcheck command for all healthchecks")
}
-
- // first try to parse option value as JSON array of strings...
- cmd := []string{}
-
- if inCmd == "none" {
- cmd = []string{"NONE"}
- } else {
- err := json.Unmarshal([]byte(inCmd), &cmd)
- if err != nil {
- // ...otherwise pass it to "/bin/sh -c" inside the container
- cmd = []string{"CMD-SHELL", inCmd}
+ concat := ""
+ if cmdArr[0] == "CMD" || cmdArr[0] == "none" { // this is for compat, we are already split properly for most compat cases
+ cmdArr = strings.Fields(inCmd)
+ } else if cmdArr[0] != "CMD-SHELL" { // this is for podman side of things, wont contain the keywords
+ if isArr && len(cmdArr) > 1 { // an array of consecutive commands
+ cmdArr = append([]string{"CMD"}, cmdArr...)
+ } else { // one singular command
+ if len(cmdArr) == 1 {
+ concat = cmdArr[0]
+ } else {
+ concat = strings.Join(cmdArr[0:], " ")
+ }
+ cmdArr = append([]string{"CMD-SHELL"}, concat)
}
}
+
+ if cmdArr[0] == "none" { // if specified to remove healtcheck
+ cmdArr = []string{"NONE"}
+ }
+
+ // healthcheck is by default an array, so we simply pass the user input
hc := manifest.Schema2HealthConfig{
- Test: cmd,
+ Test: cmdArr,
}
if interval == "disable" {
diff --git a/cmd/podman/containers/cp.go b/cmd/podman/containers/cp.go
index 67bb13aa1..7b5846a35 100644
--- a/cmd/podman/containers/cp.go
+++ b/cmd/podman/containers/cp.go
@@ -131,43 +131,17 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
return errors.Wrapf(err, "%q could not be found on container %s", sourcePath, sourceContainer)
}
- var destContainerBaseName string
- destContainerInfo, destContainerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), destContainer, destPath)
- if destContainerInfoErr != nil {
- if strings.HasSuffix(destPath, "/") {
- return errors.Wrapf(destContainerInfoErr, "%q could not be found on container %s", destPath, destContainer)
- }
- // NOTE: containerInfo may actually be set. That happens when
- // the container path is a symlink into nirvana. In that case,
- // we must use the symlinked path instead.
- path := destPath
- if destContainerInfo != nil {
- destContainerBaseName = filepath.Base(destContainerInfo.LinkTarget)
- path = destContainerInfo.LinkTarget
- } else {
- destContainerBaseName = filepath.Base(destPath)
- }
-
- parentDir, err := containerParentDir(destContainer, path)
- if err != nil {
- return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, destContainer)
- }
- destContainerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), destContainer, parentDir)
- if err != nil {
- return errors.Wrapf(err, "%q could not be found on container %s", destPath, destContainer)
- }
- } else {
- // If the specified path exists on the container, we must use
- // its base path as it may have changed due to symlink
- // evaluations.
- destContainerBaseName = filepath.Base(destContainerInfo.LinkTarget)
+ destContainerBaseName, destContainerInfo, destResolvedToParentDir, err := resolvePathOnDestinationContainer(destContainer, destPath, false)
+ if err != nil {
+ return err
}
if sourceContainerInfo.IsDir && !destContainerInfo.IsDir {
return errors.New("destination must be a directory when copying a directory")
}
- sourceContainerTarget, destContainerTarget := sourceContainerInfo.LinkTarget, destContainerInfo.LinkTarget
+ sourceContainerTarget := sourceContainerInfo.LinkTarget
+ destContainerTarget := destContainerInfo.LinkTarget
if !destContainerInfo.IsDir {
destContainerTarget = filepath.Dir(destPath)
}
@@ -180,7 +154,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
// Hence, whenever "." is the source and the destination does not
// exist, we copy the source's parent and let the copier package create
// the destination via the Rename option.
- if destContainerInfoErr != nil && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") {
+ if destResolvedToParentDir && sourceContainerInfo.IsDir && strings.HasSuffix(sourcePath, ".") {
sourceContainerTarget = filepath.Dir(sourceContainerTarget)
}
@@ -202,7 +176,7 @@ func copyContainerToContainer(sourceContainer string, sourcePath string, destCon
defer reader.Close()
copyOptions := entities.CopyOptions{Chown: chown}
- if (!sourceContainerInfo.IsDir && !destContainerInfo.IsDir) || destContainerInfoErr != nil {
+ if (!sourceContainerInfo.IsDir && !destContainerInfo.IsDir) || destResolvedToParentDir {
// If we're having a file-to-file copy, make sure to
// rename accordingly.
copyOptions.Rename = map[string]string{filepath.Base(sourceContainerTarget): destContainerBaseName}
@@ -239,6 +213,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
}
var hostBaseName string
+ var resolvedToHostParentDir bool
hostInfo, hostInfoErr := copy.ResolveHostPath(hostPath)
if hostInfoErr != nil {
if strings.HasSuffix(hostPath, "/") {
@@ -254,6 +229,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
// it'll be created while copying. Hence, we use it as the
// base path.
hostBaseName = filepath.Base(hostPath)
+ resolvedToHostParentDir = true
} else {
// If the specified path exists on the host, we must use its
// base path as it may have changed due to symlink evaluations.
@@ -281,7 +257,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
// we copy the source's parent and let the copier package create the
// destination via the Rename option.
containerTarget := containerInfo.LinkTarget
- if hostInfoErr != nil && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
+ if resolvedToHostParentDir && containerInfo.IsDir && strings.HasSuffix(containerTarget, ".") {
containerTarget = filepath.Dir(containerTarget)
}
@@ -322,7 +298,7 @@ func copyFromContainer(container string, containerPath string, hostPath string)
ChownFiles: &idPair,
IgnoreDevices: true,
}
- if (!containerInfo.IsDir && !hostInfo.IsDir) || hostInfoErr != nil {
+ if (!containerInfo.IsDir && !hostInfo.IsDir) || resolvedToHostParentDir {
// If we're having a file-to-file copy, make sure to
// rename accordingly.
putOptions.Rename = map[string]string{filepath.Base(containerTarget): hostBaseName}
@@ -369,42 +345,9 @@ func copyToContainer(container string, containerPath string, hostPath string) er
return errors.Wrapf(err, "%q could not be found on the host", hostPath)
}
- // If the path on the container does not exist. We need to make sure
- // that it's parent directory exists. The destination may be created
- // while copying.
- var containerBaseName string
- containerInfo, containerInfoErr := registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
- if containerInfoErr != nil {
- if strings.HasSuffix(containerPath, "/") {
- return errors.Wrapf(containerInfoErr, "%q could not be found on container %s", containerPath, container)
- }
- if isStdin {
- return errors.New("destination must be a directory when copying from stdin")
- }
- // NOTE: containerInfo may actually be set. That happens when
- // the container path is a symlink into nirvana. In that case,
- // we must use the symlinked path instead.
- path := containerPath
- if containerInfo != nil {
- containerBaseName = filepath.Base(containerInfo.LinkTarget)
- path = containerInfo.LinkTarget
- } else {
- containerBaseName = filepath.Base(containerPath)
- }
-
- parentDir, err := containerParentDir(container, path)
- if err != nil {
- return errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
- }
- containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
- if err != nil {
- return errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
- }
- } else {
- // If the specified path exists on the container, we must use
- // its base path as it may have changed due to symlink
- // evaluations.
- containerBaseName = filepath.Base(containerInfo.LinkTarget)
+ containerBaseName, containerInfo, containerResolvedToParentDir, err := resolvePathOnDestinationContainer(container, containerPath, isStdin)
+ if err != nil {
+ return err
}
// If we copy a directory via the "." notation and the container path
@@ -416,7 +359,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
// exist, we copy the source's parent and let the copier package create
// the destination via the Rename option.
hostTarget := hostInfo.LinkTarget
- if containerInfoErr != nil && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
+ if containerResolvedToParentDir && hostInfo.IsDir && strings.HasSuffix(hostTarget, ".") {
hostTarget = filepath.Dir(hostTarget)
}
@@ -468,7 +411,7 @@ func copyToContainer(container string, containerPath string, hostPath string) er
// copy the base directory.
KeepDirectoryNames: hostInfo.IsDir && filepath.Base(hostTarget) != ".",
}
- if (!hostInfo.IsDir && !containerInfo.IsDir) || containerInfoErr != nil {
+ if (!hostInfo.IsDir && !containerInfo.IsDir) || containerResolvedToParentDir {
// If we're having a file-to-file copy, make sure to
// rename accordingly.
getOptions.Rename = map[string]string{filepath.Base(hostTarget): containerBaseName}
@@ -499,6 +442,52 @@ func copyToContainer(container string, containerPath string, hostPath string) er
return doCopy(hostCopy, containerCopy)
}
+// resolvePathOnDestinationContainer resolves the specified path on the
+// container. If the path does not exist, it attempts to use the parent
+// directory.
+func resolvePathOnDestinationContainer(container string, containerPath string, isStdin bool) (baseName string, containerInfo *entities.ContainerStatReport, resolvedToParentDir bool, err error) {
+ containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, containerPath)
+ if err == nil {
+ baseName = filepath.Base(containerInfo.LinkTarget)
+ return
+ }
+
+ if strings.HasSuffix(containerPath, "/") {
+ err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
+ return
+ }
+ if isStdin {
+ err = errors.New("destination must be a directory when copying from stdin")
+ return
+ }
+
+ // NOTE: containerInfo may actually be set. That happens when
+ // the container path is a symlink into nirvana. In that case,
+ // we must use the symlinked path instead.
+ path := containerPath
+ if containerInfo != nil {
+ baseName = filepath.Base(containerInfo.LinkTarget)
+ path = containerInfo.LinkTarget
+ } else {
+ baseName = filepath.Base(containerPath)
+ }
+
+ parentDir, err := containerParentDir(container, path)
+ if err != nil {
+ err = errors.Wrapf(err, "could not determine parent dir of %q on container %s", path, container)
+ return
+ }
+
+ containerInfo, err = registry.ContainerEngine().ContainerStat(registry.GetContext(), container, parentDir)
+ if err != nil {
+ err = errors.Wrapf(err, "%q could not be found on container %s", containerPath, container)
+ return
+ }
+
+ resolvedToParentDir = true
+ return baseName, containerInfo, resolvedToParentDir, nil
+}
+
// containerParentDir returns the parent directory of the specified path on the
// container. If the path is relative, it will be resolved relative to the
// container's working directory (or "/" if the work dir isn't set).
diff --git a/cmd/podman/containers/restore.go b/cmd/podman/containers/restore.go
index b908ea493..3b6f74efa 100644
--- a/cmd/podman/containers/restore.go
+++ b/cmd/podman/containers/restore.go
@@ -71,6 +71,9 @@ func init() {
)
_ = restoreCommand.RegisterFlagCompletionFunc("publish", completion.AutocompleteNone)
+ flags.StringVar(&restoreOptions.Pod, "pod", "", "Restore container into existing Pod (only works with --import)")
+ _ = restoreCommand.RegisterFlagCompletionFunc("pod", common.AutocompletePodsRunning)
+
validate.AddLatestFlag(restoreCommand, &restoreOptions.Latest)
}
@@ -91,6 +94,9 @@ func restore(cmd *cobra.Command, args []string) error {
if restoreOptions.Import == "" && restoreOptions.Name != "" {
return errors.Errorf("--name can only be used with --import")
}
+ if restoreOptions.Import == "" && restoreOptions.Pod != "" {
+ return errors.Errorf("--pod can only be used with --import")
+ }
if restoreOptions.Name != "" && restoreOptions.TCPEstablished {
return errors.Errorf("--tcp-established cannot be used with --name")
}