Skip to content

Commit

Permalink
Merge pull request #2562 from norio-nomura/vz-support-kernel-image
Browse files Browse the repository at this point in the history
VZ: Support Kernel Image
  • Loading branch information
AkihiroSuda committed Sep 19, 2024
2 parents df5d2e6 + 5223ad9 commit 3c40ba4
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 16 deletions.
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) {
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

0 comments on commit 3c40ba4

Please sign in to comment.