diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/api/handlers/compat/images.go | 12 | ||||
-rw-r--r-- | pkg/api/handlers/compat/images_push.go | 10 | ||||
-rw-r--r-- | pkg/api/handlers/libpod/generate.go | 2 | ||||
-rw-r--r-- | pkg/api/server/register_generate.go | 5 | ||||
-rw-r--r-- | pkg/bindings/generate/types.go | 2 | ||||
-rw-r--r-- | pkg/bindings/generate/types_systemd_options.go | 15 | ||||
-rw-r--r-- | pkg/bindings/images/build.go | 5 | ||||
-rw-r--r-- | pkg/domain/entities/generate.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/images.go | 2 | ||||
-rw-r--r-- | pkg/domain/infra/abi/generate.go | 12 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 17 | ||||
-rw-r--r-- | pkg/domain/infra/abi/play.go | 71 | ||||
-rw-r--r-- | pkg/domain/infra/abi/system.go | 7 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/generate.go | 3 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/kube.go | 12 | ||||
-rw-r--r-- | pkg/specgen/generate/kube/volume.go | 64 | ||||
-rw-r--r-- | pkg/specgen/generate/oci.go | 8 | ||||
-rw-r--r-- | pkg/specgenutil/specgen.go | 17 | ||||
-rw-r--r-- | pkg/systemd/generate/pods.go | 9 | ||||
-rw-r--r-- | pkg/systemd/generate/pods_test.go | 46 |
20 files changed, 276 insertions, 45 deletions
diff --git a/pkg/api/handlers/compat/images.go b/pkg/api/handlers/compat/images.go index af8b6b63d..4533fddeb 100644 --- a/pkg/api/handlers/compat/images.go +++ b/pkg/api/handlers/compat/images.go @@ -409,14 +409,20 @@ func GetImages(w http.ResponseWriter, r *http.Request) { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed get images")) return } - var summaries = make([]*entities.ImageSummary, len(images)) - for j, img := range images { + + summaries := make([]*entities.ImageSummary, 0, len(images)) + for _, img := range images { + // If the image is a manifest list, extract as much as we can. + if isML, _ := img.IsManifestList(r.Context()); isML { + continue + } + is, err := handlers.ImageToImageSummary(img) if err != nil { utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "Failed transform image summaries")) return } - summaries[j] = is + summaries = append(summaries, is) } utils.WriteResponse(w, http.StatusOK, summaries) } diff --git a/pkg/api/handlers/compat/images_push.go b/pkg/api/handlers/compat/images_push.go index 5ecb429ae..3a84b5799 100644 --- a/pkg/api/handlers/compat/images_push.go +++ b/pkg/api/handlers/compat/images_push.go @@ -74,10 +74,16 @@ func PushImage(w http.ResponseWriter, r *http.Request) { return } imageName = possiblyNormalizedName - if _, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, nil); err != nil { + localImage, _, err := runtime.LibimageRuntime().LookupImage(possiblyNormalizedName, nil) + if err != nil { utils.ImageNotFound(w, imageName, errors.Wrapf(err, "failed to find image %s", imageName)) return } + rawManifest, _, err := localImage.Manifest(r.Context()) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusBadRequest, err) + return + } authconf, authfile, key, err := auth.GetCredentials(r) if err != nil { @@ -196,7 +202,7 @@ loop: // break out of for/select infinite loop if tag == "" { tag = "latest" } - report.Status = fmt.Sprintf("%s: digest: %s", tag, string(digestBytes)) + report.Status = fmt.Sprintf("%s: digest: %s size: %d", tag, string(digestBytes), len(rawManifest)) if err := enc.Encode(report); err != nil { logrus.Warnf("Failed to json encode error %q", err.Error()) } diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go index 1411c680e..88fd69d45 100644 --- a/pkg/api/handlers/libpod/generate.go +++ b/pkg/api/handlers/libpod/generate.go @@ -22,6 +22,7 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) { NoHeader bool `schema:"noHeader"` TemplateUnitFile bool `schema:"templateUnitFile"` RestartPolicy *string `schema:"restartPolicy"` + RestartSec uint `schema:"restartSec"` StopTimeout uint `schema:"stopTimeout"` StartTimeout uint `schema:"startTimeout"` ContainerPrefix string `schema:"containerPrefix"` @@ -53,6 +54,7 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) { ContainerPrefix: query.ContainerPrefix, PodPrefix: query.PodPrefix, Separator: query.Separator, + RestartSec: &query.RestartSec, } report, err := containerEngine.GenerateSystemd(r.Context(), utils.GetName(r), options) diff --git a/pkg/api/server/register_generate.go b/pkg/api/server/register_generate.go index 0e36394cf..65340bf56 100644 --- a/pkg/api/server/register_generate.go +++ b/pkg/api/server/register_generate.go @@ -67,6 +67,11 @@ func (s *APIServer) registerGenerateHandlers(r *mux.Router) error { // type: string // default: "-" // description: Systemd unit name separator between name/id and prefix. + // - in: query + // name: restartSec + // type: integer + // default: 0 + // description: Configures the time to sleep before restarting a service. // produces: // - application/json // responses: diff --git a/pkg/bindings/generate/types.go b/pkg/bindings/generate/types.go index 092474e4a..ce560c547 100644 --- a/pkg/bindings/generate/types.go +++ b/pkg/bindings/generate/types.go @@ -20,6 +20,8 @@ type SystemdOptions struct { TemplateUnitFile *bool // RestartPolicy - systemd restart policy. RestartPolicy *string + // RestartSec - systemd service restartsec. Configures the time to sleep before restarting a service. + RestartSec *uint // StartTimeout - time when starting the container. StartTimeout *uint // StopTimeout - time when stopping the container. diff --git a/pkg/bindings/generate/types_systemd_options.go b/pkg/bindings/generate/types_systemd_options.go index d60f1d70e..504d4da7f 100644 --- a/pkg/bindings/generate/types_systemd_options.go +++ b/pkg/bindings/generate/types_systemd_options.go @@ -92,6 +92,21 @@ func (o *SystemdOptions) GetRestartPolicy() string { return *o.RestartPolicy } +// WithRestartSec set field RestartSec to given value +func (o *SystemdOptions) WithRestartSec(value uint) *SystemdOptions { + o.RestartSec = &value + return o +} + +// GetRestartSec returns value of field RestartSec +func (o *SystemdOptions) GetRestartSec() uint { + if o.RestartSec == nil { + var z uint + return z + } + return *o.RestartSec +} + // WithStartTimeout set field StartTimeout to given value func (o *SystemdOptions) WithStartTimeout(value uint) *SystemdOptions { o.StartTimeout = &value diff --git a/pkg/bindings/images/build.go b/pkg/bindings/images/build.go index 25770fdfc..be6e5ab55 100644 --- a/pkg/bindings/images/build.go +++ b/pkg/bindings/images/build.go @@ -346,6 +346,11 @@ func Build(ctx context.Context, containerFiles []string, options entities.BuildO } c = tmpFile.Name() } + cfDir := filepath.Dir(c) + if absDir, err := filepath.EvalSymlinks(cfDir); err == nil { + name := filepath.ToSlash(strings.TrimPrefix(c, cfDir+string(filepath.Separator))) + c = filepath.Join(absDir, name) + } containerfile, err := filepath.Abs(c) if err != nil { logrus.Errorf("Cannot find absolute path of %v: %v", c, err) diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go index 7e80e5d2d..e431a70af 100644 --- a/pkg/domain/entities/generate.go +++ b/pkg/domain/entities/generate.go @@ -10,6 +10,8 @@ type GenerateSystemdOptions struct { New bool // RestartPolicy - systemd restart policy. RestartPolicy *string + // RestartSec - systemd service restartsec. Configures the time to sleep before restarting a service. + RestartSec *uint // StartTimeout - time when starting the container. StartTimeout *uint // StopTimeout - time when stopping the container. diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index 54f7b5d45..8b0fd2b85 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -208,6 +208,8 @@ type ImagePushOptions struct { SkipTLSVerify types.OptionalBool // Progress to get progress notifications Progress chan types.ProgressProperties + // CompressionFormat is the format to use for the compression of the blobs + CompressionFormat string } // ImageSearchOptions are the arguments for searching images. diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 0defa1923..68bb351bf 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -139,7 +139,11 @@ func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrIDs []string, podContent = append(podContent, b) if options.Service { - b, err := generateKubeYAML(libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{})) + svc, err := libpod.GenerateKubeServiceFromV1Pod(po, []k8sAPI.ServicePort{}) + if err != nil { + return nil, err + } + b, err := generateKubeYAML(svc) if err != nil { return nil, err } @@ -177,7 +181,11 @@ func getKubePods(ctx context.Context, pods []*libpod.Pod, getService bool) ([][] pos = append(pos, b) if getService { - b, err := generateKubeYAML(libpod.GenerateKubeServiceFromV1Pod(po, sp)) + svc, err := libpod.GenerateKubeServiceFromV1Pod(po, sp) + if err != nil { + return nil, nil, err + } + b, err := generateKubeYAML(svc) if err != nil { return nil, nil, err } diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 8b44b869a..4346182d6 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -18,6 +18,7 @@ import ( "github.com/containers/image/v5/docker" "github.com/containers/image/v5/docker/reference" "github.com/containers/image/v5/manifest" + "github.com/containers/image/v5/pkg/compression" "github.com/containers/image/v5/signature" "github.com/containers/image/v5/transports" "github.com/containers/image/v5/transports/alltransports" @@ -305,6 +306,22 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri pushOptions.SignBy = options.SignBy pushOptions.InsecureSkipTLSVerify = options.SkipTLSVerify + compressionFormat := options.CompressionFormat + if compressionFormat == "" { + config, err := ir.Libpod.GetConfigNoCopy() + if err != nil { + return err + } + compressionFormat = config.Engine.CompressionFormat + } + if compressionFormat != "" { + algo, err := compression.AlgorithmByName(compressionFormat) + if err != nil { + return err + } + pushOptions.CompressionFormat = &algo + } + if !options.Quiet { pushOptions.Writer = os.Stderr } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index ed70078b2..4c024a3d8 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -239,27 +239,6 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY return nil, err } podSpec := entities.PodSpec{PodSpecGen: *p} - volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes) - if err != nil { - return nil, err - } - - seccompPaths, err := kube.InitializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot) - if err != nil { - return nil, err - } - - var ctrRestartPolicy string - switch podYAML.Spec.RestartPolicy { - case v1.RestartPolicyAlways: - ctrRestartPolicy = define.RestartPolicyAlways - case v1.RestartPolicyOnFailure: - ctrRestartPolicy = define.RestartPolicyOnFailure - case v1.RestartPolicyNever: - ctrRestartPolicy = define.RestartPolicyNo - default: // Default to Always - ctrRestartPolicy = define.RestartPolicyAlways - } configMapIndex := make(map[string]struct{}) for _, configMap := range configMaps { @@ -284,6 +263,56 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY configMaps = append(configMaps, cm) } + volumes, err := kube.InitializeVolumes(podYAML.Spec.Volumes, configMaps) + if err != nil { + return nil, err + } + + // Go through the volumes and create a podman volume for all volumes that have been + // defined by a configmap + for _, v := range volumes { + if v.Type == kube.KubeVolumeTypeConfigMap && !v.Optional { + vol, err := ic.Libpod.NewVolume(ctx, libpod.WithVolumeName(v.Source)) + if err != nil { + return nil, errors.Wrapf(err, "cannot create a local volume for volume from configmap %q", v.Source) + } + mountPoint, err := vol.MountPoint() + if err != nil || mountPoint == "" { + return nil, errors.Wrapf(err, "unable to get mountpoint of volume %q", vol.Name()) + } + // Create files and add data to the volume mountpoint based on the Items in the volume + for k, v := range v.Items { + dataPath := filepath.Join(mountPoint, k) + f, err := os.Create(dataPath) + if err != nil { + return nil, errors.Wrapf(err, "cannot create file %q at volume mountpoint %q", k, mountPoint) + } + defer f.Close() + _, err = f.WriteString(v) + if err != nil { + return nil, err + } + } + } + } + + seccompPaths, err := kube.InitializeSeccompPaths(podYAML.ObjectMeta.Annotations, options.SeccompProfileRoot) + if err != nil { + return nil, err + } + + var ctrRestartPolicy string + switch podYAML.Spec.RestartPolicy { + case v1.RestartPolicyAlways: + ctrRestartPolicy = define.RestartPolicyAlways + case v1.RestartPolicyOnFailure: + ctrRestartPolicy = define.RestartPolicyOnFailure + case v1.RestartPolicyNever: + ctrRestartPolicy = define.RestartPolicyNo + default: // Default to Always + ctrRestartPolicy = define.RestartPolicyAlways + } + if podOpt.Infra { infraImage := util.DefaultContainerConfig().Engine.InfraImage infraOptions := entities.NewInfraContainerCreateOptions() diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go index 7da7754f2..e6c9d850b 100644 --- a/pkg/domain/infra/abi/system.go +++ b/pkg/domain/infra/abi/system.go @@ -365,9 +365,12 @@ func (ic *ContainerEngine) Unshare(ctx context.Context, args []string, options e if err != nil { return err } - // make sure to unlock, unshare can run for a long time + // Make sure to unlock, unshare can run for a long time. rootlessNetNS.Lock.Unlock() - defer rootlessNetNS.Cleanup(ic.Libpod) + // We do not want to cleanup the netns after unshare. + // The problem is that we cannot know if we need to cleanup and + // secondly unshare should allow user to setup the namespace with + // special things, e.g. potentially macvlan or something like that. return rootlessNetNS.Do(unshare) } return unshare() diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go index d62a318d6..dd895b61f 100644 --- a/pkg/domain/infra/tunnel/generate.go +++ b/pkg/domain/infra/tunnel/generate.go @@ -19,6 +19,9 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, if opts.RestartPolicy != nil { options.WithRestartPolicy(*opts.RestartPolicy) } + if opts.RestartSec != nil { + options.WithRestartSec(*opts.RestartSec) + } return generate.Systemd(ic.ClientCtx, nameOrID, options) } diff --git a/pkg/specgen/generate/kube/kube.go b/pkg/specgen/generate/kube/kube.go index c502a6e62..6d9f598c9 100644 --- a/pkg/specgen/generate/kube/kube.go +++ b/pkg/specgen/generate/kube/kube.go @@ -310,6 +310,11 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener if !exists { return nil, errors.Errorf("Volume mount %s specified for container but not configured in volumes", volume.Name) } + // Skip if the volume is optional. This means that a configmap for a configmap volume was not found but it was + // optional so we can move on without throwing an error + if exists && volumeSource.Optional { + continue + } dest, options, err := parseMountPath(volume.MountPath, volume.ReadOnly) if err != nil { @@ -341,6 +346,13 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener Options: options, } s.Volumes = append(s.Volumes, &namedVolume) + case KubeVolumeTypeConfigMap: + cmVolume := specgen.NamedVolume{ + Dest: volume.MountPath, + Name: volumeSource.Source, + Options: options, + } + s.Volumes = append(s.Volumes, &cmVolume) default: return nil, errors.Errorf("Unsupported volume source type") } diff --git a/pkg/specgen/generate/kube/volume.go b/pkg/specgen/generate/kube/volume.go index a8042b532..76ec0a390 100644 --- a/pkg/specgen/generate/kube/volume.go +++ b/pkg/specgen/generate/kube/volume.go @@ -23,6 +23,7 @@ type KubeVolumeType int const ( KubeVolumeTypeBindMount KubeVolumeType = iota KubeVolumeTypeNamed KubeVolumeType = iota + KubeVolumeTypeConfigMap KubeVolumeType = iota ) // nolint:golint @@ -31,6 +32,14 @@ type KubeVolume struct { Type KubeVolumeType // Path for bind mount or volume name for named volume Source string + // Items to add to a named volume created where the key is the file name and the value is the data + // This is only used when there are volumes in the yaml that refer to a configmap + // Example: if configmap has data "SPECIAL_LEVEL: very" then the file name is "SPECIAL_LEVEL" and the + // data in that file is "very". + Items map[string]string + // If the volume is optional, we can move on if it is not found + // Only used when there are volumes in a yaml that refer to a configmap + Optional bool } // Create a KubeVolume from an HostPathVolumeSource @@ -98,23 +107,64 @@ func VolumeFromPersistentVolumeClaim(claim *v1.PersistentVolumeClaimVolumeSource }, nil } +func VolumeFromConfigMap(configMapVolumeSource *v1.ConfigMapVolumeSource, configMaps []v1.ConfigMap) (*KubeVolume, error) { + var configMap *v1.ConfigMap + kv := &KubeVolume{Type: KubeVolumeTypeConfigMap, Items: map[string]string{}} + for _, cm := range configMaps { + if cm.Name == configMapVolumeSource.Name { + matchedCM := cm + // Set the source to the config map name + kv.Source = cm.Name + configMap = &matchedCM + break + } + } + + if configMap == nil { + // If the volumeSource was optional, move on even if a matching configmap wasn't found + if *configMapVolumeSource.Optional { + kv.Source = configMapVolumeSource.Name + kv.Optional = *configMapVolumeSource.Optional + return kv, nil + } + return nil, errors.Errorf("no such ConfigMap %q", configMapVolumeSource.Name) + } + + // If there are Items specified in the volumeSource, that overwrites the Data from the configmap + if len(configMapVolumeSource.Items) > 0 { + for _, item := range configMapVolumeSource.Items { + if val, ok := configMap.Data[item.Key]; ok { + kv.Items[item.Path] = val + } + } + } else { + for k, v := range configMap.Data { + kv.Items[k] = v + } + } + return kv, nil +} + // Create a KubeVolume from one of the supported VolumeSource -func VolumeFromSource(volumeSource v1.VolumeSource) (*KubeVolume, error) { - if volumeSource.HostPath != nil { +func VolumeFromSource(volumeSource v1.VolumeSource, configMaps []v1.ConfigMap) (*KubeVolume, error) { + switch { + case volumeSource.HostPath != nil: return VolumeFromHostPath(volumeSource.HostPath) - } else if volumeSource.PersistentVolumeClaim != nil { + case volumeSource.PersistentVolumeClaim != nil: return VolumeFromPersistentVolumeClaim(volumeSource.PersistentVolumeClaim) - } else { - return nil, errors.Errorf("HostPath and PersistentVolumeClaim are currently the only supported VolumeSource") + case volumeSource.ConfigMap != nil: + return VolumeFromConfigMap(volumeSource.ConfigMap, configMaps) + default: + return nil, errors.Errorf("HostPath, ConfigMap, and PersistentVolumeClaim are currently the only supported VolumeSource") } } // Create a map of volume name to KubeVolume -func InitializeVolumes(specVolumes []v1.Volume) (map[string]*KubeVolume, error) { +func InitializeVolumes(specVolumes []v1.Volume, configMaps []v1.ConfigMap) (map[string]*KubeVolume, error) { volumes := make(map[string]*KubeVolume) for _, specVolume := range specVolumes { - volume, err := VolumeFromSource(specVolume.VolumeSource) + volume, err := VolumeFromSource(specVolume.VolumeSource, configMaps) if err != nil { return nil, errors.Wrapf(err, "failed to create volume %q", specVolume.Name) } diff --git a/pkg/specgen/generate/oci.go b/pkg/specgen/generate/oci.go index 1b022b912..df5788099 100644 --- a/pkg/specgen/generate/oci.go +++ b/pkg/specgen/generate/oci.go @@ -329,6 +329,14 @@ func SpecGenToOCI(ctx context.Context, s *specgen.SpecGenerator, rt *libpod.Runt g.AddLinuxResourcesDevice(true, dev.Type, dev.Major, dev.Minor, dev.Access) } + for k, v := range s.WeightDevice { + statT := unix.Stat_t{} + if err := unix.Stat(k, &statT); err != nil { + return nil, errors.Wrapf(err, "failed to inspect '%s' in --blkio-weight-device", k) + } + g.AddLinuxResourcesBlockIOWeightDevice((int64(unix.Major(uint64(statT.Rdev)))), (int64(unix.Minor(uint64(statT.Rdev)))), *v.Weight) + } + BlockAccessToKernelFilesystems(s.Privileged, s.PidNS.IsHost(), s.Mask, s.Unmask, &g) g.ClearProcessEnv() diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index 7a572e730..637a6a8dd 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -85,7 +85,7 @@ func getIOLimits(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions) ( } if len(c.BlkIOWeightDevice) > 0 { - if err := parseWeightDevices(s, c.BlkIOWeightDevice); err != nil { + if s.WeightDevice, err = parseWeightDevices(c.BlkIOWeightDevice); err != nil { return nil, err } hasLimits = true @@ -791,29 +791,30 @@ func makeHealthCheckFromCli(inCmd, interval string, retries uint, timeout, start return &hc, nil } -func parseWeightDevices(s *specgen.SpecGenerator, weightDevs []string) error { +func parseWeightDevices(weightDevs []string) (map[string]specs.LinuxWeightDevice, error) { + wd := make(map[string]specs.LinuxWeightDevice) for _, val := range weightDevs { split := strings.SplitN(val, ":", 2) if len(split) != 2 { - return fmt.Errorf("bad format: %s", val) + return nil, fmt.Errorf("bad format: %s", val) } if !strings.HasPrefix(split[0], "/dev/") { - return fmt.Errorf("bad format for device path: %s", val) + return nil, fmt.Errorf("bad format for device path: %s", val) } weight, err := strconv.ParseUint(split[1], 10, 0) if err != nil { - return fmt.Errorf("invalid weight for device: %s", val) + return nil, fmt.Errorf("invalid weight for device: %s", val) } if weight > 0 && (weight < 10 || weight > 1000) { - return fmt.Errorf("invalid weight for device: %s", val) + return nil, fmt.Errorf("invalid weight for device: %s", val) } w := uint16(weight) - s.WeightDevice[split[0]] = specs.LinuxWeightDevice{ + wd[split[0]] = specs.LinuxWeightDevice{ Weight: &w, LeafWeight: nil, } } - return nil + return wd, nil } func parseThrottleBPSDevices(bpsDevices []string) (map[string]specs.LinuxThrottleDevice, error) { diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go index 48252c737..f2d04dadc 100644 --- a/pkg/systemd/generate/pods.go +++ b/pkg/systemd/generate/pods.go @@ -30,6 +30,8 @@ type podInfo struct { StopTimeout uint // RestartPolicy of the systemd unit (e.g., no, on-failure, always). RestartPolicy string + // RestartSec of the systemd unit. Configures the time to sleep before restarting a service. + RestartSec uint // PIDFile of the service. Required for forking services. Must point to the // PID of the associated conmon process. PIDFile string @@ -89,6 +91,9 @@ Before={{{{- range $index, $value := .RequiredServices -}}}}{{{{if $index}}}} {{ [Service] Environment={{{{.EnvVariable}}}}=%n Restart={{{{.RestartPolicy}}}} +{{{{- if .RestartSec}}}} +RestartSec={{{{.RestartSec}}}} +{{{{- end}}}} TimeoutStopSec={{{{.TimeoutStopSec}}}} {{{{- if .ExecStartPre1}}}} ExecStartPre={{{{.ExecStartPre1}}}} @@ -242,6 +247,10 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) info.RestartPolicy = *options.RestartPolicy } + if options.RestartSec != nil { + info.RestartSec = *options.RestartSec + } + // Make sure the executable is set. if info.Executable == "" { executable, err := os.Executable() diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go index 612908991..0889507a5 100644 --- a/pkg/systemd/generate/pods_test.go +++ b/pkg/systemd/generate/pods_test.go @@ -67,6 +67,33 @@ WantedBy=default.target podGood := serviceInfo + headerInfo + podContent podGoodNoHeaderInfo := serviceInfo + podContent + podGoodRestartSec := `# pod-123abc.service +# autogenerated by Podman CI + +[Unit] +Description=Podman pod-123abc.service +Documentation=man:podman-generate-systemd(1) +Wants=network-online.target +After=network-online.target +RequiresMountsFor=/var/run/containers/storage +Requires=container-1.service container-2.service +Before=container-1.service container-2.service + +[Service] +Environment=PODMAN_SYSTEMD_UNIT=%n +Restart=on-failure +RestartSec=15 +TimeoutStopSec=102 +ExecStart=/usr/bin/podman start jadda-jadda-infra +ExecStop=/usr/bin/podman stop -t 42 jadda-jadda-infra +ExecStopPost=/usr/bin/podman stop -t 42 jadda-jadda-infra +PIDFile=/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid +Type=forking + +[Install] +WantedBy=default.target +` + podGoodNamedNew := `# pod-123abc.service # autogenerated by Podman CI @@ -205,6 +232,25 @@ WantedBy=default.target false, false, }, + {"pod restartSec", + podInfo{ + Executable: "/usr/bin/podman", + ServiceName: "pod-123abc", + InfraNameOrID: "jadda-jadda-infra", + PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 42, + PodmanVersion: "CI", + GraphRoot: "/var/lib/containers/storage", + RunRoot: "/var/run/containers/storage", + RequiredServices: []string{"container-1", "container-2"}, + CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "bar=arg with space"}, + RestartSec: 15, + }, + podGoodRestartSec, + false, + false, + false, + }, {"pod noHeader", podInfo{ Executable: "/usr/bin/podman", |