Skip to content

Commit

Permalink
Merge pull request #19006 from deuill/quadlet-volume-network-names
Browse files Browse the repository at this point in the history
Allow setting volume and network names in Quadlet
  • Loading branch information
openshift-merge-robot authored Jul 12, 2023
2 parents 958191a + 932fae4 commit 9d9f4aa
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 74 deletions.
61 changes: 42 additions & 19 deletions cmd/quadlet/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os/user"
"path"
"path/filepath"
"sort"
"strings"
"unicode"

Expand Down Expand Up @@ -132,19 +133,22 @@ func isExtSupported(filename string) bool {
return ok
}

func loadUnitsFromDir(sourcePath string, units map[string]*parser.UnitFile) error {
func loadUnitsFromDir(sourcePath string) ([]*parser.UnitFile, error) {
var prevError error
files, err := os.ReadDir(sourcePath)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return err
return nil, err
}
return nil
return []*parser.UnitFile{}, nil
}

var units []*parser.UnitFile
var seen = make(map[string]struct{})

for _, file := range files {
name := file.Name()
if units[name] == nil && isExtSupported(name) {
if _, ok := seen[name]; !ok && isExtSupported(name) {
path := path.Join(sourcePath, name)

Debugf("Loading source unit file %s", path)
Expand All @@ -155,11 +159,13 @@ func loadUnitsFromDir(sourcePath string, units map[string]*parser.UnitFile) erro
prevError = fmt.Errorf("%s\n%s", prevError, err)
}
} else {
units[name] = f
seen[name] = void
units = append(units, f)
}
}
}
return prevError

return units, prevError
}

