diff options
Diffstat (limited to 'pkg/specgen/generate')
-rw-r--r-- | pkg/specgen/generate/container.go | 114 | ||||
-rw-r--r-- | pkg/specgen/generate/container_create.go | 3 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 10 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/play_test.go | 2 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/volume.go | 56 | ||||
-rw-r--r-- | pkg/specgen/generate/oci.go | 35 | ||||
-rw-r--r-- | pkg/specgen/generate/pod_create.go | 37 |
7 files changed, 188 insertions, 69 deletions
diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 2248c9235..9bb7caace 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -302,60 +302,6 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat return warnings, nil } -// FinishThrottleDevices takes the temporary representation of the throttle -// devices in the specgen and looks up the major and major minors. it then -// sets the throttle devices proper in the specgen -func FinishThrottleDevices(s *specgen.SpecGenerator) error { - if bps := s.ThrottleReadBpsDevice; len(bps) > 0 { - for k, v := range bps { - statT := unix.Stat_t{} - if err := unix.Stat(k, &statT); err != nil { - return err - } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert - if s.ResourceLimits.BlockIO == nil { - s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO) - } - s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v) - } - } - if bps := s.ThrottleWriteBpsDevice; len(bps) > 0 { - for k, v := range bps { - statT := unix.Stat_t{} - if err := unix.Stat(k, &statT); err != nil { - return err - } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert - s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v) - } - } - if iops := s.ThrottleReadIOPSDevice; len(iops) > 0 { - for k, v := range iops { - statT := unix.Stat_t{} - if err := unix.Stat(k, &statT); err != nil { - return err - } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert - s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v) - } - } - if iops := s.ThrottleWriteIOPSDevice; len(iops) > 0 { - for k, v := range iops { - statT := unix.Stat_t{} - if err := unix.Stat(k, &statT); err != nil { - return err - } - v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert - v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert - s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v) - } - } - return nil -} - // ConfigToSpec takes a completed container config and converts it back into a specgenerator for purposes of cloning an existing container func ConfigToSpec(rt *libpod.Runtime, specg *specgen.SpecGenerator, contaierID string) (*libpod.Container, *libpod.InfraInherit, error) { c, err := rt.LookupContainer(contaierID) @@ -540,3 +486,63 @@ func mapSecurityConfig(c *libpod.ContainerConfig, s *specgen.SpecGenerator) { s.Groups = c.Groups s.HostUsers = c.HostUsers } + +// FinishThrottleDevices takes the temporary representation of the throttle +// devices in the specgen and looks up the major and major minors. it then +// sets the throttle devices proper in the specgen +func FinishThrottleDevices(s *specgen.SpecGenerator) error { + if s.ResourceLimits == nil { + s.ResourceLimits = &spec.LinuxResources{} + } + if s.ResourceLimits.BlockIO == nil { + s.ResourceLimits.BlockIO = &spec.LinuxBlockIO{} + } + if bps := s.ThrottleReadBpsDevice; len(bps) > 0 { + for k, v := range bps { + statT := unix.Stat_t{} + if err := unix.Stat(k, &statT); err != nil { + return fmt.Errorf("could not parse throttle device at %s: %w", k, err) + } + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert + if s.ResourceLimits.BlockIO == nil { + s.ResourceLimits.BlockIO = new(spec.LinuxBlockIO) + } + s.ResourceLimits.BlockIO.ThrottleReadBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleReadBpsDevice, v) + } + } + if bps := s.ThrottleWriteBpsDevice; len(bps) > 0 { + for k, v := range bps { + statT := unix.Stat_t{} + if err := unix.Stat(k, &statT); err != nil { + return fmt.Errorf("could not parse throttle device at %s: %w", k, err) + } + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert + s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteBpsDevice, v) + } + } + if iops := s.ThrottleReadIOPSDevice; len(iops) > 0 { + for k, v := range iops { + statT := unix.Stat_t{} + if err := unix.Stat(k, &statT); err != nil { + return fmt.Errorf("could not parse throttle device at %s: %w", k, err) + } + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert + s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleReadIOPSDevice, v) + } + } + if iops := s.ThrottleWriteIOPSDevice; len(iops) > 0 { + for k, v := range iops { + statT := unix.Stat_t{} + if err := unix.Stat(k, &statT); err != nil { + return fmt.Errorf("could not parse throttle device at %s: %w", k, err) + } + v.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert + v.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert + s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice = append(s.ResourceLimits.BlockIO.ThrottleWriteIOPSDevice, v) + } + } + return nil +} diff --git a/pkg/specgen/generate/container_create.go b/pkg/specgen/generate/container_create.go index 51d290bb4..389900820 100644 --- a/pkg/specgen/generate/container_create.go +++ b/pkg/specgen/generate/container_create.go @@ -55,9 +55,6 @@ func MakeContainer(ctx context.Context, rt *libpod.Runtime, s *specgen.SpecGener } } - if err := FinishThrottleDevices(s); err != nil { - return nil, nil, nil, err - } // Set defaults for unset namespaces if s.PidNS.IsDefault() { defaultNS, err := GetDefaultNamespaceMode("pid", rtc, pod) diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index 454a1e1d0..e9abf419b 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -398,6 +398,16 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener Type: "b", } s.Devices = append(s.Devices, device) + case KubeVolumeTypeSecret: + // in podman play kube we need to add these secrets as volumes rather than as + // specgen.Secrets. Adding them as volumes allows for all key: value pairs to be mounted + secretVolume := specgen.NamedVolume{ + Dest: volume.MountPath, + Name: volumeSource.Source, + Options: options, + } + + s.Volumes = append(s.Volumes, &secretVolume) default: return nil, errors.New("unsupported volume source type") } diff --git a/pkg/specgen/generate/kube/play_test.go b/pkg/specgen/generate/kube/play_test.go index 466dab610..470c0c39c 100644 --- a/pkg/specgen/generate/kube/play_test.go +++ b/pkg/specgen/generate/kube/play_test.go @@ -28,7 +28,7 @@ func createSecrets(t *testing.T, d string) *secrets.SecretsManager { data, err := json.Marshal(s.Data) assert.NoError(t, err) - _, err = secretsManager.Store(s.ObjectMeta.Name, data, driver, driverOpts) + _, err = secretsManager.Store(s.ObjectMeta.Name, data, driver, driverOpts, nil) assert.NoError(t, err) } diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go index f5c0c241d..c12adadd8 100644 --- a/pkg/specgen/generate/kube/volume.go +++ b/pkg/specgen/generate/kube/volume.go @@ -6,9 +6,13 @@ import ( "os" "github.com/containers/common/pkg/parse" + "github.com/containers/common/pkg/secrets" "github.com/containers/podman/v4/libpod" v1 "github.com/containers/podman/v4/pkg/k8s.io/api/core/v1" + metav1 "github.com/containers/podman/v4/pkg/k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" ) const ( @@ -27,6 +31,7 @@ const ( KubeVolumeTypeConfigMap KubeVolumeTypeBlockDevice KubeVolumeTypeCharDevice + KubeVolumeTypeSecret ) //nolint:revive @@ -125,6 +130,49 @@ func VolumeFromHostPath(hostPath *v1.HostPathVolumeSource) (*KubeVolume, error) }, nil } +// VolumeFromSecret creates a new kube volume from a kube secret. +func VolumeFromSecret(secretSource *v1.SecretVolumeSource, secretsManager *secrets.SecretsManager) (*KubeVolume, error) { + // returns a byte array of a kube secret data, meaning this needs to go into a string map + _, secretByte, err := secretsManager.LookupSecretData(secretSource.SecretName) + if err != nil { + return nil, err + } + + // unmarshaling directly into a v1.secret creates type mismatch errors + // use a more friendly, string only secret struct. + type KubeSecret struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Immutable *bool `json:"immutable,omitempty"` + Data map[string]string `json:"data,omitempty"` + // +optional + StringData map[string]string `json:"stringData,omitempty"` + // +optional + Type string `json:"type,omitempty"` + } + + data := &KubeSecret{} + + err = yaml.Unmarshal(secretByte, data) + if err != nil { + return nil, err + } + + kv := &KubeVolume{} + kv.Type = KubeVolumeTypeSecret + kv.Source = secretSource.SecretName + kv.Optional = *secretSource.Optional + kv.Items = make(map[string]string) + + // add key: value pairs to the items array + for key, entry := range data.Data { + kv.Items[key] = entry + } + return kv, nil +} + // Create a KubeVolume from a PersistentVolumeClaimVolumeSource func VolumeFromPersistentVolumeClaim(claim *v1.PersistentVolumeClaimVolumeSource) (*KubeVolume, error) { return &KubeVolume{ @@ -172,7 +220,7 @@ func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, config } // Create a KubeVolume from one of the supported VolumeSource -func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap) (*KubeVolume, error) { +func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager) (*KubeVolume, error) { switch { case volumeSource.HostPath != nil: return VolumeFromHostPath(volumeSource.HostPath) @@ -180,17 +228,19 @@ func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap) ( return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim) case volumeSource.ConfigMap != nil: return VolumeFromConfigMap(volumeSource.ConfigMap, configMaps) + case volumeSource.Secret != nil: + return VolumeFromSecret(volumeSource.Secret, secretsManager) default: return nil, errors.New("HostPath, ConfigMap, and PersistentVolumeClaim are currently the only supported VolumeSource") } } // Create a map of volume name to KubeVolume -func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap) (map[string]*KubeVolume, error) { +func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap, secretsManager *secrets.SecretsManager) (map[string]*KubeVolume, error) { volumes := make(map[string]*KubeVolume) for _, specVolume := range specVolumes { - volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps) + volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps, secretsManager) if err != nil { return nil, fmt.Errorf("failed to create volume %q: %w", specVolume.Name, err) } diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index bb5f2d0ec..f59fe1011 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -309,6 +309,17 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt } g.Config.Linux.Resources = s.ResourceLimits } + + weightDevices, err := WeightDevices(s.WeightDevice) + if err != nil { + return nil, err + } + if len(weightDevices) > 0 { + for _, dev := range weightDevices { + g.AddLinuxResourcesBlockIOWeightDevice(dev.Major, dev.Minor, *dev.Weight) + } + } + // Devices // set the default rule at the beginning of device configuration if !inUserNS && !s.Privileged { @@ -345,14 +356,6 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt } } - for k, v := range s.WeightDevice { - statT := unix.Stat_t{} - if err := unix.Stat(k, &statT); err != nil { - return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err) - } - g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) //nolint: unconvert - } - BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g) g.ClearProcessEnv() @@ -413,3 +416,19 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt return configSpec, nil } + +func WeightDevices(wtDevices map[string]spec.LinuxWeightDevice) ([]spec.LinuxWeightDevice, error) { + devs := []spec.LinuxWeightDevice{} + for k, v := range wtDevices { + statT := unix.Stat_t{} + if err := unix.Stat(k, &statT); err != nil { + return nil, fmt.Errorf("failed to inspect '%s' in --blkio-weight-device: %w", k, err) + } + dev := new(spec.LinuxWeightDevice) + dev.Major = (int64(unix.Major(uint64(statT.Rdev)))) //nolint: unconvert + dev.Minor = (int64(unix.Minor(uint64(statT.Rdev)))) //nolint: unconvert + dev.Weight = v.Weight + devs = append(devs, *dev) + } + return devs, nil +} diff --git a/pkg/specgen/generate/pod_create.go b/pkg/specgen/generate/pod_create.go index 212d613fe..4e6362c9b 100644 --- a/pkg/specgen/generate/pod_create.go +++ b/pkg/specgen/generate/pod_create.go @@ -13,6 +13,7 @@ import ( "github.com/containers/podman/v4/pkg/domain/entities" "github.com/containers/podman/v4/pkg/specgen" "github.com/containers/podman/v4/pkg/specgenutil" + "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" ) @@ -21,6 +22,10 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) { return nil, err } + if p.PodSpecGen.ResourceLimits == nil { + p.PodSpecGen.ResourceLimits = &specs.LinuxResources{} + } + if !p.PodSpecGen.NoInfra { imageName, err := PullOrBuildInfraImage(rt, p.PodSpecGen.InfraImage) if err != nil { @@ -38,10 +43,33 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) { } } + if !p.PodSpecGen.NoInfra { + err := FinishThrottleDevices(p.PodSpecGen.InfraContainerSpec) + if err != nil { + return nil, err + } + if p.PodSpecGen.InfraContainerSpec.ResourceLimits.BlockIO != nil { + p.PodSpecGen.ResourceLimits.BlockIO = p.PodSpecGen.InfraContainerSpec.ResourceLimits.BlockIO + } + + weightDevices, err := WeightDevices(p.PodSpecGen.InfraContainerSpec.WeightDevice) + if err != nil { + return nil, err + } + + if p.PodSpecGen.ResourceLimits != nil && len(weightDevices) > 0 { + if p.PodSpecGen.ResourceLimits.BlockIO == nil { + p.PodSpecGen.ResourceLimits.BlockIO = &specs.LinuxBlockIO{} + } + p.PodSpecGen.ResourceLimits.BlockIO.WeightDevice = weightDevices + } + } + options, err := createPodOptions(&p.PodSpecGen) if err != nil { return nil, err } + pod, err := rt.NewPod(context.Background(), p.PodSpecGen, options...) if err != nil { return nil, err @@ -55,6 +83,11 @@ func MakePod(p *entities.PodSpec, rt *libpod.Runtime) (*libpod.Pod, error) { return nil, err } p.PodSpecGen.InfraContainerSpec.User = "" // infraSpec user will get incorrectly assigned via the container creation process, overwrite here + // infra's resource limits are used as a parsing tool, + // we do not want infra to get these resources in its cgroup + // make sure of that here. + p.PodSpecGen.InfraContainerSpec.ResourceLimits = nil + p.PodSpecGen.InfraContainerSpec.WeightDevice = nil rtSpec, spec, opts, err := MakeContainer(context.Background(), rt, p.PodSpecGen.InfraContainerSpec, false, nil) if err != nil { return nil, err @@ -122,6 +155,10 @@ func createPodOptions(p *specgen.PodSpecGenerator) ([]libpod.PodCreateOption, er options = append(options, libpod.WithPodHostname(p.Hostname)) } + if p.ResourceLimits != nil { + options = append(options, libpod.WithPodResources(*p.ResourceLimits)) + } + options = append(options, libpod.WithPodExitPolicy(p.ExitPolicy)) return options, nil |