diff options
Diffstat (limited to 'pkg/domain')
-rw-r--r-- | pkg/domain/entities/engine_container.go | 6 | ||||
-rw-r--r-- | pkg/domain/entities/generate.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/images.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/play.go | 13 | ||||
-rw-r--r-- | pkg/domain/entities/pods.go | 210 | ||||
-rw-r--r-- | pkg/domain/entities/secrets.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/types.go | 38 | ||||
-rw-r--r-- | pkg/domain/infra/abi/containers.go | 38 | ||||
-rw-r--r-- | pkg/domain/infra/abi/generate.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/abi/manifest.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 324 | ||||
-rw-r--r-- | pkg/domain/infra/abi/pods.go | 49 | ||||
-rw-r--r-- | pkg/domain/infra/abi/secrets.go | 31 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/events.go | 1 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/generate.go | 5 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/manifest.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/play.go | 4 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/pods.go | 17 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/secrets.go | 5 | ||||
-rw-r--r-- | pkg/domain/utils/secrets_filters.go | 24 |
21 files changed, 586 insertions, 194 deletions
diff --git a/pkg/domain/entities/engine_container.go b/pkg/domain/entities/engine_container.go index 5d3c9480e..3da31d8a0 100644 --- a/pkg/domain/entities/engine_container.go +++ b/pkg/domain/entities/engine_container.go @@ -67,10 +67,12 @@ type ContainerEngine interface { NetworkReload(ctx context.Context, names []string, options NetworkReloadOptions) ([]*NetworkReloadReport, 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) + PlayKubeDown(ctx context.Context, path string, opts PlayKubeDownOptions) (*PlayKubeReport, error) + PodCreate(ctx context.Context, specg PodSpec) (*PodCreateReport, error) PodExists(ctx context.Context, nameOrID string) (*BoolReport, error) PodInspect(ctx context.Context, options PodInspectOptions) (*PodInspectReport, error) PodKill(ctx context.Context, namesOrIds []string, options PodKillOptions) ([]*PodKillReport, error) + PodLogs(ctx context.Context, pod string, options PodLogsOptions) error PodPause(ctx context.Context, namesOrIds []string, options PodPauseOptions) ([]*PodPauseReport, error) PodPrune(ctx context.Context, options PodPruneOptions) ([]*PodPruneReport, error) PodPs(ctx context.Context, options PodPSOptions) ([]*ListPodsReport, error) @@ -84,7 +86,7 @@ type ContainerEngine interface { SetupRootless(ctx context.Context, noMoveProcess bool) error SecretCreate(ctx context.Context, name string, reader io.Reader, options SecretCreateOptions) (*SecretCreateReport, error) SecretInspect(ctx context.Context, nameOrIDs []string) ([]*SecretInfoReport, []error, error) - SecretList(ctx context.Context) ([]*SecretInfoReport, error) + SecretList(ctx context.Context, opts SecretListRequest) ([]*SecretInfoReport, error) SecretRm(ctx context.Context, nameOrID []string, opts SecretRmOptions) ([]*SecretRmReport, error) Shutdown(ctx context.Context) SystemDf(ctx context.Context, options SystemDfOptions) (*SystemDfReport, error) diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go index 8a437061f..7809c5241 100644 --- a/pkg/domain/entities/generate.go +++ b/pkg/domain/entities/generate.go @@ -9,7 +9,7 @@ type GenerateSystemdOptions struct { // New - create a new container instead of starting a new one. New bool // RestartPolicy - systemd restart policy. - RestartPolicy string + RestartPolicy *string // StopTimeout - time when stopping the container. StopTimeout *uint // ContainerPrefix - systemd unit name prefix for containers diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 262b09cad..c575212b1 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -89,6 +89,8 @@ type ImageRemoveOptions struct { All bool // Foce will force image removal including containers using the images. Force bool + // Confirms if given name is a manifest list and removes it, otherwise returns error. + LookupManifest bool } // ImageRemoveResponse is the response for removing one or more image(s) from storage diff --git a/pkg/domain/entities/play.go b/pkg/domain/entities/play.go index 01de73ebe..77329e328 100644 --- a/pkg/domain/entities/play.go +++ b/pkg/domain/entities/play.go @@ -14,6 +14,9 @@ type PlayKubeOptions struct { Build bool // CertDir - to a directory containing TLS certifications and keys. CertDir string + // Down indicates whether to bring contents of a yaml file "down" + // as in stop + Down bool // Username for authenticating against the registry. Username string // Password for authenticating against the registry. @@ -67,4 +70,14 @@ type PlayKubeReport struct { Pods []PlayKubePod // Volumes - volumes created by play kube. Volumes []PlayKubeVolume + PlayKubeTeardown +} + +// PlayKubeDownOptions are options for tearing down pods +type PlayKubeDownOptions struct{} + +// PlayKubeDownReport contains the results of tearing down play kube +type PlayKubeTeardown struct { + StopReport []*PodStopReport + RmReport []*PodRmReport } diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index c66bf96fc..d9dd0c532 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -106,6 +106,14 @@ type PodRmReport struct { Id string //nolint } +// PddSpec is an abstracted version of PodSpecGen designed to eventually accept options +// not meant to be in a specgen +type PodSpec struct { + PodSpecGen specgen.PodSpecGenerator +} + +// PodCreateOptions provides all possible options for creating a pod and its infra container +// swagger:model PodCreateOptions type PodCreateOptions struct { CGroupParent string CreateCommand []string @@ -125,6 +133,131 @@ type PodCreateOptions struct { Userns specgen.Namespace } +// PodLogsOptions describes the options to extract pod logs. +type PodLogsOptions struct { + // Other fields are exactly same as ContainerLogOpts + ContainerLogsOptions + // If specified will only fetch the logs of specified container + ContainerName string +} + +type ContainerCreateOptions struct { + Annotation []string + Attach []string + Authfile string + BlkIOWeight string + BlkIOWeightDevice []string + CapAdd []string + CapDrop []string + CgroupNS string + CGroupsMode string + CGroupParent string + CIDFile string + ConmonPIDFile string + CPUPeriod uint64 + CPUQuota int64 + CPURTPeriod uint64 + CPURTRuntime int64 + CPUShares uint64 + CPUS float64 + CPUSetCPUs string + CPUSetMems string + Devices []string + DeviceCGroupRule []string + DeviceReadBPs []string + DeviceReadIOPs []string + DeviceWriteBPs []string + DeviceWriteIOPs []string + Entrypoint *string + Env []string + EnvHost bool + EnvFile []string + Expose []string + GIDMap []string + GroupAdd []string + HealthCmd string + HealthInterval string + HealthRetries uint + HealthStartPeriod string + HealthTimeout string + Hostname string + HTTPProxy bool + ImageVolume string + Init bool + InitContainerType string + InitPath string + Interactive bool + IPC string + KernelMemory string + Label []string + LabelFile []string + LogDriver string + LogOptions []string + Memory string + MemoryReservation string + MemorySwap string + MemorySwappiness int64 + Name string + NoHealthCheck bool + OOMKillDisable bool + OOMScoreAdj int + Arch string + OS string + Variant string + PID string + PIDsLimit *int64 + Platform string + Pod string + PodIDFile string + Personality string + PreserveFDs uint + Privileged bool + PublishAll bool + Pull string + Quiet bool + ReadOnly bool + ReadOnlyTmpFS bool + Restart string + Replace bool + Requires []string + Rm bool + RootFS bool + Secrets []string + SecurityOpt []string + SdNotifyMode string + ShmSize string + SignaturePolicy string + StopSignal string + StopTimeout uint + StorageOpt []string + SubUIDName string + SubGIDName string + Sysctl []string + Systemd string + Timeout uint + TLSVerify bool + TmpFS []string + TTY bool + Timezone string + Umask string + UIDMap []string + Ulimit []string + User string + UserNS string + UTS string + Mount []string + Volume []string + VolumesFrom []string + Workdir string + SeccompPolicy string + PidFile string + IsInfra bool + + Net *NetOptions + + CgroupConf []string +} + type PodCreateReport struct { Id string //nolint } @@ -149,21 +282,15 @@ func (p *PodCreateOptions) CPULimits() *specs.LinuxCPU { return cpu } -func setNamespaces(p *PodCreateOptions) ([4]specgen.Namespace, error) { - allNS := [4]specgen.Namespace{} - if p.Pid != "" { - pid, err := specgen.ParseNamespace(p.Pid) - if err != nil { - return [4]specgen.Namespace{}, err - } - allNS[0] = pid - } - return allNS, nil -} - -func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error { +func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.PodSpecGenerator, error) { // Basic Config s.Name = p.Name + s.InfraName = p.InfraName + out, err := specgen.ParseNamespace(p.Pid) + if err != nil { + return nil, err + } + s.Pid = out s.Hostname = p.Hostname s.Labels = p.Labels s.NoInfra = !p.Infra @@ -174,32 +301,26 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error { s.InfraConmonPidFile = p.InfraConmonPidFile } s.InfraImage = p.InfraImage - s.InfraName = p.InfraName s.SharedNamespaces = p.Share s.PodCreateCommand = p.CreateCommand // Networking config - s.NetNS = p.Net.Network - s.StaticIP = p.Net.StaticIP - s.StaticMAC = p.Net.StaticMAC - s.PortMappings = p.Net.PublishPorts - s.CNINetworks = p.Net.CNINetworks - s.NetworkOptions = p.Net.NetworkOptions - if p.Net.UseImageResolvConf { - s.NoManageResolvConf = true - } - s.DNSServer = p.Net.DNSServers - s.DNSSearch = p.Net.DNSSearch - s.DNSOption = p.Net.DNSOptions - s.NoManageHosts = p.Net.NoHosts - s.HostAdd = p.Net.AddHosts - namespaces, err := setNamespaces(p) - if err != nil { - return err - } - if !namespaces[0].IsDefault() { - s.Pid = namespaces[0] + if p.Net != nil { + s.NetNS = p.Net.Network + s.StaticIP = p.Net.StaticIP + s.StaticMAC = p.Net.StaticMAC + s.PortMappings = p.Net.PublishPorts + s.CNINetworks = p.Net.CNINetworks + s.NetworkOptions = p.Net.NetworkOptions + if p.Net.UseImageResolvConf { + s.NoManageResolvConf = true + } + s.DNSServer = p.Net.DNSServers + s.DNSSearch = p.Net.DNSSearch + s.DNSOption = p.Net.DNSOptions + s.NoManageHosts = p.Net.NoHosts + s.HostAdd = p.Net.AddHosts } // Cgroup @@ -219,7 +340,7 @@ func (p *PodCreateOptions) ToPodSpecGen(s *specgen.PodSpecGenerator) error { } } s.Userns = p.Userns - return nil + return &s, nil } type PodPruneOptions struct { @@ -313,3 +434,22 @@ func ValidatePodStatsOptions(args []string, options *PodStatsOptions) error { return errors.New("--all, --latest and arguments cannot be used together") } } + +// Converts PodLogOptions to ContainerLogOptions +func PodLogsOptionsToContainerLogsOptions(options PodLogsOptions) ContainerLogsOptions { + // PodLogsOptions are similar but contains few extra fields like ctrName + // So cast other values as is so we can re-use the code + containerLogsOpts := ContainerLogsOptions{ + Details: options.Details, + Latest: options.Latest, + Follow: options.Follow, + Names: options.Names, + Since: options.Since, + Until: options.Until, + Tail: options.Tail, + Timestamps: options.Timestamps, + StdoutWriter: options.StdoutWriter, + StderrWriter: options.StderrWriter, + } + return containerLogsOpts +} diff --git a/pkg/domain/entities/secrets.go b/pkg/domain/entities/secrets.go index 56a1465b7..55b470d7b 100644 --- a/pkg/domain/entities/secrets.go +++ b/pkg/domain/entities/secrets.go @@ -16,7 +16,7 @@ type SecretCreateOptions struct { } type SecretListRequest struct { - Filters map[string]string + Filters map[string][]string } type SecretListReport struct { diff --git a/pkg/domain/entities/types.go b/pkg/domain/entities/types.go index db4c6bb8a..ec4d4a902 100644 --- a/pkg/domain/entities/types.go +++ b/pkg/domain/entities/types.go @@ -31,21 +31,33 @@ type VolumeDeleteReport struct{ Report } // NetOptions reflect the shared network options between // pods and containers +type NetFlags struct { + AddHosts []string `json:"add-host,omitempty"` + DNS []string `json:"dns,omitempty"` + DNSOpt []string `json:"dns-opt,omitempty"` + DNDSearch []string `json:"dns-search,omitempty"` + MacAddr string `json:"mac-address,omitempty"` + Publish []string `json:"publish,omitempty"` + IP string `json:"ip,omitempty"` + NoHosts bool `json:"no-hosts,omitempty"` + Network string `json:"network,omitempty"` + NetworkAlias []string `json:"network-alias,omitempty"` +} type NetOptions struct { - AddHosts []string - Aliases []string - CNINetworks []string - UseImageResolvConf bool - DNSOptions []string - DNSSearch []string - DNSServers []net.IP - Network specgen.Namespace - NoHosts bool - PublishPorts []types.PortMapping - StaticIP *net.IP - StaticMAC *net.HardwareAddr + AddHosts []string `json:"hostadd,omitempty"` + Aliases []string `json:"network_alias,omitempty"` + CNINetworks []string `json:"cni_networks,omitempty"` + UseImageResolvConf bool `json:"no_manage_resolv_conf,omitempty"` + DNSOptions []string `json:"dns_option,omitempty"` + DNSSearch []string `json:"dns_search,omitempty"` + DNSServers []net.IP `json:"dns_server,omitempty"` + Network specgen.Namespace `json:"netns,omitempty"` + NoHosts bool `json:"no_manage_hosts,omitempty"` + PublishPorts []types.PortMapping `json:"portmappings,omitempty"` + StaticIP *net.IP `json:"static_ip,omitempty"` + StaticMAC *net.HardwareAddr `json:"static_mac,omitempty"` // NetworkOptions are additional options for each network - NetworkOptions map[string][]string + NetworkOptions map[string][]string `json:"network_options,omitempty"` } // All CLI inspect commands and inspect sub-commands use the same options diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go index a74b65ab9..dc5f7a0df 100644 --- a/pkg/domain/infra/abi/containers.go +++ b/pkg/domain/infra/abi/containers.go @@ -173,13 +173,17 @@ func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []strin return err } } - if c.AutoRemove() { - // Issue #7384: if the container is configured for - // auto-removal, it might already have been removed at - // this point. - return nil + err = c.Cleanup(ctx) + if err != nil { + // Issue #7384 and #11384: If the container is configured for + // auto-removal, it might already have been removed at this point. + // We still need to to cleanup since we do not know if the other cleanup process is successful + if c.AutoRemove() && (errors.Is(err, define.ErrNoSuchCtr) || errors.Is(err, define.ErrCtrRemoved)) { + return nil + } + return err } - return c.Cleanup(ctx) + return nil }) if err != nil { return nil, err @@ -367,7 +371,7 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st if options.Latest { ctr, err := ic.Libpod.GetLatestContainer() if err != nil { - if errors.Cause(err) == define.ErrNoSuchCtr { + if errors.Is(err, define.ErrNoSuchCtr) { return nil, []error{errors.Wrapf(err, "no containers to inspect")}, nil } return nil, nil, err @@ -393,7 +397,7 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st if err != nil { // ErrNoSuchCtr is non-fatal, other errors will be // treated as fatal. - if errors.Cause(err) == define.ErrNoSuchCtr { + if errors.Is(err, define.ErrNoSuchCtr) { errs = append(errs, errors.Errorf("no such container %s", name)) continue } @@ -402,6 +406,12 @@ func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []st inspect, err := ctr.Inspect(options.Size) if err != nil { + // ErrNoSuchCtr is non-fatal, other errors will be + // treated as fatal. + if errors.Is(err, define.ErrNoSuchCtr) { + errs = append(errs, errors.Errorf("no such container %s", name)) + continue + } return nil, nil, err } @@ -583,7 +593,11 @@ func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecG for _, w := range warn { fmt.Fprintf(os.Stderr, "%s\n", w) } - ctr, err := generate.MakeContainer(ctx, ic.Libpod, s) + rtSpec, spec, opts, err := generate.MakeContainer(context.Background(), ic.Libpod, s) + if err != nil { + return nil, err + } + ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) if err != nil { return nil, err } @@ -915,7 +929,11 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta for _, w := range warn { fmt.Fprintf(os.Stderr, "%s\n", w) } - ctr, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec) + rtSpec, spec, optsN, err := generate.MakeContainer(ctx, ic.Libpod, opts.Spec) + if err != nil { + return nil, err + } + ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, optsN...) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index b0853b554..2d7bc15f5 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -60,9 +60,7 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, return nil, err } } else { - if len(ctr.Dependencies()) > 0 { - return nil, errors.Wrapf(define.ErrNotImplemented, "containers with dependencies") - } + // now that infra holds NS data, we need to support dependencies. // 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()) diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index e8739615d..a88d38a10 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -521,6 +521,7 @@ func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entitie libimageOptions := &libimage.RemoveImagesOptions{} libimageOptions.Filters = []string{"readonly=false"} libimageOptions.Force = opts.Force + libimageOptions.LookupManifest = opts.LookupManifest if !opts.All { libimageOptions.Filters = append(libimageOptions.Filters, "intermediate=false") } diff --git a/pkg/domain/infra/abi/manifest.go b/pkg/domain/infra/abi/manifest.go index 666bc997d..1dd0686ac 100644 --- a/pkg/domain/infra/abi/manifest.go +++ b/pkg/domain/infra/abi/manifest.go @@ -306,7 +306,7 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri // ManifestRm removes the specified manifest list from storage func (ir *ImageEngine) ManifestRm(ctx context.Context, names []string) (report *entities.ImageRemoveReport, rmErrors []error) { - return ir.Remove(ctx, names, entities.ImageRemoveOptions{}) + return ir.Remove(ctx, names, entities.ImageRemoveOptions{LookupManifest: true}) } // ManifestPush pushes a manifest list or image index to the destination diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 6224feff5..c9a6930f7 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "io/ioutil" + "net" "os" "path/filepath" "strconv" @@ -22,6 +23,7 @@ import ( "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/specgenutil" "github.com/containers/podman/v3/pkg/util" "github.com/ghodss/yaml" "github.com/pkg/errors" @@ -179,10 +181,12 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } } - p, err := kube.ToPodGen(ctx, podName, podYAML) + podOpt := entities.PodCreateOptions{Infra: true, Net: &entities.NetOptions{StaticIP: &net.IP{}, StaticMAC: &net.HardwareAddr{}}} + podOpt, err = kube.ToPodOpt(ctx, podName, podOpt, podYAML) if err != nil { return nil, err } + if options.Network != "" { ns, cniNets, netOpts, err := specgen.ParseNetworkString(options.Network) if err != nil { @@ -192,43 +196,40 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if (ns.IsBridge() && len(cniNets) == 0) || ns.IsHost() { return nil, errors.Errorf("invalid value passed to --network: bridge or host networking must be configured in YAML") } - logrus.Debugf("Pod %q joining CNI networks: %v", podName, cniNets) - p.NetNS.NSMode = specgen.Bridge - p.CNINetworks = append(p.CNINetworks, cniNets...) + + podOpt.Net.Network = ns + if len(cniNets) > 0 { + podOpt.Net.CNINetworks = append(podOpt.Net.CNINetworks, cniNets...) + } if len(netOpts) > 0 { - p.NetworkOptions = netOpts + podOpt.Net.NetworkOptions = netOpts } } if len(options.StaticIPs) > *ipIndex { - p.StaticIP = &options.StaticIPs[*ipIndex] + podOpt.Net.StaticIP = &options.StaticIPs[*ipIndex] } else if len(options.StaticIPs) > 0 { // only warn if the user has set at least one ip logrus.Warn("No more static ips left using a random one") } if len(options.StaticMACs) > *ipIndex { - p.StaticMAC = &options.StaticMACs[*ipIndex] + podOpt.Net.StaticMAC = &options.StaticMACs[*ipIndex] } else if len(options.StaticIPs) > 0 { // only warn if the user has set at least one mac logrus.Warn("No more static macs left using a random one") } *ipIndex++ - // Create the Pod - pod, err := generate.MakePod(p, ic.Libpod) + p := specgen.NewPodSpecGenerator() if err != nil { return nil, err } - podInfraID, err := pod.InfraContainerID() + p, err = entities.ToPodSpecGen(*p, &podOpt) if err != nil { return nil, err } - - if !options.Quiet { - writer = os.Stderr - } - + podSpec := entities.PodSpec{PodSpecGen: *p} volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes) if err != nil { return nil, err @@ -267,112 +268,146 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY configMaps = append(configMaps, cm) } - containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers)) - cwd, err := os.Getwd() - if err != nil { - return nil, err - } - for _, container := range podYAML.Spec.Containers { - // Contains all labels obtained from kube - labels := make(map[string]string) - var pulledImage *libimage.Image - buildFile, err := getBuildFile(container.Image, cwd) + if podOpt.Infra { + imagePull := config.DefaultInfraImage + if podOpt.InfraImage != config.DefaultInfraImage && podOpt.InfraImage != "" { + imagePull = podOpt.InfraImage + } + + pulledImages, err := pullImage(ic, writer, imagePull, options, config.PullPolicyNewer) if err != nil { return nil, err } - existsLocally, err := ic.Libpod.LibimageRuntime().Exists(container.Image) + infraOptions := entities.ContainerCreateOptions{ImageVolume: "bind"} + + podSpec.PodSpecGen.InfraImage = pulledImages[0].Names()[0] + podSpec.PodSpecGen.NoInfra = false + podSpec.PodSpecGen.InfraContainerSpec = specgen.NewSpecGenerator(pulledImages[0].Names()[0], false) + podSpec.PodSpecGen.InfraContainerSpec.NetworkOptions = p.NetworkOptions + + err = specgenutil.FillOutSpecGen(podSpec.PodSpecGen.InfraContainerSpec, &infraOptions, []string{}) if err != nil { return nil, err } - if (len(buildFile) > 0 && !existsLocally) || (len(buildFile) > 0 && options.Build) { - buildOpts := new(buildahDefine.BuildOptions) - commonOpts := new(buildahDefine.CommonBuildOptions) - buildOpts.ConfigureNetwork = buildahDefine.NetworkDefault - buildOpts.Isolation = buildahDefine.IsolationChroot - buildOpts.CommonBuildOpts = commonOpts - buildOpts.Output = container.Image - if _, _, err := ic.Libpod.Build(ctx, *buildOpts, []string{buildFile}...); err != nil { + } + + // Create the Pod + pod, err := generate.MakePod(&podSpec, ic.Libpod) + if err != nil { + return nil, err + } + + podInfraID, err := pod.InfraContainerID() + if err != nil { + return nil, err + } + + if !options.Quiet { + writer = os.Stderr + } + + containers := make([]*libpod.Container, 0, len(podYAML.Spec.Containers)) + cwd, err := os.Getwd() + if err != nil { + return nil, err + } + for _, container := range podYAML.Spec.Containers { + if !strings.Contains("infra", container.Name) { + // Contains all labels obtained from kube + labels := make(map[string]string) + var pulledImage *libimage.Image + buildFile, err := getBuildFile(container.Image, cwd) + if err != nil { return nil, err } - i, _, err := ic.Libpod.LibimageRuntime().LookupImage(container.Image, new(libimage.LookupImageOptions)) + existsLocally, err := ic.Libpod.LibimageRuntime().Exists(container.Image) if err != nil { return nil, err } - pulledImage = i - } else { - // NOTE: set the pull policy to "newer". This will cover cases - // where the "latest" tag requires a pull and will also - // transparently handle "localhost/" prefixed files which *may* - // refer to a locally built image OR an image running a - // registry on localhost. - pullPolicy := config.PullPolicyNewer - if len(container.ImagePullPolicy) > 0 { - // Make sure to lower the strings since K8s pull policy - // may be capitalized (see bugzilla.redhat.com/show_bug.cgi?id=1985905). - rawPolicy := string(container.ImagePullPolicy) - pullPolicy, err = config.ParsePullPolicy(strings.ToLower(rawPolicy)) + if (len(buildFile) > 0 && !existsLocally) || (len(buildFile) > 0 && options.Build) { + buildOpts := new(buildahDefine.BuildOptions) + commonOpts := new(buildahDefine.CommonBuildOptions) + buildOpts.ConfigureNetwork = buildahDefine.NetworkDefault + buildOpts.Isolation = buildahDefine.IsolationChroot + buildOpts.CommonBuildOpts = commonOpts + buildOpts.Output = container.Image + if _, _, err := ic.Libpod.Build(ctx, *buildOpts, []string{buildFile}...); err != nil { + return nil, err + } + i, _, err := ic.Libpod.LibimageRuntime().LookupImage(container.Image, new(libimage.LookupImageOptions)) + if err != nil { + return nil, err + } + pulledImage = i + } else { + // NOTE: set the pull policy to "newer". This will cover cases + // where the "latest" tag requires a pull and will also + // transparently handle "localhost/" prefixed files which *may* + // refer to a locally built image OR an image running a + // registry on localhost. + pullPolicy := config.PullPolicyNewer + if len(container.ImagePullPolicy) > 0 { + // Make sure to lower the strings since K8s pull policy + // may be capitalized (see bugzilla.redhat.com/show_bug.cgi?id=1985905). + rawPolicy := string(container.ImagePullPolicy) + pullPolicy, err = config.ParsePullPolicy(strings.ToLower(rawPolicy)) + if err != nil { + return nil, err + } + } + pulledImages, err := pullImage(ic, writer, container.Image, options, pullPolicy) if err != nil { return nil, err } + pulledImage = pulledImages[0] } - // This ensures the image is the image store - pullOptions := &libimage.PullOptions{} - pullOptions.AuthFilePath = options.Authfile - pullOptions.CertDirPath = options.CertDir - pullOptions.SignaturePolicyPath = options.SignaturePolicy - pullOptions.Writer = writer - pullOptions.Username = options.Username - pullOptions.Password = options.Password - pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify - - pulledImages, err := ic.Libpod.LibimageRuntime().Pull(ctx, container.Image, pullPolicy, pullOptions) + + // Handle kube annotations + for k, v := range annotations { + switch k { + // Auto update annotation without container name will apply to + // all containers within the pod + case autoupdate.Label, autoupdate.AuthfileLabel: + labels[k] = v + // Auto update annotation with container name will apply only + // to the specified container + case fmt.Sprintf("%s/%s", autoupdate.Label, container.Name), + fmt.Sprintf("%s/%s", autoupdate.AuthfileLabel, container.Name): + prefixAndCtr := strings.Split(k, "/") + labels[prefixAndCtr[0]] = v + } + } + + specgenOpts := kube.CtrSpecGenOptions{ + Container: container, + Image: pulledImage, + Volumes: volumes, + PodID: pod.ID(), + PodName: podName, + PodInfraID: podInfraID, + ConfigMaps: configMaps, + SeccompPaths: seccompPaths, + RestartPolicy: ctrRestartPolicy, + NetNSIsHost: p.NetNS.IsHost(), + SecretsManager: secretsManager, + LogDriver: options.LogDriver, + Labels: labels, + } + specGen, err := kube.ToSpecGen(ctx, &specgenOpts) if err != nil { return nil, err } - pulledImage = pulledImages[0] - } - // Handle kube annotations - for k, v := range annotations { - switch k { - // Auto update annotation without container name will apply to - // all containers within the pod - case autoupdate.Label, autoupdate.AuthfileLabel: - labels[k] = v - // Auto update annotation with container name will apply only - // to the specified container - case fmt.Sprintf("%s/%s", autoupdate.Label, container.Name), - fmt.Sprintf("%s/%s", autoupdate.AuthfileLabel, container.Name): - prefixAndCtr := strings.Split(k, "/") - labels[prefixAndCtr[0]] = v + rtSpec, spec, opts, err := generate.MakeContainer(ctx, ic.Libpod, specGen) + if err != nil { + return nil, err } + ctr, err := generate.ExecuteCreate(ctx, ic.Libpod, rtSpec, spec, false, opts...) + if err != nil { + return nil, err + } + containers = append(containers, ctr) } - - specgenOpts := kube.CtrSpecGenOptions{ - Container: container, - Image: pulledImage, - Volumes: volumes, - PodID: pod.ID(), - PodName: podName, - PodInfraID: podInfraID, - ConfigMaps: configMaps, - SeccompPaths: seccompPaths, - RestartPolicy: ctrRestartPolicy, - NetNSIsHost: p.NetNS.IsHost(), - SecretsManager: secretsManager, - LogDriver: options.LogDriver, - Labels: labels, - } - specGen, err := kube.ToSpecGen(ctx, &specgenOpts) - if err != nil { - return nil, err - } - - ctr, err := generate.MakeContainer(ctx, ic.Libpod, specGen) - if err != nil { - return nil, err - } - containers = append(containers, ctr) } if options.Start != types.OptionalBoolFalse { @@ -383,6 +418,7 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY } for id, err := range podStartErrors { playKubePod.ContainerErrors = append(playKubePod.ContainerErrors, errors.Wrapf(err, "error starting container %s", id).Error()) + fmt.Println(playKubePod.ContainerErrors) } } @@ -586,3 +622,91 @@ func getBuildFile(imageName string, cwd string) (string, error) { } return "", err } + +func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) { + var ( + podNames []string + ) + reports := new(entities.PlayKubeReport) + + // read yaml document + content, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + + // split yaml document + documentList, err := splitMultiDocYAML(content) + if err != nil { + 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) + } + + for _, document := range documentList { + kind, err := getKubeKind(document) + if err != nil { + return nil, errors.Wrapf(err, "unable to read %q as kube YAML", path) + } + + switch kind { + case "Pod": + var podYAML v1.Pod + if err := yaml.Unmarshal(document, &podYAML); err != nil { + return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Pod", path) + } + podNames = append(podNames, podYAML.ObjectMeta.Name) + case "Deployment": + var deploymentYAML v1apps.Deployment + + if err := yaml.Unmarshal(document, &deploymentYAML); err != nil { + return nil, errors.Wrapf(err, "unable to read YAML %q as Kube Deployment", path) + } + var numReplicas int32 = 1 + deploymentName := deploymentYAML.ObjectMeta.Name + if deploymentYAML.Spec.Replicas != nil { + numReplicas = *deploymentYAML.Spec.Replicas + } + for i := 0; i < int(numReplicas); i++ { + podName := fmt.Sprintf("%s-pod-%d", deploymentName, i) + podNames = append(podNames, podName) + } + default: + continue + } + } + + // Add the reports + reports.StopReport, err = ic.PodStop(ctx, podNames, entities.PodStopOptions{}) + if err != nil { + return nil, err + } + + reports.RmReport, err = ic.PodRm(ctx, podNames, entities.PodRmOptions{}) + if err != nil { + return nil, err + } + return reports, nil +} + +// pullImage is a helper function to set up the proper pull options and pull the image for certain containers +func pullImage(ic *ContainerEngine, writer io.Writer, imagePull string, options entities.PlayKubeOptions, pullPolicy config.PullPolicy) ([]*libimage.Image, error) { + // This ensures the image is the image store + pullOptions := &libimage.PullOptions{} + pullOptions.AuthFilePath = options.Authfile + pullOptions.CertDirPath = options.CertDir + pullOptions.SignaturePolicyPath = options.SignaturePolicy + pullOptions.Writer = writer + pullOptions.Username = options.Username + pullOptions.Password = options.Password + pullOptions.InsecureSkipTLSVerify = options.SkipTLSVerify + pulledImages, err := ic.Libpod.LibimageRuntime().Pull(context.Background(), imagePull, pullPolicy, pullOptions) + if err != nil { + return nil, err + } + return pulledImages, nil +} diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go index 055c495d5..6b432c214 100644 --- a/pkg/domain/infra/abi/pods.go +++ b/pkg/domain/infra/abi/pods.go @@ -8,7 +8,6 @@ import ( "github.com/containers/podman/v3/pkg/domain/entities" dfilters "github.com/containers/podman/v3/pkg/domain/filters" "github.com/containers/podman/v3/pkg/signal" - "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/specgen/generate" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -84,6 +83,46 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt return reports, nil } +func (ic *ContainerEngine) PodLogs(ctx context.Context, nameOrID string, options entities.PodLogsOptions) error { + // Implementation accepts slice + podName := []string{nameOrID} + pod, err := getPodsByContext(false, options.Latest, podName, ic.Libpod) + if err != nil { + return err + } + // Get pod containers + podCtrs, err := pod[0].AllContainers() + if err != nil { + return err + } + + ctrNames := []string{} + // Check if `kubectl pod logs -c ctrname <podname>` alike command is used + if options.ContainerName != "" { + ctrFound := false + for _, ctr := range podCtrs { + if ctr.ID() == options.ContainerName || ctr.Name() == options.ContainerName { + ctrNames = append(ctrNames, options.ContainerName) + ctrFound = true + } + } + if !ctrFound { + return errors.Wrapf(define.ErrNoSuchCtr, "container %s is not in pod %s", options.ContainerName, nameOrID) + } + } else { + // No container name specified select all containers + for _, ctr := range podCtrs { + ctrNames = append(ctrNames, ctr.Name()) + } + } + + // PodLogsOptions are similar but contains few extra fields like ctrName + // So cast other values as is so we can re-use the code + containerLogsOpts := entities.PodLogsOptionsToContainerLogsOptions(options) + + return ic.ContainerLogs(ctx, ctrNames, containerLogsOpts) +} + func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) { reports := []*entities.PodPauseReport{} pods, err := getPodsByContext(options.All, options.Latest, namesOrIds, ic.Libpod) @@ -248,12 +287,8 @@ func (ic *ContainerEngine) prunePodHelper(ctx context.Context) ([]*entities.PodP return reports, nil } -func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) { - podSpec := specgen.NewPodSpecGenerator() - if err := opts.ToPodSpecGen(podSpec); err != nil { - return nil, err - } - pod, err := generate.MakePod(podSpec, ic.Libpod) +func (ic *ContainerEngine) PodCreate(ctx context.Context, specg entities.PodSpec) (*entities.PodCreateReport, error) { + pod, err := generate.MakePod(&specg, ic.Libpod) if err != nil { return nil, err } diff --git a/pkg/domain/infra/abi/secrets.go b/pkg/domain/infra/abi/secrets.go index 0bdb4ce60..2bf8eaae3 100644 --- a/pkg/domain/infra/abi/secrets.go +++ b/pkg/domain/infra/abi/secrets.go @@ -7,6 +7,7 @@ import ( "path/filepath" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/containers/podman/v3/pkg/domain/utils" "github.com/pkg/errors" ) @@ -84,7 +85,7 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string return reports, errs, nil } -func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretInfoReport, error) { +func (ic *ContainerEngine) SecretList(ctx context.Context, opts entities.SecretListRequest) ([]*entities.SecretInfoReport, error) { manager, err := ic.Libpod.SecretsManager() if err != nil { return nil, err @@ -95,19 +96,25 @@ func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretIn } report := make([]*entities.SecretInfoReport, 0, len(secretList)) for _, secret := range secretList { - reportItem := entities.SecretInfoReport{ - ID: secret.ID, - CreatedAt: secret.CreatedAt, - UpdatedAt: secret.CreatedAt, - Spec: entities.SecretSpec{ - Name: secret.Name, - Driver: entities.SecretDriverSpec{ - Name: secret.Driver, - Options: secret.DriverOptions, + result, err := utils.IfPassesSecretsFilter(secret, opts.Filters) + if err != nil { + return nil, err + } + if result { + reportItem := entities.SecretInfoReport{ + ID: secret.ID, + CreatedAt: secret.CreatedAt, + UpdatedAt: secret.CreatedAt, + Spec: entities.SecretSpec{ + Name: secret.Name, + Driver: entities.SecretDriverSpec{ + Name: secret.Driver, + Options: secret.DriverOptions, + }, }, - }, + } + report = append(report, &reportItem) } - report = append(report, &reportItem) } return report, nil } diff --git a/pkg/domain/infra/tunnel/events.go b/pkg/domain/infra/tunnel/events.go index 6e2c3f8ba..203550c5d 100644 --- a/pkg/domain/infra/tunnel/events.go +++ b/pkg/domain/infra/tunnel/events.go @@ -7,6 +7,7 @@ import ( "github.com/containers/podman/v3/libpod/events" "github.com/containers/podman/v3/pkg/bindings/system" "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/pkg/errors" ) diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go index 3d3cd52be..9f69abb1a 100644 --- a/pkg/domain/infra/tunnel/generate.go +++ b/pkg/domain/infra/tunnel/generate.go @@ -9,7 +9,10 @@ import ( func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, opts entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) { options := new(generate.SystemdOptions).WithUseName(opts.Name).WithContainerPrefix(opts.ContainerPrefix).WithNew(opts.New).WithNoHeader(opts.NoHeader) - options.WithPodPrefix(opts.PodPrefix).WithRestartPolicy(opts.RestartPolicy).WithSeparator(opts.Separator) + options.WithPodPrefix(opts.PodPrefix).WithSeparator(opts.Separator) + if opts.RestartPolicy != nil { + options.WithRestartPolicy(*opts.RestartPolicy) + } if to := opts.StopTimeout; to != nil { options.WithStopTimeout(*opts.StopTimeout) } diff --git a/pkg/domain/infra/tunnel/manifest.go b/pkg/domain/infra/tunnel/manifest.go index b8069405a..62634f561 100644 --- a/pkg/domain/infra/tunnel/manifest.go +++ b/pkg/domain/infra/tunnel/manifest.go @@ -85,7 +85,7 @@ func (ir *ImageEngine) ManifestRemove(ctx context.Context, names []string) (stri // ManifestRm removes the specified manifest list from storage func (ir *ImageEngine) ManifestRm(ctx context.Context, names []string) (*entities.ImageRemoveReport, []error) { - return ir.Remove(ctx, names, entities.ImageRemoveOptions{}) + return ir.Remove(ctx, names, entities.ImageRemoveOptions{LookupManifest: true}) } // ManifestPush pushes a manifest list or image index to the destination diff --git a/pkg/domain/infra/tunnel/play.go b/pkg/domain/infra/tunnel/play.go index e66ff0308..e39751a18 100644 --- a/pkg/domain/infra/tunnel/play.go +++ b/pkg/domain/infra/tunnel/play.go @@ -22,3 +22,7 @@ func (ic *ContainerEngine) PlayKube(ctx context.Context, path string, opts entit } return play.Kube(ic.ClientCtx, path, options) } + +func (ic *ContainerEngine) PlayKubeDown(ctx context.Context, path string, _ entities.PlayKubeDownOptions) (*entities.PlayKubeReport, error) { + return play.KubeDown(ic.ClientCtx, path) +} diff --git a/pkg/domain/infra/tunnel/pods.go b/pkg/domain/infra/tunnel/pods.go index 82f062b2c..8139216b3 100644 --- a/pkg/domain/infra/tunnel/pods.go +++ b/pkg/domain/infra/tunnel/pods.go @@ -6,7 +6,6 @@ import ( "github.com/containers/podman/v3/libpod/define" "github.com/containers/podman/v3/pkg/bindings/pods" "github.com/containers/podman/v3/pkg/domain/entities" - "github.com/containers/podman/v3/pkg/specgen" "github.com/containers/podman/v3/pkg/util" "github.com/pkg/errors" ) @@ -43,6 +42,16 @@ func (ic *ContainerEngine) PodKill(ctx context.Context, namesOrIds []string, opt return reports, nil } +func (ic *ContainerEngine) PodLogs(_ context.Context, nameOrIDs string, options entities.PodLogsOptions) error { + // PodLogsOptions are similar but contains few extra fields like ctrName + // So cast other values as is so we can re-use the code + containerLogsOpts := entities.PodLogsOptionsToContainerLogsOptions(options) + + // interface only accepts slice, keep everything consistent + name := []string{options.ContainerName} + return ic.ContainerLogs(nil, name, containerLogsOpts) +} + func (ic *ContainerEngine) PodPause(ctx context.Context, namesOrIds []string, options entities.PodPauseOptions) ([]*entities.PodPauseReport, error) { foundPods, err := getPodsByContext(ic.ClientCtx, options.All, namesOrIds) if err != nil { @@ -179,10 +188,8 @@ func (ic *ContainerEngine) PodPrune(ctx context.Context, opts entities.PodPruneO return pods.Prune(ic.ClientCtx, nil) } -func (ic *ContainerEngine) PodCreate(ctx context.Context, opts entities.PodCreateOptions) (*entities.PodCreateReport, error) { - podSpec := specgen.NewPodSpecGenerator() - opts.ToPodSpecGen(podSpec) - return pods.CreatePodFromSpec(ic.ClientCtx, podSpec, nil) +func (ic *ContainerEngine) PodCreate(ctx context.Context, specg entities.PodSpec) (*entities.PodCreateReport, error) { + return pods.CreatePodFromSpec(ic.ClientCtx, &specg) } func (ic *ContainerEngine) PodTop(ctx context.Context, opts entities.PodTopOptions) (*entities.StringSliceReport, error) { diff --git a/pkg/domain/infra/tunnel/secrets.go b/pkg/domain/infra/tunnel/secrets.go index ecbb80931..6337c7fbe 100644 --- a/pkg/domain/infra/tunnel/secrets.go +++ b/pkg/domain/infra/tunnel/secrets.go @@ -43,8 +43,9 @@ func (ic *ContainerEngine) SecretInspect(ctx context.Context, nameOrIDs []string return allInspect, errs, nil } -func (ic *ContainerEngine) SecretList(ctx context.Context) ([]*entities.SecretInfoReport, error) { - secrs, _ := secrets.List(ic.ClientCtx, nil) +func (ic *ContainerEngine) SecretList(ctx context.Context, opts entities.SecretListRequest) ([]*entities.SecretInfoReport, error) { + options := new(secrets.ListOptions).WithFilters(opts.Filters) + secrs, _ := secrets.List(ic.ClientCtx, options) return secrs, nil } diff --git a/pkg/domain/utils/secrets_filters.go b/pkg/domain/utils/secrets_filters.go new file mode 100644 index 000000000..3ff7c7530 --- /dev/null +++ b/pkg/domain/utils/secrets_filters.go @@ -0,0 +1,24 @@ +package utils + +import ( + "strings" + + "github.com/containers/common/pkg/secrets" + "github.com/containers/podman/v3/pkg/util" + "github.com/pkg/errors" +) + +func IfPassesSecretsFilter(s secrets.Secret, filters map[string][]string) (bool, error) { + result := true + for key, filterValues := range filters { + switch strings.ToLower(key) { + case "name": + result = util.StringMatchRegexSlice(s.Name, filterValues) + case "id": + result = util.StringMatchRegexSlice(s.ID, filterValues) + default: + return false, errors.Errorf("invalid filter %q", key) + } + } + return result, nil +} |