Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VZ: Support Kernel Image #2562

Merged
merged 1 commit into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions hack/inject-cmdline-to-template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,17 @@ readonly yq_filter="
parsed=$(yq eval "${yq_filter}" "${template}")

# 3. get the image location
function check_location() {
local location=$1 http_code
http_code=$(curl -sIL -w "%{http_code}" "${location}" -o /dev/null)
[[ ${http_code} -eq 200 ]]
}
while IFS= read -r line; do arr+=("${line}"); done <<<"${parsed}"
readonly locations=("${arr[@]}")
for ((i = 0; i < ${#locations[@]}; i++)); do
[[ ${locations[i]} != "null" ]] || continue
http_code=$(curl -sIL -w "%{http_code}" "${locations[i]}" -o /dev/null)
if [[ ${http_code} -eq 200 ]]; then
# shellcheck disable=SC2310
if check_location "${locations[i]}"; then
location=${locations[i]}
index=${i}
break
Expand Down Expand Up @@ -78,14 +83,18 @@ initrd_digest=$(awk "/${initrd_basename}/{print \"sha256:\"\$1}" <<<"${sha256sum
initrd_location="${location_dirname}/${initrd_basename}"

# 6. inject the kernel and initrd location, digest, and cmdline to the template
yq -i eval "
[(.images.[] | select(.arch == \"${arch}\") | path)].[${index}] + \"kernel\" as \$path|
setpath(\$path; { \"location\": \"${kernel_location}\", \"digest\": \"${kernel_digest}\", \"cmdline\": \"${cmdline}\" })
" "${template}"
yq -i eval "
[(.images.[] | select(.arch == \"${arch}\") | path)].[${index}] + \"initrd\" as \$path|
setpath(\$path ; { \"location\": \"${initrd_location}\", \"digest\": \"${initrd_digest}\" })
" "${template}"
function inject_to() {
# shellcheck disable=SC2034
local template=$1 arch=$2 index=$3 key=$4 location=$5 digest=$6 cmdline=${7:-} fields=() IFS=,
# shellcheck disable=SC2310
check_location "${location}" || return 0
for field_name in location digest cmdline; do
[[ -z ${!field_name} ]] || fields+=("\"${field_name}\": \"${!field_name}\"")
done
yq -i -I 2 eval "setpath([(.images[] | select(.arch == \"${arch}\") | path)].[${index}] + \"${key}\"; { ${fields[*]}})" "${template}"
}
inject_to "${template}" "${arch}" "${index}" "kernel" "${kernel_location}" "${kernel_digest}" "${cmdline}"
inject_to "${template}" "${arch}" "${index}" "initrd" "${initrd_location}" "${initrd_digest}"

# 7. output kernel_location, kernel_digest, cmdline, initrd_location, initrd_digest
readonly outputs=(kernel_location kernel_digest cmdline initrd_location initrd_digest)
Expand Down
32 changes: 32 additions & 0 deletions pkg/downloader/downloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,10 @@ func copyLocal(ctx context.Context, dst, src, ext string, decompress bool, descr
if command != "" {
return decompressLocal(ctx, command, dstPath, srcPath, ext, description)
}
commandByMagic := decompressorByMagic(srcPath)
if commandByMagic != "" {
return decompressLocal(ctx, commandByMagic, dstPath, srcPath, ext, description)
}
}
// TODO: progress bar for copy
return fs.CopyFile(dstPath, srcPath)
Expand All @@ -428,6 +432,34 @@ func decompressor(ext string) string {
}
}

func decompressorByMagic(file string) string {
f, err := os.Open(file)
if err != nil {
return ""
}
defer f.Close()
header := make([]byte, 6)
if _, err := f.Read(header); err != nil {
return ""
}
if _, err := f.Seek(0, io.SeekStart); err != nil {
return ""
}
if bytes.HasPrefix(header, []byte{0x1f, 0x8b}) {
return "gzip"
}
if bytes.HasPrefix(header, []byte{0x42, 0x5a}) {
return "bzip2"
}
if bytes.HasPrefix(header, []byte{0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00}) {
return "xz"
}
if bytes.HasPrefix(header, []byte{0x28, 0xb5, 0x2f, 0xfd}) {
return "zstd"
}
return ""
}

func decompressLocal(ctx context.Context, decompressCmd, dst, src, ext, description string) error {
logrus.Infof("decompressing %s with %v", ext, decompressCmd)

Expand Down
22 changes: 22 additions & 0 deletions pkg/vz/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ func EnsureDisk(ctx context.Context, driver *driver.BaseDriver) error {
}

baseDisk := filepath.Join(driver.Instance.Dir, filenames.BaseDisk)
kernel := filepath.Join(driver.Instance.Dir, filenames.Kernel)
kernelCmdline := filepath.Join(driver.Instance.Dir, filenames.KernelCmdline)
initrd := filepath.Join(driver.Instance.Dir, filenames.Initrd)
if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) {
var ensuredBaseDisk bool
errs := make([]error, len(driver.Yaml.Images))
Expand All @@ -31,6 +34,25 @@ func EnsureDisk(ctx context.Context, driver *driver.BaseDriver) error {
errs[i] = err
continue
}
if f.Kernel != nil {
// ensure decompress kernel because vz expects it to be decompressed
if _, err := fileutils.DownloadFile(ctx, kernel, f.Kernel.File, true, "the kernel", *driver.Yaml.Arch); err != nil {
errs[i] = err
continue
}
if f.Kernel.Cmdline != "" {
if err := os.WriteFile(kernelCmdline, []byte(f.Kernel.Cmdline), 0o644); err != nil {
errs[i] = err
continue
}
}
}
if f.Initrd != nil {
if _, err := fileutils.DownloadFile(ctx, initrd, *f.Initrd, false, "the initrd", *driver.Yaml.Arch); err != nil {
errs[i] = err
continue
}
}
ensuredBaseDisk = true
break
}
Expand Down
48 changes: 42 additions & 6 deletions pkg/vz/vm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,12 +203,7 @@ func createVM(driver *driver.BaseDriver) (*vz.VirtualMachine, error) {
}

func createInitialConfig(driver *driver.BaseDriver) (*vz.VirtualMachineConfiguration, error) {
efiVariableStore, err := getEFI(driver)
if err != nil {
return nil, err
}

bootLoader, err := vz.NewEFIBootLoader(vz.WithEFIVariableStore(efiVariableStore))
bootLoader, err := bootLoader(driver)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -686,6 +681,47 @@ func getMachineIdentifier(driver *driver.BaseDriver) (*vz.GenericMachineIdentifi
return vz.NewGenericMachineIdentifierWithDataPath(identifier)
}

func bootLoader(driver *driver.BaseDriver) (vz.BootLoader, error) {
linuxBootLoder, err := linuxBootLoader(driver)
if linuxBootLoder != nil {
return linuxBootLoder, nil
} else if !errors.Is(err, os.ErrNotExist) {
return nil, err
}

efiVariableStore, err := getEFI(driver)
if err != nil {
return nil, err
}
logrus.Debugf("Using EFI Boot Loader")
return vz.NewEFIBootLoader(vz.WithEFIVariableStore(efiVariableStore))
}

func linuxBootLoader(driver *driver.BaseDriver) (*vz.LinuxBootLoader, error) {
norio-nomura marked this conversation as resolved.
Show resolved Hide resolved
kernel := filepath.Join(driver.Instance.Dir, filenames.Kernel)
kernelCmdline := filepath.Join(driver.Instance.Dir, filenames.KernelCmdline)
initrd := filepath.Join(driver.Instance.Dir, filenames.Initrd)
if _, err := os.Stat(kernel); err != nil {
if errors.Is(err, os.ErrNotExist) {
logrus.Debugf("Kernel file %q not found", kernel)
} else {
logrus.WithError(err).Debugf("Error while checking kernel file %q", kernel)
}
return nil, err
}
var opt []vz.LinuxBootLoaderOption
if b, err := os.ReadFile(kernelCmdline); err == nil {
logrus.Debugf("Using kernel command line %q", string(b))
opt = append(opt, vz.WithCommandLine(string(b)))
}
if _, err := os.Stat(initrd); err == nil {
logrus.Debugf("Using initrd %q", initrd)
opt = append(opt, vz.WithInitrd(initrd))
}
logrus.Debugf("Using Linux Boot Loader with kernel %q", kernel)
return vz.NewLinuxBootLoader(kernel, opt...)
}

func getEFI(driver *driver.BaseDriver) (*vz.EFIVariableStore, error) {
efi := filepath.Join(driver.Instance.Dir, filenames.VzEfi)
if _, err := os.Stat(efi); os.IsNotExist(err) {
Expand Down
Loading