summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOpenShift Merge Robot <openshift-merge-robot@users.noreply.github.com>2020-05-06 20:34:13 +0200
committerGitHub <noreply@github.com>2020-05-06 20:34:13 +0200
commit8b5df5b5d97facad5bb84fe4597bf7f0059c09fa (patch)
tree66296d6b47bc9627053bd0b3dadb07059cf711c6
parent22bf906e8cc440cb3c33b9eed620ae91f447b269 (diff)
parentf269be3a314a0903bb74a20de0e93b4f274531e6 (diff)
downloadpodman-8b5df5b5d97facad5bb84fe4597bf7f0059c09fa.tar.gz
podman-8b5df5b5d97facad5bb84fe4597bf7f0059c09fa.tar.bz2
podman-8b5df5b5d97facad5bb84fe4597bf7f0059c09fa.zip
Merge pull request #6092 from vrothberg/v2-kube
add {generate,play} kube
-rw-r--r--cmd/podman/common/specgen.go3
-rw-r--r--cmd/podman/common/types.go3
-rw-r--r--cmd/podman/generate/generate.go2
-rw-r--r--cmd/podman/generate/kube.go68
-rw-r--r--cmd/podman/generate/systemd.go2
-rw-r--r--cmd/podman/main.go1
-rw-r--r--cmd/podman/play/kube.go101
-rw-r--r--cmd/podman/play/play.go26
-rw-r--r--cmd/podman/pods/create.go3
-rw-r--r--libpod/container.go2
-rw-r--r--libpod/container_inspect.go83
-rw-r--r--libpod/define/annotations.go68
-rw-r--r--libpod/kube.go2
-rw-r--r--pkg/api/handlers/libpod/generate.go38
-rw-r--r--pkg/api/handlers/libpod/play.go64
-rw-r--r--pkg/api/handlers/swagger/swagger.go7
-rw-r--r--pkg/api/server/register_generate.go41
-rw-r--r--pkg/api/server/register_play.go42
-rw-r--r--pkg/api/server/server.go2
-rw-r--r--pkg/bindings/generate/generate.go32
-rw-r--r--pkg/bindings/play/play.go42
-rw-r--r--pkg/domain/entities/engine_container.go2
-rw-r--r--pkg/domain/entities/generate.go14
-rw-r--r--pkg/domain/entities/play.go36
-rw-r--r--pkg/domain/infra/abi/generate.go85
-rw-r--r--pkg/domain/infra/abi/play.go544
-rw-r--r--pkg/domain/infra/tunnel/generate.go5
-rw-r--r--pkg/domain/infra/tunnel/play.go12
-rw-r--r--pkg/spec/namespaces.go8
-rw-r--r--pkg/spec/security.go7
-rw-r--r--pkg/spec/spec.go17
-rw-r--r--pkg/specgen/generate/namespaces.go4
-rw-r--r--pkg/specgen/generate/oci.go11
-rw-r--r--test/e2e/generate_kube_test.go1
-rw-r--r--test/e2e/play_kube_test.go1
35 files changed, 1269 insertions, 110 deletions
diff --git a/cmd/podman/common/specgen.go b/cmd/podman/common/specgen.go
index 3681804ea..3e9772576 100644
--- a/cmd/podman/common/specgen.go
+++ b/cmd/podman/common/specgen.go
@@ -534,10 +534,13 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *ContainerCLIOpts, args []string
case "label":
// TODO selinux opts and label opts are the same thing
s.ContainerSecurityConfig.SelinuxOpts = append(s.ContainerSecurityConfig.SelinuxOpts, con[1])
+ s.Annotations[define.InspectAnnotationLabel] = con[1]
case "apparmor":
s.ContainerSecurityConfig.ApparmorProfile = con[1]
+ s.Annotations[define.InspectAnnotationApparmor] = con[1]
case "seccomp":
s.SeccompProfilePath = con[1]
+ s.Annotations[define.InspectAnnotationSeccomp] = con[1]
default:
return fmt.Errorf("invalid --security-opt 2: %q", opt)
}
diff --git a/cmd/podman/common/types.go b/cmd/podman/common/types.go
deleted file mode 100644
index 2427ae975..000000000
--- a/cmd/podman/common/types.go
+++ /dev/null
@@ -1,3 +0,0 @@
-package common
-
-var DefaultKernelNamespaces = "cgroup,ipc,net,uts"
diff --git a/cmd/podman/generate/generate.go b/cmd/podman/generate/generate.go
index b112e666a..7803c0c78 100644
--- a/cmd/podman/generate/generate.go
+++ b/cmd/podman/generate/generate.go
@@ -22,7 +22,7 @@ var (
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
- Mode: []entities.EngineMode{entities.ABIMode},
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
Command: generateCmd,
})
}
diff --git a/cmd/podman/generate/kube.go b/cmd/podman/generate/kube.go
new file mode 100644
index 000000000..86a9cc686
--- /dev/null
+++ b/cmd/podman/generate/kube.go
@@ -0,0 +1,68 @@
+package pods
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+var (
+ kubeOptions = entities.GenerateKubeOptions{}
+ kubeFile = ""
+ kubeDescription = `Command generates Kubernetes pod and service YAML (v1 specification) from a Podman container or pod.
+
+Whether the input is for a container or pod, Podman will always generate the specification as a pod.`
+
+ kubeCmd = &cobra.Command{
+ Use: "kube [flags] CONTAINER | POD",
+ Short: "Generate Kubernetes YAML from a container or pod.",
+ Long: kubeDescription,
+ RunE: kube,
+ Args: cobra.ExactArgs(1),
+ Example: `podman generate kube ctrID
+ podman generate kube podID
+ podman generate kube --service podID`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: kubeCmd,
+ Parent: generateCmd,
+ })
+ flags := kubeCmd.Flags()
+ flags.BoolVarP(&kubeOptions.Service, "service", "s", false, "Generate YAML for a Kubernetes service object")
+ flags.StringVarP(&kubeFile, "filename", "f", "", "Write output to the specified path")
+ flags.SetNormalizeFunc(utils.AliasFlags)
+}
+
+func kube(cmd *cobra.Command, args []string) error {
+ report, err := registry.ContainerEngine().GenerateKube(registry.GetContext(), args[0], kubeOptions)
+ if err != nil {
+ return err
+ }
+
+ content, err := ioutil.ReadAll(report.Reader)
+ if err != nil {
+ return err
+ }
+ if cmd.Flags().Changed("filename") {
+ if _, err := os.Stat(kubeFile); err == nil {
+ return errors.Errorf("cannot write to %q", kubeFile)
+ }
+ if err := ioutil.WriteFile(kubeFile, content, 0644); err != nil {
+ return errors.Wrapf(err, "cannot write to %q", kubeFile)
+ }
+ return nil
+ }
+
+ fmt.Println(string(content))
+ return nil
+}
diff --git a/cmd/podman/generate/systemd.go b/cmd/podman/generate/systemd.go
index 55d770249..20d9748d4 100644
--- a/cmd/podman/generate/systemd.go
+++ b/cmd/podman/generate/systemd.go
@@ -29,7 +29,7 @@ var (
func init() {
registry.Commands = append(registry.Commands, registry.CliCommand{
- Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Mode: []entities.EngineMode{entities.ABIMode},
Command: systemdCmd,
Parent: generateCmd,
})
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index 422dee90b..76ec7bc8e 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -10,6 +10,7 @@ import (
_ "github.com/containers/libpod/cmd/podman/images"
_ "github.com/containers/libpod/cmd/podman/manifest"
_ "github.com/containers/libpod/cmd/podman/networks"
+ _ "github.com/containers/libpod/cmd/podman/play"
_ "github.com/containers/libpod/cmd/podman/pods"
"github.com/containers/libpod/cmd/podman/registry"
_ "github.com/containers/libpod/cmd/podman/system"
diff --git a/cmd/podman/play/kube.go b/cmd/podman/play/kube.go
new file mode 100644
index 000000000..2499b54b9
--- /dev/null
+++ b/cmd/podman/play/kube.go
@@ -0,0 +1,101 @@
+package pods
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/containers/common/pkg/auth"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+// playKubeOptionsWrapper allows for separating CLI-only fields from API-only
+// fields.
+type playKubeOptionsWrapper struct {
+ entities.PlayKubeOptions
+
+ TLSVerifyCLI bool
+}
+
+var (
+ // https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet/
+ defaultSeccompRoot = "/var/lib/kubelet/seccomp"
+ kubeOptions = playKubeOptionsWrapper{}
+ kubeDescription = `Command reads in a structured file of Kubernetes YAML.
+
+ It creates the pod and containers described in the YAML. The containers within the pod are then started and the ID of the new Pod is output.`
+
+ kubeCmd = &cobra.Command{
+ Use: "kube [flags] KUBEFILE",
+ Short: "Play a pod based on Kubernetes YAML.",
+ Long: kubeDescription,
+ RunE: kube,
+ Args: cobra.ExactArgs(1),
+ Example: `podman play kube nginx.yml
+ podman play kube --creds user:password --seccomp-profile-root /custom/path apache.yml`,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: kubeCmd,
+ Parent: playCmd,
+ })
+
+ flags := kubeCmd.Flags()
+ flags.SetNormalizeFunc(utils.AliasFlags)
+ flags.StringVar(&kubeOptions.Credentials, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
+ flags.StringVar(&kubeOptions.Network, "network", "", "Connect pod to CNI network(s)")
+ flags.BoolVarP(&kubeOptions.Quiet, "quiet", "q", false, "Suppress output information when pulling images")
+ if !registry.IsRemote() {
+ flags.StringVar(&kubeOptions.Authfile, "authfile", auth.GetDefaultAuthFile(), "Path of the authentication file. Use REGISTRY_AUTH_FILE environment variable to override")
+ flags.StringVar(&kubeOptions.CertDir, "cert-dir", "", "`Pathname` of a directory containing TLS certificates and keys")
+ flags.BoolVar(&kubeOptions.TLSVerifyCLI, "tls-verify", true, "Require HTTPS and verify certificates when contacting registries")
+ flags.StringVar(&kubeOptions.SignaturePolicy, "signature-policy", "", "`Pathname` of signature policy file (not usually used)")
+ flags.StringVar(&kubeOptions.SeccompProfileRoot, "seccomp-profile-root", defaultSeccompRoot, "Directory path for seccomp profiles")
+ }
+}
+
+func kube(cmd *cobra.Command, args []string) error {
+ // TLS verification in c/image is controlled via a `types.OptionalBool`
+ // which allows for distinguishing among set-true, set-false, unspecified
+ // which is important to implement a sane way of dealing with defaults of
+ // boolean CLI flags.
+ if cmd.Flags().Changed("tls-verify") {
+ kubeOptions.SkipTLSVerify = types.NewOptionalBool(!kubeOptions.TLSVerifyCLI)
+ }
+ if kubeOptions.Authfile != "" {
+ if _, err := os.Stat(kubeOptions.Authfile); err != nil {
+ return errors.Wrapf(err, "error getting authfile %s", kubeOptions.Authfile)
+ }
+ }
+
+ report, err := registry.ContainerEngine().PlayKube(registry.GetContext(), args[0], kubeOptions.PlayKubeOptions)
+ if err != nil {
+ return err
+ }
+
+ for _, l := range report.Logs {
+ fmt.Fprintf(os.Stderr, l)
+ }
+
+ fmt.Printf("Pod:\n%s\n", report.Pod)
+ switch len(report.Containers) {
+ case 0:
+ return nil
+ case 1:
+ fmt.Printf("Container:\n")
+ default:
+ fmt.Printf("Containers:\n")
+ }
+ for _, ctr := range report.Containers {
+ fmt.Println(ctr)
+ }
+
+ return nil
+}
diff --git a/cmd/podman/play/play.go b/cmd/podman/play/play.go
new file mode 100644
index 000000000..b151e5f5d
--- /dev/null
+++ b/cmd/podman/play/play.go
@@ -0,0 +1,26 @@
+package pods
+
+import (
+ "github.com/containers/libpod/cmd/podman/registry"
+ "github.com/containers/libpod/cmd/podman/validate"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/spf13/cobra"
+)
+
+var (
+ // Command: podman _play_
+ playCmd = &cobra.Command{
+ Use: "play",
+ Short: "Play a pod and its containers from a structured file.",
+ Long: "Play structured data (e.g., Kubernetes pod or service yaml) based on containers and pods.",
+ TraverseChildren: true,
+ RunE: validate.SubCommandExists,
+ }
+)
+
+func init() {
+ registry.Commands = append(registry.Commands, registry.CliCommand{
+ Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode},
+ Command: playCmd,
+ })
+}
diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go
index 85b96d37b..0a2016496 100644
--- a/cmd/podman/pods/create.go
+++ b/cmd/podman/pods/create.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/cmd/podman/validate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/errorhandling"
+ createconfig "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/specgen"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
@@ -57,7 +58,7 @@ func init() {
flags.StringVarP(&createOptions.Name, "name", "n", "", "Assign a name to the pod")
flags.StringVarP(&createOptions.Hostname, "hostname", "", "", "Set a hostname to the pod")
flags.StringVar(&podIDFile, "pod-id-file", "", "Write the pod ID to the file")
- flags.StringVar(&share, "share", common.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
+ flags.StringVar(&share, "share", createconfig.DefaultKernelNamespaces, "A comma delimited list of kernel namespaces the pod will share")
}
func create(cmd *cobra.Command, args []string) error {
diff --git a/libpod/container.go b/libpod/container.go
index 5cd719ab6..d4a779b13 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -1221,5 +1221,5 @@ func (c *Container) AutoRemove() bool {
if spec.Annotations == nil {
return false
}
- return c.Spec().Annotations[InspectAnnotationAutoremove] == InspectResponseTrue
+ return c.Spec().Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue
}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 276429b11..ae28dde94 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -16,73 +16,6 @@ import (
"github.com/syndtr/gocapability/capability"
)
-const (
- // InspectAnnotationCIDFile is used by Inspect to determine if a
- // container ID file was created for the container.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationCIDFile = "io.podman.annotations.cid-file"
- // InspectAnnotationAutoremove is used by Inspect to determine if a
- // container will be automatically removed on exit.
- // If an annotation with this key is found in the OCI spec and is one of
- // the two supported boolean values (InspectResponseTrue and
- // InspectResponseFalse) it will be used in the output of Inspect().
- InspectAnnotationAutoremove = "io.podman.annotations.autoremove"
- // InspectAnnotationVolumesFrom is used by Inspect to identify
- // containers whose volumes are are being used by this container.
- // It is expected to be a comma-separated list of container names and/or
- // IDs.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationVolumesFrom = "io.podman.annotations.volumes-from"
- // InspectAnnotationPrivileged is used by Inspect to identify containers
- // which are privileged (IE, running with elevated privileges).
- // It is expected to be a boolean, populated by one of
- // InspectResponseTrue or InspectResponseFalse.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationPrivileged = "io.podman.annotations.privileged"
- // InspectAnnotationPublishAll is used by Inspect to identify containers
- // which have all the ports from their image published.
- // It is expected to be a boolean, populated by one of
- // InspectResponseTrue or InspectResponseFalse.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationPublishAll = "io.podman.annotations.publish-all"
- // InspectAnnotationInit is used by Inspect to identify containers that
- // mount an init binary in.
- // It is expected to be a boolean, populated by one of
- // InspectResponseTrue or InspectResponseFalse.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationInit = "io.podman.annotations.init"
- // InspectAnnotationLabel is used by Inspect to identify containers with
- // special SELinux-related settings. It is used to populate the output
- // of the SecurityOpt setting.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationLabel = "io.podman.annotations.label"
- // InspectAnnotationSeccomp is used by Inspect to identify containers
- // with special Seccomp-related settings. It is used to populate the
- // output of the SecurityOpt setting in Inspect.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationSeccomp = "io.podman.annotations.seccomp"
- // InspectAnnotationApparmor is used by Inspect to identify containers
- // with special Apparmor-related settings. It is used to populate the
- // output of the SecurityOpt setting.
- // If an annotation with this key is found in the OCI spec, it will be
- // used in the output of Inspect().
- InspectAnnotationApparmor = "io.podman.annotations.apparmor"
-
- // InspectResponseTrue is a boolean True response for an inspect
- // annotation.
- InspectResponseTrue = "TRUE"
- // InspectResponseFalse is a boolean False response for an inspect
- // annotation.
- InspectResponseFalse = "FALSE"
-)
-
// inspectLocked inspects a container for low-level information.
// The caller must held c.lock.
func (c *Container) inspectLocked(size bool) (*define.InspectContainerData, error) {
@@ -452,26 +385,26 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
// Annotations
if ctrSpec.Annotations != nil {
- hostConfig.ContainerIDFile = ctrSpec.Annotations[InspectAnnotationCIDFile]
- if ctrSpec.Annotations[InspectAnnotationAutoremove] == InspectResponseTrue {
+ hostConfig.ContainerIDFile = ctrSpec.Annotations[define.InspectAnnotationCIDFile]
+ if ctrSpec.Annotations[define.InspectAnnotationAutoremove] == define.InspectResponseTrue {
hostConfig.AutoRemove = true
}
- if ctrs, ok := ctrSpec.Annotations[InspectAnnotationVolumesFrom]; ok {
+ if ctrs, ok := ctrSpec.Annotations[define.InspectAnnotationVolumesFrom]; ok {
hostConfig.VolumesFrom = strings.Split(ctrs, ",")
}
- if ctrSpec.Annotations[InspectAnnotationPrivileged] == InspectResponseTrue {
+ if ctrSpec.Annotations[define.InspectAnnotationPrivileged] == define.InspectResponseTrue {
hostConfig.Privileged = true
}
- if ctrSpec.Annotations[InspectAnnotationInit] == InspectResponseTrue {
+ if ctrSpec.Annotations[define.InspectAnnotationInit] == define.InspectResponseTrue {
hostConfig.Init = true
}
- if label, ok := ctrSpec.Annotations[InspectAnnotationLabel]; ok {
+ if label, ok := ctrSpec.Annotations[define.InspectAnnotationLabel]; ok {
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("label=%s", label))
}
- if seccomp, ok := ctrSpec.Annotations[InspectAnnotationSeccomp]; ok {
+ if seccomp, ok := ctrSpec.Annotations[define.InspectAnnotationSeccomp]; ok {
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("seccomp=%s", seccomp))
}
- if apparmor, ok := ctrSpec.Annotations[InspectAnnotationApparmor]; ok {
+ if apparmor, ok := ctrSpec.Annotations[define.InspectAnnotationApparmor]; ok {
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("apparmor=%s", apparmor))
}
}
diff --git a/libpod/define/annotations.go b/libpod/define/annotations.go
new file mode 100644
index 000000000..f6b1c06ea
--- /dev/null
+++ b/libpod/define/annotations.go
@@ -0,0 +1,68 @@
+package define
+
+const (
+ // InspectAnnotationCIDFile is used by Inspect to determine if a
+ // container ID file was created for the container.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationCIDFile = "io.podman.annotations.cid-file"
+ // InspectAnnotationAutoremove is used by Inspect to determine if a
+ // container will be automatically removed on exit.
+ // If an annotation with this key is found in the OCI spec and is one of
+ // the two supported boolean values (InspectResponseTrue and
+ // InspectResponseFalse) it will be used in the output of Inspect().
+ InspectAnnotationAutoremove = "io.podman.annotations.autoremove"
+ // InspectAnnotationVolumesFrom is used by Inspect to identify
+ // containers whose volumes are are being used by this container.
+ // It is expected to be a comma-separated list of container names and/or
+ // IDs.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationVolumesFrom = "io.podman.annotations.volumes-from"
+ // InspectAnnotationPrivileged is used by Inspect to identify containers
+ // which are privileged (IE, running with elevated privileges).
+ // It is expected to be a boolean, populated by one of
+ // InspectResponseTrue or InspectResponseFalse.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationPrivileged = "io.podman.annotations.privileged"
+ // InspectAnnotationPublishAll is used by Inspect to identify containers
+ // which have all the ports from their image published.
+ // It is expected to be a boolean, populated by one of
+ // InspectResponseTrue or InspectResponseFalse.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationPublishAll = "io.podman.annotations.publish-all"
+ // InspectAnnotationInit is used by Inspect to identify containers that
+ // mount an init binary in.
+ // It is expected to be a boolean, populated by one of
+ // InspectResponseTrue or InspectResponseFalse.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationInit = "io.podman.annotations.init"
+ // InspectAnnotationLabel is used by Inspect to identify containers with
+ // special SELinux-related settings. It is used to populate the output
+ // of the SecurityOpt setting.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationLabel = "io.podman.annotations.label"
+ // InspectAnnotationSeccomp is used by Inspect to identify containers
+ // with special Seccomp-related settings. It is used to populate the
+ // output of the SecurityOpt setting in Inspect.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationSeccomp = "io.podman.annotations.seccomp"
+ // InspectAnnotationApparmor is used by Inspect to identify containers
+ // with special Apparmor-related settings. It is used to populate the
+ // output of the SecurityOpt setting.
+ // If an annotation with this key is found in the OCI spec, it will be
+ // used in the output of Inspect().
+ InspectAnnotationApparmor = "io.podman.annotations.apparmor"
+
+ // InspectResponseTrue is a boolean True response for an inspect
+ // annotation.
+ InspectResponseTrue = "TRUE"
+ // InspectResponseFalse is a boolean False response for an inspect
+ // annotation.
+ InspectResponseFalse = "FALSE"
+)
diff --git a/libpod/kube.go b/libpod/kube.go
index 5511d303d..a3c5e912f 100644
--- a/libpod/kube.go
+++ b/libpod/kube.go
@@ -469,7 +469,7 @@ func generateKubeSecurityContext(c *Container) (*v1.SecurityContext, error) {
}
var selinuxOpts v1.SELinuxOptions
- opts := strings.SplitN(c.config.Spec.Annotations[InspectAnnotationLabel], ":", 2)
+ opts := strings.SplitN(c.config.Spec.Annotations[define.InspectAnnotationLabel], ":", 2)
if len(opts) == 2 {
switch opts[0] {
case "type":
diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go
new file mode 100644
index 000000000..23320d346
--- /dev/null
+++ b/pkg/api/handlers/libpod/generate.go
@@ -0,0 +1,38 @@
+package libpod
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/infra/abi"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+)
+
+func GenerateKube(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Service bool `schema:"service"`
+ }{
+ // Defaults would go here.
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+ options := entities.GenerateKubeOptions{Service: query.Service}
+ report, err := containerEngine.GenerateKube(r.Context(), utils.GetName(r), options)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error generating YAML"))
+ return
+ }
+
+ utils.WriteResponse(w, http.StatusOK, report.Reader)
+}
diff --git a/pkg/api/handlers/libpod/play.go b/pkg/api/handlers/libpod/play.go
new file mode 100644
index 000000000..26e02bf4f
--- /dev/null
+++ b/pkg/api/handlers/libpod/play.go
@@ -0,0 +1,64 @@
+package libpod
+
+import (
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/api/handlers/utils"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/libpod/pkg/domain/infra/abi"
+ "github.com/gorilla/schema"
+ "github.com/pkg/errors"
+)
+
+func PlayKube(w http.ResponseWriter, r *http.Request) {
+ runtime := r.Context().Value("runtime").(*libpod.Runtime)
+ decoder := r.Context().Value("decoder").(*schema.Decoder)
+ query := struct {
+ Network string `schema:"reference"`
+ TLSVerify bool `schema:"tlsVerify"`
+ }{
+ TLSVerify: true,
+ }
+
+ if err := decoder.Decode(&query, r.URL.Query()); err != nil {
+ utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
+ errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
+ return
+ }
+
+ // Fetch the K8s YAML file from the body, and copy it to a temp file.
+ tmpfile, err := ioutil.TempFile("", "libpod-play-kube.yml")
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to create tempfile"))
+ return
+ }
+ defer os.Remove(tmpfile.Name())
+ if _, err := io.Copy(tmpfile, r.Body); err != nil && err != io.EOF {
+ tmpfile.Close()
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "unable to write archive to temporary file"))
+ return
+ }
+ if err := tmpfile.Close(); err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error closing temporary file"))
+ return
+ }
+
+ containerEngine := abi.ContainerEngine{Libpod: runtime}
+ options := entities.PlayKubeOptions{Network: query.Network, Quiet: true}
+ if _, found := r.URL.Query()["tlsVerify"]; found {
+ options.SkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
+ }
+
+ report, err := containerEngine.PlayKube(r.Context(), tmpfile.Name(), options)
+ if err != nil {
+ utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error playing YAML file"))
+ return
+ }
+
+ utils.WriteResponse(w, http.StatusOK, report)
+}
diff --git a/pkg/api/handlers/swagger/swagger.go b/pkg/api/handlers/swagger/swagger.go
index 0aceaf5f6..5d125417b 100644
--- a/pkg/api/handlers/swagger/swagger.go
+++ b/pkg/api/handlers/swagger/swagger.go
@@ -56,6 +56,13 @@ type swagLibpodImagesRemoveResponse struct {
Body handlers.LibpodImagesRemoveReport
}
+// PlayKube response
+// swagger:response DocsLibpodPlayKubeResponse
+type swagLibpodPlayKubeResponse struct {
+ // in:body
+ Body entities.PlayKubeReport
+}
+
// Delete response
// swagger:response DocsImageDeleteResponse
type swagImageDeleteResponse struct {
diff --git a/pkg/api/server/register_generate.go b/pkg/api/server/register_generate.go
new file mode 100644
index 000000000..391e60111
--- /dev/null
+++ b/pkg/api/server/register_generate.go
@@ -0,0 +1,41 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerGenerateHandlers(r *mux.Router) error {
+ // swagger:operation GET /libpod/generate/{name:.*}/kube libpod libpodGenerateKube
+ // ---
+ // tags:
+ // - containers
+ // - pods
+ // summary: Play a Kubernetes YAML file.
+ // description: Create and run pods based on a Kubernetes YAML file (pod or service kind).
+ // parameters:
+ // - in: path
+ // name: name:.*
+ // type: string
+ // required: true
+ // description: Name or ID of the container or pod.
+ // - in: query
+ // name: service
+ // type: boolean
+ // default: false
+ // description: Generate YAML for a Kubernetes service object.
+ // produces:
+ // - application/json
+ // responses:
+ // 200:
+ // description: no error
+ // schema:
+ // type: string
+ // format: binary
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/generate/{name:.*}/kube"), s.APIHandler(libpod.GenerateKube)).Methods(http.MethodGet)
+ return nil
+}
diff --git a/pkg/api/server/register_play.go b/pkg/api/server/register_play.go
new file mode 100644
index 000000000..d04879c19
--- /dev/null
+++ b/pkg/api/server/register_play.go
@@ -0,0 +1,42 @@
+package server
+
+import (
+ "net/http"
+
+ "github.com/containers/libpod/pkg/api/handlers/libpod"
+ "github.com/gorilla/mux"
+)
+
+func (s *APIServer) registerPlayHandlers(r *mux.Router) error {
+ // swagger:operation POST /libpod/play/kube libpod libpodPlayKube
+ // ---
+ // tags:
+ // - containers
+ // - pods
+ // summary: Play a Kubernetes YAML file.
+ // description: Create and run pods based on a Kubernetes YAML file (pod or service kind).
+ // parameters:
+ // - in: query
+ // name: network
+ // type: string
+ // description: Connect the pod to this network.
+ // - in: query
+ // name: tlsVerify
+ // type: boolean
+ // default: true
+ // description: Require HTTPS and verify signatures when contating registries.
+ // - in: body
+ // name: request
+ // description: Kubernetes YAML file.
+ // schema:
+ // type: string
+ // produces:
+ // - application/json
+ // responses:
+ // 200:
+ // $ref: "#/responses/DocsLibpodPlayKubeResponse"
+ // 500:
+ // $ref: "#/responses/InternalError"
+ r.HandleFunc(VersionedPath("/libpod/play/kube"), s.APIHandler(libpod.PlayKube)).Methods(http.MethodPost)
+ return nil
+}
diff --git a/pkg/api/server/server.go b/pkg/api/server/server.go
index ce2d152e0..a6c5d8e1e 100644
--- a/pkg/api/server/server.go
+++ b/pkg/api/server/server.go
@@ -98,12 +98,14 @@ func newServer(runtime *libpod.Runtime, duration time.Duration, listener *net.Li
server.registerDistributionHandlers,
server.registerEventsHandlers,
server.registerExecHandlers,
+ server.registerGenerateHandlers,
server.registerHealthCheckHandlers,
server.registerImagesHandlers,
server.registerInfoHandlers,
server.registerManifestHandlers,
server.registerMonitorHandlers,
server.registerPingHandlers,
+ server.registerPlayHandlers,
server.registerPluginsHandlers,
server.registerPodsHandlers,
server.RegisterSwaggerHandlers,
diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go
index 2916754b8..d3177133f 100644
--- a/pkg/bindings/generate/generate.go
+++ b/pkg/bindings/generate/generate.go
@@ -1,4 +1,32 @@
package generate
-func GenerateKube() {}
-func GenerateSystemd() {}
+import (
+ "context"
+ "net/http"
+ "net/url"
+ "strconv"
+
+ "github.com/containers/libpod/pkg/bindings"
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+ params := url.Values{}
+ params.Set("service", strconv.FormatBool(options.Service))
+
+ response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/kube", params, nameOrID)
+ if err != nil {
+ return nil, err
+ }
+
+ if response.StatusCode == http.StatusOK {
+ return &entities.GenerateKubeReport{Reader: response.Body}, nil
+ }
+
+ // Unpack the error.
+ return nil, response.Process(nil)
+}
diff --git a/pkg/bindings/play/play.go b/pkg/bindings/play/play.go
index a6f03cad2..653558a3c 100644
--- a/pkg/bindings/play/play.go
+++ b/pkg/bindings/play/play.go
@@ -1,7 +1,43 @@
package play
-import "github.com/containers/libpod/pkg/bindings"
+import (
+ "context"
+ "net/http"
+ "net/url"
+ "os"
+ "strconv"
-func PlayKube() error {
- return bindings.ErrNotImplemented
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/pkg/bindings"
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+ var report entities.PlayKubeReport
+ conn, err := bindings.GetClient(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+
+ params := url.Values{}
+ params.Set("network", options.Network)
+ if options.SkipTLSVerify != types.OptionalBoolUndefined {
+ params.Set("tlsVerify", strconv.FormatBool(options.SkipTLSVerify == types.OptionalBoolTrue))
+ }
+
+ response, err := conn.DoRequest(f, http.MethodPost, "/play/kube", params)
+ if err != nil {
+ return nil, err
+ }
+ if err := response.Process(&report); err != nil {
+ return nil, err
+ }
+
+ return &report, nil
}
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go
index 2e4e486b5..1bfac4514 100644
--- a/pkg/domain/entities/engine_container.go
+++ b/pkg/domain/entities/engine_container.go
@@ -43,6 +43,7 @@ type ContainerEngine interface {
ContainerWait(ctx context.Context, namesOrIds []string, options WaitOptions) ([]WaitReport, error)
Events(ctx context.Context, opts EventsOptions) error
GenerateSystemd(ctx context.Context, nameOrID string, opts GenerateSystemdOptions) (*GenerateSystemdReport, error)
+ GenerateKube(ctx context.Context, nameOrID string, opts GenerateKubeOptions) (*GenerateKubeReport, error)
SystemPrune(ctx context.Context, options SystemPruneOptions) (*SystemPruneReport, error)
HealthCheckRun(ctx context.Context, nameOrId string, options HealthCheckOptions) (*define.HealthCheckResults, error)
Info(ctx context.Context) (*define.Info, error)
@@ -50,6 +51,7 @@ type ContainerEngine interface {
NetworkInspect(ctx context.Context, namesOrIds []string, options NetworkInspectOptions) ([]NetworkInspectReport, error)
NetworkList(ctx context.Context, options NetworkListOptions) ([]*NetworkListReport, error)
NetworkRm(ctx context.Context, namesOrIds []string, options NetworkRmOptions) ([]*NetworkRmReport, error)
+ PlayKube(ctx context.Context, path string, opts PlayKubeOptions) (*PlayKubeReport, error)
PodCreate(ctx context.Context, opts PodCreateOptions) (*PodCreateReport, error)
PodExists(ctx context.Context, nameOrId string) (*BoolReport, error)
PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error)
diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go
index 6d65b52f8..edd217615 100644
--- a/pkg/domain/entities/generate.go
+++ b/pkg/domain/entities/generate.go
@@ -1,5 +1,7 @@
package entities
+import "io"
+
// GenerateSystemdOptions control the generation of systemd unit files.
type GenerateSystemdOptions struct {
// Files - generate files instead of printing to stdout.
@@ -20,3 +22,15 @@ type GenerateSystemdReport struct {
// entire content.
Output string
}
+
+// GenerateKubeOptions control the generation of Kubernetes YAML files.
+type GenerateKubeOptions struct {
+ // Service - generate YAML for a Kubernetes _service_ object.
+ Service bool
+}
+
+// GenerateKubeReport
+type GenerateKubeReport struct {
+ // Reader - the io.Reader to reader the generated YAML file.
+ Reader io.Reader
+}
diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go
new file mode 100644
index 000000000..93864c23b
--- /dev/null
+++ b/pkg/domain/entities/play.go
@@ -0,0 +1,36 @@
+package entities
+
+import "github.com/containers/image/v5/types"
+
+// PlayKubeOptions controls playing kube YAML files.
+type PlayKubeOptions struct {
+ // Authfile - path to an authentication file.
+ Authfile string
+ // CertDir - to a directory containing TLS certifications and keys.
+ CertDir string
+ // Credentials - `username:password` for authentication against a
+ // container registry.
+ Credentials string
+ // Network - name of the CNI network to connect to.
+ Network string
+ // Quiet - suppress output when pulling images.
+ Quiet bool
+ // SignaturePolicy - path to a signature-policy file.
+ SignaturePolicy string
+ // SkipTLSVerify - skip https and certificate validation when
+ // contacting container registries.
+ SkipTLSVerify types.OptionalBool
+ // SeccompProfileRoot - path to a directory containing seccomp
+ // profiles.
+ SeccompProfileRoot string
+}
+
+// PlayKubeReport contains the results of running play kube.
+type PlayKubeReport struct {
+ // Pod - the ID of the created pod.
+ Pod string
+ // Containers - the IDs of the containers running in the created pod.
+ Containers []string
+ // Logs - non-fatal erros and log messages while processing.
+ Logs []string
+}
diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go
index f69ba560e..be5d452bd 100644
--- a/pkg/domain/infra/abi/generate.go
+++ b/pkg/domain/infra/abi/generate.go
@@ -1,14 +1,18 @@
package abi
import (
+ "bytes"
"context"
"fmt"
"strings"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/systemd/generate"
+ "github.com/ghodss/yaml"
"github.com/pkg/errors"
+ k8sAPI "k8s.io/api/core/v1"
)
func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
@@ -172,3 +176,84 @@ func generateServiceName(ctr *libpod.Container, pod *libpod.Pod, options entitie
}
return ctrName, fmt.Sprintf("%s-%s", kind, name)
}
+
+func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+ var (
+ pod *libpod.Pod
+ podYAML *k8sAPI.Pod
+ err error
+ ctr *libpod.Container
+ servicePorts []k8sAPI.ServicePort
+ serviceYAML k8sAPI.Service
+ )
+ // Get the container in question.
+ ctr, err = ic.Libpod.LookupContainer(nameOrID)
+ if err != nil {
+ pod, err = ic.Libpod.LookupPod(nameOrID)
+ if err != nil {
+ return nil, err
+ }
+ podYAML, servicePorts, err = pod.GenerateForKube()
+ } else {
+ if len(ctr.Dependencies()) > 0 {
+ return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies")
+ }
+ podYAML, err = ctr.GenerateForKube()
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ if options.Service {
+ serviceYAML = libpod.GenerateKubeServiceFromV1Pod(podYAML, servicePorts)
+ }
+
+ content, err := generateKubeOutput(podYAML, &serviceYAML)
+ if err != nil {
+ return nil, err
+ }
+
+ return &entities.GenerateKubeReport{Reader: bytes.NewReader(content)}, nil
+}
+
+func generateKubeOutput(podYAML *k8sAPI.Pod, serviceYAML *k8sAPI.Service) ([]byte, error) {
+ var (
+ output []byte
+ marshalledPod []byte
+ marshalledService []byte
+ err error
+ )
+
+ marshalledPod, err = yaml.Marshal(podYAML)
+ if err != nil {
+ return nil, err
+ }
+
+ if serviceYAML != nil {
+ marshalledService, err = yaml.Marshal(serviceYAML)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ header := `# Generation of Kubernetes YAML is still under development!
+#
+# Save the output of this file and use kubectl create -f to import
+# it into Kubernetes.
+#
+# Created with podman-%s
+`
+ podmanVersion, err := define.GetVersion()
+ if err != nil {
+ return nil, err
+ }
+
+ output = append(output, []byte(fmt.Sprintf(header, podmanVersion.Version))...)
+ output = append(output, marshalledPod...)
+ if serviceYAML != nil {
+ output = append(output, []byte("---\n")...)
+ output = append(output, marshalledService...)
+ }
+
+ return output, nil
+}
diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go
new file mode 100644
index 000000000..cd7eec7e6
--- /dev/null
+++ b/pkg/domain/infra/abi/play.go
@@ -0,0 +1,544 @@
+package abi
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/buildah/pkg/parse"
+ "github.com/containers/image/v5/types"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
+ ann "github.com/containers/libpod/pkg/annotations"
+ "github.com/containers/libpod/pkg/domain/entities"
+ envLib "github.com/containers/libpod/pkg/env"
+ ns "github.com/containers/libpod/pkg/namespaces"
+ createconfig "github.com/containers/libpod/pkg/spec"
+ "github.com/containers/libpod/pkg/specgen/generate"
+ "github.com/containers/libpod/pkg/util"
+ "github.com/containers/storage"
+ "github.com/cri-o/ocicni/pkg/ocicni"
+ "github.com/docker/distribution/reference"
+ "github.com/ghodss/yaml"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+ v1 "k8s.io/api/core/v1"
+)
+
+const (
+ // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
+ kubeDirectoryPermission = 0755
+ // https://kubernetes.io/docs/concepts/storage/volumes/#hostpath
+ kubeFilePermission = 0644
+)
+
+func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+ var (
+ containers []*libpod.Container
+ pod *libpod.Pod
+ podOptions []libpod.PodCreateOption
+ podYAML v1.Pod
+ registryCreds *types.DockerAuthConfig
+ writer io.Writer
+ report entities.PlayKubeReport
+ )
+
+ content, err := ioutil.ReadFile(path)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := yaml.Unmarshal(content, &podYAML); err != nil {
+ return nil, errors.Wrapf(err, "unable to read %q as YAML", path)
+ }
+
+ if podYAML.Kind != "Pod" {
+ return nil, errors.Errorf("invalid YAML kind: %q. Pod is the only supported Kubernetes YAML kind", podYAML.Kind)
+ }
+
+ // check for name collision between pod and container
+ podName := podYAML.ObjectMeta.Name
+ if podName == "" {
+ return nil, errors.Errorf("pod does not have a name")
+ }
+ for _, n := range podYAML.Spec.Containers {
+ if n.Name == podName {
+ report.Logs = append(report.Logs,
+ fmt.Sprintf("a container exists with the same name (%q) as the pod in your YAML file; changing pod name to %s_pod\n", podName, podName))
+ podName = fmt.Sprintf("%s_pod", podName)
+ }
+ }
+
+ podOptions = append(podOptions, libpod.WithInfraContainer())
+ podOptions = append(podOptions, libpod.WithPodName(podName))
+ // TODO for now we just used the default kernel namespaces; we need to add/subtract this from yaml
+
+ hostname := podYAML.Spec.Hostname
+ if hostname == "" {
+ hostname = podName
+ }
+ podOptions = append(podOptions, libpod.WithPodHostname(hostname))
+
+ if podYAML.Spec.HostNetwork {
+ podOptions = append(podOptions, libpod.WithPodHostNetwork())
+ }
+
+ nsOptions, err := generate.GetNamespaceOptions(strings.Split(createconfig.DefaultKernelNamespaces, ","))
+ if err != nil {
+ return nil, err
+ }
+ podOptions = append(podOptions, nsOptions...)
+ podPorts := getPodPorts(podYAML.Spec.Containers)
+ podOptions = append(podOptions, libpod.WithInfraContainerPorts(podPorts))
+
+ if options.Network != "" {
+ switch strings.ToLower(options.Network) {
+ case "bridge", "host":
+ return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML")
+ case "":
+ return nil, errors.Errorf("invalid value passed to --network: must provide a comma-separated list of CNI networks")
+ default:
+ // We'll assume this is a comma-separated list of CNI
+ // networks.
+ networks := strings.Split(options.Network, ",")
+ logrus.Debugf("Pod joining CNI networks: %v", networks)
+ podOptions = append(podOptions, libpod.WithPodNetworks(networks))
+ }
+ }
+
+ // Create the Pod
+ pod, err = ic.Libpod.NewPod(ctx, podOptions...)
+ if err != nil {
+ return nil, err
+ }
+
+ podInfraID, err := pod.InfraContainerID()
+ if err != nil {
+ return nil, err
+ }
+ hasUserns := false
+ if podInfraID != "" {
+ podCtr, err := ic.Libpod.GetContainer(podInfraID)
+ if err != nil {
+ return nil, err
+ }
+ mappings, err := podCtr.IDMappings()
+ if err != nil {
+ return nil, err
+ }
+ hasUserns = len(mappings.UIDMap) > 0
+ }
+
+ namespaces := map[string]string{
+ // Disabled during code review per mheon
+ //"pid": fmt.Sprintf("container:%s", podInfraID),
+ "net": fmt.Sprintf("container:%s", podInfraID),
+ "ipc": fmt.Sprintf("container:%s", podInfraID),
+ "uts": fmt.Sprintf("container:%s", podInfraID),
+ }
+ if hasUserns {
+ namespaces["user"] = fmt.Sprintf("container:%s", podInfraID)
+ }
+ if !options.Quiet {
+ writer = os.Stderr
+ }
+
+ dockerRegistryOptions := image.DockerRegistryOptions{
+ DockerRegistryCreds: registryCreds,
+ DockerCertPath: options.CertDir,
+ DockerInsecureSkipTLSVerify: options.SkipTLSVerify,
+ }
+
+ // map from name to mount point
+ volumes := make(map[string]string)
+ for _, volume := range podYAML.Spec.Volumes {
+ hostPath := volume.VolumeSource.HostPath
+ if hostPath == nil {
+ return nil, errors.Errorf("HostPath is currently the only supported VolumeSource")
+ }
+ if hostPath.Type != nil {
+ switch *hostPath.Type {
+ case v1.HostPathDirectoryOrCreate:
+ if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
+ if err := os.Mkdir(hostPath.Path, kubeDirectoryPermission); err != nil {
+ return nil, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path)
+ }
+ }
+ // Label a newly created volume
+ if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
+ return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path)
+ }
+ case v1.HostPathFileOrCreate:
+ if _, err := os.Stat(hostPath.Path); os.IsNotExist(err) {
+ f, err := os.OpenFile(hostPath.Path, os.O_RDONLY|os.O_CREATE, kubeFilePermission)
+ if err != nil {
+ return nil, errors.Errorf("Error creating HostPath %s at %s", volume.Name, hostPath.Path)
+ }
+ if err := f.Close(); err != nil {
+ logrus.Warnf("Error in closing newly created HostPath file: %v", err)
+ }
+ }
+ // unconditionally label a newly created volume
+ if err := libpod.LabelVolumePath(hostPath.Path); err != nil {
+ return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path)
+ }
+ case v1.HostPathDirectory:
+ case v1.HostPathFile:
+ case v1.HostPathUnset:
+ // do nothing here because we will verify the path exists in validateVolumeHostDir
+ break
+ default:
+ return nil, errors.Errorf("Directories are the only supported HostPath type")
+ }
+ }
+
+ if err := parse.ValidateVolumeHostDir(hostPath.Path); err != nil {
+ return nil, errors.Wrapf(err, "Error in parsing HostPath in YAML")
+ }
+ volumes[volume.Name] = hostPath.Path
+ }
+
+ seccompPaths, err := initializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot)
+ if err != nil {
+ return nil, err
+ }
+
+ for _, container := range podYAML.Spec.Containers {
+ pullPolicy := util.PullImageMissing
+ if len(container.ImagePullPolicy) > 0 {
+ pullPolicy, err = util.ValidatePullType(string(container.ImagePullPolicy))
+ if err != nil {
+ return nil, err
+ }
+ }
+ named, err := reference.ParseNormalizedNamed(container.Image)
+ if err != nil {
+ return nil, err
+ }
+ // In kube, if the image is tagged with latest, it should always pull
+ if tagged, isTagged := named.(reference.NamedTagged); isTagged {
+ if tagged.Tag() == image.LatestTag {
+ pullPolicy = util.PullImageAlways
+ }
+ }
+ newImage, err := ic.Libpod.ImageRuntime().New(ctx, container.Image, options.SignaturePolicy, options.Authfile, writer, &dockerRegistryOptions, image.SigningOptions{}, nil, pullPolicy)
+ if err != nil {
+ return nil, err
+ }
+ conf, err := kubeContainerToCreateConfig(ctx, container, ic.Libpod, newImage, namespaces, volumes, pod.ID(), podInfraID, seccompPaths)
+ if err != nil {
+ return nil, err
+ }
+ ctr, err := createconfig.CreateContainerFromCreateConfig(ic.Libpod, conf, ctx, pod)
+ if err != nil {
+ return nil, err
+ }
+ containers = append(containers, ctr)
+ }
+
+ // start the containers
+ for _, ctr := range containers {
+ if err := ctr.Start(ctx, true); err != nil {
+ // Making this a hard failure here to avoid a mess
+ // the other containers are in created status
+ return nil, err
+ }
+ }
+
+ report.Pod = pod.ID()
+ for _, ctr := range containers {
+ report.Containers = append(report.Containers, ctr.ID())
+ }
+
+ return &report, nil
+}
+
+// getPodPorts converts a slice of kube container descriptions to an
+// array of ocicni portmapping descriptions usable in libpod
+func getPodPorts(containers []v1.Container) []ocicni.PortMapping {
+ var infraPorts []ocicni.PortMapping
+ for _, container := range containers {
+ for _, p := range container.Ports {
+ if p.HostPort != 0 && p.ContainerPort == 0 {
+ p.ContainerPort = p.HostPort
+ }
+ if p.Protocol == "" {
+ p.Protocol = "tcp"
+ }
+ portBinding := ocicni.PortMapping{
+ HostPort: p.HostPort,
+ ContainerPort: p.ContainerPort,
+ Protocol: strings.ToLower(string(p.Protocol)),
+ }
+ if p.HostIP != "" {
+ logrus.Debug("HostIP on port bindings is not supported")
+ }
+ // only hostPort is utilized in podman context, all container ports
+ // are accessible inside the shared network namespace
+ if p.HostPort != 0 {
+ infraPorts = append(infraPorts, portBinding)
+ }
+
+ }
+ }
+ return infraPorts
+}
+
+func setupSecurityContext(securityConfig *createconfig.SecurityConfig, userConfig *createconfig.UserConfig, containerYAML v1.Container) {
+ if containerYAML.SecurityContext == nil {
+ return
+ }
+ if containerYAML.SecurityContext.ReadOnlyRootFilesystem != nil {
+ securityConfig.ReadOnlyRootfs = *containerYAML.SecurityContext.ReadOnlyRootFilesystem
+ }
+ if containerYAML.SecurityContext.Privileged != nil {
+ securityConfig.Privileged = *containerYAML.SecurityContext.Privileged
+ }
+
+ if containerYAML.SecurityContext.AllowPrivilegeEscalation != nil {
+ securityConfig.NoNewPrivs = !*containerYAML.SecurityContext.AllowPrivilegeEscalation
+ }
+
+ if seopt := containerYAML.SecurityContext.SELinuxOptions; seopt != nil {
+ if seopt.User != "" {
+ securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=user:%s", seopt.User))
+ securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("user:%s", seopt.User))
+ }
+ if seopt.Role != "" {
+ securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=role:%s", seopt.Role))
+ securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("role:%s", seopt.Role))
+ }
+ if seopt.Type != "" {
+ securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=type:%s", seopt.Type))
+ securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("type:%s", seopt.Type))
+ }
+ if seopt.Level != "" {
+ securityConfig.SecurityOpts = append(securityConfig.SecurityOpts, fmt.Sprintf("label=level:%s", seopt.Level))
+ securityConfig.LabelOpts = append(securityConfig.LabelOpts, fmt.Sprintf("level:%s", seopt.Level))
+ }
+ }
+ if caps := containerYAML.SecurityContext.Capabilities; caps != nil {
+ for _, capability := range caps.Add {
+ securityConfig.CapAdd = append(securityConfig.CapAdd, string(capability))
+ }
+ for _, capability := range caps.Drop {
+ securityConfig.CapDrop = append(securityConfig.CapDrop, string(capability))
+ }
+ }
+ if containerYAML.SecurityContext.RunAsUser != nil {
+ userConfig.User = fmt.Sprintf("%d", *containerYAML.SecurityContext.RunAsUser)
+ }
+ if containerYAML.SecurityContext.RunAsGroup != nil {
+ if userConfig.User == "" {
+ userConfig.User = "0"
+ }
+ userConfig.User = fmt.Sprintf("%s:%d", userConfig.User, *containerYAML.SecurityContext.RunAsGroup)
+ }
+}
+
+// kubeContainerToCreateConfig takes a v1.Container and returns a createconfig describing a container
+func kubeContainerToCreateConfig(ctx context.Context, containerYAML v1.Container, runtime *libpod.Runtime, newImage *image.Image, namespaces map[string]string, volumes map[string]string, podID, infraID string, seccompPaths *kubeSeccompPaths) (*createconfig.CreateConfig, error) {
+ var (
+ containerConfig createconfig.CreateConfig
+ pidConfig createconfig.PidConfig
+ networkConfig createconfig.NetworkConfig
+ cgroupConfig createconfig.CgroupConfig
+ utsConfig createconfig.UtsConfig
+ ipcConfig createconfig.IpcConfig
+ userConfig createconfig.UserConfig
+ securityConfig createconfig.SecurityConfig
+ )
+
+ // The default for MemorySwappiness is -1, not 0
+ containerConfig.Resources.MemorySwappiness = -1
+
+ containerConfig.Image = containerYAML.Image
+ containerConfig.ImageID = newImage.ID()
+ containerConfig.Name = containerYAML.Name
+ containerConfig.Tty = containerYAML.TTY
+
+ containerConfig.Pod = podID
+
+ imageData, _ := newImage.Inspect(ctx)
+
+ userConfig.User = "0"
+ if imageData != nil {
+ userConfig.User = imageData.Config.User
+ }
+
+ setupSecurityContext(&securityConfig, &userConfig, containerYAML)
+
+ securityConfig.SeccompProfilePath = seccompPaths.findForContainer(containerConfig.Name)
+
+ containerConfig.Command = []string{}
+ if imageData != nil && imageData.Config != nil {
+ containerConfig.Command = append(containerConfig.Command, imageData.Config.Entrypoint...)
+ }
+ if len(containerYAML.Command) != 0 {
+ containerConfig.Command = append(containerConfig.Command, containerYAML.Command...)
+ } else if imageData != nil && imageData.Config != nil {
+ containerConfig.Command = append(containerConfig.Command, imageData.Config.Cmd...)
+ }
+ if imageData != nil && len(containerConfig.Command) == 0 {
+ return nil, errors.Errorf("No command specified in container YAML or as CMD or ENTRYPOINT in this image for %s", containerConfig.Name)
+ }
+
+ containerConfig.UserCommand = containerConfig.Command
+
+ containerConfig.StopSignal = 15
+
+ containerConfig.WorkDir = "/"
+ if imageData != nil {
+ // FIXME,
+ // we are currently ignoring imageData.Config.ExposedPorts
+ containerConfig.BuiltinImgVolumes = imageData.Config.Volumes
+ if imageData.Config.WorkingDir != "" {
+ containerConfig.WorkDir = imageData.Config.WorkingDir
+ }
+ containerConfig.Labels = imageData.Config.Labels
+ if imageData.Config.StopSignal != "" {
+ stopSignal, err := util.ParseSignal(imageData.Config.StopSignal)
+ if err != nil {
+ return nil, err
+ }
+ containerConfig.StopSignal = stopSignal
+ }
+ }
+
+ if containerYAML.WorkingDir != "" {
+ containerConfig.WorkDir = containerYAML.WorkingDir
+ }
+ // If the user does not pass in ID mappings, just set to basics
+ if userConfig.IDMappings == nil {
+ userConfig.IDMappings = &storage.IDMappingOptions{}
+ }
+
+ networkConfig.NetMode = ns.NetworkMode(namespaces["net"])
+ ipcConfig.IpcMode = ns.IpcMode(namespaces["ipc"])
+ utsConfig.UtsMode = ns.UTSMode(namespaces["uts"])
+ // disabled in code review per mheon
+ //containerConfig.PidMode = ns.PidMode(namespaces["pid"])
+ userConfig.UsernsMode = ns.UsernsMode(namespaces["user"])
+ if len(containerConfig.WorkDir) == 0 {
+ containerConfig.WorkDir = "/"
+ }
+
+ containerConfig.Pid = pidConfig
+ containerConfig.Network = networkConfig
+ containerConfig.Uts = utsConfig
+ containerConfig.Ipc = ipcConfig
+ containerConfig.Cgroup = cgroupConfig
+ containerConfig.User = userConfig
+ containerConfig.Security = securityConfig
+
+ annotations := make(map[string]string)
+ if infraID != "" {
+ annotations[ann.SandboxID] = infraID
+ annotations[ann.ContainerType] = ann.ContainerTypeContainer
+ }
+ containerConfig.Annotations = annotations
+
+ // Environment Variables
+ envs := map[string]string{}
+ if imageData != nil {
+ imageEnv, err := envLib.ParseSlice(imageData.Config.Env)
+ if err != nil {
+ return nil, errors.Wrap(err, "error parsing image environment variables")
+ }
+ envs = imageEnv
+ }
+ for _, e := range containerYAML.Env {
+ envs[e.Name] = e.Value
+ }
+ containerConfig.Env = envs
+
+ for _, volume := range containerYAML.VolumeMounts {
+ hostPath, exists := volumes[volume.Name]
+ if !exists {
+ return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name)
+ }
+ if err := parse.ValidateVolumeCtrDir(volume.MountPath); err != nil {
+ return nil, errors.Wrapf(err, "error in parsing MountPath")
+ }
+ containerConfig.Volumes = append(containerConfig.Volumes, fmt.Sprintf("%s:%s", hostPath, volume.MountPath))
+ }
+ return &containerConfig, nil
+}
+
+// kubeSeccompPaths holds information about a pod YAML's seccomp configuration
+// it holds both container and pod seccomp paths
+type kubeSeccompPaths struct {
+ containerPaths map[string]string
+ podPath string
+}
+
+// findForContainer checks whether a container has a seccomp path configured for it
+// if not, it returns the podPath, which should always have a value
+func (k *kubeSeccompPaths) findForContainer(ctrName string) string {
+ if path, ok := k.containerPaths[ctrName]; ok {
+ return path
+ }
+ return k.podPath
+}
+
+// initializeSeccompPaths takes annotations from the pod object metadata and finds annotations pertaining to seccomp
+// it parses both pod and container level
+// if the annotation is of the form "localhost/%s", the seccomp profile will be set to profileRoot/%s
+func initializeSeccompPaths(annotations map[string]string, profileRoot string) (*kubeSeccompPaths, error) {
+ seccompPaths := &kubeSeccompPaths{containerPaths: make(map[string]string)}
+ var err error
+ if annotations != nil {
+ for annKeyValue, seccomp := range annotations {
+ // check if it is prefaced with container.seccomp.security.alpha.kubernetes.io/
+ prefixAndCtr := strings.Split(annKeyValue, "/")
+ if prefixAndCtr[0]+"/" != v1.SeccompContainerAnnotationKeyPrefix {
+ continue
+ } else if len(prefixAndCtr) != 2 {
+ // this could be caused by a user inputting either of
+ // container.seccomp.security.alpha.kubernetes.io{,/}
+ // both of which are invalid
+ return nil, errors.Errorf("Invalid seccomp path: %s", prefixAndCtr[0])
+ }
+
+ path, err := verifySeccompPath(seccomp, profileRoot)
+ if err != nil {
+ return nil, err
+ }
+ seccompPaths.containerPaths[prefixAndCtr[1]] = path
+ }
+
+ podSeccomp, ok := annotations[v1.SeccompPodAnnotationKey]
+ if ok {
+ seccompPaths.podPath, err = verifySeccompPath(podSeccomp, profileRoot)
+ } else {
+ seccompPaths.podPath, err = libpod.DefaultSeccompPath()
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+ return seccompPaths, nil
+}
+
+// verifySeccompPath takes a path and checks whether it is a default, unconfined, or a path
+// the available options are parsed as defined in https://kubernetes.io/docs/concepts/policy/pod-security-policy/#seccomp
+func verifySeccompPath(path string, profileRoot string) (string, error) {
+ switch path {
+ case v1.DeprecatedSeccompProfileDockerDefault:
+ fallthrough
+ case v1.SeccompProfileRuntimeDefault:
+ return libpod.DefaultSeccompPath()
+ case "unconfined":
+ return path, nil
+ default:
+ parts := strings.Split(path, "/")
+ if parts[0] == "localhost" {
+ return filepath.Join(profileRoot, parts[1]), nil
+ }
+ return "", errors.Errorf("invalid seccomp path: %s", path)
+ }
+}
diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go
index 3cd483053..eb5587f89 100644
--- a/pkg/domain/infra/tunnel/generate.go
+++ b/pkg/domain/infra/tunnel/generate.go
@@ -3,6 +3,7 @@ package tunnel
import (
"context"
+ "github.com/containers/libpod/pkg/bindings/generate"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/pkg/errors"
)
@@ -10,3 +11,7 @@ import (
func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) {
return nil, errors.New("not implemented for tunnel")
}
+
+func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) {
+ return generate.GenerateKube(ic.ClientCxt, nameOrID, options)
+}
diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go
new file mode 100644
index 000000000..15383a703
--- /dev/null
+++ b/pkg/domain/infra/tunnel/play.go
@@ -0,0 +1,12 @@
+package tunnel
+
+import (
+ "context"
+
+ "github.com/containers/libpod/pkg/bindings/play"
+ "github.com/containers/libpod/pkg/domain/entities"
+)
+
+func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) {
+ return play.PlayKube(ic.ClientCxt, path, options)
+}
diff --git a/pkg/spec/namespaces.go b/pkg/spec/namespaces.go
index aebc90f68..40364b054 100644
--- a/pkg/spec/namespaces.go
+++ b/pkg/spec/namespaces.go
@@ -17,6 +17,10 @@ import (
"github.com/sirupsen/logrus"
)
+// DefaultKernelNamespaces is a comma-separated list of default kernel
+// namespaces.
+const DefaultKernelNamespaces = "cgroup,ipc,net,uts"
+
// ToCreateOptions converts the input to a slice of container create options.
func (c *NetworkConfig) ToCreateOptions(runtime *libpod.Runtime, userns *UserConfig) ([]libpod.CtrCreateOption, error) {
var portBindings []ocicni.PortMapping
@@ -154,9 +158,9 @@ func (c *NetworkConfig) ConfigureGenerator(g *generate.Generator) error {
}
if c.PublishAll {
- g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
+ g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue
} else {
- g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
+ g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse
}
return nil
diff --git a/pkg/spec/security.go b/pkg/spec/security.go
index 0f8d36f00..6d74e97e6 100644
--- a/pkg/spec/security.go
+++ b/pkg/spec/security.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/common/pkg/capabilities"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/util"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
@@ -184,11 +185,11 @@ func (c *SecurityConfig) ConfigureGenerator(g *generate.Generator, user *UserCon
}
switch splitOpt[0] {
case "label":
- configSpec.Annotations[libpod.InspectAnnotationLabel] = splitOpt[1]
+ configSpec.Annotations[define.InspectAnnotationLabel] = splitOpt[1]
case "seccomp":
- configSpec.Annotations[libpod.InspectAnnotationSeccomp] = splitOpt[1]
+ configSpec.Annotations[define.InspectAnnotationSeccomp] = splitOpt[1]
case "apparmor":
- configSpec.Annotations[libpod.InspectAnnotationApparmor] = splitOpt[1]
+ configSpec.Annotations[define.InspectAnnotationApparmor] = splitOpt[1]
}
}
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 41ed5f1f0..77e92ae29 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -7,6 +7,7 @@ import (
cconfig "github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/sysinfo"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/env"
"github.com/containers/libpod/pkg/rootless"
@@ -436,29 +437,29 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
}
if config.CidFile != "" {
- configSpec.Annotations[libpod.InspectAnnotationCIDFile] = config.CidFile
+ configSpec.Annotations[define.InspectAnnotationCIDFile] = config.CidFile
}
if config.Rm {
- configSpec.Annotations[libpod.InspectAnnotationAutoremove] = libpod.InspectResponseTrue
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
} else {
- configSpec.Annotations[libpod.InspectAnnotationAutoremove] = libpod.InspectResponseFalse
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
}
if len(config.VolumesFrom) > 0 {
- configSpec.Annotations[libpod.InspectAnnotationVolumesFrom] = strings.Join(config.VolumesFrom, ",")
+ configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(config.VolumesFrom, ",")
}
if config.Security.Privileged {
- configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseTrue
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
} else {
- configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseFalse
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
}
if config.Init {
- configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseTrue
+ configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseTrue
} else {
- configSpec.Annotations[libpod.InspectAnnotationInit] = libpod.InspectResponseFalse
+ configSpec.Annotations[define.InspectAnnotationInit] = define.InspectResponseFalse
}
return configSpec, nil
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index 96c65b551..138d9e0cd 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -438,9 +438,9 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
g.Config.Annotations = make(map[string]string)
}
if s.PublishExposedPorts {
- g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseTrue
+ g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseTrue
} else {
- g.Config.Annotations[libpod.InspectAnnotationPublishAll] = libpod.InspectResponseFalse
+ g.Config.Annotations[define.InspectAnnotationPublishAll] = define.InspectResponseFalse
}
return nil
diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go
index 8136c0993..a2bb66a44 100644
--- a/pkg/specgen/generate/oci.go
+++ b/pkg/specgen/generate/oci.go
@@ -6,6 +6,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/specgen"
@@ -327,19 +328,19 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt
//}
if s.Remove {
- configSpec.Annotations[libpod.InspectAnnotationAutoremove] = libpod.InspectResponseTrue
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseTrue
} else {
- configSpec.Annotations[libpod.InspectAnnotationAutoremove] = libpod.InspectResponseFalse
+ configSpec.Annotations[define.InspectAnnotationAutoremove] = define.InspectResponseFalse
}
if len(s.VolumesFrom) > 0 {
- configSpec.Annotations[libpod.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
+ configSpec.Annotations[define.InspectAnnotationVolumesFrom] = strings.Join(s.VolumesFrom, ",")
}
if s.Privileged {
- configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseTrue
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseTrue
} else {
- configSpec.Annotations[libpod.InspectAnnotationPrivileged] = libpod.InspectResponseFalse
+ configSpec.Annotations[define.InspectAnnotationPrivileged] = define.InspectResponseFalse
}
// TODO Init might not make it into the specgen and therefore is not available here. We should deal
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index e4f487634..389f2c822 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -21,7 +21,6 @@ var _ = Describe("Podman generate kube", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)
diff --git a/test/e2e/play_kube_test.go b/test/e2e/play_kube_test.go
index 16f7af55e..9daf266b8 100644
--- a/test/e2e/play_kube_test.go
+++ b/test/e2e/play_kube_test.go
@@ -217,7 +217,6 @@ var _ = Describe("Podman generate kube", func() {
)
BeforeEach(func() {
- Skip(v2fail)
tempdir, err = CreateTempDirInTempDir()
if err != nil {
os.Exit(1)