The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6455
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 3f2440f924581a57aeafdd61022fa87e8ba680aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 13 Nov 2019 14:18:20 -0800 Subject: [PATCH 1/2] lxd-agent: Generate the cloud-init configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd-agent/main_agent.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/lxd-agent/main_agent.go b/lxd-agent/main_agent.go index 60a4d9c81d..bdfe3b9ffb 100644 --- a/lxd-agent/main_agent.go +++ b/lxd-agent/main_agent.go @@ -2,6 +2,8 @@ package main import ( "log" + "os" + "path/filepath" "github.com/pkg/errors" "github.com/spf13/cobra" @@ -31,6 +33,35 @@ func (c *cmdAgent) Command() *cobra.Command { } func (c *cmdAgent) Run(cmd *cobra.Command, args []string) error { + // Setup cloud-init + if shared.PathExists("/etc/cloud") && !shared.PathExists("/var/lib/cloud/seed/nocloud-net") { + err := os.MkdirAll("/var/lib/cloud/seed/nocloud-net/", 0700) + if err != nil { + return err + } + + for _, fName := range []string{"meta-data", "user-data", "vendor-data", "network-config"} { + if !shared.PathExists(filepath.Join("cloud-init", fName)) { + continue + } + + err := shared.FileCopy(filepath.Join("cloud-init", fName), filepath.Join("/var/lib/cloud/seed/nocloud-net", fName)) + if err != nil { + return err + } + } + + if shared.PathExists("/run/cloud-init") { + err = os.RemoveAll("/run/cloud-init") + if err != nil { + return err + } + } + + shared.RunCommand("systemctl", "daemon-reload") + shared.RunCommand("systemctl", "start", "cloud-init.target") + } + // Setup the listener. l, err := vsock.Listen(8443) if err != nil { From 30b012cf1bb6844265a308897f43ae0e5a2b2a75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Wed, 13 Nov 2019 14:35:40 -0800 Subject: [PATCH 2/2] lxd/vm: Use 9p for agent drive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/vm_qemu.go | 207 ++++++++++++++++++++++++++----------------------- 1 file changed, 109 insertions(+), 98 deletions(-) diff --git a/lxd/vm_qemu.go b/lxd/vm_qemu.go index 4f75feb046..b7b2a5f190 100644 --- a/lxd/vm_qemu.go +++ b/lxd/vm_qemu.go @@ -400,7 +400,7 @@ func (vm *vmQemu) Start(stateful bool) error { return fmt.Errorf("The instance is already running") } - configISOPath, err := vm.generateConfigDrive() + err = vm.generateConfigShare() if err != nil { return err } @@ -465,7 +465,7 @@ func (vm *vmQemu) Start(stateful bool) error { } } - confFile, err := vm.generateQemuConfigFile(configISOPath, tapDev) + confFile, err := vm.generateQemuConfigFile(tapDev) if err != nil { return err } @@ -623,143 +623,152 @@ func (vm *vmQemu) getNvramPath() string { return filepath.Join(vm.Path(), "qemu.nvram") } -func (vm *vmQemu) generateConfigDrive() (string, error) { - configDrivePath := filepath.Join(vm.Path(), "configdrv") +func (vm *vmQemu) generateConfigShare() error { + configDrivePath := filepath.Join(vm.Path(), "config") // Create config drive dir. - err := os.MkdirAll(configDrivePath, 0100) + os.RemoveAll(configDrivePath) + err := os.MkdirAll(configDrivePath, 0500) if err != nil { - return "", err + return err + } + + // Generate the cloud-init config. + err = os.MkdirAll(filepath.Join(configDrivePath, "cloud-init"), 0500) + if err != nil { + return err + } + + if vm.ExpandedConfig()["user.user-data"] != "" { + err = ioutil.WriteFile(filepath.Join(configDrivePath, "cloud-init", "user-data"), []byte(vm.ExpandedConfig()["user.user-data"]), 0400) + if err != nil { + return err + } + } else { + err = ioutil.WriteFile(filepath.Join(configDrivePath, "cloud-init", "user-data"), []byte("#cloud-config\n"), 0400) + if err != nil { + return err + } + } + + if vm.ExpandedConfig()["user.vendor-data"] != "" { + err = ioutil.WriteFile(filepath.Join(configDrivePath, "cloud-init", "vendor-data"), []byte(vm.ExpandedConfig()["user.vendor-data"]), 0400) + if err != nil { + return err + } + } else { + err = ioutil.WriteFile(filepath.Join(configDrivePath, "cloud-init", "vendor-data"), []byte("#cloud-config\n"), 0400) + if err != nil { + return err + } } - // Add config drive mount instructions to cloud init. - vendorData := `#cloud-config -runcmd: - - "mkdir /media/lxd_config" - - "mount -o ro -t iso9660 /dev/disk/by-label/cidata /media/lxd_config" - - "cp /media/lxd_config/media-lxd_config.mount /etc/systemd/system/" - - "systemctl enable media-lxd_config.mount"` + if vm.ExpandedConfig()["user.network-config"] != "" { + err = ioutil.WriteFile(filepath.Join(configDrivePath, "cloud-init", "network-config"), []byte(vm.ExpandedConfig()["user.network-config"]), 0400) + if err != nil { + return err + } + } else { + os.Remove(filepath.Join(configDrivePath, "cloud-init", "network-config")) + } + err = ioutil.WriteFile(filepath.Join(configDrivePath, "cloud-init", "meta-data"), []byte(fmt.Sprintf("instance-id: %s\nlocal-hostname: %s\n%s\n", vm.Name(), vm.Name(), vm.ExpandedConfig()["user.meta-data"])), 0400) + if err != nil { + return err + } + + // Add the VM agent. path, err := exec.LookPath("lxd-agent") if err != nil { logger.Warnf("lxd-agent not found, skipping its inclusion in the VM config drive: %v", err) } else { // Install agent into config drive dir if found. - err = shared.FileCopy(path, configDrivePath+"/lxd-agent") + err = shared.FileCopy(path, filepath.Join(configDrivePath, "lxd-agent")) if err != nil { - return "", err + return err } - os.Chmod(configDrivePath+"/lxd-agent", 0700) + err = os.Chmod(filepath.Join(configDrivePath, "lxd-agent"), 0500) + if err != nil { + return err + } - // Add agent install and startup config to cloud init. - vendorData += ` - - "cp /media/lxd_config/lxd-agent.service /etc/systemd/system/" - - "systemctl enable lxd-agent.service" - - "systemctl start lxd-agent"` + err = os.Chown(filepath.Join(configDrivePath, "lxd-agent"), 0, 0) + if err != nil { + return err + } } - err = ioutil.WriteFile(configDrivePath+"/vendor-data", []byte(vendorData), 0400) + agentCert, agentKey, clientCert, _, err := vm.generateAgentCert() if err != nil { - return "", err + return err } - userData := vm.expandedConfig["user.user-data"] - - // Use an empty user-data file if no custom user-data supplied. - if userData == "" { - userData = "#cloud-config" + err = ioutil.WriteFile(filepath.Join(configDrivePath, "server.crt"), []byte(clientCert), 0400) + if err != nil { + return err } - err = ioutil.WriteFile(configDrivePath+"/user-data", []byte(userData), 0400) + err = ioutil.WriteFile(filepath.Join(configDrivePath, "agent.crt"), []byte(agentCert), 0400) if err != nil { - return "", err + return err } - metaData := fmt.Sprintf(`instance-id: %s -local-hostname: %s -`, vm.Name(), vm.Name()) + err = ioutil.WriteFile(filepath.Join(configDrivePath, "agent.key"), []byte(agentKey), 0400) + if err != nil { + return err + } - err = ioutil.WriteFile(configDrivePath+"/meta-data", []byte(metaData), 0400) + // Systemd units. + err = os.MkdirAll(filepath.Join(configDrivePath, "systemd"), 0500) if err != nil { - return "", err + return err } lxdAgentServiceUnit := `[Unit] Description=LXD - agent -After=media-lxd_config.mount +After=run-lxd_config.mount +Before=cloud-init-local.service [Service] Type=simple -WorkingDirectory=/media/lxd_config/ -ExecStart=/media/lxd_config/lxd-agent +WorkingDirectory=/run/lxd_config/ +ExecStart=/run/lxd_config/lxd-agent [Install] WantedBy=multi-user.target ` - err = ioutil.WriteFile(configDrivePath+"/lxd-agent.service", []byte(lxdAgentServiceUnit), 0400) + err = ioutil.WriteFile(filepath.Join(configDrivePath, "systemd", "lxd-agent.service"), []byte(lxdAgentServiceUnit), 0400) if err != nil { - return "", err + return err } - lxdConfigDriveMountUnit := `[Unit] + lxdConfigShareMountUnit := `[Unit] +[Unit] Description = LXD - config drive Before=local-fs.target +ConditionPathExists=/dev/virtio-ports/org.linuxcontainers.lxd [Mount] -Where=/media/lxd_config -What=/dev/disk/by-label/cidata -Type=iso9660 +Where=/run/lxd_config +What=config +Type=9p [Install] WantedBy=multi-user.target ` - err = ioutil.WriteFile(configDrivePath+"/media-lxd_config.mount", []byte(lxdConfigDriveMountUnit), 0400) + err = ioutil.WriteFile(filepath.Join(configDrivePath, "systemd", "run-lxd_config.mount"), []byte(lxdConfigShareMountUnit), 0400) if err != nil { - return "", err - } - - // Get the certificates. - agentCert, agentKey, clientCert, _, err := vm.generateAgentCert() - if err != nil { - return "", err - } - - err = ioutil.WriteFile(configDrivePath+"/server.crt", []byte(clientCert), 0400) - if err != nil { - return "", err - } - - err = ioutil.WriteFile(configDrivePath+"/agent.crt", []byte(agentCert), 0400) - if err != nil { - return "", err - } - - err = ioutil.WriteFile(configDrivePath+"/agent.key", []byte(agentKey), 0400) - if err != nil { - return "", err - } - - // Finally convert the config drive dir into an ISO file. The cidata label is important - // as this is what cloud-init uses to detect, mount the drive and run the cloud-init - // templates on first boot. The vendor-data template then modifies the system so that the - // config drive is mounted and the agent is started on subsequent boots. - isoPath := filepath.Join(vm.Path(), "config.iso") - _, err = shared.RunCommand("mkisofs", "-R", "-V", "cidata", "-o", isoPath, configDrivePath) - if err != nil { - return "", err + return err } - // Remove the config drive folder. - os.RemoveAll(configDrivePath) - - return isoPath, nil + return nil } // generateQemuConfigFile writes the qemu config file and returns its location. -func (vm *vmQemu) generateQemuConfigFile(configISOPath string, tapDev map[string]string) (string, error) { +func (vm *vmQemu) generateQemuConfigFile(tapDev map[string]string) (string, error) { var sb *strings.Builder = &strings.Builder{} // Base config. This is common for all VMs and has no variables in it. @@ -862,7 +871,7 @@ backend = "pty" vm.addFirmwareConfig(sb) vm.addVsockConfig(sb) vm.addMonitorConfig(sb) - vm.addConfDriveConfig(sb, configISOPath) + vm.addConfDriveConfig(sb) vm.addNetConfig(sb, tapDev) // Write the config file to disk. @@ -904,6 +913,7 @@ port = "0x13" chassis = "4" bus = "pcie.0" addr = "0x2.0x3" + [device] driver = "vhost-vsock-pci" guest-cid = "%d" @@ -948,6 +958,7 @@ backend = "socket" path = "%s" server = "on" wait = "off" + [mon] chardev = "monitor" mode = "control" @@ -967,6 +978,7 @@ if = "pflash" format = "raw" unit = "0" readonly = "on" + [drive] file = "%s" if = "pflash" @@ -996,6 +1008,7 @@ format = "%s" if = "none" cache = "none" aio = "native" + [device "dev-lxd_root"] driver = "scsi-hd" bus = "qemu_scsi.0" @@ -1009,24 +1022,20 @@ bootindex = "1" return nil } -func (vm *vmQemu) addConfDriveConfig(sb *strings.Builder, configISOPath string) { +func (vm *vmQemu) addConfDriveConfig(sb *strings.Builder) { sb.WriteString(fmt.Sprintf(` -# Config drive (set to last lun) -[drive "qemu_config"] -file = "%s" -format = "raw" -if = "none" -cache = "none" -aio = "native" +# Config drive +[fsdev "qemu_config"] +fsdriver = "local" +security_model = "none" readonly = "on" +path = "%s" + [device "dev-qemu_config"] -driver = "scsi-hd" -bus = "qemu_scsi.0" -channel = "0" -scsi-id = "1" -lun = "1" -drive = "qemu_config" -`, configISOPath)) +driver = "virtio-9p-pci" +fsdev = "qemu_config" +mount_tag = "config" +`, filepath.Join(vm.Path(), "config"))) return } @@ -1039,12 +1048,14 @@ type = "tap" ifname = "%s" script = "no" downscript = "no" + [device "qemu_pcie5"] driver = "pcie-root-port" port = "0x11" chassis = "5" bus = "pcie.0" addr = "0x2.0x4" + [device "dev-lxd_eth0"] driver = "virtio-net-pci" netdev = "lxd_eth0"
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel