From 3acf21159cca2b56793d8db8cf5f163f54f6d18c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Wed, 31 Jul 2019 15:28:57 +0300 Subject: [PATCH 1/3] Make it possible to directly patch a file using the library --- pkg/util/patch/patch.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pkg/util/patch/patch.go b/pkg/util/patch/patch.go index 6f25fb0d8..5eb43466e 100644 --- a/pkg/util/patch/patch.go +++ b/pkg/util/patch/patch.go @@ -2,6 +2,7 @@ package patch import ( "fmt" + "io/ioutil" "github.com/weaveworks/ignite/pkg/apis/ignite/scheme" meta "github.com/weaveworks/ignite/pkg/apis/meta/v1alpha1" @@ -52,3 +53,17 @@ func Apply(original, patch []byte, gvk schema.GroupVersionKind) ([]byte, error) return strategicpatch.StrategicMergePatch(original, patch, emptyobj) } + +func ApplyOnFile(filePath string, patch []byte, gvk schema.GroupVersionKind) error { + oldContent, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + + newContent, err := Apply(oldContent, patch, gvk) + if err != nil { + return err + } + + return ioutil.WriteFile(filePath, newContent, 0644) +} From 5cc8590021c018962af26c6b27e8a912233bf789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Wed, 31 Jul 2019 15:31:29 +0300 Subject: [PATCH 2/3] Stop patching the annotation to the VM object when starting it; mount the metadata.json file into /vm.json --- pkg/constants/vm.go | 3 +++ pkg/operations/start.go | 25 +++++++------------------ 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/pkg/constants/vm.go b/pkg/constants/vm.go index 8c17de560..e8dbf247a 100644 --- a/pkg/constants/vm.go +++ b/pkg/constants/vm.go @@ -18,4 +18,7 @@ const ( // Prometheus socket filename PROMETHEUS_SOCKET = "prometheus.sock" + + // Where the VM specification is located inside of the container + IGNITE_SPAWN_VM_FILE_PATH = "/vm.json" ) diff --git a/pkg/operations/start.go b/pkg/operations/start.go index 7e3ef9ae3..57f729ab2 100644 --- a/pkg/operations/start.go +++ b/pkg/operations/start.go @@ -2,7 +2,6 @@ package operations import ( "fmt" - "github.com/weaveworks/ignite/pkg/logs" "io" "io/ioutil" "path" @@ -11,14 +10,13 @@ import ( log "github.com/sirupsen/logrus" api "github.com/weaveworks/ignite/pkg/apis/ignite" - meta "github.com/weaveworks/ignite/pkg/apis/meta/v1alpha1" "github.com/weaveworks/ignite/pkg/constants" "github.com/weaveworks/ignite/pkg/dmlegacy" + "github.com/weaveworks/ignite/pkg/logs" "github.com/weaveworks/ignite/pkg/operations/lookup" "github.com/weaveworks/ignite/pkg/providers" "github.com/weaveworks/ignite/pkg/runtime" "github.com/weaveworks/ignite/pkg/util" - patchutil "github.com/weaveworks/ignite/pkg/util/patch" "github.com/weaveworks/ignite/pkg/version" ) @@ -49,7 +47,7 @@ func StartVM(vm *api.VM, debug bool) error { } config := &runtime.ContainerConfig{ - Cmd: []string{vm.GetUID().String(), "--log-level", logs.Logger.Level.String()}, + Cmd: []string{fmt.Sprintf("--log-level=%s", logs.Logger.Level.String()), vm.GetUID().String()}, Labels: map[string]string{"ignite.name": vm.GetName()}, Binds: []*runtime.Bind{ { @@ -60,6 +58,11 @@ func StartVM(vm *api.VM, debug bool) error { HostPath: kernelDir, ContainerPath: kernelDir, }, + { + // Mount the metadata.json file specifically into the container, to a well-known place for ignite-spawn to access + HostPath: path.Join(vmDir, constants.METADATA), + ContainerPath: constants.IGNITE_SPAWN_VM_FILE_PATH, + }, }, CapAdds: []string{ "SYS_ADMIN", // Needed to run "dmsetup remove" inside the container @@ -103,20 +106,6 @@ func StartVM(vm *api.VM, debug bool) error { log.Infof("Started Firecracker VM %q in a container with ID %q", vm.GetUID(), containerID) - // Set an annotation on the VM object with the containerID for now - patch, err := patchutil.Create(vm, func(obj meta.Object) error { - patchVM := obj.(*api.VM) - patchVM.SetAnnotation("v1alpha1.ignite.weave.works.containerID", containerID) - return nil - }) - if err != nil { - return err - } - // Perform the patch - if err := providers.Client.VMs().Patch(vm.GetUID(), patch); err != nil { - return err - } - // TODO: Follow-up the container here with a defer, or dedicated goroutine. We should output // if it started successfully or not // TODO: This is temporary until we have proper communication to the container From cd21c03bd48801ab0ed261008adc923bc0c8d873 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20K=C3=A4ldstr=C3=B6m?= Date: Wed, 31 Jul 2019 15:31:58 +0300 Subject: [PATCH 3/3] Stop using the client in ignite-spawn, instead decode /vm.json "by hand" --- cmd/ignite-spawn/ignite-spawn.go | 52 +++++++++++++++++++++----------- cmd/ignite-spawn/options.go | 23 -------------- cmd/ignite-spawn/root.go | 4 +-- 3 files changed, 36 insertions(+), 43 deletions(-) delete mode 100644 cmd/ignite-spawn/options.go diff --git a/cmd/ignite-spawn/ignite-spawn.go b/cmd/ignite-spawn/ignite-spawn.go index 8007f7823..a5fd0fa8a 100644 --- a/cmd/ignite-spawn/ignite-spawn.go +++ b/cmd/ignite-spawn/ignite-spawn.go @@ -8,6 +8,7 @@ import ( "github.com/weaveworks/ignite/cmd/ignite/cmd/cmdutil" api "github.com/weaveworks/ignite/pkg/apis/ignite" + "github.com/weaveworks/ignite/pkg/apis/ignite/scheme" meta "github.com/weaveworks/ignite/pkg/apis/meta/v1alpha1" "github.com/weaveworks/ignite/pkg/constants" "github.com/weaveworks/ignite/pkg/container" @@ -24,7 +25,22 @@ func main() { RunIgniteSpawn() } -func StartVM(co *options) error { +func decodeVM(vmID string) (*api.VM, error) { + filePath := constants.IGNITE_SPAWN_VM_FILE_PATH + obj, err := scheme.Serializer.DecodeFile(filePath, true) + if err != nil { + return nil, err + } + vm, ok := obj.(*api.VM) + if !ok { + return nil, fmt.Errorf("object couldn't be converted to VM") + } + // Explicitely set the GVK on this object + vm.SetGroupVersionKind(api.SchemeGroupVersion.WithKind(api.KindVM.Title())) + return vm, nil +} + +func StartVM(vm *api.VM) error { // Setup networking inside of the container, return the available interfaces dhcpIfaces, err := container.SetupContainerNetworking() if err != nil { @@ -34,61 +50,61 @@ func StartVM(co *options) error { // Serve DHCP requests for those interfaces // This function returns the available IP addresses that are being // served over DHCP now - ipAddrs, err := container.StartDHCPServers(co.vm, dhcpIfaces) + ipAddrs, err := container.StartDHCPServers(vm, dhcpIfaces) if err != nil { return err } // Serve metrics over an unix socket in the VM's own directory - metricsSocket := path.Join(co.vm.ObjectPath(), constants.PROMETHEUS_SOCKET) + metricsSocket := path.Join(vm.ObjectPath(), constants.PROMETHEUS_SOCKET) go prometheus.ServeMetrics(metricsSocket) // Update the VM status and IP address information - if err := patchRunning(co.vm, ipAddrs); err != nil { + if err := patchRunning(vm, ipAddrs); err != nil { return fmt.Errorf("failed to patch VM state: %v", err) } // Patches the VM object to set state to stopped, and clear IP addresses - defer patchStopped(co.vm) + defer patchStopped(vm) // Remove the snapshot overlay post-run, which also removes the detached backing loop devices - defer dmlegacy.DeactivateSnapshot(co.vm) + defer dmlegacy.DeactivateSnapshot(vm) // Remove the Prometheus socket post-run defer os.Remove(metricsSocket) // Execute Firecracker - if err := container.ExecuteFirecracker(co.vm, dhcpIfaces); err != nil { - return fmt.Errorf("runtime error for VM %q: %v", co.vm.GetUID(), err) + if err := container.ExecuteFirecracker(vm, dhcpIfaces); err != nil { + return fmt.Errorf("runtime error for VM %q: %v", vm.GetUID(), err) } return nil } func patchRunning(vm *api.VM, ipAddrs []net.IP) error { - patch, err := patchutil.Create(vm, func(obj meta.Object) error { - patchVM := obj.(*api.VM) + return patchVM(vm, func(patchVM *api.VM) error { patchVM.Status.State = api.VMStateRunning patchVM.Status.IPAddresses = ipAddrs return nil }) - if err != nil { - return err - } - // Perform the patch - return providers.Client.VMs().Patch(vm.GetUID(), patch) } func patchStopped(vm *api.VM) error { - patch, err := patchutil.Create(vm, func(obj meta.Object) error { - patchVM := obj.(*api.VM) + return patchVM(vm, func(patchVM *api.VM) error { patchVM.Status.State = api.VMStateStopped patchVM.Status.IPAddresses = nil return nil }) +} + +func patchVM(vm *api.VM, fn func(*api.VM) error) error { + patch, err := patchutil.Create(vm, func(obj meta.Object) error { + patchVM := obj.(*api.VM) + return fn(patchVM) + }) if err != nil { return err } // Perform the patch - return providers.Client.VMs().Patch(vm.GetUID(), patch) + return patchutil.ApplyOnFile(constants.IGNITE_SPAWN_VM_FILE_PATH, patch, vm.GroupVersionKind()) } diff --git a/cmd/ignite-spawn/options.go b/cmd/ignite-spawn/options.go deleted file mode 100644 index 218d1a61c..000000000 --- a/cmd/ignite-spawn/options.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - api "github.com/weaveworks/ignite/pkg/apis/ignite" - "github.com/weaveworks/ignite/pkg/filter" - "github.com/weaveworks/ignite/pkg/providers" -) - -type options struct { - vm *api.VM -} - -func NewOptions(vmMatch string) (*options, error) { - co := &options{} - - if vm, err := providers.Client.VMs().Find(filter.NewIDNameFilter(vmMatch)); err == nil { - co.vm = vm - } else { - return nil, err - } - - return co, nil -} diff --git a/cmd/ignite-spawn/root.go b/cmd/ignite-spawn/root.go index dd9b1c193..2e700f640 100644 --- a/cmd/ignite-spawn/root.go +++ b/cmd/ignite-spawn/root.go @@ -27,12 +27,12 @@ func RunIgniteSpawn() { } cmdutil.CheckErr(func() error { - opts, err := NewOptions(fs.Args()[0]) + vm, err := decodeVM(fs.Args()[0]) if err != nil { return err } - return StartVM(opts) + return StartVM(vm) }()) }