From ebfea2f4f89328ec3f74a8deedb3e727ce89ea59 Mon Sep 17 00:00:00 2001 From: Paul Holzinger Date: Wed, 5 Aug 2020 09:29:59 +0200 Subject: APIv2 add generate systemd endpoint Add support for generating systemd units via the api and podman-remote. Change the GenerateSystemdReport type to return the units as map[string]string with the unit name as key. Add `--format` flag to `podman generate systemd` to allow the output to be formatted as json. Signed-off-by: Paul Holzinger --- pkg/systemd/generate/containers.go | 30 +++++++------------- pkg/systemd/generate/containers_test.go | 27 +++++++++++------- pkg/systemd/generate/pods.go | 49 ++++++++++++--------------------- pkg/systemd/generate/pods_test.go | 9 +++--- 4 files changed, 49 insertions(+), 66 deletions(-) (limited to 'pkg/systemd/generate') 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 { -- cgit v1.2.3-54-g00ecf