mirror of
https://github.com/containers/podman.git
synced 2025-06-28 06:18:57 +08:00
Quadlet: Add support for .kube files
Get the path to the yaml file and call podman kube play Add tests Signed-off-by: Ygal Blum <ygal.blum@gmail.com>
This commit is contained in:
@ -34,6 +34,15 @@ var (
|
||||
kmsgFile *os.File
|
||||
)
|
||||
|
||||
var (
|
||||
void struct{}
|
||||
supportedExtensions = map[string]struct{}{
|
||||
".container": void,
|
||||
".volume": void,
|
||||
".kube": void,
|
||||
}
|
||||
)
|
||||
|
||||
// We log directly to /dev/kmsg, because that is the only way to get information out
|
||||
// of the generator into the system logs.
|
||||
func logToKmsg(s string) bool {
|
||||
@ -105,6 +114,12 @@ func getUnitDirs(user bool) []string {
|
||||
return dirs
|
||||
}
|
||||
|
||||
func isExtSupported(filename string) bool {
|
||||
ext := filepath.Ext(filename)
|
||||
_, ok := supportedExtensions[ext]
|
||||
return ok
|
||||
}
|
||||
|
||||
func loadUnitsFromDir(sourcePath string, units map[string]*parser.UnitFile) {
|
||||
files, err := os.ReadDir(sourcePath)
|
||||
if err != nil {
|
||||
@ -116,9 +131,7 @@ func loadUnitsFromDir(sourcePath string, units map[string]*parser.UnitFile) {
|
||||
|
||||
for _, file := range files {
|
||||
name := file.Name()
|
||||
if units[name] == nil &&
|
||||
(strings.HasSuffix(name, ".container") ||
|
||||
strings.HasSuffix(name, ".volume")) {
|
||||
if units[name] == nil && isExtSupported(name) {
|
||||
path := path.Join(sourcePath, name)
|
||||
|
||||
Debugf("Loading source unit file %s", path)
|
||||
@ -322,6 +335,8 @@ func main() {
|
||||
service, err = quadlet.ConvertContainer(unit, isUser)
|
||||
case strings.HasSuffix(name, ".volume"):
|
||||
service, err = quadlet.ConvertVolume(unit, name)
|
||||
case strings.HasSuffix(name, ".kube"):
|
||||
service, err = quadlet.ConvertKube(unit)
|
||||
default:
|
||||
Logf("Unsupported file type '%s'", name)
|
||||
continue
|
||||
|
@ -22,6 +22,8 @@ const (
|
||||
XContainerGroup = "X-Container"
|
||||
VolumeGroup = "Volume"
|
||||
XVolumeGroup = "X-Volume"
|
||||
KubeGroup = "Kube"
|
||||
XKubeGroup = "X-Kube"
|
||||
)
|
||||
|
||||
var validPortRange = regexp.MustCompile(`\d+(-\d+)?(/udp|/tcp)?$`)
|
||||
@ -55,6 +57,7 @@ const (
|
||||
KeySeccompProfile = "SeccompProfile"
|
||||
KeyAddDevice = "AddDevice"
|
||||
KeyNetwork = "Network"
|
||||
KeyYaml = "Yaml"
|
||||
)
|
||||
|
||||
// Supported keys in "Container" group
|
||||
@ -95,6 +98,11 @@ var supportedVolumeKeys = map[string]bool{
|
||||
KeyLabel: true,
|
||||
}
|
||||
|
||||
// Supported keys in "Kube" group
|
||||
var supportedKubeKeys = map[string]bool{
|
||||
KeyYaml: true,
|
||||
}
|
||||
|
||||
func replaceExtension(name string, extension string, extraPrefix string, extraSuffix string) string {
|
||||
baseName := name
|
||||
|
||||
@ -593,3 +601,65 @@ func ConvertVolume(volume *parser.UnitFile, name string) (*parser.UnitFile, erro
|
||||
|
||||
return service, nil
|
||||
}
|
||||
|
||||
func ConvertKube(kube *parser.UnitFile) (*parser.UnitFile, error) {
|
||||
service := kube.Dup()
|
||||
service.Filename = replaceExtension(kube.Filename, ".service", "", "")
|
||||
|
||||
if kube.Path != "" {
|
||||
service.Add(UnitGroup, "SourcePath", kube.Path)
|
||||
}
|
||||
|
||||
if err := checkForUnknownKeys(kube, KubeGroup, supportedKubeKeys); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Rename old Kube group to x-Kube so that systemd ignores it
|
||||
service.RenameGroup(KubeGroup, XKubeGroup)
|
||||
|
||||
yamlPath, ok := kube.Lookup(KubeGroup, KeyYaml)
|
||||
if !ok || len(yamlPath) == 0 {
|
||||
return nil, fmt.Errorf("no Yaml key specified")
|
||||
}
|
||||
|
||||
// Only allow mixed or control-group, as nothing else works well
|
||||
killMode, ok := service.Lookup(ServiceGroup, "KillMode")
|
||||
if !ok || !(killMode == "mixed" || killMode == "control-group") {
|
||||
if ok {
|
||||
return nil, fmt.Errorf("invalid KillMode '%s'", killMode)
|
||||
}
|
||||
|
||||
// We default to mixed instead of control-group, because it lets conmon do its thing
|
||||
service.Set(ServiceGroup, "KillMode", "mixed")
|
||||
}
|
||||
|
||||
// Set PODMAN_SYSTEMD_UNIT so that podman auto-update can restart the service.
|
||||
service.Add(ServiceGroup, "Environment", "PODMAN_SYSTEMD_UNIT=%n")
|
||||
|
||||
// Need the containers filesystem mounted to start podman
|
||||
service.Add(UnitGroup, "RequiresMountsFor", "%t/containers")
|
||||
|
||||
service.Setv(ServiceGroup,
|
||||
"Type", "notify",
|
||||
"NotifyAccess", "all")
|
||||
|
||||
execStart := NewPodmanCmdline("kube", "play")
|
||||
|
||||
execStart.add(
|
||||
// Replace any previous container with the same name, not fail
|
||||
"--replace",
|
||||
|
||||
// Use a service container
|
||||
"--service-container=true",
|
||||
)
|
||||
|
||||
execStart.add(yamlPath)
|
||||
|
||||
service.AddCmdline(ServiceGroup, "ExecStart", execStart.Args)
|
||||
|
||||
execStop := NewPodmanCmdline("kube", "down")
|
||||
execStop.add(yamlPath)
|
||||
service.AddCmdline(ServiceGroup, "ExecStop", execStop.Args)
|
||||
|
||||
return service, nil
|
||||
}
|
||||
|
17
test/e2e/quadlet/basic.kube
Normal file
17
test/e2e/quadlet/basic.kube
Normal file
@ -0,0 +1,17 @@
|
||||
## assert-podman-args "kube"
|
||||
## assert-podman-args "play"
|
||||
## assert-podman-final-args deployment.yml
|
||||
## assert-podman-args "--replace"
|
||||
## assert-podman-args "--service-container=true"
|
||||
## assert-podman-stop-args "kube"
|
||||
## assert-podman-stop-args "down"
|
||||
## assert-podman-stop-final-args deployment.yml
|
||||
## assert-key-is "Unit" "RequiresMountsFor" "%t/containers"
|
||||
## assert-key-is "Service" "KillMode" "mixed"
|
||||
## assert-key-is "Service" "Type" "notify"
|
||||
## assert-key-is "Service" "NotifyAccess" "all"
|
||||
## assert-key-is "Service" "Environment" "PODMAN_SYSTEMD_UNIT=%n"
|
||||
|
||||
|
||||
[Kube]
|
||||
Yaml=deployment.yml
|
@ -110,19 +110,35 @@ func (t *quadletTestcase) assertKeyContains(args []string, unit *parser.UnitFile
|
||||
return ok && strings.Contains(realValue, value)
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertPodmanArgs(args []string, unit *parser.UnitFile) bool {
|
||||
podmanArgs, _ := unit.LookupLastArgs("Service", "ExecStart")
|
||||
func (t *quadletTestcase) assertPodmanArgs(args []string, unit *parser.UnitFile, key string) bool {
|
||||
podmanArgs, _ := unit.LookupLastArgs("Service", key)
|
||||
return findSublist(podmanArgs, args) != -1
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertFinalArgs(args []string, unit *parser.UnitFile) bool {
|
||||
podmanArgs, _ := unit.LookupLastArgs("Service", "ExecStart")
|
||||
func (t *quadletTestcase) assertPodmanFinalArgs(args []string, unit *parser.UnitFile, key string) bool {
|
||||
podmanArgs, _ := unit.LookupLastArgs("Service", key)
|
||||
if len(podmanArgs) < len(args) {
|
||||
return false
|
||||
}
|
||||
return matchSublistAt(podmanArgs, len(podmanArgs)-len(args), args)
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertStartPodmanArgs(args []string, unit *parser.UnitFile) bool {
|
||||
return t.assertPodmanArgs(args, unit, "ExecStart")
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertStartPodmanFinalArgs(args []string, unit *parser.UnitFile) bool {
|
||||
return t.assertPodmanFinalArgs(args, unit, "ExecStart")
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertStopPodmanArgs(args []string, unit *parser.UnitFile) bool {
|
||||
return t.assertPodmanArgs(args, unit, "ExecStop")
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertStopPodmanFinalArgs(args []string, unit *parser.UnitFile) bool {
|
||||
return t.assertPodmanFinalArgs(args, unit, "ExecStop")
|
||||
}
|
||||
|
||||
func (t *quadletTestcase) assertSymlink(args []string, unit *parser.UnitFile) bool {
|
||||
symlink := args[0]
|
||||
expectedTarget := args[1]
|
||||
@ -161,11 +177,15 @@ func (t *quadletTestcase) doAssert(check []string, unit *parser.UnitFile, sessio
|
||||
case "assert-key-contains":
|
||||
ok = t.assertKeyContains(args, unit)
|
||||
case "assert-podman-args":
|
||||
ok = t.assertPodmanArgs(args, unit)
|
||||
ok = t.assertStartPodmanArgs(args, unit)
|
||||
case "assert-podman-final-args":
|
||||
ok = t.assertFinalArgs(args, unit)
|
||||
ok = t.assertStartPodmanFinalArgs(args, unit)
|
||||
case "assert-symlink":
|
||||
ok = t.assertSymlink(args, unit)
|
||||
case "assert-podman-stop-args":
|
||||
ok = t.assertStopPodmanArgs(args, unit)
|
||||
case "assert-podman-stop-final-args":
|
||||
ok = t.assertStopPodmanFinalArgs(args, unit)
|
||||
default:
|
||||
return fmt.Errorf("Unsupported assertion %s", op)
|
||||
}
|
||||
@ -300,6 +320,8 @@ var _ = Describe("quadlet system generator", func() {
|
||||
Entry("basic.volume", "basic.volume"),
|
||||
Entry("label.volume", "label.volume"),
|
||||
Entry("uid.volume", "uid.volume"),
|
||||
|
||||
Entry("Basic kube", "basic.kube"),
|
||||
)
|
||||
|
||||
})
|
||||
|
Reference in New Issue
Block a user