kvm

package
v0.0.0-...-7139314 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 22, 2024 License: AGPL-3.0 Imports: 48 Imported by: 57

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

View Source
const DiskImageType = "disk1.img"

DiskImageType is the file type we want to fetch and use for kvm instances.

Variables

View Source
var (

	// KVMObjectFactory implements the container factory interface for kvm
	// containers.
	// TODO (stickupkid): This _only_ exists here because we can patch it in
	// tests. This is horrid!
	KVMObjectFactory ContainerFactory = &containerFactory{
		fetcher: simplestreams.NewSimpleStreams(simplestreams.DefaultDataSourceFactory()),
	}

	// 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.

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

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.

Types

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
	Version           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
	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 {
	Version           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.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL