diff options
Diffstat (limited to 'pkg')
25 files changed, 328 insertions, 129 deletions
diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go index 966874a2b..33bb75391 100644 --- a/pkg/api/handlers/libpod/generate.go +++ b/pkg/api/handlers/libpod/generate.go @@ -7,10 +7,55 @@ import ( "github.com/containers/podman/v2/pkg/api/handlers/utils" "github.com/containers/podman/v2/pkg/domain/entities" "github.com/containers/podman/v2/pkg/domain/infra/abi" + "github.com/containers/podman/v2/pkg/util" "github.com/gorilla/schema" "github.com/pkg/errors" ) +func GenerateSystemd(w http.ResponseWriter, r *http.Request) { + runtime := r.Context().Value("runtime").(*libpod.Runtime) + decoder := r.Context().Value("decoder").(*schema.Decoder) + query := struct { + Name bool `schema:"useName"` + New bool `schema:"new"` + RestartPolicy string `schema:"restartPolicy"` + StopTimeout uint `schema:"stopTimeout"` + ContainerPrefix string `schema:"containerPrefix"` + PodPrefix string `schema:"podPrefix"` + Separator string `schema:"separator"` + }{ + RestartPolicy: "on-failure", + StopTimeout: util.DefaultContainerConfig().Engine.StopTimeout, + ContainerPrefix: "container", + PodPrefix: "pod", + Separator: "-", + } + + if err := decoder.Decode(&query, r.URL.Query()); err != nil { + utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest, + errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String())) + return + } + + containerEngine := abi.ContainerEngine{Libpod: runtime} + options := entities.GenerateSystemdOptions{ + Name: query.Name, + New: query.New, + RestartPolicy: query.RestartPolicy, + StopTimeout: &query.StopTimeout, + ContainerPrefix: query.ContainerPrefix, + PodPrefix: query.PodPrefix, + Separator: query.Separator, + } + report, err := containerEngine.GenerateSystemd(r.Context(), utils.GetName(r), options) + if err != nil { + utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error generating systemd units")) + return + } + + utils.WriteResponse(w, http.StatusOK, report.Units) +} + func GenerateKube(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go index 51013acf1..8d3fc4e00 100644 --- a/pkg/api/handlers/libpod/images.go +++ b/pkg/api/handlers/libpod/images.go @@ -338,11 +338,12 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { runtime := r.Context().Value("runtime").(*libpod.Runtime) decoder := r.Context().Value("decoder").(*schema.Decoder) query := struct { - Reference string `schema:"reference"` - OverrideOS string `schema:"overrideOS"` - OverrideArch string `schema:"overrideArch"` - TLSVerify bool `schema:"tlsVerify"` - AllTags bool `schema:"allTags"` + Reference string `schema:"reference"` + OverrideOS string `schema:"overrideOS"` + OverrideArch string `schema:"overrideArch"` + OverrideVariant string `schema:"overrideVariant"` + TLSVerify bool `schema:"tlsVerify"` + AllTags bool `schema:"allTags"` }{ TLSVerify: true, } @@ -393,6 +394,7 @@ func ImagesPull(w http.ResponseWriter, r *http.Request) { DockerRegistryCreds: authConf, OSChoice: query.OverrideOS, ArchitectureChoice: query.OverrideArch, + VariantChoice: query.OverrideVariant, } if _, found := r.URL.Query()["tlsVerify"]; found { dockerRegistryOptions.DockerInsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify) diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index 6e704fe65..8f8292567 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -135,8 +135,8 @@ func PodStop(w http.ResponseWriter, r *http.Request) { } } var errs []error //nolint - for _, err := range responses { - errs = append(errs, err) + for id, err := range responses { + errs = append(errs, errors.Wrapf(err, "error stopping container %s", id)) } report := entities.PodStopReport{ Errs: errs, @@ -164,12 +164,12 @@ func PodStart(w http.ResponseWriter, r *http.Request) { return } responses, err := pod.Start(r.Context()) - if err != nil { + if err != nil && errors.Cause(err) != define.ErrPodPartialFail { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) return } - for _, err := range responses { - errs = append(errs, err) + for id, err := range responses { + errs = append(errs, errors.Wrapf(err, "error starting container %s", id)) } report := entities.PodStartReport{ Errs: errs, @@ -220,12 +220,12 @@ func PodRestart(w http.ResponseWriter, r *http.Request) { return } responses, err := pod.Restart(r.Context()) - if err != nil { + if err != nil && errors.Cause(err) != define.ErrPodPartialFail { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) return } - for _, err := range responses { - errs = append(errs, err) + for id, err := range responses { + errs = append(errs, errors.Wrapf(err, "error restarting container %s", id)) } report := entities.PodRestartReport{ Errs: errs, @@ -271,12 +271,12 @@ func PodPause(w http.ResponseWriter, r *http.Request) { return } responses, err := pod.Pause() - if err != nil { + if err != nil && errors.Cause(err) != define.ErrPodPartialFail { utils.Error(w, "Something went wrong", http.StatusInternalServerError, err) return } - for _, v := range responses { - errs = append(errs, v) + for id, v := range responses { + errs = append(errs, errors.Wrapf(v, "error pausing container %s", id)) } report := entities.PodPauseReport{ Errs: errs, @@ -295,12 +295,12 @@ func PodUnpause(w http.ResponseWriter, r *http.Request) { return } responses, err := pod.Unpause() - if err != nil { + if err != nil && errors.Cause(err) != define.ErrPodPartialFail { utils.Error(w, "failed to pause pod", http.StatusInternalServerError, err) return } - for _, v := range responses { - errs = append(errs, v) + for id, v := range responses { + errs = append(errs, errors.Wrapf(v, "error unpausing container %s", id)) } report := entities.PodUnpauseReport{ Errs: errs, @@ -403,7 +403,7 @@ func PodKill(w http.ResponseWriter, r *http.Request) { } responses, err := pod.Kill(uint(sig)) - if err != nil { + if err != nil && errors.Cause(err) != define.ErrPodPartialFail { utils.Error(w, "failed to kill pod", http.StatusInternalServerError, err) return } diff --git a/pkg/api/server/register_generate.go b/pkg/api/server/register_generate.go index 7db8ee387..60e5b03f7 100644 --- a/pkg/api/server/register_generate.go +++ b/pkg/api/server/register_generate.go @@ -8,6 +8,68 @@ import ( ) func (s *APIServer) registerGenerateHandlers(r *mux.Router) error { + // swagger:operation GET /libpod/generate/{name:.*}/systemd libpod libpodGenerateSystemd + // --- + // tags: + // - containers + // - pods + // summary: Generate Systemd Units + // description: Generate Systemd Units based on a pod or container. + // parameters: + // - in: path + // name: name:.* + // type: string + // required: true + // description: Name or ID of the container or pod. + // - in: query + // name: useName + // type: boolean + // default: false + // description: Use container/pod names instead of IDs. + // - in: query + // name: new + // type: boolean + // default: false + // description: Create a new container instead of starting an existing one. + // - in: query + // name: time + // type: integer + // default: 10 + // description: Stop timeout override. + // - in: query + // name: restartPolicy + // default: on-failure + // type: string + // enum: ["no", on-success, on-failure, on-abnormal, on-watchdog, on-abort, always] + // description: Systemd restart-policy. + // - in: query + // name: containerPrefix + // type: string + // default: container + // description: Systemd unit name prefix for containers. + // - in: query + // name: podPrefix + // type: string + // default: pod + // description: Systemd unit name prefix for pods. + // - in: query + // name: separator + // type: string + // default: "-" + // description: Systemd unit name separator between name/id and prefix. + // produces: + // - application/json + // responses: + // 200: + // description: no error + // schema: + // type: object + // additionalProperties: + // type: string + // 500: + // $ref: "#/responses/InternalError" + r.HandleFunc(VersionedPath("/libpod/generate/{name:.*}/systemd"), s.APIHandler(libpod.GenerateSystemd)).Methods(http.MethodGet) + // swagger:operation GET /libpod/generate/{name:.*}/kube libpod libpodGenerateKube // --- // tags: diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go index cb4ce4fe7..64258a073 100644 --- a/pkg/api/server/register_images.go +++ b/pkg/api/server/register_images.go @@ -625,7 +625,7 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // swagger:operation POST /libpod/images/{name:.*}/push libpod libpodPushImage // --- // tags: - // - images (libpod) + // - images // summary: Push Image // description: Push an image to a container registry // parameters: @@ -905,12 +905,16 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error { // description: "username:password for the registry" // type: string // - in: query + // name: overrideArch + // description: Pull image for the specified architecture. + // type: string + // - in: query // name: overrideOS // description: Pull image for the specified operating system. // type: string // - in: query - // name: overrideArch - // description: Pull image for the specified architecture. + // name: overrideVariant + // description: Pull image for the specified variant. // type: string // - in: query // name: tlsVerify diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go index 8f7848ed4..22488b158 100644 --- a/pkg/api/server/register_volumes.go +++ b/pkg/api/server/register_volumes.go @@ -9,8 +9,10 @@ import ( ) func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { - // swagger:operation POST /libpod/volumes/create volumes libpodCreateVolume + // swagger:operation POST /libpod/volumes/create libpod libpodCreateVolume // --- + // tags: + // - volumes // summary: Create a volume // parameters: // - in: body @@ -26,8 +28,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // '500': // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/libpod/volumes/create"), s.APIHandler(libpod.CreateVolume)).Methods(http.MethodPost) - // swagger:operation GET /libpod/volumes/json volumes libpodListVolumes + // swagger:operation GET /libpod/volumes/json libpod libpodListVolumes // --- + // tags: + // - volumes // summary: List volumes // description: Returns a list of volumes // produces: @@ -48,8 +52,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // '500': // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/libpod/volumes/json"), s.APIHandler(libpod.ListVolumes)).Methods(http.MethodGet) - // swagger:operation POST /libpod/volumes/prune volumes libpodPruneVolumes + // swagger:operation POST /libpod/volumes/prune libpod libpodPruneVolumes // --- + // tags: + // - volumes // summary: Prune volumes // produces: // - application/json @@ -59,8 +65,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // '500': // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/libpod/volumes/prune"), s.APIHandler(libpod.PruneVolumes)).Methods(http.MethodPost) - // swagger:operation GET /libpod/volumes/{name}/json volumes libpodInspectVolume + // swagger:operation GET /libpod/volumes/{name}/json libpod libpodInspectVolume // --- + // tags: + // - volumes // summary: Inspect volume // parameters: // - in: path @@ -78,8 +86,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // '500': // "$ref": "#/responses/InternalError" r.Handle(VersionedPath("/libpod/volumes/{name}/json"), s.APIHandler(libpod.InspectVolume)).Methods(http.MethodGet) - // swagger:operation DELETE /libpod/volumes/{name} volumes libpodRemoveVolume + // swagger:operation DELETE /libpod/volumes/{name} libpod libpodRemoveVolume // --- + // tags: + // - volumes // summary: Remove volume // parameters: // - in: path @@ -110,6 +120,8 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { // swagger:operation GET /volumes compat listVolumes // --- + // tags: + // - volumes (compat) // summary: List volumes // description: Returns a list of volume // produces: @@ -134,8 +146,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { r.Handle(VersionedPath("/volumes"), s.APIHandler(compat.ListVolumes)).Methods(http.MethodGet) r.Handle("/volumes", s.APIHandler(compat.ListVolumes)).Methods(http.MethodGet) - // swagger:operation POST /volumes/create volumes createVolume + // swagger:operation POST /volumes/create compat createVolume // --- + // tags: + // - volumes (compat) // summary: Create a volume // parameters: // - in: body @@ -153,8 +167,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { r.Handle(VersionedPath("/volumes/create"), s.APIHandler(compat.CreateVolume)).Methods(http.MethodPost) r.Handle("/volumes/create", s.APIHandler(compat.CreateVolume)).Methods(http.MethodPost) - // swagger:operation GET /volumes/{name} volumes inspectVolume + // swagger:operation GET /volumes/{name} compat inspectVolume // --- + // tags: + // - volumes (compat) // summary: Inspect volume // parameters: // - in: path @@ -174,8 +190,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { r.Handle(VersionedPath("/volumes/{name}"), s.APIHandler(compat.InspectVolume)).Methods(http.MethodGet) r.Handle("/volumes/{name}", s.APIHandler(compat.InspectVolume)).Methods(http.MethodGet) - // swagger:operation DELETE /volumes/{name} volumes removeVolume + // swagger:operation DELETE /volumes/{name} compat removeVolume // --- + // tags: + // - volumes (compat) // summary: Remove volume // parameters: // - in: path @@ -204,8 +222,10 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error { r.Handle(VersionedPath("/volumes/{name}"), s.APIHandler(compat.RemoveVolume)).Methods(http.MethodDelete) r.Handle("/volumes/{name}", s.APIHandler(compat.RemoveVolume)).Methods(http.MethodDelete) - // swagger:operation POST /volumes/prune volumes pruneVolumes + // swagger:operation POST /volumes/prune compat pruneVolumes // --- + // tags: + // - volumes (compat) // summary: Prune volumes // produces: // - application/json diff --git a/pkg/api/tags.yaml b/pkg/api/tags.yaml index f86f8dbea..0cfb3f440 100644 --- a/pkg/api/tags.yaml +++ b/pkg/api/tags.yaml @@ -23,5 +23,7 @@ tags: description: Actions related to images for the compatibility endpoints - name: networks (compat) description: Actions related to compatibility networks + - name: volumes (compat) + description: Actions related to volumes for the compatibility endpoints - name: system (compat) description: Actions related to Podman and compatibility engines diff --git a/pkg/bindings/generate/generate.go b/pkg/bindings/generate/generate.go index b02221765..dde1cc29c 100644 --- a/pkg/bindings/generate/generate.go +++ b/pkg/bindings/generate/generate.go @@ -10,6 +10,33 @@ import ( "github.com/containers/podman/v2/pkg/domain/entities" ) +func Systemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) { + conn, err := bindings.GetClient(ctx) + if err != nil { + return nil, err + } + params := url.Values{} + + params.Set("useName", strconv.FormatBool(options.Name)) + params.Set("new", strconv.FormatBool(options.New)) + if options.RestartPolicy != "" { + params.Set("restartPolicy", options.RestartPolicy) + } + if options.StopTimeout != nil { + params.Set("stopTimeout", strconv.FormatUint(uint64(*options.StopTimeout), 10)) + } + params.Set("containerPrefix", options.ContainerPrefix) + params.Set("podPrefix", options.PodPrefix) + params.Set("separator", options.Separator) + + response, err := conn.DoRequest(nil, http.MethodGet, "/generate/%s/systemd", params, nil, nameOrID) + if err != nil { + return nil, err + } + report := &entities.GenerateSystemdReport{} + return report, response.Process(&report.Units) +} + func Kube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) { conn, err := bindings.GetClient(ctx) if err != nil { diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go index 12d1a9ce9..9f6e78b79 100644 --- a/pkg/bindings/images/images.go +++ b/pkg/bindings/images/images.go @@ -365,6 +365,7 @@ func Pull(ctx context.Context, rawImage string, options entities.ImagePullOption params.Set("reference", rawImage) params.Set("overrideArch", options.OverrideArch) params.Set("overrideOS", options.OverrideOS) + params.Set("overrideVariant", options.OverrideVariant) if options.SkipTLSVerify != types.OptionalBoolUndefined { // Note: we have to verify if skipped is false. verifyTLS := bool(options.SkipTLSVerify == types.OptionalBoolFalse) diff --git a/pkg/bindings/test/containers_test.go b/pkg/bindings/test/containers_test.go index db5be4909..bf2ceab2a 100644 --- a/pkg/bindings/test/containers_test.go +++ b/pkg/bindings/test/containers_test.go @@ -2,7 +2,6 @@ package test_bindings import ( "net/http" - "strconv" "strings" "time" @@ -10,7 +9,6 @@ import ( "github.com/containers/podman/v2/pkg/bindings" "github.com/containers/podman/v2/pkg/bindings/containers" "github.com/containers/podman/v2/pkg/specgen" - "github.com/containers/podman/v2/test/utils" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" @@ -182,14 +180,6 @@ var _ = Describe("Podman containers ", func() { }) It("podman remove a paused container by id with force", func() { - // FIXME: Skip on F31 and later - host := utils.GetHostDistributionInfo() - osVer, err := strconv.Atoi(host.Version) - Expect(err).To(BeNil()) - if host.Distribution == "fedora" && osVer >= 31 { - Skip("FIXME: https://github.com/containers/podman/issues/5325") - } - // Removing a paused container with force should work var name = "top" cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil) @@ -280,7 +270,6 @@ var _ = Describe("Podman containers ", func() { }) It("podman wait to pause|unpause condition", func() { - Skip("FIXME: https://github.com/containers/podman/issues/6518") var ( name = "top" exitCode int32 = -1 diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go index a8ad13705..4a0d7537e 100644 --- a/pkg/domain/entities/generate.go +++ b/pkg/domain/entities/generate.go @@ -4,8 +4,6 @@ import "io" // GenerateSystemdOptions control the generation of systemd unit files. type GenerateSystemdOptions struct { - // Files - generate files instead of printing to stdout. - Files bool // Name - use container/pod name instead of its ID. Name bool // New - create a new container instead of starting a new one. @@ -24,9 +22,8 @@ type GenerateSystemdOptions struct { // GenerateSystemdReport type GenerateSystemdReport struct { - // Output of the generate process. Either the generated files or their - // entire content. - Output string + // Units of the generate process. key = unit name -> value = unit content + Units map[string]string } // GenerateKubeOptions control the generation of Kubernetes YAML files. diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index cb970b09a..3a12a4e22 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -137,6 +137,8 @@ type ImagePullOptions struct { // OverrideOS will overwrite the local operating system (OS) for image // pulls. OverrideOS string + // OverrideVariant will overwrite the local variant for image pulls. + OverrideVariant string // Quiet can be specified to suppress pull progress when pulling. Ignored // for remote calls. Quiet bool diff --git a/pkg/domain/infra/abi/generate.go b/pkg/domain/infra/abi/generate.go index 0b73ddd7e..79bf2291e 100644 --- a/pkg/domain/infra/abi/generate.go +++ b/pkg/domain/infra/abi/generate.go @@ -19,11 +19,11 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, ctr, ctrErr := ic.Libpod.LookupContainer(nameOrID) if ctrErr == nil { // Generate the unit for the container. - s, err := generate.ContainerUnit(ctr, options) + name, content, err := generate.ContainerUnit(ctr, options) if err != nil { return nil, err } - return &entities.GenerateSystemdReport{Output: s}, nil + return &entities.GenerateSystemdReport{Units: map[string]string{name: content}}, nil } // If it's not a container, we either have a pod or garbage. @@ -34,11 +34,11 @@ func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, } // Generate the units for the pod and all its containers. - s, err := generate.PodUnits(pod, options) + units, err := generate.PodUnits(pod, options) if err != nil { return nil, err } - return &entities.GenerateSystemdReport{Output: s}, nil + return &entities.GenerateSystemdReport{Units: units}, nil } func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) { diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index 70d740bb5..6b94ca9c0 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -251,6 +251,7 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, options entiti DockerCertPath: options.CertDir, OSChoice: options.OverrideOS, ArchitectureChoice: options.OverrideArch, + VariantChoice: options.OverrideVariant, DockerInsecureSkipTLSVerify: options.SkipTLSVerify, } diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index 4ebc37cda..31ad51672 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -144,6 +144,16 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY podOptions = append(podOptions, libpod.WithPodHostNetwork()) } + if podYAML.Spec.HostAliases != nil { + hosts := make([]string, 0, len(podYAML.Spec.HostAliases)) + for _, hostAlias := range podYAML.Spec.HostAliases { + for _, host := range hostAlias.Hostnames { + hosts = append(hosts, host+":"+hostAlias.IP) + } + } + podOptions = append(podOptions, libpod.WithPodHosts(hosts)) + } + nsOptions, err := generate.GetNamespaceOptions(strings.Split(createconfig.DefaultKernelNamespaces, ",")) if err != nil { return nil, err @@ -250,13 +260,22 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if err := libpod.LabelVolumePath(hostPath.Path); err != nil { return nil, errors.Wrapf(err, "Error giving %s a label", hostPath.Path) } + case v1.HostPathSocket: + st, err := os.Stat(hostPath.Path) + if err != nil { + return nil, errors.Wrapf(err, "Error checking HostPathSocket") + } + if st.Mode()&os.ModeSocket != os.ModeSocket { + return nil, errors.Errorf("Error checking HostPathSocket: path %s is not a socket", hostPath.Path) + } + case v1.HostPathDirectory: case v1.HostPathFile: case v1.HostPathUnset: // do nothing here because we will verify the path exists in validateVolumeHostDir break default: - return nil, errors.Errorf("Directories are the only supported HostPath type") + return nil, errors.Errorf("Invalid HostPath type %v", hostPath.Type) } } diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go index c7d5cd9e2..966f707b1 100644 --- a/pkg/domain/infra/tunnel/generate.go +++ b/pkg/domain/infra/tunnel/generate.go @@ -5,11 +5,10 @@ import ( "github.com/containers/podman/v2/pkg/bindings/generate" "github.com/containers/podman/v2/pkg/domain/entities" - "github.com/pkg/errors" ) func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) { - return nil, errors.New("not implemented for tunnel") + return generate.Systemd(ic.ClientCxt, nameOrID, options) } func (ic *ContainerEngine) GenerateKube(ctx context.Context, nameOrID string, options entities.GenerateKubeOptions) (*entities.GenerateKubeReport, error) { diff --git a/pkg/spec/createconfig.go b/pkg/spec/createconfig.go index e0c875fe9..4887e9262 100644 --- a/pkg/spec/createconfig.go +++ b/pkg/spec/createconfig.go @@ -267,6 +267,16 @@ func (c *CreateConfig) getContainerCreateOptions(runtime *libpod.Runtime, pod *l options = append(options, runtime.WithPod(pod)) } + // handle some spec from the InfraContainer when it's a pod + if pod != nil && pod.HasInfraContainer() { + InfraCtr, err := pod.InfraContainer() + if err != nil { + return nil, err + } + // handle the pod.spec.hostAliases + options = append(options, libpod.WithHosts(InfraCtr.HostsAdd())) + } + if len(mounts) != 0 || len(namedVolumes) != 0 { destinations := []string{} diff --git a/pkg/specgen/generate/config_linux.go b/pkg/specgen/generate/config_linux.go index 35508c023..1d5dcd8e7 100644 --- a/pkg/specgen/generate/config_linux.go +++ b/pkg/specgen/generate/config_linux.go @@ -90,7 +90,7 @@ func DevicesFromPath(g *generate.Generator, devicePath string) error { } st, err := os.Stat(resolvedDevicePath) if err != nil { - return errors.Wrapf(err, "cannot stat %s", devicePath) + return errors.Wrapf(err, "cannot stat device path %s", devicePath) } if st.IsDir() { found := false diff --git a/pkg/specgen/generate/container.go b/pkg/specgen/generate/container.go index 53d160442..147ebd61b 100644 --- a/pkg/specgen/generate/container.go +++ b/pkg/specgen/generate/container.go @@ -2,6 +2,7 @@ package generate import ( "context" + "os" "github.com/containers/image/v5/manifest" "github.com/containers/podman/v2/libpod" @@ -62,14 +63,24 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat if err != nil { return nil, err } - // Get Default Environment - defaultEnvs, err := envLib.ParseSlice(rtc.Containers.Env) + // First transform the os env into a map. We need it for the labels later in + // any case. + osEnv, err := envLib.ParseSlice(os.Environ()) if err != nil { - return nil, errors.Wrap(err, "Env fields in containers.conf failed to parse") + return nil, errors.Wrap(err, "error parsing host environment variables") } + // Get Default Environment from containers.conf + defaultEnvs, err := envLib.ParseSlice(rtc.GetDefaultEnv()) + if err != nil { + return nil, errors.Wrap(err, "error parsing fields in containers.conf") + } + if defaultEnvs["containers"] == "" { + defaultEnvs["containers"] = "podman" + } var envs map[string]string + // Image Environment defaults if newImage != nil { // Image envs from the image if they don't exist // already, overriding the default environments @@ -82,9 +93,30 @@ func CompleteSpec(ctx context.Context, r *libpod.Runtime, s *specgen.SpecGenerat if err != nil { return nil, errors.Wrap(err, "Env fields from image failed to parse") } + defaultEnvs = envLib.Join(defaultEnvs, envs) + } + + // Caller Specified defaults + if s.EnvHost { + defaultEnvs = envLib.Join(defaultEnvs, osEnv) + } else if s.HTTPProxy { + for _, envSpec := range []string{ + "http_proxy", + "HTTP_PROXY", + "https_proxy", + "HTTPS_PROXY", + "ftp_proxy", + "FTP_PROXY", + "no_proxy", + "NO_PROXY", + } { + if v, ok := osEnv[envSpec]; ok { + defaultEnvs[envSpec] = v + } + } } - s.Env = envLib.Join(envLib.Join(defaultEnvs, envs), s.Env) + s.Env = envLib.Join(defaultEnvs, s.Env) // Labels and Annotations annotations := make(map[string]string) diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go index a52225f87..cca05eddb 100644 --- a/pkg/specgen/specgen.go +++ b/pkg/specgen/specgen.go @@ -43,6 +43,13 @@ type ContainerBasicConfig struct { // image's configuration. // Optional. Command []string `json:"command,omitempty"` + // EnvHost indicates that the host environment should be added to container + // Optional. + EnvHost bool `json:"env_host,omitempty"` + // EnvHTTPProxy indicates that the http host proxy environment variables + // should be added to container + // Optional. + HTTPProxy bool `json:"httpproxy,omitempty"` // Env is a set of environment variables that will be set in the // container. // Optional. diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index 5f6376977..caf5de357 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -3,9 +3,7 @@ package generate import ( "bytes" "fmt" - "io/ioutil" "os" - "path/filepath" "sort" "strings" "text/template" @@ -87,17 +85,22 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` // ContainerUnit generates a systemd unit for the specified container. Based // on the options, the return value might be the entire unit or a file it has // been written to. -func ContainerUnit(ctr *libpod.Container, options entities.GenerateSystemdOptions) (string, error) { +func ContainerUnit(ctr *libpod.Container, options entities.GenerateSystemdOptions) (string, string, error) { info, err := generateContainerInfo(ctr, options) if err != nil { - return "", err + return "", "", err + } + content, err := executeContainerTemplate(info, options) + if err != nil { + return "", "", err } - return executeContainerTemplate(info, options) + return info.ServiceName, content, nil } func generateContainerInfo(ctr *libpod.Container, options entities.GenerateSystemdOptions) (*containerInfo, error) { @@ -288,18 +291,5 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst return "", err } - if !options.Files { - return buf.String(), nil - } - - buf.WriteByte('\n') - cwd, err := os.Getwd() - if err != nil { - return "", errors.Wrap(err, "error getting current working directory") - } - path := filepath.Join(cwd, fmt.Sprintf("%s.service", info.ServiceName)) - if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil { - return "", errors.Wrap(err, "error generating systemd unit") - } - return path, nil + return buf.String(), nil } diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go index b5c736c5a..d27062ef3 100644 --- a/pkg/systemd/generate/containers_test.go +++ b/pkg/systemd/generate/containers_test.go @@ -56,7 +56,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` goodName := `# container-foobar.service # autogenerated by Podman CI @@ -78,7 +79,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` goodNameBoundTo := `# container-foobar.service # autogenerated by Podman CI @@ -102,7 +104,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` goodWithNameAndGeneric := `# jadda-jadda.service # autogenerated by Podman CI @@ -125,7 +128,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` goodWithExplicitShortDetachParam := `# jadda-jadda.service # autogenerated by Podman CI @@ -148,7 +152,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` goodNameNewWithPodFile := `# jadda-jadda.service # autogenerated by Podman CI @@ -171,7 +176,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` goodNameNewDetach := `# jadda-jadda.service # autogenerated by Podman CI @@ -194,7 +200,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` goodIDNew := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service # autogenerated by Podman CI @@ -217,7 +224,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` tests := []struct { name string @@ -375,8 +383,7 @@ WantedBy=multi-user.target default.target` test := tt t.Run(tt.name, func(t *testing.T) { opts := entities.GenerateSystemdOptions{ - Files: false, - New: test.new, + New: test.new, } got, err := executeContainerTemplate(&test.info, opts) if (err != nil) != test.wantErr { diff --git a/pkg/systemd/generate/pods.go b/pkg/systemd/generate/pods.go index dec9587d9..c41eedd17 100644 --- a/pkg/systemd/generate/pods.go +++ b/pkg/systemd/generate/pods.go @@ -3,9 +3,7 @@ package generate import ( "bytes" "fmt" - "io/ioutil" "os" - "path/filepath" "sort" "strings" "text/template" @@ -88,39 +86,40 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` // PodUnits generates systemd units for the specified pod and its containers. // Based on the options, the return value might be the content of all units or // the files they been written to. -func PodUnits(pod *libpod.Pod, options entities.GenerateSystemdOptions) (string, error) { +func PodUnits(pod *libpod.Pod, options entities.GenerateSystemdOptions) (map[string]string, error) { // Error out if the pod has no infra container, which we require to be the // main service. if !pod.HasInfraContainer() { - return "", errors.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name()) + return nil, errors.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name()) } podInfo, err := generatePodInfo(pod, options) if err != nil { - return "", err + return nil, err } infraID, err := pod.InfraContainerID() if err != nil { - return "", err + return nil, err } // Compute the container-dependency graph for the Pod. containers, err := pod.AllContainers() if err != nil { - return "", err + return nil, err } if len(containers) == 0 { - return "", errors.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name()) + return nil, errors.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name()) } graph, err := libpod.BuildContainerGraph(containers) if err != nil { - return "", err + return nil, err } // Traverse the dependency graph and create systemdgen.containerInfo's for @@ -133,7 +132,7 @@ func PodUnits(pod *libpod.Pod, options entities.GenerateSystemdOptions) (string, } ctrInfo, err := generateContainerInfo(ctr, options) if err != nil { - return "", err + return nil, err } // Now add the container's dependencies and at the container as a // required service of the infra container. @@ -149,24 +148,23 @@ func PodUnits(pod *libpod.Pod, options entities.GenerateSystemdOptions) (string, containerInfos = append(containerInfos, ctrInfo) } + units := map[string]string{} // Now generate the systemd service for all containers. - builder := strings.Builder{} out, err := executePodTemplate(podInfo, options) if err != nil { - return "", err + return nil, err } - builder.WriteString(out) + units[podInfo.ServiceName] = out for _, info := range containerInfos { info.pod = podInfo - builder.WriteByte('\n') out, err := executeContainerTemplate(info, options) if err != nil { - return "", err + return nil, err } - builder.WriteString(out) + units[info.ServiceName] = out } - return builder.String(), nil + return units, nil } func generatePodInfo(pod *libpod.Pod, options entities.GenerateSystemdOptions) (*podInfo, error) { @@ -339,18 +337,5 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) return "", err } - if !options.Files { - return buf.String(), nil - } - - buf.WriteByte('\n') - cwd, err := os.Getwd() - if err != nil { - return "", errors.Wrap(err, "error getting current working directory") - } - path := filepath.Join(cwd, fmt.Sprintf("%s.service", info.ServiceName)) - if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil { - return "", errors.Wrap(err, "error generating systemd unit") - } - return path, nil + return buf.String(), nil } diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go index 8bf4705a7..7f1f63b7e 100644 --- a/pkg/systemd/generate/pods_test.go +++ b/pkg/systemd/generate/pods_test.go @@ -58,7 +58,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` podGoodNamedNew := `# pod-123abc.service # autogenerated by Podman CI @@ -84,7 +85,8 @@ KillMode=none Type=forking [Install] -WantedBy=multi-user.target default.target` +WantedBy=multi-user.target default.target +` tests := []struct { name string @@ -130,8 +132,7 @@ WantedBy=multi-user.target default.target` test := tt t.Run(tt.name, func(t *testing.T) { opts := entities.GenerateSystemdOptions{ - Files: false, - New: test.new, + New: test.new, } got, err := executePodTemplate(&test.info, opts) if (err != nil) != test.wantErr { diff --git a/pkg/util/utils_supported.go b/pkg/util/utils_supported.go index bf59240c6..d627208d8 100644 --- a/pkg/util/utils_supported.go +++ b/pkg/util/utils_supported.go @@ -83,9 +83,6 @@ func GetRootlessConfigHomeDir() (string, error) { return } tmpDir := filepath.Join(resolvedHome, ".config") - if err := os.MkdirAll(tmpDir, 0755); err != nil { - logrus.Errorf("unable to make temp dir %s", tmpDir) - } st, err := os.Stat(tmpDir) if err == nil && int(st.Sys().(*syscall.Stat_t).Uid) == os.Geteuid() && st.Mode().Perm() >= 0700 { cfgHomeDir = tmpDir |