diff options
-rw-r--r-- | cmd/podman/common/create.go | 12 | ||||
-rw-r--r-- | cmd/podman/common/create_test.go | 53 | ||||
-rw-r--r-- | cmd/podman/machine/init.go | 21 | ||||
-rw-r--r-- | cmd/podman/pods/create.go | 32 | ||||
-rw-r--r-- | docs/source/markdown/podman-machine-init.1.md | 4 | ||||
-rw-r--r-- | docs/source/markdown/podman-rmi.1.md | 4 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 52 | ||||
-rw-r--r-- | pkg/api/handlers/types.go | 3 | ||||
-rw-r--r-- | pkg/domain/entities/pods.go | 63 | ||||
-rw-r--r-- | test/apiv2/python/rest_api/test_v2_0_0_image.py | 5 |
10 files changed, 170 insertions, 79 deletions
diff --git a/cmd/podman/common/create.go b/cmd/podman/common/create.go index 6200592b4..a65e90fab 100644 --- a/cmd/podman/common/create.go +++ b/cmd/podman/common/create.go @@ -15,6 +15,18 @@ const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes), var containerConfig = registry.PodmanConfig() +// ContainerToPodOptions takes the Container and Pod Create options, assigning the matching values back to podCreate for the purpose of the libpod API +// For this function to succeed, the JSON tags in PodCreateOptions and ContainerCreateOptions need to match due to the Marshaling and Unmarshaling done. +// The types of the options also need to match or else the unmarshaling will fail even if the tags match +func ContainerToPodOptions(containerCreate *entities.ContainerCreateOptions, podCreate *entities.PodCreateOptions) error { + contMarshal, err := json.Marshal(containerCreate) + if err != nil { + return err + } + return json.Unmarshal(contMarshal, podCreate) +} + +// DefineCreateFlags declares and instantiates the container create flags func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, isInfra bool) { createFlags := cmd.Flags() diff --git a/cmd/podman/common/create_test.go b/cmd/podman/common/create_test.go new file mode 100644 index 000000000..17b47dd16 --- /dev/null +++ b/cmd/podman/common/create_test.go @@ -0,0 +1,53 @@ +package common_test + +import ( + "reflect" + "strings" + "testing" + + "github.com/containers/podman/v3/cmd/podman/common" + "github.com/containers/podman/v3/pkg/domain/entities" + "github.com/stretchr/testify/assert" +) + +func TestPodOptions(t *testing.T) { + entry := "/test1" + exampleOptions := entities.ContainerCreateOptions{CPUS: 5.5, CPUSetCPUs: "0-4", Entrypoint: &entry, Hostname: "foo", Name: "testing123", Volume: []string{"/fakeVol1", "/fakeVol2"}, Net: &entities.NetOptions{CNINetworks: []string{"FakeNetwork"}}, PID: "ns:/proc/self/ns"} + + podOptions := entities.PodCreateOptions{} + err := common.ContainerToPodOptions(&exampleOptions, &podOptions) + assert.Nil(t, err) + + cc := reflect.ValueOf(&exampleOptions).Elem() + pc := reflect.ValueOf(&podOptions).Elem() + + pcType := reflect.TypeOf(podOptions) + for i := 0; i < pc.NumField(); i++ { + podField := pc.FieldByIndex([]int{i}) + podType := pcType.Field(i) + for j := 0; j < cc.NumField(); j++ { + containerField := cc.FieldByIndex([]int{j}) + containerType := reflect.TypeOf(exampleOptions).Field(j) + tagPod := strings.Split(string(podType.Tag.Get("json")), ",")[0] + tagContainer := strings.Split(string(containerType.Tag.Get("json")), ",")[0] + if tagPod == tagContainer && (tagPod != "" && tagContainer != "") { + areEqual := true + if containerField.Kind() == podField.Kind() { + switch containerField.Kind() { + case reflect.Slice: + for i, w := range containerField.Interface().([]string) { + areEqual = podField.Interface().([]string)[i] == w + } + case reflect.String: + areEqual = (podField.String() == containerField.String()) + case reflect.Bool: + areEqual = (podField.Bool() == containerField.Bool()) + case reflect.Ptr: + areEqual = (reflect.DeepEqual(podField.Elem().Interface(), containerField.Elem().Interface())) + } + } + assert.True(t, areEqual) + } + } + } +} diff --git a/cmd/podman/machine/init.go b/cmd/podman/machine/init.go index ec44a707d..19f31d1a6 100644 --- a/cmd/podman/machine/init.go +++ b/cmd/podman/machine/init.go @@ -3,6 +3,8 @@ package machine import ( + "fmt" + "github.com/containers/common/pkg/completion" "github.com/containers/podman/v3/cmd/podman/registry" "github.com/containers/podman/v3/pkg/machine" @@ -26,6 +28,7 @@ var ( var ( initOpts = machine.InitOptions{} defaultMachineName = "podman-machine-default" + now bool ) func init() { @@ -61,6 +64,12 @@ func init() { ) _ = initCmd.RegisterFlagCompletionFunc(memoryFlagName, completion.AutocompleteNone) + flags.BoolVar( + &now, + "now", false, + "Start machine now", + ) + ImagePathFlagName := "image-path" flags.StringVar(&initOpts.ImagePath, ImagePathFlagName, cfg.Engine.MachineImage, "Path to qcow image") _ = initCmd.RegisterFlagCompletionFunc(ImagePathFlagName, completion.AutocompleteDefault) @@ -91,5 +100,15 @@ func initMachine(cmd *cobra.Command, args []string) error { if err != nil { return err } - return vm.Init(initOpts) + err = vm.Init(initOpts) + if err != nil { + return err + } + if now { + err = vm.Start(initOpts.Name, machine.StartOptions{}) + if err == nil { + fmt.Printf("Machine %q started successfully\n", initOpts.Name) + } + } + return err } diff --git a/cmd/podman/pods/create.go b/cmd/podman/pods/create.go index 7000c92c8..ca73a8356 100644 --- a/cmd/podman/pods/create.go +++ b/cmd/podman/pods/create.go @@ -132,7 +132,6 @@ func create(cmd *cobra.Command, args []string) error { createOptions.Share = nil } else { // reassign certain optios for lbpod api, these need to be populated in spec - MapOptions() flags := cmd.Flags() infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false) if err != nil { @@ -142,13 +141,11 @@ func create(cmd *cobra.Command, args []string) error { if err != nil { return err } - createOptions.Net = infraOptions.Net createOptions.Share = strings.Split(share, ",") if cmd.Flag("infra-command").Changed { // Only send content to server side if user changed defaults cmdIn, err := cmd.Flags().GetString("infra-command") infraOptions.Entrypoint = &cmdIn - createOptions.InfraCommand = cmdIn if err != nil { return err } @@ -161,6 +158,10 @@ func create(cmd *cobra.Command, args []string) error { return err } } + err = common.ContainerToPodOptions(&infraOptions, &createOptions) + if err != nil { + return err + } } if cmd.Flag("pod-id-file").Changed { @@ -196,8 +197,8 @@ func create(cmd *cobra.Command, args []string) error { if createOptions.Cpus > float64(numCPU) { createOptions.Cpus = float64(numCPU) } - copy := createOptions.CpusetCpus - cpuSet := createOptions.Cpus + copy := infraOptions.CPUSetCPUs + cpuSet := infraOptions.CPUS if cpuSet == 0 { cpuSet = float64(sysinfo.NumCPU()) } @@ -217,10 +218,10 @@ func create(cmd *cobra.Command, args []string) error { if core > int(cpuSet) { if copy == "" { copy = "0-" + strconv.Itoa(int(cpuSet)) - createOptions.CpusetCpus = copy + infraOptions.CPUSetCPUs = copy break } else { - createOptions.CpusetCpus = copy + infraOptions.CPUSetCPUs = copy break } } else if ind != 0 { @@ -229,6 +230,8 @@ func create(cmd *cobra.Command, args []string) error { copy = "" + strconv.Itoa(core) } } + createOptions.Cpus = infraOptions.CPUS + createOptions.CpusetCpus = infraOptions.CPUSetCPUs podSpec := specgen.NewPodSpecGenerator() podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions) if err != nil { @@ -248,11 +251,8 @@ func create(cmd *cobra.Command, args []string) error { } podSpec.InfraImage = imageName if infraOptions.Entrypoint != nil { - createOptions.InfraCommand = *infraOptions.Entrypoint + createOptions.InfraCommand = infraOptions.Entrypoint } - infraOptions.CPUS = createOptions.Cpus - infraOptions.CPUSetCPUs = createOptions.CpusetCpus - infraOptions.PID = createOptions.Pid podSpec.InfraContainerSpec = specgen.NewSpecGenerator(imageName, false) podSpec.InfraContainerSpec.RawImageName = rawImageName podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions @@ -290,13 +290,3 @@ func replacePod(name string) error { } return removePods([]string{name}, rmOptions, false) } - -func MapOptions() { - createOptions.Cpus = infraOptions.CPUS - createOptions.CpusetCpus = infraOptions.CPUSetCPUs - createOptions.Hostname = infraOptions.Hostname - createOptions.InfraConmonPidFile = infraOptions.ConmonPIDFile - createOptions.InfraName = infraOptions.Name - createOptions.Pid = infraOptions.PID - createOptions.Volume = infraOptions.Volume -} diff --git a/docs/source/markdown/podman-machine-init.1.md b/docs/source/markdown/podman-machine-init.1.md index c864a87ef..1236db602 100644 --- a/docs/source/markdown/podman-machine-init.1.md +++ b/docs/source/markdown/podman-machine-init.1.md @@ -47,6 +47,10 @@ Defaults to `testing`. Memory (in MB). +#### **--now** + +Start the virtual machine immediately after it has been initialized. + #### **--help** Print usage statement. diff --git a/docs/source/markdown/podman-rmi.1.md b/docs/source/markdown/podman-rmi.1.md index e34b1964b..4f3ec5541 100644 --- a/docs/source/markdown/podman-rmi.1.md +++ b/docs/source/markdown/podman-rmi.1.md @@ -12,6 +12,8 @@ podman\-rmi - Removes one or more locally stored images Removes one or more locally stored images. Passing an argument _image_ deletes it, along with any of its dangling parent images. A dangling image is an image without a tag and without being referenced by another image. +Note: To delete an image from a remote registry, use the [**skopeo delete**](https://github.com/containers/skopeo/blob/main/docs/skopeo-delete.1.md) command. Some registries do not allow users to delete an image via a CLI remotely. + ## OPTIONS #### **--all**, **-a** @@ -51,7 +53,7 @@ $ podman rmi -a -f **125** The command fails for any other reason ## SEE ALSO -podman(1) +podman(1), skopeo-delete(1) ## HISTORY March 2017, Originally compiled by Dan Walsh <dwalsh@redhat.com> diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index 6ebbfd1f3..dbecea031 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -2050,35 +2050,39 @@ func (c *Container) getHosts() string { } } - // Add gateway entry - var depCtr *Container - netStatus := c.getNetworkStatus() - if c.config.NetNsCtr != "" { - // ignoring the error because there isn't anything to do - depCtr, _ = c.getRootNetNsDepCtr() - } else if len(netStatus) != 0 { - depCtr = c - } - - if depCtr != nil { - for _, status := range depCtr.getNetworkStatus() { - for _, netInt := range status.Interfaces { - for _, netAddress := range netInt.Networks { - if netAddress.Gateway != nil { - hosts += fmt.Sprintf("%s host.containers.internal\n", netAddress.Gateway.String()) + // Add gateway entry if we are not in a machine. If we use podman machine + // the gvproxy dns server will take care of host.containers.internal. + // https://github.com/containers/gvisor-tap-vsock/commit/1108ea45162281046d239047a6db9bc187e64b08 + if !c.runtime.config.Engine.MachineEnabled { + var depCtr *Container + netStatus := c.getNetworkStatus() + if c.config.NetNsCtr != "" { + // ignoring the error because there isn't anything to do + depCtr, _ = c.getRootNetNsDepCtr() + } else if len(netStatus) != 0 { + depCtr = c + } + + if depCtr != nil { + for _, status := range depCtr.getNetworkStatus() { + for _, netInt := range status.Interfaces { + for _, netAddress := range netInt.Networks { + if netAddress.Gateway != nil { + hosts += fmt.Sprintf("%s host.containers.internal\n", netAddress.Gateway.String()) + } } } } - } - } else if c.config.NetMode.IsSlirp4netns() { - gatewayIP, err := GetSlirp4netnsGateway(c.slirp4netnsSubnet) - if err != nil { - logrus.Warn("failed to determine gatewayIP: ", err.Error()) + } else if c.config.NetMode.IsSlirp4netns() { + gatewayIP, err := GetSlirp4netnsGateway(c.slirp4netnsSubnet) + if err != nil { + logrus.Warn("failed to determine gatewayIP: ", err.Error()) + } else { + hosts += fmt.Sprintf("%s host.containers.internal\n", gatewayIP.String()) + } } else { - hosts += fmt.Sprintf("%s host.containers.internal\n", gatewayIP.String()) + logrus.Debug("network configuration does not support host.containers.internal address") } - } else { - logrus.Debug("network configuration does not support host.containers.internal address") } return hosts diff --git a/pkg/api/handlers/types.go b/pkg/api/handlers/types.go index b82c586ea..fedab3bb3 100644 --- a/pkg/api/handlers/types.go +++ b/pkg/api/handlers/types.go @@ -183,7 +183,8 @@ func ImageToImageSummary(l *libimage.Image) (*entities.ImageSummary, error) { } is := entities.ImageSummary{ - ID: l.ID(), + // docker adds sha256: in front of the ID + ID: "sha256:" + l.ID(), ParentId: imageData.Parent, RepoTags: imageData.RepoTags, RepoDigests: imageData.RepoDigests, diff --git a/pkg/domain/entities/pods.go b/pkg/domain/entities/pods.go index a74725c63..88bd3c6ce 100644 --- a/pkg/domain/entities/pods.go +++ b/pkg/domain/entities/pods.go @@ -112,26 +112,27 @@ type PodSpec struct { PodSpecGen specgen.PodSpecGenerator } -// PodCreateOptions provides all possible options for creating a pod and its infra container +// PodCreateOptions provides all possible options for creating a pod and its infra container. +// The JSON tags below are made to match the respective field in ContainerCreateOptions for the purpose of mapping. // swagger:model PodCreateOptions type PodCreateOptions struct { - CGroupParent string - CreateCommand []string - Hostname string - Infra bool - InfraImage string - InfraName string - InfraCommand string - InfraConmonPidFile string - Labels map[string]string - Name string - Net *NetOptions - Share []string - Pid string - Cpus float64 - CpusetCpus string - Userns specgen.Namespace - Volume []string + CGroupParent string `json:"cgroup_parent,omitempty"` + CreateCommand []string `json:"create_command,omitempty"` + Hostname string `json:"hostname,omitempty"` + Infra bool `json:"infra,omitempty"` + InfraImage string `json:"infra_image,omitempty"` + InfraName string `json:"container_name,omitempty"` + InfraCommand *string `json:"container_command,omitempty"` + InfraConmonPidFile string `json:"container_conmon_pidfile,omitempty"` + Labels map[string]string `json:"labels,omitempty"` + Name string `json:"name,omitempty"` + Net *NetOptions `json:"net,omitempty"` + Share []string `json:"share,omitempty"` + Pid string `json:"pid,omitempty"` + Cpus float64 `json:"cpus,omitempty"` + CpusetCpus string `json:"cpuset_cpus,omitempty"` + Userns specgen.Namespace `json:"-"` + Volume []string `json:"volume,omitempty"` } // PodLogsOptions describes the options to extract pod logs. @@ -152,16 +153,16 @@ type ContainerCreateOptions struct { CapDrop []string CgroupNS string CGroupsMode string - CGroupParent string + CGroupParent string `json:"cgroup_parent,omitempty"` CIDFile string - ConmonPIDFile string + ConmonPIDFile string `json:"container_conmon_pidfile,omitempty"` CPUPeriod uint64 CPUQuota int64 CPURTPeriod uint64 CPURTRuntime int64 CPUShares uint64 - CPUS float64 - CPUSetCPUs string + CPUS float64 `json:"cpus,omitempty"` + CPUSetCPUs string `json:"cpuset_cpus,omitempty"` CPUSetMems string Devices []string DeviceCGroupRule []string @@ -169,7 +170,7 @@ type ContainerCreateOptions struct { DeviceReadIOPs []string DeviceWriteBPs []string DeviceWriteIOPs []string - Entrypoint *string + Entrypoint *string `json:"container_command,omitempty"` Env []string EnvHost bool EnvFile []string @@ -181,7 +182,7 @@ type ContainerCreateOptions struct { HealthRetries uint HealthStartPeriod string HealthTimeout string - Hostname string + Hostname string `json:"hostname,omitempty"` HTTPProxy bool ImageVolume string Init bool @@ -198,14 +199,14 @@ type ContainerCreateOptions struct { MemoryReservation string MemorySwap string MemorySwappiness int64 - Name string + Name string `json:"container_name,omitempty"` NoHealthCheck bool OOMKillDisable bool OOMScoreAdj int Arch string OS string Variant string - PID string + PID string `json:"pid,omitempty"` PIDsLimit *int64 Platform string Pod string @@ -244,17 +245,17 @@ type ContainerCreateOptions struct { UIDMap []string Ulimit []string User string - UserNS string + UserNS string `json:"-"` UTS string Mount []string - Volume []string + Volume []string `json:"volume,omitempty"` VolumesFrom []string Workdir string SeccompPolicy string PidFile string IsInfra bool - Net *NetOptions + Net *NetOptions `json:"net,omitempty"` CgroupConf []string } @@ -295,8 +296,8 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod s.Hostname = p.Hostname s.Labels = p.Labels s.NoInfra = !p.Infra - if len(p.InfraCommand) > 0 { - s.InfraCommand = strings.Split(p.InfraCommand, " ") + if p.InfraCommand != nil && len(*p.InfraCommand) > 0 { + s.InfraCommand = strings.Split(*p.InfraCommand, " ") } if len(p.InfraConmonPidFile) > 0 { s.InfraConmonPidFile = p.InfraConmonPidFile diff --git a/test/apiv2/python/rest_api/test_v2_0_0_image.py b/test/apiv2/python/rest_api/test_v2_0_0_image.py index bcacaa935..58d03b149 100644 --- a/test/apiv2/python/rest_api/test_v2_0_0_image.py +++ b/test/apiv2/python/rest_api/test_v2_0_0_image.py @@ -32,6 +32,9 @@ class ImageTestCase(APITestCase): for k in required_keys: self.assertIn(k, item) + # Id should be prefixed with sha256: (#11645) + self.assertIn("sha256:",item['Id']) + def test_inspect(self): r = requests.get(self.podman_url + "/v1.40/images/alpine/json") self.assertEqual(r.status_code, 200, r.text) @@ -59,6 +62,8 @@ class ImageTestCase(APITestCase): for item in required_keys: self.assertIn(item, image) _ = parse(image["Created"]) + # Id should be prefixed with sha256: (#11645) + self.assertIn("sha256:",image['Id']) def test_delete(self): r = requests.delete(self.podman_url + "/v1.40/images/alpine?force=true") |