Add a feature to pass user provided files during qcow2ova image conversion - #851
Add a feature to pass user provided files during qcow2ova image conversion#851Amulyam24 wants to merge 1 commit into
Conversation
|
/cc @kishen-v |
|
/lgtm |
0d7a269 to
d21a092
Compare
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Amulyam24 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
@kishen-v @anup-kodlekere, PTAL! |
|
LGTM! |
|
/lgtm |
There was a problem hiding this comment.
Code Review
Thanks for the feature! I've left inline comments on the specific issues below. Summary of what needs attention before merge:
- 🔴 [High] Missing flag co-validation —
--write-files-listwithout--write-to-dir-pathsilently dumps files into the image root - 🟡 [Medium]
coreossilently drops user-provided files with no warning - 🟡 [Medium]
MkdirAllruns unconditionally even when no files are specified - 🟠 [Medium] No path traversal guard on
--write-to-dir-path - 🟡 [Low]
os.StatincopyFilesfollows symlinks transparently - 🟢 [Low] Double stat call in
copyFile(minor) - 🟡 [Medium] Broken example command (missing
--image-namevalue) - 🟡 [Medium] No unit tests for the new copy logic
Also worth considering: the flag names --write-files-list and --write-to-dir-path are more verbose than the project style. Something like --inject-files + --inject-dest would be terser and more intent-driven, matching how --prep-template, --cloud-config, --temp-dir are named.
Review done by Bob
| @@ -144,6 +145,19 @@ func prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd string) error { | |||
| return err | |||
| } | |||
|
|
|||
There was a problem hiding this comment.
[Correctness] Unconditional MkdirAll when no files are specified
When neither flag is provided, writeToDirPath is "" and writeFilesList is empty. filepath.Join(mnt, "") resolves to mnt (the image root), so MkdirAll runs on the root — harmless but unnecessary. More importantly, if a user passes --write-to-dir-path /some/path without --write-files-list, a spurious empty directory is silently created inside the image.
Wrap the entire block in a guard:
if len(writeFilesList) > 0 {
imageWritePath := filepath.Join(mnt, writeToDirPath)
if err := os.MkdirAll(imageWritePath, 0755); err != nil {
return fmt.Errorf("failed to create directory %s: %w", imageWritePath, err)
}
for _, filePath := range writeFilesList {
destinationPath := filepath.Join(imageWritePath, filepath.Base(filePath))
if err := copyFiles(filePath, destinationPath); err != nil {
return err
}
}
}| return err | ||
| } | ||
|
|
||
| // Write user provided files to given path in the image |
There was a problem hiding this comment.
[Security] No path traversal guard on writeToDirPath
filepath.Join does not prevent ../ escape sequences. A user passing --write-to-dir-path ../../etc could resolve a path outside the intended mnt subtree.
Add a check after constructing imageWritePath:
if !strings.HasPrefix(filepath.Clean(imageWritePath), filepath.Clean(mnt)+"/") {
return fmt.Errorf("write-to-dir-path %q escapes the image mount root", writeToDirPath)
}| case "rhel", "centos": | ||
| return prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd) | ||
| return prepare(mnt, volume, dist, rhnuser, rhnpasswd, rootpasswd, writeToDirPath, writeFilesList) | ||
| case "coreos": |
There was a problem hiding this comment.
[Correctness] coreos silently drops user-provided files
The file-copy block only runs inside prepare(), which is only called for rhel/centos. For coreos, any --write-files-list entries are silently ignored. A user would get no error and no warning.
Either propagate the copy step for coreos too, or return an explicit error when writeFilesList is non-empty for that distro:
case "coreos":
if len(writeFilesList) > 0 {
return fmt.Errorf("--write-files-list is not supported for coreos distro")
}
klog.Info("No image preparation required for the coreos.")
return nil| func copyFiles(src, dest string) error { | ||
| fileInfo, err := os.Stat(src) | ||
| if err != nil { | ||
| return err |
There was a problem hiding this comment.
[Security] os.Stat follows symlinks transparently
os.Stat resolves symlinks, so if any entry in --write-files-list is a symlink (e.g. pointing to /etc/shadow), it will be silently read and copied into the image as a regular file. Consider using os.Lstat here and explicitly deciding whether to follow, skip, or error on symlinks.
| if err != nil { | ||
| return err | ||
| } | ||
|
|
There was a problem hiding this comment.
[Readability] Trailing blank line before closing brace
return copyFile(src, dest)
// ← remove this blank line
}gofmt does not produce a blank line before a closing brace. Minor, but inconsistent with the rest of the file.
| in, err := os.Open(src) | ||
| if err != nil { | ||
| return err | ||
| } |
There was a problem hiding this comment.
[Performance] Double stat call in copyFile
os.Stat(src) was already called in copyFiles to determine if the path is a file or directory — then in.Stat() is called again here on the open file handle to retrieve permissions. You could pass fileInfo down from copyFiles to copyFile to avoid the redundant syscall:
func copyFile(src, dest string, srcInfo os.FileInfo) error {
in, err := os.Open(src)
...
out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, srcInfo.Mode())
...
}|
|
||
| # For adding custom files to the image, run the qcow2ova with flags --write-files-list and --write-to-dir-path | ||
| pvsadm image qcow2ova --image-name --image-dist centos --image-url /root/CentOS-8-GenericCloud-8.2.2004-20200611.2.ppc64le.qcow2 --prep-template image-prep.template --write-files-list a.txt,b.log --write-to-dir-path /home/user | ||
|
|
There was a problem hiding this comment.
[Correctness — High] Missing flag co-validation: --write-files-list requires --write-to-dir-path
When --write-files-list is provided without --write-to-dir-path, writeToDirPath defaults to "". filepath.Join(mnt, "") resolves to mnt (the image root), so all user files get dumped at / inside the image — almost certainly not intended.
Add a validation check in PreRunE, consistent with how other flag dependencies are validated in this file:
if len(opt.WriteFilesList) > 0 && opt.WriteToDirPath == "" {
return fmt.Errorf("--write-to-dir-path is required when --write-files-list is specified")
}
What this PR does / why we need it:
This PR adds a feature to allow user to add custom files to the image built.
--write-files-list is a comma separated list of files and --write-to-dir-path is the path where the files are written in the built image
example:
Tested the following scenarios
Which issue(s) this PR fixes (optional, in
fixes #<issue number>(, fixes #<issue_number>, ...)format, will close the issue(s) when PR gets merged):Fixes #811
Special notes for your reviewer:
**Output/Demonstration