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

View File

@ -15,6 +15,18 @@ const sizeWithUnitFormat = "(format: `<number>[<unit>]`, where unit = b (bytes),
var containerConfig = registry.PodmanConfig() 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) { func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions, isInfra bool) {
createFlags := cmd.Flags() createFlags := cmd.Flags()

View File

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

View File

@ -132,7 +132,6 @@ func create(cmd *cobra.Command, args []string) error {
createOptions.Share = nil createOptions.Share = nil
} else { } else {
// reassign certain optios for lbpod api, these need to be populated in spec // reassign certain optios for lbpod api, these need to be populated in spec
MapOptions()
flags := cmd.Flags() flags := cmd.Flags()
infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false) infraOptions.Net, err = common.NetFlagsToNetOptions(nil, *flags, false)
if err != nil { if err != nil {
@ -142,13 +141,11 @@ func create(cmd *cobra.Command, args []string) error {
if err != nil { if err != nil {
return err return err
} }
createOptions.Net = infraOptions.Net
createOptions.Share = strings.Split(share, ",") createOptions.Share = strings.Split(share, ",")
if cmd.Flag("infra-command").Changed { if cmd.Flag("infra-command").Changed {
// Only send content to server side if user changed defaults // Only send content to server side if user changed defaults
cmdIn, err := cmd.Flags().GetString("infra-command") cmdIn, err := cmd.Flags().GetString("infra-command")
infraOptions.Entrypoint = &cmdIn infraOptions.Entrypoint = &cmdIn
createOptions.InfraCommand = cmdIn
if err != nil { if err != nil {
return err return err
} }
@ -161,6 +158,10 @@ func create(cmd *cobra.Command, args []string) error {
return err return err
} }
} }
err = common.ContainerToPodOptions(&infraOptions, &createOptions)
if err != nil {
return err
}
} }
if cmd.Flag("pod-id-file").Changed { if cmd.Flag("pod-id-file").Changed {
@ -196,8 +197,8 @@ func create(cmd *cobra.Command, args []string) error {
if createOptions.Cpus > float64(numCPU) { if createOptions.Cpus > float64(numCPU) {
createOptions.Cpus = float64(numCPU) createOptions.Cpus = float64(numCPU)
} }
copy := createOptions.CpusetCpus copy := infraOptions.CPUSetCPUs
cpuSet := createOptions.Cpus cpuSet := infraOptions.CPUS
if cpuSet == 0 { if cpuSet == 0 {
cpuSet = float64(sysinfo.NumCPU()) cpuSet = float64(sysinfo.NumCPU())
} }
@ -217,10 +218,10 @@ func create(cmd *cobra.Command, args []string) error {
if core > int(cpuSet) { if core > int(cpuSet) {
if copy == "" { if copy == "" {
copy = "0-" + strconv.Itoa(int(cpuSet)) copy = "0-" + strconv.Itoa(int(cpuSet))
createOptions.CpusetCpus = copy infraOptions.CPUSetCPUs = copy
break break
} else { } else {
createOptions.CpusetCpus = copy infraOptions.CPUSetCPUs = copy
break break
} }
} else if ind != 0 { } else if ind != 0 {
@ -229,6 +230,8 @@ func create(cmd *cobra.Command, args []string) error {
copy = "" + strconv.Itoa(core) copy = "" + strconv.Itoa(core)
} }
} }
createOptions.Cpus = infraOptions.CPUS
createOptions.CpusetCpus = infraOptions.CPUSetCPUs
podSpec := specgen.NewPodSpecGenerator() podSpec := specgen.NewPodSpecGenerator()
podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions) podSpec, err = entities.ToPodSpecGen(*podSpec, &createOptions)
if err != nil { if err != nil {
@ -248,11 +251,8 @@ func create(cmd *cobra.Command, args []string) error {
} }
podSpec.InfraImage = imageName podSpec.InfraImage = imageName
if infraOptions.Entrypoint != nil { 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 = specgen.NewSpecGenerator(imageName, false)
podSpec.InfraContainerSpec.RawImageName = rawImageName podSpec.InfraContainerSpec.RawImageName = rawImageName
podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions podSpec.InfraContainerSpec.NetworkOptions = podSpec.NetworkOptions
@ -290,13 +290,3 @@ func replacePod(name string) error {
} }
return removePods([]string{name}, rmOptions, false) 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
}

View File

@ -112,26 +112,27 @@ type PodSpec struct {
PodSpecGen specgen.PodSpecGenerator 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 // swagger:model PodCreateOptions
type PodCreateOptions struct { type PodCreateOptions struct {
CGroupParent string CGroupParent string `json:"cgroup_parent,omitempty"`
CreateCommand []string CreateCommand []string `json:"create_command,omitempty"`
Hostname string Hostname string `json:"hostname,omitempty"`
Infra bool Infra bool `json:"infra,omitempty"`
InfraImage string InfraImage string `json:"infra_image,omitempty"`
InfraName string InfraName string `json:"container_name,omitempty"`
InfraCommand string InfraCommand *string `json:"container_command,omitempty"`
InfraConmonPidFile string InfraConmonPidFile string `json:"container_conmon_pidfile,omitempty"`
Labels map[string]string Labels map[string]string `json:"labels,omitempty"`
Name string Name string `json:"name,omitempty"`
Net *NetOptions Net *NetOptions `json:"net,omitempty"`
Share []string Share []string `json:"share,omitempty"`
Pid string Pid string `json:"pid,omitempty"`
Cpus float64 Cpus float64 `json:"cpus,omitempty"`
CpusetCpus string CpusetCpus string `json:"cpuset_cpus,omitempty"`
Userns specgen.Namespace Userns specgen.Namespace `json:"-"`
Volume []string Volume []string `json:"volume,omitempty"`
} }
// PodLogsOptions describes the options to extract pod logs. // PodLogsOptions describes the options to extract pod logs.
@ -152,16 +153,16 @@ type ContainerCreateOptions struct {
CapDrop []string CapDrop []string
CgroupNS string CgroupNS string
CGroupsMode string CGroupsMode string
CGroupParent string CGroupParent string `json:"cgroup_parent,omitempty"`
CIDFile string CIDFile string
ConmonPIDFile string ConmonPIDFile string `json:"container_conmon_pidfile,omitempty"`
CPUPeriod uint64 CPUPeriod uint64
CPUQuota int64 CPUQuota int64
CPURTPeriod uint64 CPURTPeriod uint64
CPURTRuntime int64 CPURTRuntime int64
CPUShares uint64 CPUShares uint64
CPUS float64 CPUS float64 `json:"cpus,omitempty"`
CPUSetCPUs string CPUSetCPUs string `json:"cpuset_cpus,omitempty"`
CPUSetMems string CPUSetMems string
Devices []string Devices []string
DeviceCGroupRule []string DeviceCGroupRule []string
@ -169,7 +170,7 @@ type ContainerCreateOptions struct {
DeviceReadIOPs []string DeviceReadIOPs []string
DeviceWriteBPs []string DeviceWriteBPs []string
DeviceWriteIOPs []string DeviceWriteIOPs []string
Entrypoint *string Entrypoint *string `json:"container_command,omitempty"`
Env []string Env []string
EnvHost bool EnvHost bool
EnvFile []string EnvFile []string
@ -181,7 +182,7 @@ type ContainerCreateOptions struct {
HealthRetries uint HealthRetries uint
HealthStartPeriod string HealthStartPeriod string
HealthTimeout string HealthTimeout string
Hostname string Hostname string `json:"hostname,omitempty"`
HTTPProxy bool HTTPProxy bool
ImageVolume string ImageVolume string
Init bool Init bool
@ -198,14 +199,14 @@ type ContainerCreateOptions struct {
MemoryReservation string MemoryReservation string
MemorySwap string MemorySwap string
MemorySwappiness int64 MemorySwappiness int64
Name string Name string `json:"container_name,omitempty"`
NoHealthCheck bool NoHealthCheck bool
OOMKillDisable bool OOMKillDisable bool
OOMScoreAdj int OOMScoreAdj int
Arch string Arch string
OS string OS string
Variant string Variant string
PID string PID string `json:"pid,omitempty"`
PIDsLimit *int64 PIDsLimit *int64
Platform string Platform string
Pod string Pod string
@ -244,17 +245,17 @@ type ContainerCreateOptions struct {
UIDMap []string UIDMap []string
Ulimit []string Ulimit []string
User string User string
UserNS string UserNS string `json:"-"`
UTS string UTS string
Mount []string Mount []string
Volume []string Volume []string `json:"volume,omitempty"`
VolumesFrom []string VolumesFrom []string
Workdir string Workdir string
SeccompPolicy string SeccompPolicy string
PidFile string PidFile string
IsInfra bool IsInfra bool
Net *NetOptions Net *NetOptions `json:"net,omitempty"`
CgroupConf []string CgroupConf []string
} }
@ -295,8 +296,8 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod
s.Hostname = p.Hostname s.Hostname = p.Hostname
s.Labels = p.Labels s.Labels = p.Labels
s.NoInfra = !p.Infra s.NoInfra = !p.Infra
if len(p.InfraCommand) > 0 { if p.InfraCommand != nil && len(*p.InfraCommand) > 0 {
s.InfraCommand = strings.Split(p.InfraCommand, " ") s.InfraCommand = strings.Split(*p.InfraCommand, " ")
} }
if len(p.InfraConmonPidFile) > 0 { if len(p.InfraConmonPidFile) > 0 {
s.InfraConmonPidFile = p.InfraConmonPidFile s.InfraConmonPidFile = p.InfraConmonPidFile