Documentation ¶
Overview ¶
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: github.com/digitalocean/go-libvirt and github.com/digitalocean/go-qemu. 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.
Index ¶
- Constants
- Variables
- func AutostartMachine(c *kvmContainer) error
- func CreateMachine(params CreateMachineParams) error
- func DestroyMachine(c *kvmContainer) error
- func ListMachines(runCmd runFunc) (map[string]string, error)
- func NewContainerInitialiser() container.Initialiser
- func NewContainerManager(conf container.ManagerConfig) (container.Manager, error)
- func Sync(o Oner, f Fetcher, progress ProgressCallback) error
- type Container
- type ContainerFactory
- type CreateMachineParams
- func (p CreateMachineParams) Arch() string
- func (p CreateMachineParams) CPUs() uint64
- func (p CreateMachineParams) DiskInfo() []libvirt.DiskInfo
- func (p CreateMachineParams) Host() string
- func (p CreateMachineParams) Loader() string
- func (p CreateMachineParams) NetworkInfo() []libvirt.InterfaceInfo
- func (p CreateMachineParams) RAM() uint64
- func (p CreateMachineParams) ValidateDomainParams() error
- type Fetcher
- type Image
- type Oner
- type ProgressCallback
- type StartParams
Constants ¶
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.
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.
Variables ¶
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 )
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.
Functions ¶
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 ¶
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, progress ProgressCallback) error
Sync updates the local cached images by reading the simplestreams data and caching if an image matching the contrainsts 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.
Types ¶
type Container ¶
type Container interface { // Name returns the name of the container. Name() string // 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 NetworkBridge 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 Close() }
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.