juju: github.com/wallyworld/juju/container/kvm Index | Files | Directories

package kvm

import "github.com/wallyworld/juju/container/kvm"

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.


Package Files

container.go containerfactory.go doc.go initialisation.go instance.go interface.go kvm.go run.go run_linux.go sync.go wrappedcmds.go


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.


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.

func AutostartMachine Uses

func AutostartMachine(c *kvmContainer) error

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

func CreateMachine Uses

func CreateMachine(params CreateMachineParams) error

CreateMachine creates a virtual machine and starts it.

func DestroyMachine Uses

func DestroyMachine(c *kvmContainer) error

DestroyMachine destroys the virtual machine represented by the kvmContainer.

func ListMachines Uses

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 Uses

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 Uses

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

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

func Sync Uses

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 Uses

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 Uses

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 Uses

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 Uses

func (p CreateMachineParams) Arch() string

Arch returns the architecture to be used.

func (CreateMachineParams) CPUs Uses

func (p CreateMachineParams) CPUs() uint64

CPUs implements libvirt.domainParams.

func (CreateMachineParams) DiskInfo Uses

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

DiskInfo implements libvirt.domainParams.

func (CreateMachineParams) Host Uses

func (p CreateMachineParams) Host() string

Host implements libvirt.domainParams.

func (CreateMachineParams) Loader Uses

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 Uses

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

NetworkInfo implements libvirt.domainParams.

func (CreateMachineParams) RAM Uses

func (p CreateMachineParams) RAM() uint64

RAM implements libvirt.domainParams.

func (CreateMachineParams) ValidateDomainParams Uses

func (p CreateMachineParams) ValidateDomainParams() error

ValidateDomainParams implements libvirt.domainParams.

type Fetcher Uses

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 Uses

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

Image represents a server image.

type Oner Uses

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

Oner gets the one matching item from simplestreams.

type ProgressCallback Uses

type ProgressCallback func(message string)

type StartParams Uses

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 Uses

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.



Package kvm imports 47 packages (graph). Updated 2020-08-03. Refresh now. Tools for package owners.