mirror of
https://github.com/containers/podman.git
synced 2025-11-29 01:28:22 +08:00
cmd/podman: add replace flag to quadlet install
Signed-off-by: Celso Henrique Souza Silva <celsohenrique367@gmail.com> Fixes: #26930
This commit is contained in:
committed by
nothiaki
parent
b342596e1c
commit
0ea4eaee70
@@ -36,6 +36,7 @@ podman quadlet install https://github.com/containers/podman/blob/main/test/e2e/q
|
||||
func installFlags(cmd *cobra.Command) {
|
||||
flags := cmd.Flags()
|
||||
flags.BoolVar(&installOptions.ReloadSystemd, "reload-systemd", true, "Reload systemd after installing Quadlets")
|
||||
flags.BoolVarP(&installOptions.Replace, "replace", "r", false, "Replace the installation even if the quadlet already exists")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -28,6 +28,12 @@ Reload systemd after installing Quadlets (default true).
|
||||
In order to disable it users need to manually set the value
|
||||
of this flag to `false`.
|
||||
|
||||
#### **--replace**, **-r**
|
||||
|
||||
Replace the Quadlet installation even if the generated unit file already exists (default false).
|
||||
In order to enable it, users need to manually set the value
|
||||
of this flag to `true`. This flag is used primarily to update an existing unit.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
Install quadlet from a file.
|
||||
|
||||
@@ -4,6 +4,8 @@ package entities
|
||||
type QuadletInstallOptions struct {
|
||||
// Whether to reload systemd after installation is completed
|
||||
ReloadSystemd bool
|
||||
// Replace the installation even if the quadlet already exists
|
||||
Replace bool
|
||||
}
|
||||
|
||||
// QuadletInstallReport contains the output of the `quadlet install` command
|
||||
|
||||
@@ -197,7 +197,7 @@ func (ic *ContainerEngine) QuadletInstall(ctx context.Context, pathsOrURLs []str
|
||||
installReport.QuadletErrors[toInstall] = fmt.Errorf("populating temporary file: %w", err)
|
||||
continue
|
||||
}
|
||||
installedPath, err := ic.installQuadlet(ctx, tmpFile.Name(), quadletFileName, installDir, assetFile, validateQuadletFile)
|
||||
installedPath, err := ic.installQuadlet(ctx, tmpFile.Name(), quadletFileName, installDir, assetFile, validateQuadletFile, options.Replace)
|
||||
if err != nil {
|
||||
installReport.QuadletErrors[toInstall] = err
|
||||
continue
|
||||
@@ -210,7 +210,7 @@ func (ic *ContainerEngine) QuadletInstall(ctx context.Context, pathsOrURLs []str
|
||||
continue
|
||||
}
|
||||
// If toInstall is a single file, execute the original logic
|
||||
installedPath, err := ic.installQuadlet(ctx, toInstall, "", installDir, assetFile, validateQuadletFile)
|
||||
installedPath, err := ic.installQuadlet(ctx, toInstall, "", installDir, assetFile, validateQuadletFile, options.Replace)
|
||||
if err != nil {
|
||||
installReport.QuadletErrors[toInstall] = err
|
||||
continue
|
||||
@@ -254,7 +254,7 @@ func getFileName(resp *http.Response, fileURL string) (string, error) {
|
||||
// Perform some minimal validation, but not much.
|
||||
// We can't know about a lot of problems without running the Quadlet binary, which we
|
||||
// only want to do once.
|
||||
func (ic *ContainerEngine) installQuadlet(_ context.Context, path, destName, installDir, assetFile string, isQuadletFile bool) (string, error) {
|
||||
func (ic *ContainerEngine) installQuadlet(_ context.Context, path, destName, installDir, assetFile string, isQuadletFile, replace bool) (string, error) {
|
||||
// First, validate that the source path exists and is a file
|
||||
stat, err := os.Stat(path)
|
||||
if err != nil {
|
||||
@@ -274,9 +274,15 @@ func (ic *ContainerEngine) installQuadlet(_ context.Context, path, destName, ins
|
||||
return "", fmt.Errorf("%q is not a supported Quadlet file type", filepath.Ext(finalPath))
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(finalPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644)
|
||||
var osFlags = os.O_CREATE | os.O_WRONLY
|
||||
|
||||
if !replace {
|
||||
osFlags |= os.O_EXCL
|
||||
}
|
||||
|
||||
file, err := os.OpenFile(finalPath, osFlags, 0644)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrExist) {
|
||||
if errors.Is(err, fs.ErrExist) && !replace {
|
||||
return "", fmt.Errorf("a Quadlet with name %s already exists, refusing to overwrite", filepath.Base(finalPath))
|
||||
}
|
||||
return "", fmt.Errorf("unable to open file %s: %w", filepath.Base(finalPath), err)
|
||||
|
||||
@@ -461,4 +461,43 @@ EOF
|
||||
assert $status -eq 0 "quadlet rm --ignore should succeed even for non-existent quadlets"
|
||||
}
|
||||
|
||||
@test "quadlet install --replace" {
|
||||
local install_dir=$(get_quadlet_install_dir)
|
||||
# Create a test quadlet file
|
||||
local quadlet_file=$PODMAN_TMPDIR/alpine-quadlet.container
|
||||
local initial_exec='Exec=sh -c "echo STARTED CONTAINER; trap '\''exit'\'' SIGTERM; while :; do sleep 0.1; done"'
|
||||
cat > $quadlet_file <<EOF
|
||||
[Container]
|
||||
Image=$IMAGE
|
||||
$initial_exec
|
||||
EOF
|
||||
# Test quadlet install
|
||||
run_podman quadlet install $quadlet_file
|
||||
# Verify install output contains the quadlet name on a single line
|
||||
assert "$output" =~ "alpine-quadlet.container" "install output should contain quadlet name"
|
||||
|
||||
# Without replace should fail
|
||||
run_podman 125 quadlet install $quadlet_file
|
||||
assert "$output" =~ "refusing to overwrite" "reinstall without --replace must fail with the overwrite error message"
|
||||
|
||||
cat > $quadlet_file <<EOF
|
||||
[Container]
|
||||
Image=$IMAGE
|
||||
Exec=sh -c "echo STARTED CONTAINER UPDATED; trap 'exit' SIGTERM; while :; do sleep 0.1; done"
|
||||
EOF
|
||||
# With replace should pass and update quadlet
|
||||
run_podman quadlet install --replace $quadlet_file
|
||||
|
||||
# Verify install output contains the quadlet name on a single line
|
||||
assert "$output" =~ "alpine-quadlet.container" "install output should contain quadlet name"
|
||||
|
||||
run_podman quadlet print alpine-quadlet.container
|
||||
|
||||
assert "$output" !~ "$initial_exec" "Printed content must not show the initial version"
|
||||
assert "$output" == "$(<$quadlet_file)" "Printed content must match the updated file content"
|
||||
|
||||
# Clean up
|
||||
run_podman quadlet rm alpine-quadlet.container
|
||||
}
|
||||
|
||||
# vim: filetype=sh
|
||||
|
||||
Reference in New Issue
Block a user