func generateServiceFile(service *parser.UnitFile) error {
Expand Down Expand Up @@ -357,10 +363,12 @@ func process() error {

sourcePaths := getUnitDirs(isUserFlag)

units := make(map[string]*parser.UnitFile)
var units []*parser.UnitFile
for _, d := range sourcePaths {
if err := loadUnitsFromDir(d, units); err != nil {
if result, err := loadUnitsFromDir(d); err != nil {
reportError(err)
} else {
units = append(units, result...)
}
}

Expand All @@ -379,29 +387,44 @@ func process() error {
}
}

for name, unit := range units {
// Sort unit files according to potential inter-dependencies, with Volume and Network units
// taking precedence over all others.
sort.Slice(units, func(i, j int) bool {
name := units[i].Filename
return strings.HasSuffix(name, ".volume") || strings.HasSuffix(name, ".network")
})

// A map of network/volume unit file-names, against their calculated names, as needed by Podman.
var resourceNames = make(map[string]string)

for _, unit := range units {
var service *parser.UnitFile
var name string
var err error

switch {
case strings.HasSuffix(name, ".container"):
case strings.HasSuffix(unit.Filename, ".container"):
warnIfAmbiguousName(unit)
service, err = quadlet.ConvertContainer(unit, isUserFlag)
case strings.HasSuffix(name, ".volume"):
service, err = quadlet.ConvertVolume(unit, name)
case strings.HasSuffix(name, ".kube"):
service, err = quadlet.ConvertKube(unit, isUserFlag)
case strings.HasSuffix(name, ".network"):
service, err = quadlet.ConvertNetwork(unit, name)
service, err = quadlet.ConvertContainer(unit, resourceNames, isUserFlag)
case strings.HasSuffix(unit.Filename, ".volume"):
service, name, err = quadlet.ConvertVolume(unit, unit.Filename)
case strings.HasSuffix(unit.Filename, ".kube"):
service, err = quadlet.ConvertKube(unit, resourceNames, isUserFlag)
case strings.HasSuffix(unit.Filename, ".network"):
service, name, err = quadlet.ConvertNetwork(unit, unit.Filename)
default:
Logf("Unsupported file type %q", name)
Logf("Unsupported file type %q", unit.Filename)
continue
}

if err != nil {
reportError(fmt.Errorf("converting %q: %w", name, err))
reportError(fmt.Errorf("converting %q: %w", unit.Filename, err))
continue
}

if name != "" {
resourceNames[unit.Filename] = name
}
service.Path = path.Join(outputPath, service.Filename)

if dryRunFlag {
Expand Down
73 changes: 46 additions & 27 deletions docs/source/markdown/podman-systemd.unit.5.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,9 @@ the container that is run as a service. The resulting service file contains a li
options passed to Podman. However, some options also affect the details of how systemd is set up to run and
interact with the container.

By default, the Podman container has the same name as the unit, but with a `systemd-` prefix.
I.e. a `$name.container` file creates a `$name.service` unit and a `systemd-$name` Podman container.
By default, the Podman container has the same name as the unit, but with a `systemd-` prefix, i.e.
a `$name.container` file creates a `$name.service` unit and a `systemd-$name` Podman container. The
`ContainerName` option allows for overriding this default name with a user-provided one.

There is only one required key, `Image`, which defines the container image the service runs.

Expand Down Expand Up @@ -633,27 +634,30 @@ Network files are named with a `.network` extension and contain a section `[Netw
named Podman network. The generated service is a one-time command that ensures that the network
exists on the host, creating it if needed.

For a network file named `$NAME.network`, the generated Podman network is called `systemd-$NAME`,
and the generated service file `$NAME-network.service`.
By default, the Podman network has the same name as the unit, but with a `systemd-` prefix, i.e. for
a network file named `$NAME.network`, the generated Podman network is called `systemd-$NAME`, and
the generated service file is `$NAME-network.service`. The `NetworkName` option allows for
overriding this default name with a user-provided one.

Using network units allows containers to depend on networks being automatically pre-created. This is
particularly interesting when using special options to control network creation, as Podman otherwise creates networks with the default options.

Valid options for `[Network]` are listed below:

| **[Network] options** | **podman network create equivalent** |
| ----------------- | ------------------ |
| DisableDNS=true | --disable-dns |
| Driver=bridge | --driver bridge |
| Gateway=192.168.55.3 | --gateway 192.168.55.3 |
| Internal=true | --internal |
| IPAMDriver=dhcp | --ipam-driver dhcp |
| IPRange=192.168.55.128/25 | --ip-range 192.168.55.128/25 |
| IPv6=true | --ipv6 |
| Label="YXZ" | --label "XYZ" |
| Options=isolate | --opt isolate |
| PodmanArgs=--dns=192.168.55.1 | --dns=192.168.55.1 |
| Subnet=192.5.0.0/16 | --subnet 192.5.0.0/16 |
| **[Network] options** | **podman network create equivalent** |
|-------------------------------|--------------------------------------|
| DisableDNS=true | --disable-dns |
| Driver=bridge | --driver bridge |
| Gateway=192.168.55.3 | --gateway 192.168.55.3 |
| Internal=true | --internal |
| IPAMDriver=dhcp | --ipam-driver dhcp |
| IPRange=192.168.55.128/25 | --ip-range 192.168.55.128/25 |
| IPv6=true | --ipv6 |
| Label="YXZ" | --label "XYZ" |
| NetworkName=foo | podman network create foo |
| Options=isolate | --opt isolate |
| PodmanArgs=--dns=192.168.55.1 | --dns=192.168.55.1 |
| Subnet=192.5.0.0/16 | --subnet 192.5.0.0/16 |

Supported keys in `[Network]` section are:

Expand Down Expand Up @@ -712,6 +716,12 @@ Set one or more OCI labels on the network. The format is a list of

This key can be listed multiple times.

### `NetworkName=`

The (optional) name of the Podman network. If this is not specified, the default value of
`systemd-%N` is used, which is the same as the unit name but with a `systemd-` prefix to avoid
conflicts with user-managed networks.

### `Options=`

Set driver specific options.
Expand Down Expand Up @@ -745,23 +755,26 @@ Volume files are named with a `.volume` extension and contain a section `[Volume
named Podman volume. The generated service is a one-time command that ensures that the volume
exists on the host, creating it if needed.

For a volume file named `$NAME.volume`, the generated Podman volume is called `systemd-$NAME`,
and the generated service file `$NAME-volume.service`.
By default, the Podman volume has the same name as the unit, but with a `systemd-` prefix, i.e. for
a volume file named `$NAME.volume`, the generated Podman volume is called `systemd-$NAME`, and the
generated service file is `$NAME-volume.service`. The `VolumeName` option allows for overriding this
default name with a user-provided one.

Using volume units allows containers to depend on volumes being automatically pre-created. This is
particularly interesting when using special options to control volume creation,
as Podman otherwise creates volumes with the default options.

Valid options for `[Volume]` are listed below:

| **[Volume] options** | **podman volume create equivalent** |
| ----------------- | ------------------ |
| Device=tmpfs | --opt device=tmpfs |
| Copy=true | --opt copy |
| Group=192 | --opt group=192 |
| Label="foo=bar" | --label "foo=bar" |
| Options=XYZ | --opt XYZ |
| PodmanArgs=--driver=image | --driver=image |
| **[Volume] options** | **podman volume create equivalent** |
|---------------------------|-------------------------------------|
| Device=tmpfs | --opt device=tmpfs |
| Copy=true | --opt copy |
| Group=192 | --opt group=192 |
| Label="foo=bar" | --label "foo=bar" |
| Options=XYZ | --opt XYZ |
| PodmanArgs=--driver=image | --driver=image |
| VolumeName=foo | podman volume create foo |

Supported keys in `[Volume]` section are:

Expand Down Expand Up @@ -810,6 +823,12 @@ The filesystem type of `Device` as used by the **mount(8)** commands `-t` option

The host (numeric) UID, or user name to use as the owner for the volume

### `VolumeName=`

The (optional) name of the Podman volume. If this is not specified, the default value of
`systemd-%N` is used, which is the same as the unit name but with a `systemd-` prefix to avoid
conflicts with user-managed volumes.

## EXAMPLES

Example `test.container`:
Expand Down
Loading

0 comments on commit 9d9f4aa

Please sign in to comment.