summary refs log tree commit diff
path: root/cmd/c2vm
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2021-04-22 14:46:01 -0700
committerFranck Cuny <franck@fcuny.net>2021-04-22 14:46:01 -0700
commitb97da9b0092a09d5abf71bba07afe2fa6aae2ae1 (patch)
tree6fad5932248b5b22f57d6d17b10cdf45533d09c3 /cmd/c2vm
parentextract layers to a mounted loop device (diff)
downloadcontainerd-to-vm-b97da9b0092a09d5abf71bba07afe2fa6aae2ae1.tar.gz
inject a script for init
Once we will be ready to boot our VM, we will need an init script in
place. For this, we create a simple shell script which we populate using
the environment variables and command extracted from the container.

The init script is stored in /init.sh within the new image, and we will
configure the boot parameter to find it there.
Diffstat (limited to 'cmd/c2vm')
-rw-r--r--cmd/c2vm/main.go43
1 files changed, 43 insertions, 0 deletions
diff --git a/cmd/c2vm/main.go b/cmd/c2vm/main.go
index c416e47..544293e 100644
--- a/cmd/c2vm/main.go
+++ b/cmd/c2vm/main.go
@@ -1,13 +1,17 @@
 package main
 
 import (
+	"bufio"
 	"context"
+	"encoding/json"
 	"flag"
 	"fmt"
 	"io/ioutil"
 	"log"
+	"os"
 	"os/exec"
 	"path/filepath"
+	"strings"
 
 	"github.com/containerd/containerd"
 	"github.com/containerd/containerd/content"
@@ -81,6 +85,10 @@ func main() {
 		log.Fatalf("failed to extract the container: %v\n", err)
 	}
 
+	if err = initScript(ctx, client, image, mntDir); err != nil {
+		log.Fatalf("failed to create init script: %s\n", err)
+	}
+
 	if err = extraFiles(mntDir); err != nil {
 		log.Fatalf("failed to add extra files to the image: %v\n", err)
 	}
@@ -172,6 +180,41 @@ func extraFiles(mntDir string) error {
 	return nil
 }
 
+func initScript(ctx context.Context, client *containerd.Client, image containerd.Image, mntDir string) error {
+	config, err := images.Config(ctx, client.ContentStore(), image.Target(), platform)
+	if err != nil {
+		return err
+	}
+
+	configBlob, err := content.ReadBlob(ctx, client.ContentStore(), config)
+	var imageSpec ocispec.Image
+	json.Unmarshal(configBlob, &imageSpec)
+	initCmd := strings.Join(imageSpec.Config.Cmd, " ")
+	initEnvs := imageSpec.Config.Env
+
+	initPath := filepath.Join(mntDir, "init.sh")
+	f, err := renameio.TempFile("", initPath)
+	if err != nil {
+		return err
+	}
+	defer f.Cleanup()
+
+	writer := bufio.NewWriter(f)
+	fmt.Fprintf(writer, "#!/bin/sh\n")
+	for _, env := range initEnvs {
+		fmt.Fprintf(writer, "export %s\n", env)
+	}
+	fmt.Fprintf(writer, "%s\n", initCmd)
+	writer.Flush()
+
+	f.CloseAtomicallyReplace()
+
+	mode := int(0755)
+	os.Chmod(initPath, os.FileMode(mode))
+	log.Printf("init script created")
+	return nil
+}
+
 func writeToFile(filepath string, content string) error {
 	if err := ioutil.WriteFile(filepath, []byte(content), 0644); err != nil {
 		return fmt.Errorf("writeToFile %s: %v", filepath, err)