diff options
Diffstat (limited to 'pkg/domain')
-rw-r--r-- | pkg/domain/entities/engine_container.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/play.go | 16 | ||||
-rw-r--r-- | pkg/domain/entities/system.go | 5 | ||||
-rw-r--r-- | pkg/domain/entities/types/auth.go | 3 | ||||
-rw-r--r-- | pkg/domain/entities/types/types.go | 3 | ||||
-rw-r--r-- | pkg/domain/filters/volumes.go | 20 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 14 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers_runlabel.go | 25 | ||||
-rw-r--r-- | pkg/domain/infra/abi/generate.go | 172 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 127 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 26 | ||||
-rw-r--r-- | pkg/domain/infra/abi/terminal/terminal_linux.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/containers.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/network.go | 3 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/play.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/system.go | 2 |
16 files changed, 325 insertions, 101 deletions
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index bcab617af..f695d32fd 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -88,7 +88,7 @@ type ContainerEngine interface { SecretRm(ctx context.Context, nameOrID []string, opts SecretRmOptions) ([]*SecretRmReport, error) Shutdown(ctx context.Context) SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error) - Unshare(ctx context.Context, args []string) error + Unshare(ctx context.Context, args []string, options SystemUnshareOptions) error Version(ctx context.Context) (*SystemVersionReport, error) VolumeCreate(ctx context.Context, opts VolumeCreateOptions) (*IDOrNameResponse, error) VolumeExists(ctx context.Context, namesOrID string) (*BoolReport, error) diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index 6883fe6c5..c69bb0867 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -1,6 +1,10 @@ package entities -import "github.com/containers/image/v5/types" +import ( + "net" + + "github.com/containers/image/v5/types" +) // PlayKubeOptions controls playing kube YAML files. type PlayKubeOptions struct { @@ -24,6 +28,8 @@ type PlayKubeOptions struct { // SeccompProfileRoot - path to a directory containing seccomp // profiles. SeccompProfileRoot string + // StaticIPs - Static IP address used by the pod(s). + StaticIPs []net.IP // ConfigMaps - slice of pathnames to kubernetes configmap YAMLs. ConfigMaps []string // LogDriver for the container. For example: journald @@ -45,8 +51,16 @@ type PlayKubePod struct { ContainerErrors []string } +// PlayKubeVolume represents a single volume created by play kube. +type PlayKubeVolume struct { + // Name - Name of the volume created by play kube. + Name string +} + // PlayKubeReport contains the results of running play kube. type PlayKubeReport struct { // Pods - pods created by play kube. Pods []PlayKubePod + // Volumes - volumes created by play kube. + Volumes []PlayKubeVolume } diff --git a/pkg/domain/entities/system.go b/pkg/domain/entities/system.go index 1a671d59e..31a6185dc 100644 --- a/pkg/domain/entities/system.go +++ b/pkg/domain/entities/system.go @@ -98,6 +98,11 @@ type SystemVersionReport struct { Server *define.Version `json:",omitempty"` } +// SystemUnshareOptions describes the options for the unshare command +type SystemUnshareOptions struct { + RootlessCNI bool +} + type ComponentVersion struct { types.Version } diff --git a/pkg/domain/entities/types/auth.go b/pkg/domain/entities/types/auth.go index ddf15bb18..7f2480173 100644 --- a/pkg/domain/entities/types/auth.go +++ b/pkg/domain/entities/types/auth.go @@ -1,4 +1,5 @@ -package types // import "github.com/docker/docker/api/types" +// copied from github.com/docker/docker/api/types +package types // AuthConfig contains authorization information for connecting to a Registry type AuthConfig struct { diff --git a/pkg/domain/entities/types/types.go b/pkg/domain/entities/types/types.go index 77834c0cb..7dc785078 100644 --- a/pkg/domain/entities/types/types.go +++ b/pkg/domain/entities/types/types.go @@ -1,4 +1,5 @@ -package types // import "github.com/docker/docker/api/types" +// copied from github.com/docker/docker/api/types +package types // ComponentVersion describes the version information for a specific component. type ComponentVersion struct { diff --git a/pkg/domain/filters/volumes.go b/pkg/domain/filters/volumes.go index 9b2fc5280..9a08adf82 100644 --- a/pkg/domain/filters/volumes.go +++ b/pkg/domain/filters/volumes.go @@ -75,7 +75,25 @@ func GenerateVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) { return dangling }) default: - return nil, errors.Errorf("%q is in an invalid volume filter", filter) + return nil, errors.Errorf("%q is an invalid volume filter", filter) + } + } + } + return vf, nil +} + +func GeneratePruneVolumeFilters(filters url.Values) ([]libpod.VolumeFilter, error) { + var vf []libpod.VolumeFilter + for filter, v := range filters { + for _, val := range v { + switch filter { + case "label": + filter := val + vf = append(vf, func(v *libpod.Volume) bool { + return util.MatchLabelFilters([]string{filter}, v.Labels()) + }) + default: + return nil, errors.Errorf("%q is an invalid volume filter", filter) } } } diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index 24261e5ed..6f8845f10 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -585,7 +585,7 @@ func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrID string, } // If the container is in a pod, also set to recursively start dependencies - err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != "") + err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false) if err != nil && errors.Cause(err) != define.ErrDetach { return errors.Wrapf(err, "error attaching to container %s", ctr.ID()) } @@ -708,7 +708,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri ctrRunning := ctrState == define.ContainerStateRunning if options.Attach { - err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning, ctr.PodID() != "") + err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning) if errors.Cause(err) == define.ErrDetach { // User manually detached // Exit cleanly immediately @@ -784,7 +784,7 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri RawInput: rawInput, ExitCode: 125, } - if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil { + if err := ctr.Start(ctx, true); err != nil { // if lastError != nil { // fmt.Fprintln(os.Stderr, lastError) // } @@ -845,10 +845,6 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } } - var joinPod bool - if len(ctr.PodID()) > 0 { - joinPod = true - } report := entities.ContainerRunReport{Id: ctr.ID()} if logrus.GetLevel() == logrus.DebugLevel { @@ -859,7 +855,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } if opts.Detach { // if the container was created as part of a pod, also start its dependencies, if any. - if err := ctr.Start(ctx, joinPod); err != nil { + if err := ctr.Start(ctx, true); err != nil { // This means the command did not exist report.ExitCode = define.ExitCode(err) return &report, err @@ -869,7 +865,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta } // if the container was created as part of a pod, also start its dependencies, if any. - if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true, joinPod); err != nil { + if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true); err != nil { // We've manually detached from the container // Do not perform cleanup, or wait for container exit code // Just exit immediately diff --git a/pkg/domain/infra/abi/containers_runlabel.go b/pkg/domain/infra/abi/containers_runlabel.go index 8de383926..2cabab988 100644 --- a/pkg/domain/infra/abi/containers_runlabel.go +++ b/pkg/domain/infra/abi/containers_runlabel.go @@ -177,6 +177,16 @@ func generateRunlabelCommand(runlabel string, img *image.Image, args []string, o return cmd, env, nil } +func replaceName(arg, name string) string { + newarg := strings.ReplaceAll(arg, "$NAME", name) + return strings.ReplaceAll(newarg, "${NAME}", name) +} + +func replaceImage(arg, image string) string { + newarg := strings.ReplaceAll(arg, "$IMAGE", image) + return strings.ReplaceAll(newarg, "${IMAGE}", image) +} + // generateCommand takes a label (string) and converts it to an executable command func generateCommand(command, imageName, name, globalOpts string) ([]string, error) { if name == "" { @@ -196,26 +206,15 @@ func generateCommand(command, imageName, name, globalOpts string) ([]string, err for _, arg := range cmd[1:] { var newArg string switch arg { - case "IMAGE": - newArg = imageName - case "$IMAGE": - newArg = imageName case "IMAGE=IMAGE": newArg = fmt.Sprintf("IMAGE=%s", imageName) - case "IMAGE=$IMAGE": - newArg = fmt.Sprintf("IMAGE=%s", imageName) - case "NAME": - newArg = name case "NAME=NAME": newArg = fmt.Sprintf("NAME=%s", name) - case "NAME=$NAME": - newArg = fmt.Sprintf("NAME=%s", name) - case "$NAME": - newArg = name case "$GLOBAL_OPTS": newArg = globalOpts default: - newArg = arg + newArg = replaceName(arg, name) + newArg = replaceImage(newArg, imageName) } newCommand = append(newCommand, newArg) } diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 94f649e15..b0853b554 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "fmt" + "strings" "github.com/containers/podman/v3/libpod" "github.com/containers/podman/v3/libpod/define" @@ -43,120 +44,174 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) { var ( - pods []*libpod.Pod - ctrs []*libpod.Container - kubePods []*k8sAPI.Pod - kubeServices []k8sAPI.Service - content []byte + pods []*libpod.Pod + ctrs []*libpod.Container + vols []*libpod.Volume + podContent [][]byte + content [][]byte ) + + // Lookup for podman objects. for _, nameOrID := range nameOrIDs { - // Get the container in question + // Let's assume it's a container, so get the container. ctr, err := ic.Libpod.LookupContainer(nameOrID) if err != nil { - pod, err := ic.Libpod.LookupPod(nameOrID) - if err != nil { + if !strings.Contains(err.Error(), "no such container") { return nil, err } - pods = append(pods, pod) } else { if len(ctr.Dependencies()) > 0 { return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies") } - // we cannot deal with ctrs already in a pod + // we cannot deal with ctrs already in a pod. if len(ctr.PodID()) > 0 { return nil, errors.Errorf("container %s is associated with pod %s: use generate on the pod itself", ctr.ID(), ctr.PodID()) } ctrs = append(ctrs, ctr) + continue + } + + // Maybe it's a pod. + pod, err := ic.Libpod.LookupPod(nameOrID) + if err != nil { + if !strings.Contains(err.Error(), "no such pod") { + return nil, err + } + } else { + pods = append(pods, pod) + continue + } + + // Or volume. + vol, err := ic.Libpod.LookupVolume(nameOrID) + if err != nil { + if !strings.Contains(err.Error(), "no such volume") { + return nil, err + } + } else { + vols = append(vols, vol) + continue } + + // If it reaches here is because the name or id did not exist. + return nil, errors.Errorf("Name or ID %q not found", nameOrID) } - // check our inputs - if len(pods) > 0 && len(ctrs) > 0 { - return nil, errors.New("cannot generate pods and containers at the same time") + // Generate kube persistent volume claims from volumes. + if len(vols) >= 1 { + pvs, err := getKubePVCs(vols) + if err != nil { + return nil, err + } + + content = append(content, pvs...) } + // Generate kube pods and services from pods. if len(pods) >= 1 { pos, svcs, err := getKubePods(pods, options.Service) if err != nil { return nil, err } - kubePods = append(kubePods, pos...) + podContent = append(podContent, pos...) if options.Service { - kubeServices = append(kubeServices, svcs...) + content = append(content, svcs...) } - } else { + } + + // Generate the kube pods from containers. + if len(ctrs) >= 1 { po, err := libpod.GenerateForKube(ctrs) if err != nil { return nil, err } - kubePods = append(kubePods, po) + b, err := generateKubeYAML(po) + if err != nil { + return nil, err + } + + podContent = append(podContent, b) if options.Service { - kubeServices = append(kubeServices, libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{})) + b, err := generateKubeYAML(libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{})) + if err != nil { + return nil, err + } + content = append(content, b) } } - content, err := generateKubeOutput(kubePods, kubeServices, options.Service) + // Content order is based on helm install order (secret, persistentVolumeClaim, service, pod). + content = append(content, podContent...) + + // Generate kube YAML file from all kube kinds. + k, err := generateKubeOutput(content) if err != nil { return nil, err } - return &entities.GenerateKubeReport{Reader: bytes.NewReader(content)}, nil + return &entities.GenerateKubeReport{Reader: bytes.NewReader(k)}, nil } -func getKubePods(pods []*libpod.Pod, getService bool) ([]*k8sAPI.Pod, []k8sAPI.Service, error) { - kubePods := make([]*k8sAPI.Pod, 0) - kubeServices := make([]k8sAPI.Service, 0) +// getKubePods returns kube pod and service YAML files from podman pods. +func getKubePods(pods []*libpod.Pod, getService bool) ([][]byte, [][]byte, error) { + pos := [][]byte{} + svcs := [][]byte{} for _, p := range pods { - po, svc, err := p.GenerateForKube() + po, sp, err := p.GenerateForKube() + if err != nil { + return nil, nil, err + } + + b, err := generateKubeYAML(po) if err != nil { return nil, nil, err } + pos = append(pos, b) - kubePods = append(kubePods, po) if getService { - kubeServices = append(kubeServices, libpod.GenerateKubeServiceFromV1Pod(po, svc)) + b, err := generateKubeYAML(libpod.GenerateKubeServiceFromV1Pod(po, sp)) + if err != nil { + return nil, nil, err + } + svcs = append(svcs, b) } } - return kubePods, kubeServices, nil + return pos, svcs, nil } -func generateKubeOutput(kubePods []*k8sAPI.Pod, kubeServices []k8sAPI.Service, hasService bool) ([]byte, error) { - output := make([]byte, 0) - marshalledPods := make([]byte, 0) - marshalledServices := make([]byte, 0) +// getKubePVCs returns kube persistent volume claim YAML files from podman volumes. +func getKubePVCs(volumes []*libpod.Volume) ([][]byte, error) { + pvs := [][]byte{} - for i, p := range kubePods { - if i != 0 { - marshalledPods = append(marshalledPods, []byte("---\n")...) - } - - b, err := yaml.Marshal(p) + for _, v := range volumes { + b, err := generateKubeYAML(v.GenerateForKube()) if err != nil { return nil, err } - - marshalledPods = append(marshalledPods, b...) + pvs = append(pvs, b) } - if hasService { - for i, s := range kubeServices { - if i != 0 { - marshalledServices = append(marshalledServices, []byte("---\n")...) - } - - b, err := yaml.Marshal(s) - if err != nil { - return nil, err - } + return pvs, nil +} - marshalledServices = append(marshalledServices, b...) - } +// generateKubeYAML marshalls a kube kind into a YAML file. +func generateKubeYAML(kubeKind interface{}) ([]byte, error) { + b, err := yaml.Marshal(kubeKind) + if err != nil { + return nil, err } + return b, nil +} + +// generateKubeOutput generates kube YAML file containing multiple kube kinds. +func generateKubeOutput(content [][]byte) ([]byte, error) { + output := make([]byte, 0) + header := `# Generation of Kubernetes YAML is still under development! # # Save the output of this file and use kubectl create -f to import @@ -169,13 +224,18 @@ func generateKubeOutput(kubePods []*k8sAPI.Pod, kubeServices []k8sAPI.Service, h return nil, err } + // Add header to kube YAML file. output = append(output, []byte(fmt.Sprintf(header, podmanVersion.Version))...) - // kube generate order is based on helm install order (service, pod...) - if hasService { - output = append(output, marshalledServices...) - output = append(output, []byte("---\n")...) + + // kube generate order is based on helm install order (secret, persistentVolume, service, pod...). + // Add kube kinds. + for i, b := range content { + if i != 0 { + output = append(output, []byte("---\n")...) + } + + output = append(output, b...) } - output = append(output, marshalledPods...) return output, nil } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 3b5c141d7..4a13a8029 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "os" + "strconv" "strings" "github.com/containers/common/pkg/secrets" @@ -15,6 +16,7 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/libpod/image" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen/generate" "github.com/containers/podman/v3/pkg/specgen/generate/kube" "github.com/containers/podman/v3/pkg/util" @@ -43,6 +45,14 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en return nil, err } + // sort kube kinds + documentList, err = sortKubeKinds(documentList) + if err != nil { + return nil, errors.Wrapf(err, "unable to sort kube kinds in %q", path) + } + + ipIndex := 0 + // create pod on each document if it is a pod or deployment // any other kube kind will be skipped for _, document := range documentList { @@ -63,7 +73,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en podTemplateSpec.ObjectMeta = podYAML.ObjectMeta podTemplateSpec.Spec = podYAML.Spec - r, err := ic.playKubePod(ctx, podTemplateSpec.ObjectMeta.Name, &podTemplateSpec, options) + r, err := ic.playKubePod(ctx, podTemplateSpec.ObjectMeta.Name, &podTemplateSpec, options, &ipIndex) if err != nil { return nil, err } @@ -77,13 +87,27 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path) } - r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options) + r, err := ic.playKubeDeployment(ctx, &deploymentYAML, options, &ipIndex) if err != nil { return nil, err } report.Pods = append(report.Pods, r.Pods...) validKinds++ + case "PersistentVolumeClaim": + var pvcYAML v1.PersistentVolumeClaim + + if err := yaml.Unmarshal(document, &pvcYAML); err != nil { + return nil, errors.Wrapf(err, "unable to read YAML %q as Kube PersistentVolumeClaim", path) + } + + r, err := ic.playKubePVC(ctx, &pvcYAML, options) + if err != nil { + return nil, err + } + + report.Volumes = append(report.Volumes, r.Volumes...) + validKinds++ default: logrus.Infof("kube kind %s not supported", kind) continue @@ -97,7 +121,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, options en return report, nil } -func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { +func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAML *v1apps.Deployment, options entities.PlayKubeOptions, ipIndex *int) (*entities.PlayKubeReport, error) { var ( deploymentName string podSpec v1.PodTemplateSpec @@ -119,7 +143,7 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM // create "replicas" number of pods for i = 0; i < numReplicas; i++ { podName := fmt.Sprintf("%s-pod-%d", deploymentName, i) - podReport, err := ic.playKubePod(ctx, podName, &podSpec, options) + podReport, err := ic.playKubePod(ctx, podName, &podSpec, options, ipIndex) if err != nil { return nil, errors.Wrapf(err, "error encountered while bringing up pod %s", podName) } @@ -128,7 +152,7 @@ func (ic *ContainerEngine) playKubeDeployment(ctx context.Context, deploymentYAM return &report, nil } -func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { +func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podYAML *v1.PodTemplateSpec, options entities.PlayKubeOptions, ipIndex *int) (*entities.PlayKubeReport, error) { var ( registryCreds *types.DockerAuthConfig writer io.Writer @@ -169,9 +193,17 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY // networks. networks := strings.Split(options.Network, ",") logrus.Debugf("Pod joining CNI networks: %v", networks) + p.NetNS.NSMode = specgen.Bridge p.CNINetworks = append(p.CNINetworks, networks...) } } + if len(options.StaticIPs) > *ipIndex { + p.StaticIP = &options.StaticIPs[*ipIndex] + *ipIndex++ + } else if len(options.StaticIPs) > 0 { + // only warn if the user has set at least one ip ip + logrus.Warn("No more static ips left using a random one") + } // Create the Pod pod, err := generate.MakePod(p, ic.Libpod) @@ -279,6 +311,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY RestartPolicy: ctrRestartPolicy, NetNSIsHost: p.NetNS.IsHost(), SecretsManager: secretsManager, + LogDriver: options.LogDriver, } specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { @@ -313,6 +346,68 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return &report, nil } +// playKubePVC creates a podman volume from a kube persistent volume claim. +func (ic *ContainerEngine) playKubePVC(ctx context.Context, pvcYAML *v1.PersistentVolumeClaim, options entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { + var report entities.PlayKubeReport + opts := make(map[string]string) + + // Get pvc name. + // This is the only required pvc attribute to create a podman volume. + name := pvcYAML.GetName() + if strings.TrimSpace(name) == "" { + return nil, fmt.Errorf("persistent volume claim name can not be empty") + } + + // Create podman volume options. + volOptions := []libpod.VolumeCreateOption{ + libpod.WithVolumeName(name), + libpod.WithVolumeLabels(pvcYAML.GetLabels()), + } + + // Get pvc annotations and create remaining podman volume options if available. + // These are podman volume options that do not match any of the persistent volume claim + // attributes, so they can be configured using annotations since they will not affect k8s. + for k, v := range pvcYAML.GetAnnotations() { + switch k { + case util.VolumeDriverAnnotation: + volOptions = append(volOptions, libpod.WithVolumeDriver(v)) + case util.VolumeDeviceAnnotation: + opts["device"] = v + case util.VolumeTypeAnnotation: + opts["type"] = v + case util.VolumeUIDAnnotation: + uid, err := strconv.Atoi(v) + if err != nil { + return nil, errors.Wrapf(err, "cannot convert uid %s to integer", v) + } + volOptions = append(volOptions, libpod.WithVolumeUID(uid)) + opts["UID"] = v + case util.VolumeGIDAnnotation: + gid, err := strconv.Atoi(v) + if err != nil { + return nil, errors.Wrapf(err, "cannot convert gid %s to integer", v) + } + volOptions = append(volOptions, libpod.WithVolumeGID(gid)) + opts["GID"] = v + case util.VolumeMountOptsAnnotation: + opts["o"] = v + } + } + volOptions = append(volOptions, libpod.WithVolumeOptions(opts)) + + // Create volume. + vol, err := ic.Libpod.NewVolume(ctx, volOptions...) + if err != nil { + return nil, err + } + + report.Volumes = append(report.Volumes, entities.PlayKubeVolume{ + Name: vol.Name(), + }) + + return &report, nil +} + // readConfigMapFromFile returns a kubernetes configMap obtained from --configmap flag func readConfigMapFromFile(r io.Reader) (v1.ConfigMap, error) { var cm v1.ConfigMap @@ -374,3 +469,25 @@ func getKubeKind(obj []byte) (string, error) { return kubeObject.Kind, nil } + +// sortKubeKinds adds the correct creation order for the kube kinds. +// Any pod dependecy will be created first like volumes, secrets, etc. +func sortKubeKinds(documentList [][]byte) ([][]byte, error) { + var sortedDocumentList [][]byte + + for _, document := range documentList { + kind, err := getKubeKind(document) + if err != nil { + return nil, err + } + + switch kind { + case "Pod", "Deployment": + sortedDocumentList = append(sortedDocumentList, document) + default: + sortedDocumentList = append([][]byte{document}, sortedDocumentList...) + } + } + + return sortedDocumentList, nil +} diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index a3e753384..f87f9e370 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -390,13 +390,25 @@ func unshareEnv(graphroot, runroot string) []string { fmt.Sprintf("CONTAINERS_RUNROOT=%s", runroot)) } -func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error { - cmd := exec.Command(args[0], args[1:]...) - cmd.Env = unshareEnv(ic.Libpod.StorageConfig().GraphRoot, ic.Libpod.StorageConfig().RunRoot) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - return cmd.Run() +func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options entities.SystemUnshareOptions) error { + unshare := func() error { + cmd := exec.Command(args[0], args[1:]...) + cmd.Env = unshareEnv(ic.Libpod.StorageConfig().GraphRoot, ic.Libpod.StorageConfig().RunRoot) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + return cmd.Run() + } + + if options.RootlessCNI { + rootlesscni, err := ic.Libpod.GetRootlessCNINetNs(true) + if err != nil { + return err + } + defer rootlesscni.Cleanup(ic.Libpod) + return rootlesscni.Do(unshare) + } + return unshare() } func (ic ContainerEngine) Version(ctx context.Context) (*entities.SystemVersionReport, error) { diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go index 7a0c2907c..ab71f8f6f 100644 --- a/pkg/domain/infra/abi/terminal/terminal_linux.go +++ b/pkg/domain/infra/abi/terminal/terminal_linux.go @@ -39,7 +39,7 @@ func ExecAttachCtr(ctx context.Context, ctr *libpod.Container, execConfig *libpo // StartAttachCtr starts and (if required) attaches to a container // if you change the signature of this function from os.File to io.Writer, it will trigger a downstream // error. we may need to just lint disable this one. -func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool, recursive bool) error { //nolint-interfacer +func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, stdin *os.File, detachKeys string, sigProxy bool, startContainer bool) error { //nolint-interfacer resize := make(chan define.TerminalSize) haveTerminal := terminal.IsTerminal(int(os.Stdin.Fd())) @@ -88,7 +88,7 @@ func StartAttachCtr(ctx context.Context, ctr *libpod.Container, stdout, stderr, return ctr.Attach(streams, detachKeys, resize) } - attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, recursive) + attachChan, err := ctr.StartAndAttach(ctx, streams, detachKeys, resize, true) if err != nil { return err } diff --git a/pkg/domain/infra/tunnel/containers.go b/pkg/domain/infra/tunnel/containers.go index a0f65f11f..4545d266b 100644 --- a/pkg/domain/infra/tunnel/containers.go +++ b/pkg/domain/infra/tunnel/containers.go @@ -629,7 +629,7 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta if opts.Detach { // Detach and return early - err := containers.Start(ic.ClientCtx, con.ID, nil) + err := containers.Start(ic.ClientCtx, con.ID, new(containers.StartOptions).WithRecursive(true)) if err != nil { report.ExitCode = define.ExitCode(err) } diff --git a/pkg/domain/infra/tunnel/network.go b/pkg/domain/infra/tunnel/network.go index adf34460c..7e59e44c2 100644 --- a/pkg/domain/infra/tunnel/network.go +++ b/pkg/domain/infra/tunnel/network.go @@ -92,5 +92,6 @@ func (ic *ContainerEngine) NetworkExists(ctx context.Context, networkname string // Network prune removes unused cni networks func (ic *ContainerEngine) NetworkPrune(ctx context.Context, options entities.NetworkPruneOptions) ([]*entities.NetworkPruneReport, error) { - return network.Prune(ic.ClientCtx, nil) + opts := new(network.PruneOptions).WithFilters(options.Filters) + return network.Prune(ic.ClientCtx, opts) } diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go index 9f9076114..e52e1a1f7 100644 --- a/pkg/domain/infra/tunnel/play.go +++ b/pkg/domain/infra/tunnel/play.go @@ -11,7 +11,7 @@ import ( func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entities.PlayKubeOptions) (*entities.PlayKubeReport, error) { options := new(play.KubeOptions).WithAuthfile(opts.Authfile).WithUsername(opts.Username).WithPassword(opts.Password) options.WithCertDir(opts.CertDir).WithQuiet(opts.Quiet).WithSignaturePolicy(opts.SignaturePolicy).WithConfigMaps(opts.ConfigMaps) - options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot) + options.WithLogDriver(opts.LogDriver).WithNetwork(opts.Network).WithSeccompProfileRoot(opts.SeccompProfileRoot).WithStaticIPs(opts.StaticIPs) if s := opts.SkipTLSVerify; s != types.OptionalBoolUndefined { options.WithSkipTLSVerify(s == types.OptionalBoolTrue) diff --git a/pkg/domain/infra/tunnel/system.go b/pkg/domain/infra/tunnel/system.go index d2c5063c9..7400d3771 100644 --- a/pkg/domain/infra/tunnel/system.go +++ b/pkg/domain/infra/tunnel/system.go @@ -28,7 +28,7 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System return system.DiskUsage(ic.ClientCtx, nil) } -func (ic *ContainerEngine) Unshare(ctx context.Context, args []string) error { +func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options entities.SystemUnshareOptions) error { return errors.New("unshare is not supported on remote clients") } |