From d2f3098c6f9068edfe4012387cef2e6d140ef20a Mon Sep 17 00:00:00 2001 From: Jakub Guzik Date: Mon, 22 Feb 2021 14:47:08 +0100 Subject: --no-header flag implementation for generate systemd Signed-off-by: Jakub Guzik --- pkg/api/handlers/libpod/generate.go | 2 + pkg/api/server/register_generate.go | 5 +++ pkg/bindings/generate/types.go | 2 + pkg/bindings/generate/types_systemd_options.go | 16 +++++++ pkg/domain/entities/generate.go | 2 + pkg/domain/infra/tunnel/generate.go | 2 +- pkg/systemd/generate/common.go | 2 + pkg/systemd/generate/containers.go | 10 ++++- pkg/systemd/generate/containers_test.go | 59 ++++++++++++++++++++++---- pkg/systemd/generate/pods.go | 8 ++++ pkg/systemd/generate/pods_test.go | 47 ++++++++++++++++---- 11 files changed, 134 insertions(+), 21 deletions(-) (limited to 'pkg') diff --git a/pkg/api/handlers/libpod/generate.go b/pkg/api/handlers/libpod/generate.go index b3b8c1f16..fc22d0120 100644 --- a/pkg/api/handlers/libpod/generate.go +++ b/pkg/api/handlers/libpod/generate.go @@ -18,6 +18,7 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) { query := struct { Name bool `schema:"useName"` New bool `schema:"new"` + NoHeader bool `schema:"noHeader"` RestartPolicy string `schema:"restartPolicy"` StopTimeout uint `schema:"stopTimeout"` ContainerPrefix string `schema:"containerPrefix"` @@ -41,6 +42,7 @@ func GenerateSystemd(w http.ResponseWriter, r *http.Request) { options := entities.GenerateSystemdOptions{ Name: query.Name, New: query.New, + NoHeader: query.NoHeader, RestartPolicy: query.RestartPolicy, StopTimeout: &query.StopTimeout, ContainerPrefix: query.ContainerPrefix, diff --git a/pkg/api/server/register_generate.go b/pkg/api/server/register_generate.go index bce5484ab..bbab0ad5f 100644 --- a/pkg/api/server/register_generate.go +++ b/pkg/api/server/register_generate.go @@ -32,6 +32,11 @@ func (s *APIServer) registerGenerateHandlers(r *mux.Router) error { // default: false // description: Create a new container instead of starting an existing one. // - in: query + // name: noHeader + // type: boolean + // default: false + // description: Do not generate the header including the Podman version and the timestamp. + // - in: query // name: time // type: integer // default: 10 diff --git a/pkg/bindings/generate/types.go b/pkg/bindings/generate/types.go index 4e9d7a0ff..3c9ea87d4 100644 --- a/pkg/bindings/generate/types.go +++ b/pkg/bindings/generate/types.go @@ -14,6 +14,8 @@ type SystemdOptions struct { UseName *bool // New - create a new container instead of starting a new one. New *bool + // NoHeader - Removes autogenerated by Podman and timestamp if set to true + NoHeader *bool // RestartPolicy - systemd restart policy. RestartPolicy *string // 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 dc7378888..25ed446aa 100644 --- a/pkg/bindings/generate/types_systemd_options.go +++ b/pkg/bindings/generate/types_systemd_options.go @@ -52,6 +52,22 @@ func (o *SystemdOptions) GetNew() bool { return *o.New } +// WithNoHeader +func (o *SystemdOptions) WithNoHeader(value bool) *SystemdOptions { + v := &value + o.NoHeader = v + return o +} + +// GetNoHeader +func (o *SystemdOptions) GetNoHeader() bool { + var noHeader bool + if o.NoHeader == nil { + return noHeader + } + return *o.NoHeader +} + // WithRestartPolicy func (o *SystemdOptions) WithRestartPolicy(value string) *SystemdOptions { v := &value diff --git a/pkg/domain/entities/generate.go b/pkg/domain/entities/generate.go index 4a0d7537e..3ec713edf 100644 --- a/pkg/domain/entities/generate.go +++ b/pkg/domain/entities/generate.go @@ -18,6 +18,8 @@ type GenerateSystemdOptions struct { PodPrefix string // Separator - systemd unit name separator between name/id and prefix Separator string + // NoHeader - skip header generation + NoHeader bool } // GenerateSystemdReport diff --git a/pkg/domain/infra/tunnel/generate.go b/pkg/domain/infra/tunnel/generate.go index 6d68157c1..a9196adaa 100644 --- a/pkg/domain/infra/tunnel/generate.go +++ b/pkg/domain/infra/tunnel/generate.go @@ -8,7 +8,7 @@ import ( ) func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, opts entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) { - options := new(generate.SystemdOptions).WithUseName(opts.Name).WithContainerPrefix(opts.ContainerPrefix).WithNew(opts.New) + options := new(generate.SystemdOptions).WithUseName(opts.Name).WithContainerPrefix(opts.ContainerPrefix).WithNew(opts.New).WithNoHeader(opts.NoHeader) options.WithPodPrefix(opts.PodPrefix).WithRestartPolicy(opts.RestartPolicy).WithSeparator(opts.Separator) if to := opts.StopTimeout; to != nil { options.WithStopTimeout(*opts.StopTimeout) diff --git a/pkg/systemd/generate/common.go b/pkg/systemd/generate/common.go index e9902319c..bbd1a5f92 100644 --- a/pkg/systemd/generate/common.go +++ b/pkg/systemd/generate/common.go @@ -31,10 +31,12 @@ func validateRestartPolicy(restart string) error { } const headerTemplate = `# {{{{.ServiceName}}}}.service +{{{{- if (eq .GenerateNoHeader false) }}}} # autogenerated by Podman {{{{.PodmanVersion}}}} {{{{- if .TimeStamp}}}} # {{{{.TimeStamp}}}} {{{{- end}}}} +{{{{- end}}}} [Unit] Description=Podman {{{{.ServiceName}}}}.service diff --git a/pkg/systemd/generate/containers.go b/pkg/systemd/generate/containers.go index acee7be65..8fbbc727b 100644 --- a/pkg/systemd/generate/containers.go +++ b/pkg/systemd/generate/containers.go @@ -65,7 +65,8 @@ type containerInfo struct { ExecStop string // ExecStopPost of the unit. ExecStopPost string - + // Removes autogenerated by Podman and timestamp if set to true + GenerateNoHeader bool // If not nil, the container is part of the pod. We can use the // podInfo to extract the relevant data. Pod *podInfo @@ -292,10 +293,15 @@ func executeContainerTemplate(info *containerInfo, options entities.GenerateSyst if info.PodmanVersion == "" { info.PodmanVersion = version.Version.String() } + + if options.NoHeader { + info.GenerateNoHeader = true + info.GenerateTimestamp = false + } + if info.GenerateTimestamp { info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate)) } - // Sort the slices to assure a deterministic output. sort.Strings(info.BoundToServices) diff --git a/pkg/systemd/generate/containers_test.go b/pkg/systemd/generate/containers_test.go index dad14ece9..2ba73ef8d 100644 --- a/pkg/systemd/generate/containers_test.go +++ b/pkg/systemd/generate/containers_test.go @@ -37,9 +37,11 @@ func TestValidateRestartPolicyContainer(t *testing.T) { } func TestCreateContainerSystemdUnit(t *testing.T) { - goodID := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service -# autogenerated by Podman CI - + serviceInfo := `# container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service +` + headerInfo := `# autogenerated by Podman CI +` + goodIDContent := ` [Unit] Description=Podman container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.service Documentation=man:podman-generate-systemd(1) @@ -59,6 +61,8 @@ Type=forking [Install] WantedBy=multi-user.target default.target ` + goodID := serviceInfo + headerInfo + goodIDContent + goodIDNoHeaderInfo := serviceInfo + goodIDContent goodName := `# container-foobar.service # autogenerated by Podman CI @@ -377,11 +381,12 @@ Type=forking WantedBy=multi-user.target default.target ` tests := []struct { - name string - info containerInfo - want string - new bool - wantErr bool + name string + info containerInfo + want string + new bool + noHeader bool + wantErr bool }{ {"good with id", @@ -398,6 +403,23 @@ WantedBy=multi-user.target default.target goodID, false, false, + false, + }, + {"good with noHeader", + containerInfo{ + Executable: "/usr/bin/podman", + ServiceName: "container-639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401", + ContainerNameOrID: "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401", + RestartPolicy: "always", + PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 22, + PodmanVersion: "CI", + EnvVariable: EnvVariable, + }, + goodIDNoHeaderInfo, + false, + true, + false, }, {"good with name", containerInfo{ @@ -413,6 +435,7 @@ WantedBy=multi-user.target default.target goodName, false, false, + false, }, {"good with name and bound to", containerInfo{ @@ -429,6 +452,7 @@ WantedBy=multi-user.target default.target goodNameBoundTo, false, false, + false, }, {"bad restart policy", containerInfo{ @@ -442,6 +466,7 @@ WantedBy=multi-user.target default.target }, "", false, + false, true, }, {"good with name and generic", @@ -459,6 +484,7 @@ WantedBy=multi-user.target default.target goodWithNameAndGeneric, true, false, + false, }, {"good with explicit short detach param", containerInfo{ @@ -475,6 +501,7 @@ WantedBy=multi-user.target default.target goodWithExplicitShortDetachParam, true, false, + false, }, {"good with explicit short detach param and podInfo", containerInfo{ @@ -494,6 +521,7 @@ WantedBy=multi-user.target default.target goodNameNewWithPodFile, true, false, + false, }, {"good with explicit full detach param", containerInfo{ @@ -510,6 +538,7 @@ WantedBy=multi-user.target default.target goodNameNewDetach, true, false, + false, }, {"good with id and no param", containerInfo{ @@ -526,6 +555,7 @@ WantedBy=multi-user.target default.target goodIDNew, true, false, + false, }, {"good with explicit detach=true param", containerInfo{ @@ -542,6 +572,7 @@ WantedBy=multi-user.target default.target genGoodNewDetach("--detach=true"), true, false, + false, }, {"good with explicit detach=false param", containerInfo{ @@ -558,6 +589,7 @@ WantedBy=multi-user.target default.target genGoodNewDetach("-d"), true, false, + false, }, {"good with explicit detach=false param", containerInfo{ @@ -574,6 +606,7 @@ WantedBy=multi-user.target default.target goodNameNewDetachFalseWithCmd, true, false, + false, }, {"good with multiple detach=false params", containerInfo{ @@ -590,6 +623,7 @@ WantedBy=multi-user.target default.target goodNameNewDetachFalseWithCmd, true, false, + false, }, {"good with multiple shorthand params detach first", containerInfo{ @@ -606,6 +640,7 @@ WantedBy=multi-user.target default.target genGoodNewDetach("-dti"), true, false, + false, }, {"good with multiple shorthand params detach last", containerInfo{ @@ -622,6 +657,7 @@ WantedBy=multi-user.target default.target genGoodNewDetach("-tid"), true, false, + false, }, {"good with root flags", containerInfo{ @@ -638,6 +674,7 @@ WantedBy=multi-user.target default.target goodNewRootFlags, true, false, + false, }, {"good with container create", containerInfo{ @@ -654,6 +691,7 @@ WantedBy=multi-user.target default.target goodContainerCreate, true, false, + false, }, {"good with journald log tag (see #9034)", containerInfo{ @@ -670,6 +708,7 @@ WantedBy=multi-user.target default.target goodNewWithJournaldTag, true, false, + false, }, {"good with special chars", containerInfo{ @@ -686,13 +725,15 @@ WantedBy=multi-user.target default.target goodNewWithSpecialChars, true, false, + false, }, } for _, tt := range tests { test := tt t.Run(tt.name, func(t *testing.T) { opts := entities.GenerateSystemdOptions{ - New: test.new, + New: test.new, + NoHeader: test.noHeader, } 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 ff8ce3a03..14b1b7a89 100644 --- a/pkg/systemd/generate/pods.go +++ b/pkg/systemd/generate/pods.go @@ -70,6 +70,8 @@ type podInfo struct { ExecStop string // ExecStopPost of the unit. ExecStopPost string + // Removes autogenerated by Podman and timestamp if set to true + GenerateNoHeader bool } const podTemplate = headerTemplate + `Requires={{{{- range $index, $value := .RequiredServices -}}}}{{{{if $index}}}} {{{{end}}}}{{{{ $value }}}}.service{{{{end}}}} @@ -319,6 +321,12 @@ func executePodTemplate(info *podInfo, options entities.GenerateSystemdOptions) if info.PodmanVersion == "" { info.PodmanVersion = version.Version.String() } + + if options.NoHeader { + info.GenerateNoHeader = true + info.GenerateTimestamp = false + } + if info.GenerateTimestamp { info.TimeStamp = fmt.Sprintf("%v", time.Now().Format(time.UnixDate)) } diff --git a/pkg/systemd/generate/pods_test.go b/pkg/systemd/generate/pods_test.go index 2b430226b..f6ca9bced 100644 --- a/pkg/systemd/generate/pods_test.go +++ b/pkg/systemd/generate/pods_test.go @@ -37,9 +37,11 @@ func TestValidateRestartPolicyPod(t *testing.T) { } func TestCreatePodSystemdUnit(t *testing.T) { - podGood := `# pod-123abc.service -# autogenerated by Podman CI - + serviceInfo := `# pod-123abc.service +` + headerInfo := `# autogenerated by Podman CI +` + podContent := ` [Unit] Description=Podman pod-123abc.service Documentation=man:podman-generate-systemd(1) @@ -61,6 +63,8 @@ Type=forking [Install] WantedBy=multi-user.target default.target ` + podGood := serviceInfo + headerInfo + podContent + podGoodNoHeaderInfo := serviceInfo + podContent podGoodNamedNew := `# pod-123abc.service # autogenerated by Podman CI @@ -171,11 +175,12 @@ WantedBy=multi-user.target default.target ` tests := []struct { - name string - info podInfo - want string - new bool - wantErr bool + name string + info podInfo + want string + new bool + noHeader bool + wantErr bool }{ {"pod", podInfo{ @@ -192,6 +197,24 @@ WantedBy=multi-user.target default.target podGood, false, false, + false, + }, + {"pod noHeader", + podInfo{ + Executable: "/usr/bin/podman", + ServiceName: "pod-123abc", + InfraNameOrID: "jadda-jadda-infra", + RestartPolicy: "always", + PIDFile: "/run/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/conmon.pid", + StopTimeout: 42, + PodmanVersion: "CI", + RequiredServices: []string{"container-1", "container-2"}, + CreateCommand: []string{"podman", "pod", "create", "--name", "foo", "bar=arg with space"}, + }, + podGoodNoHeaderInfo, + false, + true, + false, }, {"pod with root args", podInfo{ @@ -208,6 +231,7 @@ WantedBy=multi-user.target default.target podGood, false, false, + false, }, {"pod --new", podInfo{ @@ -224,6 +248,7 @@ WantedBy=multi-user.target default.target podGoodNamedNew, true, false, + false, }, {"pod --new with root args", podInfo{ @@ -240,6 +265,7 @@ WantedBy=multi-user.target default.target podGoodNamedNewWithRootArgs, true, false, + false, }, {"pod --new with --replace=false", podInfo{ @@ -256,6 +282,7 @@ WantedBy=multi-user.target default.target podGoodNamedNewWithReplaceFalse, true, false, + false, }, {"pod --new with double curly braces", podInfo{ @@ -272,6 +299,7 @@ WantedBy=multi-user.target default.target podNewLabelWithCurlyBraces, true, false, + false, }, } @@ -279,7 +307,8 @@ WantedBy=multi-user.target default.target test := tt t.Run(tt.name, func(t *testing.T) { opts := entities.GenerateSystemdOptions{ - New: test.new, + New: test.new, + NoHeader: test.noHeader, } got, err := executePodTemplate(&test.info, opts) if (err != nil) != test.wantErr { -- cgit v1.2.3-54-g00ecf