Created MapOptions for PodCreate

MapOptions take the pod and container create options, assigning matching values from infra
back to the pod for the Libpod API. This function, unlike the previous one, does not require any
manual additions when new options are added since it uses the structs JSON tags, this is a more modular approach.

Signed-off-by: cdoern <cdoern@redhat.com>
This commit is contained in:
cdoern
2021-09-15 15:08:42 -04:00
parent 5f41ffdd19
commit cb077c968d
4 changed files with 108 additions and 52 deletions
cmd/podman
pkg/domain/entities

@ -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()

@ -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)
}
}
}
}

@ -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
}

@ -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