2022-04-19 12:01:08 +00:00
|
|
|
// Copyright 2022 Linka Cloud All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2022-04-21 16:28:50 +00:00
|
|
|
package d2vm
|
2022-04-19 12:01:08 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2022-05-20 14:36:36 +00:00
|
|
|
"strings"
|
2022-04-19 12:01:08 +00:00
|
|
|
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/sirupsen/logrus"
|
2022-08-04 16:09:11 +00:00
|
|
|
"github.com/svenwiltink/sparsecat"
|
2022-04-19 12:01:08 +00:00
|
|
|
|
|
|
|
"go.linka.cloud/d2vm/pkg/docker"
|
|
|
|
)
|
|
|
|
|
2022-08-08 15:58:49 +00:00
|
|
|
func Convert(ctx context.Context, img string, size int64, password string, output string, cmdLineExtra string, networkManager NetworkManager) error {
|
2022-04-19 12:01:08 +00:00
|
|
|
imgUUID := uuid.New().String()
|
|
|
|
tmpPath := filepath.Join(os.TempDir(), "d2vm", imgUUID)
|
|
|
|
if err := os.MkdirAll(tmpPath, os.ModePerm); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(tmpPath)
|
|
|
|
|
|
|
|
logrus.Infof("inspecting image %s", img)
|
|
|
|
r, err := FetchDockerImageOSRelease(ctx, img, tmpPath)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-08-08 15:58:49 +00:00
|
|
|
d, err := NewDockerfile(r, img, password, networkManager)
|
2022-04-19 12:01:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
logrus.Infof("docker image based on %s", d.Release.Name)
|
|
|
|
p := filepath.Join(tmpPath, docker.FormatImgName(img))
|
|
|
|
dir := filepath.Dir(p)
|
|
|
|
f, err := os.Create(p)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
if err := d.Render(f); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
logrus.Infof("building kernel enabled image")
|
2022-04-24 14:27:04 +00:00
|
|
|
if err := docker.Build(ctx, imgUUID, p, dir); err != nil {
|
2022-04-19 12:01:08 +00:00
|
|
|
return err
|
|
|
|
}
|
2022-04-24 14:27:04 +00:00
|
|
|
defer docker.Remove(ctx, imgUUID)
|
2022-04-19 12:01:08 +00:00
|
|
|
|
2022-04-24 13:49:01 +00:00
|
|
|
logrus.Infof("creating vm image")
|
2022-05-20 14:36:36 +00:00
|
|
|
format := strings.TrimPrefix(filepath.Ext(output), ".")
|
2022-08-04 16:09:11 +00:00
|
|
|
if format == "" {
|
|
|
|
format = "raw"
|
|
|
|
}
|
2022-08-07 16:24:02 +00:00
|
|
|
b, err := NewBuilder(ctx, tmpPath, imgUUID, "", size, r, format, cmdLineExtra)
|
2022-04-19 12:01:08 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-04-24 13:49:01 +00:00
|
|
|
defer b.Close()
|
2022-04-19 12:01:08 +00:00
|
|
|
if err := b.Build(ctx); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := os.RemoveAll(output); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-05-20 14:36:36 +00:00
|
|
|
if err := MoveFile(filepath.Join(tmpPath, "disk0."+format), output); err != nil {
|
2022-04-19 12:01:08 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func MoveFile(sourcePath, destPath string) error {
|
|
|
|
inputFile, err := os.Open(sourcePath)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to open source file: %s", err)
|
|
|
|
}
|
|
|
|
outputFile, err := os.Create(destPath)
|
|
|
|
if err != nil {
|
|
|
|
inputFile.Close()
|
|
|
|
return fmt.Errorf("failed to open dest file: %s", err)
|
|
|
|
}
|
|
|
|
defer outputFile.Close()
|
2022-08-04 16:09:11 +00:00
|
|
|
_, err = sparsecat.NewDecoder(sparsecat.NewEncoder(inputFile)).WriteTo(outputFile)
|
2022-04-19 12:01:08 +00:00
|
|
|
inputFile.Close()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to write to output file: %s", err)
|
|
|
|
}
|
|
|
|
// The copy was successful, so now delete the original file
|
|
|
|
err = os.Remove(sourcePath)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to remove original file: %s", err)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|