Package kvm provides the facilities to deploy to kvm instances.

    kvm implements the container interface for worker/provisioner to manage applications deployed to kvm based 'containers' (see juju/worker/provisioner/provisioner.go:containerProvisioner and juju/container/container.go:container.Manager). The worker provisioner specifics are in juju/worker/provisioner/kvm-broker.go and juju/worker/container_initilisation.go.

    The provisioner worker manages kvm containers through the interface provided in this package, see: containerfactory.go, container.go, instance, and initialization.go. That is to say those files provide the container.Manager interface while the rest of this package are the implementation of container.Manager for kvm instances.

    This package originally depended on the ubuntu uvtool apt package. This meant that kvm would only work on ubuntu on amd64. The goal of removing Juju's dependency on uvtool is to allow kvm to also work on arm64 and ppc64el. However, it is still only expected to work on ubuntu.

    When removing uvtool we (redir) performed a survey of the libvirt and qemu go package landscape. There are a number of cgo based libraries and two possibly promising ones once they are further developed: and Those packages are nascent and alpha at the time of this writing. They implement pure go interfaces to libvirt and qemu by way of libvirt/qemu's custom RPC protocol. While this would reduce the number of commands that require shelling out, it wouldn't provide a way to create and manage disk images. So unless someone implements qemu-utils and genisoimage in go, we'll always need to shell out for those calls. The wrapped commands exist, shockingly, in wrappedcmds.go with the exception of libvirt pool initialisation bits which are in initialization.go.

    After the provisioner initializes the kvm environment, we synchronise (fetch if we don't have one) an ubuntu qcow image for the appropriate series and architecture. This happens in sync.go and uses Juju's simplestreams implementation in juju/environs/simplestreams and juju/environs/imagedownloads. Once we fetch a compressed ubuntu image we then uncompress and convert it for use into the libvirt storage pool. The storage pool is named 'juju-pool' and it is located in $JUJU_DATADIR/kvm/guests, where JUJU_DATADIR is the value returned by paths.DataDir. This ubuntu image is then used as a backing store for our kvm instances for given series.

    NB: Sharing a backing store across multiple instances allow us to save significant disk space, but comes at a price too. The backing store is read only to the volumes which use it and it cannot be updated. So we cannot easily update common elements the way that lxd and snappy do with squashfs based backing stores.This is to the best of my understanding, so corrections or updates are welcome.

    Once the backing store is ready, we create a system disk and a datasource disk. The system disk is a sparse file with a maximum file size which uses the aforementioned backing store as its base image. The data source disk is an iso image with user-data and meta-data for cloud-init's NoCloud method to configure our system. The cloud init data is written in kvm.go, via a call to machinery in juju/cloudconfig/containerinit/container_userdata.go. Destruction of a container removes the system and data source disk files, but leaves the backing store alone as it may be in use by other domains.

    TBD: Put together something to send progress through a reader to the callback function. We need to follow along with the method as implemented by LXD.



    View Source
    const BIOSFType = "disk1.img"

      BIOSFType is the file type we want to fetch and use for kvm instances which boot using a legacy BIOS boot loader.

      View Source
      const UEFIFType = "uefi1.img"

        UEFIFType is the file type we want to fetch and use for kvm instances which boot using UEFI. In our case this is ARM64.


        View Source
        var (
        	// KvmObjectFactory implements the container factory interface for kvm
        	// containers.
        	KvmObjectFactory ContainerFactory = &containerFactory{}
        	// DefaultMemory is the default RAM to use in a container.
        	DefaultMemory uint64 = 512 // MB
        	// DefaultCpu is the default number of CPUs to use in a container.
        	DefaultCpu uint64 = 1
        	// DefaultDisk is the default root disk size.
        	DefaultDisk uint64 = 8 // GB
        	// MinMemory is the minimum RAM we will launch with.
        	MinMemory uint64 = 512 // MB
        	// MinCpu is the minimum number of CPUs to launch with.
        	MinCpu uint64 = 1
        	// MinDisk is the minimum root disk size we will launch with.
        	MinDisk uint64 = 2 // GB
        View Source
        var IsKVMSupported = func() (bool, error) {
        	// Prefer the user's $PATH first, but check /usr/sbin if we can't
        	// find kvm-ok there
        	var foundPath string
        	const binName = "kvm-ok"
        	if path, err := exec.LookPath(binName); err == nil {
        		foundPath = path
        	} else if path, err := exec.LookPath(filepath.Join(kvmPath, binName)); err == nil {
        		foundPath = path
        	} else {
        		return false, errors.NotFoundf("%s executable", binName)
        	command := exec.Command(foundPath)
        	output, err := command.CombinedOutput()
        	if err != nil {
        		return false, errors.Annotate(err, string(output))
        	logger.Debugf("%s output:\n%s", binName, output)
        	return command.ProcessState.Success(), nil

          IsKVMSupported calls into the kvm-ok executable from the cpu-checkers package. It is a variable to allow us to override behaviour in the tests.


          func AutostartMachine

          func AutostartMachine(c *kvmContainer) error

            AutostartMachine indicates that the virtual machines should automatically restart when the host restarts.

            func CreateMachine

            func CreateMachine(params CreateMachineParams) error

              CreateMachine creates a virtual machine and starts it.

              func DestroyMachine

              func DestroyMachine(c *kvmContainer) error

                DestroyMachine destroys the virtual machine represented by the kvmContainer.

                func ListMachines

                func ListMachines(runCmd runFunc) (map[string]string, error)

                  ListMachines returns a map of machine name to state, where state is one of: running, idle, paused, shutdown, shut off, crashed, dying, pmsuspended.

                  func NewContainerInitialiser

                  func NewContainerInitialiser() container.Initialiser

                    NewContainerInitialiser returns an instance used to perform the steps required to allow a host machine to run a KVM container.

                    func NewContainerManager

                    func NewContainerManager(conf container.ManagerConfig) (container.Manager, error)

                      NewContainerManager returns a manager object that can start and stop kvm containers.

                      func Sync

                      func Sync(o Oner, f Fetcher, imageDownloadURL string, progress ProgressCallback) error

                        Sync updates the local cached images by reading the simplestreams data and caching if an image matching the constraints doesn't exist. It retrieves metadata information from Oner and updates local cache via Fetcher. A ProgressCallback can optionally be passed which will get update messages as data is copied.


                        type Container

                        type Container interface {
                        	// Name returns the name of the container.
                        	Name() string
                        	// EnsureCachedImage ensures that a container image suitable for satisfying
                        	// the input start parameters has been cached on disk.
                        	EnsureCachedImage(params StartParams) error
                        	// Start runs the container as a daemon.
                        	Start(params StartParams) error
                        	// Stop terminates the running container.
                        	Stop() error
                        	// IsRunning returns whether or not the container is running and active.
                        	IsRunning() bool
                        	// String returns information about the container, like the name, state,
                        	// and process id.
                        	String() string

                          Container represents a virtualized container instance and provides operations to create, maintain and destroy the container.

                          type ContainerFactory

                          type ContainerFactory interface {
                          	// New returns a container instance which can then be used for operations
                          	// like Start() and Stop()
                          	New(string) Container
                          	// List returns all the existing containers on the system.
                          	List() ([]Container, error)

                            ContainerFactory represents the methods used to create Containers. This wraps the low level OS functions for dealing with the containers.

                            type CreateMachineParams

                            type CreateMachineParams struct {
                            	Hostname          string
                            	Series            string
                            	UserDataFile      string
                            	NetworkConfigData string
                            	Memory            uint64
                            	CpuCores          uint64
                            	RootDisk          uint64
                            	Interfaces        []libvirt.InterfaceInfo
                            	// contains filtered or unexported fields

                              CreateMachineParams Implements libvirt.domainParams.

                              func (CreateMachineParams) Arch

                              func (p CreateMachineParams) Arch() string

                                Arch returns the architecture to be used.

                                func (CreateMachineParams) CPUs

                                func (p CreateMachineParams) CPUs() uint64

                                  CPUs implements libvirt.domainParams.

                                  func (CreateMachineParams) DiskInfo

                                  func (p CreateMachineParams) DiskInfo() []libvirt.DiskInfo

                                    DiskInfo implements libvirt.domainParams.

                                    func (CreateMachineParams) Host

                                    func (p CreateMachineParams) Host() string

                                      Host implements libvirt.domainParams.

                                      func (CreateMachineParams) Loader

                                      func (p CreateMachineParams) Loader() string

                                        Loader is the path to the binary firmware blob used in UEFI booting. At the time of this writing only ARM64 requires this to run.

                                        func (CreateMachineParams) NetworkInfo

                                        func (p CreateMachineParams) NetworkInfo() []libvirt.InterfaceInfo

                                          NetworkInfo implements libvirt.domainParams.

                                          func (CreateMachineParams) RAM

                                          func (p CreateMachineParams) RAM() uint64

                                            RAM implements libvirt.domainParams.

                                            func (CreateMachineParams) ValidateDomainParams

                                            func (p CreateMachineParams) ValidateDomainParams() error

                                              ValidateDomainParams implements libvirt.domainParams.

                                              type Fetcher

                                              type Fetcher interface {
                                              	Fetch() error

                                                Fetcher is an interface to permit faking input in tests. The default implementation is updater, defined in this file.

                                                type Image

                                                type Image struct {
                                                	FilePath string
                                                	// contains filtered or unexported fields

                                                  Image represents a server image.

                                                  type Oner

                                                  type Oner interface {
                                                  	One() (*imagedownloads.Metadata, error)

                                                    Oner gets the one matching item from simplestreams.

                                                    type ProgressCallback

                                                    type ProgressCallback func(message string)

                                                    type StartParams

                                                    type StartParams struct {
                                                    	Series            string
                                                    	Arch              string
                                                    	Stream            string
                                                    	UserDataFile      string
                                                    	NetworkConfigData string
                                                    	Network           *container.NetworkConfig
                                                    	Memory            uint64 // MB
                                                    	CpuCores          uint64
                                                    	RootDisk          uint64 // GB
                                                    	ImageDownloadURL  string
                                                    	StatusCallback    func(status status.Status, info string, data map[string]interface{}) error

                                                      StartParams is a simple parameter struct for Container.Start.

                                                      func ParseConstraintsToStartParams

                                                      func ParseConstraintsToStartParams(cons constraints.Value) StartParams

                                                        ParseConstraintsToStartParams takes a constraints object and returns a bare StartParams object that has Memory, Cpu, and Disk populated. If there are no defined values in the constraints for those fields, default values are used. Other constrains cause a warning to be emitted.


                                                        Path Synopsis