forked from containers/podman
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request containers#5998 from vrothberg/generate-systemd
generate systemd
- Loading branch information
Showing
10 changed files
with
297 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package pods | ||
|
||
import ( | ||
"github.com/containers/libpod/cmd/podman/registry" | ||
"github.com/containers/libpod/pkg/domain/entities" | ||
"github.com/containers/libpod/pkg/util" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
// Command: podman _generate_ | ||
generateCmd = &cobra.Command{ | ||
Use: "generate", | ||
Short: "Generate structured data based on containers and pods.", | ||
Long: "Generate structured data (e.g., Kubernetes yaml or systemd units) based on containers and pods.", | ||
TraverseChildren: true, | ||
RunE: registry.SubCommandExists, | ||
} | ||
containerConfig = util.DefaultContainerConfig() | ||
) | ||
|
||
func init() { | ||
registry.Commands = append(registry.Commands, registry.CliCommand{ | ||
Mode: []entities.EngineMode{entities.ABIMode}, | ||
Command: generateCmd, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package pods | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/containers/libpod/cmd/podman/registry" | ||
"github.com/containers/libpod/cmd/podman/utils" | ||
"github.com/containers/libpod/pkg/domain/entities" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
systemdTimeout uint | ||
systemdOptions = entities.GenerateSystemdOptions{} | ||
systemdDescription = `Generate systemd units for a pod or container. | ||
The generated units can later be controlled via systemctl(1).` | ||
|
||
systemdCmd = &cobra.Command{ | ||
Use: "systemd [flags] CTR|POD", | ||
Short: "Generate systemd units.", | ||
Long: systemdDescription, | ||
RunE: systemd, | ||
Args: cobra.MinimumNArgs(1), | ||
Example: `podman generate systemd CTR | ||
podman generate systemd --new --time 10 CTR | ||
podman generate systemd --files --name POD`, | ||
} | ||
) | ||
|
||
func init() { | ||
registry.Commands = append(registry.Commands, registry.CliCommand{ | ||
Mode: []entities.EngineMode{entities.ABIMode, entities.TunnelMode}, | ||
Command: systemdCmd, | ||
Parent: generateCmd, | ||
}) | ||
flags := systemdCmd.Flags() | ||
flags.BoolVarP(&systemdOptions.Name, "name", "n", false, "Use container/pod names instead of IDs") | ||
flags.BoolVarP(&systemdOptions.Files, "files", "f", false, "Generate .service files instead of printing to stdout") | ||
flags.UintVarP(&systemdTimeout, "time", "t", containerConfig.Engine.StopTimeout, "Stop timeout override") | ||
flags.StringVar(&systemdOptions.RestartPolicy, "restart-policy", "on-failure", "Systemd restart-policy") | ||
flags.BoolVarP(&systemdOptions.New, "new", "", false, "Create a new container instead of starting an existing one") | ||
flags.SetNormalizeFunc(utils.AliasFlags) | ||
} | ||
|
||
func systemd(cmd *cobra.Command, args []string) error { | ||
if cmd.Flags().Changed("time") { | ||
systemdOptions.StopTimeout = &systemdTimeout | ||
} | ||
|
||
report, err := registry.ContainerEngine().GenerateSystemd(registry.GetContext(), args[0], systemdOptions) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Println(report.Output) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package entities | ||
|
||
// 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. | ||
New bool | ||
// RestartPolicy - systemd restart policy. | ||
RestartPolicy string | ||
// StopTimeout - time when stopping the container. | ||
StopTimeout *uint | ||
} | ||
|
||
// GenerateSystemdReport | ||
type GenerateSystemdReport struct { | ||
// Output of the generate process. Either the generated files or their | ||
// entire content. | ||
Output string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
package abi | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
|
||
"github.com/containers/libpod/libpod" | ||
"github.com/containers/libpod/pkg/domain/entities" | ||
"github.com/containers/libpod/pkg/systemd/generate" | ||
"github.com/pkg/errors" | ||
) | ||
|
||
func (ic *ContainerEngine) GenerateSystemd(ctx context.Context, nameOrID string, options entities.GenerateSystemdOptions) (*entities.GenerateSystemdReport, error) { | ||
opts := generate.Options{ | ||
Files: options.Files, | ||
New: options.New, | ||
} | ||
|
||
// First assume it's a container. | ||
if info, found, err := ic.generateSystemdgenContainerInfo(nameOrID, nil, options); found && err != nil { | ||
return nil, err | ||
} else if found && err == nil { | ||
output, err := generate.CreateContainerSystemdUnit(info, opts) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &entities.GenerateSystemdReport{Output: output}, nil | ||
} | ||
|
||
// --new does not support pods. | ||
if options.New { | ||
return nil, errors.Errorf("error generating systemd unit files: cannot generate generic files for a pod") | ||
} | ||
|
||
// We're either having a pod or garbage. | ||
pod, err := ic.Libpod.LookupPod(nameOrID) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Error out if the pod has no infra container, which we require to be the | ||
// main service. | ||
if !pod.HasInfraContainer() { | ||
return nil, fmt.Errorf("error generating systemd unit files: Pod %q has no infra container", pod.Name()) | ||
} | ||
|
||
// Generate a systemdgen.ContainerInfo for the infra container. This | ||
// ContainerInfo acts as the main service of the pod. | ||
infraID, err := pod.InfraContainerID() | ||
if err != nil { | ||
return nil, nil | ||
} | ||
podInfo, _, err := ic.generateSystemdgenContainerInfo(infraID, pod, options) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Compute the container-dependency graph for the Pod. | ||
containers, err := pod.AllContainers() | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(containers) == 0 { | ||
return nil, fmt.Errorf("error generating systemd unit files: Pod %q has no containers", pod.Name()) | ||
} | ||
graph, err := libpod.BuildContainerGraph(containers) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// Traverse the dependency graph and create systemdgen.ContainerInfo's for | ||
// each container. | ||
containerInfos := []*generate.ContainerInfo{podInfo} | ||
for ctr, dependencies := range graph.DependencyMap() { | ||
// Skip the infra container as we already generated it. | ||
if ctr.ID() == infraID { | ||
continue | ||
} | ||
ctrInfo, _, err := ic.generateSystemdgenContainerInfo(ctr.ID(), nil, options) | ||
if err != nil { | ||
return nil, err | ||
} | ||
// Now add the container's dependencies and at the container as a | ||
// required service of the infra container. | ||
for _, dep := range dependencies { | ||
if dep.ID() == infraID { | ||
ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, podInfo.ServiceName) | ||
} else { | ||
_, serviceName := generateServiceName(dep, nil, options) | ||
ctrInfo.BoundToServices = append(ctrInfo.BoundToServices, serviceName) | ||
} | ||
} | ||
podInfo.RequiredServices = append(podInfo.RequiredServices, ctrInfo.ServiceName) | ||
containerInfos = append(containerInfos, ctrInfo) | ||
} | ||
|
||
// Now generate the systemd service for all containers. | ||
builder := strings.Builder{} | ||
for i, info := range containerInfos { | ||
if i > 0 { | ||
builder.WriteByte('\n') | ||
} | ||
out, err := generate.CreateContainerSystemdUnit(info, opts) | ||
if err != nil { | ||
return nil, err | ||
} | ||
builder.WriteString(out) | ||
} | ||
|
||
return &entities.GenerateSystemdReport{Output: builder.String()}, nil | ||
} | ||
|
||
// generateSystemdgenContainerInfo is a helper to generate a | ||
// systemdgen.ContainerInfo for `GenerateSystemd`. | ||
func (ic *ContainerEngine) generateSystemdgenContainerInfo(nameOrID string, pod *libpod.Pod, options entities.GenerateSystemdOptions) (*generate.ContainerInfo, bool, error) { | ||
ctr, err := ic.Libpod.LookupContainer(nameOrID) | ||
if err != nil { | ||
return nil, false, err | ||
} | ||
|
||
timeout := ctr.StopTimeout() | ||
if options.StopTimeout != nil { | ||
timeout = *options.StopTimeout | ||
} | ||
|
||
config := ctr.Config() | ||
conmonPidFile := config.ConmonPidFile | ||
if conmonPidFile == "" { | ||
return nil, true, errors.Errorf("conmon PID file path is empty, try to recreate the container with --conmon-pidfile flag") | ||
} | ||
|
||
createCommand := []string{} | ||
if config.CreateCommand != nil { | ||
createCommand = config.CreateCommand | ||
} else if options.New { | ||
return nil, true, errors.Errorf("cannot use --new on container %q: no create command found", nameOrID) | ||
} | ||
|
||
name, serviceName := generateServiceName(ctr, pod, options) | ||
info := &generate.ContainerInfo{ | ||
ServiceName: serviceName, | ||
ContainerName: name, | ||
RestartPolicy: options.RestartPolicy, | ||
PIDFile: conmonPidFile, | ||
StopTimeout: timeout, | ||
GenerateTimestamp: true, | ||
CreateCommand: createCommand, | ||
} | ||
|
||
return info, true, nil | ||
} | ||
|
||
// generateServiceName generates the container name and the service name for systemd service. | ||
func generateServiceName(ctr *libpod.Container, pod *libpod.Pod, options entities.GenerateSystemdOptions) (string, string) { | ||
var kind, name, ctrName string | ||
if pod == nil { | ||
kind = "container" | ||
name = ctr.ID() | ||
if options.Name { | ||
name = ctr.Name() | ||
} | ||
ctrName = name | ||
} else { | ||
kind = "pod" | ||
name = pod.ID() | ||
ctrName = ctr.ID() | ||
if options.Name { | ||
name = pod.Name() | ||
ctrName = ctr.Name() | ||
} | ||
} | ||
return ctrName, fmt.Sprintf("%s-%s", kind, name) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package tunnel | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/containers/libpod/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") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters