func (p *Pod) delete() error {
	if p.state.State != StateReady &&
		p.state.State != StatePaused &&
		p.state.State != StateStopped {
		return fmt.Errorf("Pod not ready, paused or stopped, impossible to delete")
	}
	for _, c := range p.containers {
		if err := c.delete(); err != nil {
			return err
		}
	}
	return p.storage.deletePodResources(p.id, nil)
}
delete deletes an already created pod.
The VM in which the pod is running will be shut down.
package virtcontainers
import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"syscall"
	"github.com/sirupsen/logrus"
)
const controlSocket = "ctl"
const monitorSocket = "mon"
const vmStartTimeout = 10
type stateString string
const (
	StateReady stateString = "ready"
	StateRunning stateString = "running"
	StatePaused stateString = "paused"
	StateStopped stateString = "stopped"
)
type State struct {
	State stateString `json:"state"`
	BlockIndex int `json:"blockIndex"`
	Fstype string `json:"fstype"`
	HotpluggedDrive bool `json:"hotpluggedDrive"`
}
func (state *State) valid() bool {
	for _, validState := range []stateString{StateReady, StateRunning, StatePaused, StateStopped} {
		if state.State == validState {
			return true
		}
	}
	return false
}
func (state *State) validTransition(oldState stateString, newState stateString) error {
	if state.State != oldState {
		return fmt.Errorf("Invalid state %s (Expecting %s)", state.State, oldState)
	}
	switch state.State {
	case StateReady:
		if newState == StateRunning || newState == StateStopped {
			return nil
		}
	case StateRunning:
		if newState == StatePaused || newState == StateStopped {
			return nil
		}
	case StatePaused:
		if newState == StateRunning || newState == StateStopped {
			return nil
		}
	case StateStopped:
		if newState == StateRunning {
			return nil
		}
	}
	return fmt.Errorf("Can not move from %s to %s",
		state.State, newState)
}
type Volume struct {
	MountTag string
	HostPath string
}
type Volumes []Volume
func (v *Volumes) Set(volStr string) error {
	if volStr == "" {
		return fmt.Errorf("volStr cannot be empty")
	}
	volSlice := strings.Split(volStr, " ")
	const expectedVolLen = 2
	const volDelimiter = ":"
	for _, vol := range volSlice {
		volArgs := strings.Split(vol, volDelimiter)
		if len(volArgs) != expectedVolLen {
			return fmt.Errorf("Wrong string format: %s, expecting only %v parameters separated with %q",
				vol, expectedVolLen, volDelimiter)
		}
		if volArgs[0] == "" || volArgs[1] == "" {
			return fmt.Errorf("Volume parameters cannot be empty")
		}
		volume := Volume{
			MountTag: volArgs[0],
			HostPath: volArgs[1],
		}
		*v = append(*v, volume)
	}
	return nil
}
func (v *Volumes) String() string {
	var volSlice []string
	for _, volume := range *v {
		volSlice = append(volSlice, fmt.Sprintf("%s:%s", volume.MountTag, volume.HostPath))
	}
	return strings.Join(volSlice, " ")
}
type Socket struct {
	DeviceID string
	ID       string
	HostPath string
	Name     string
}
type Sockets []Socket
func (s *Sockets) Set(sockStr string) error {
	if sockStr == "" {
		return fmt.Errorf("sockStr cannot be empty")
	}
	sockSlice := strings.Split(sockStr, " ")
	const expectedSockCount = 4
	const sockDelimiter = ":"
	for _, sock := range sockSlice {
		sockArgs := strings.Split(sock, sockDelimiter)
		if len(sockArgs) != expectedSockCount {
			return fmt.Errorf("Wrong string format: %s, expecting only %v parameters separated with %q", sock, expectedSockCount, sockDelimiter)
		}
		for _, a := range sockArgs {
			if a == "" {
				return fmt.Errorf("Socket parameters cannot be empty")
			}
		}
		socket := Socket{
			DeviceID: sockArgs[0],
			ID:       sockArgs[1],
			HostPath: sockArgs[2],
			Name:     sockArgs[3],
		}
		*s = append(*s, socket)
	}
	return nil
}
func (s *Sockets) String() string {
	var sockSlice []string
	for _, sock := range *s {
		sockSlice = append(sockSlice, fmt.Sprintf("%s:%s:%s:%s", sock.DeviceID, sock.ID, sock.HostPath, sock.Name))
	}
	return strings.Join(sockSlice, " ")
}
type Drive struct {
	File string
	Format string
	ID string
	Index int
}
type EnvVar struct {
	Var   string
	Value string
}
type LinuxCapabilities struct {
	Bounding []string
	Effective []string
	Inheritable []string
	Permitted []string
	Ambient []string
}
type Cmd struct {
	Args    []string
	Envs    []EnvVar
	WorkDir string
	User                string
	PrimaryGroup        string
	SupplementaryGroups []string
	Interactive     bool
	Console         string
	Detach          bool
	NoNewPrivileges bool
	Capabilities    LinuxCapabilities
}
type Resources struct {
	VCPUs uint
	Memory uint
}
type PodStatus struct {
	ID               string
	State            State
	Hypervisor       HypervisorType
	HypervisorConfig HypervisorConfig
	Agent            AgentType
	ContainersStatus []ContainerStatus
	Annotations map[string]string
}
type PodConfig struct {
	ID string
	Hostname string
	Hooks Hooks
	VMConfig Resources
	HypervisorType   HypervisorType
	HypervisorConfig HypervisorConfig
	AgentType   AgentType
	AgentConfig interface{}
	ProxyType   ProxyType
	ProxyConfig ProxyConfig
	ShimType   ShimType
	ShimConfig interface{}
	NetworkModel  NetworkModel
	NetworkConfig NetworkConfig
	Volumes []Volume
	Containers []ContainerConfig
	Annotations map[string]string
}
func (podConfig *PodConfig) valid() bool {
	if podConfig.ID == "" {
		return false
	}
	if _, err := newHypervisor(podConfig.HypervisorType); err != nil {
		podConfig.HypervisorType = QemuHypervisor
	}
	return true
}
const (
	exclusiveLock = syscall.LOCK_EX
	sharedLock = syscall.LOCK_SH
)
func rLockPod(podID string) (*os.File, error) {
	return lockPod(podID, sharedLock)
}
func rwLockPod(podID string) (*os.File, error) {
	return lockPod(podID, exclusiveLock)
}
func lockPod(podID string, lockType int) (*os.File, error) {
	if podID == "" {
		return nil, errNeedPodID
	}
	fs := filesystem{}
	podlockFile, _, err := fs.podURI(podID, lockFileType)
	if err != nil {
		return nil, err
	}
	lockFile, err := os.Open(podlockFile)
	if err != nil {
		return nil, err
	}
	if err := syscall.Flock(int(lockFile.Fd()), lockType); err != nil {
		return nil, err
	}
	return lockFile, nil
}
func unlockPod(lockFile *os.File) error {
	if lockFile == nil {
		return fmt.Errorf("lockFile cannot be empty")
	}
	err := syscall.Flock(int(lockFile.Fd()), syscall.LOCK_UN)
	if err != nil {
		return err
	}
	lockFile.Close()
	return nil
}
type Pod struct {
	id string
	hypervisor hypervisor
	agent      agent
	storage    resourceStorage
	network    network
	config *PodConfig
	volumes []Volume
	containers []*Container
	runPath    string
	configPath string
	state State
	networkNS NetworkNamespace
	lockFile *os.File
	annotationsLock *sync.RWMutex
	wg *sync.WaitGroup
}
func (p *Pod) ID() string {
	return p.id
}
func (p *Pod) Logger() *logrus.Entry {
	return virtLog.WithFields(logrus.Fields{
		"subsystem": "pod",
		"pod-id":    p.id,
	})
}
func (p *Pod) Annotations(key string) (string, error) {
	value, exist := p.config.Annotations[key]
	if exist == false {
		return "", fmt.Errorf("Annotations key %s does not exist", key)
	}
	return value, nil
}
func (p *Pod) SetAnnotations(annotations map[string]string) error {
	p.annotationsLock.Lock()
	defer p.annotationsLock.Unlock()
	for k, v := range annotations {
		p.config.Annotations[k] = v
	}
	err := p.storage.storePodResource(p.id, configFileType, *(p.config))
	if err != nil {
		return err
	}
	return nil
}
func (p *Pod) GetAnnotations() map[string]string {
	p.annotationsLock.RLock()
	defer p.annotationsLock.RUnlock()
	return p.config.Annotations
}
func (p *Pod) GetAllContainers() []VCContainer {
	ifa := make([]VCContainer, len(p.containers))
	for i, v := range p.containers {
		ifa[i] = v
	}
	return ifa
}
func (p *Pod) GetContainer(containerID string) VCContainer {
	for _, c := range p.containers {
		if c.id == containerID {
			return c
		}
	}
	return nil
}
func createAssets(podConfig *PodConfig) error {
	kernel, err := newAsset(podConfig, kernelAsset)
	if err != nil {
		return err
	}
	image, err := newAsset(podConfig, imageAsset)
	if err != nil {
		return err
	}
	for _, a := range []*asset{kernel, image} {
		if err := podConfig.HypervisorConfig.addCustomAsset(a); err != nil {
			return err
		}
	}
	return nil
}
func createPod(podConfig PodConfig) (*Pod, error) {
	if err := createAssets(&podConfig); err != nil {
		return nil, err
	}
	p, err := newPod(podConfig)
	if err != nil {
		return nil, err
	}
	networkNS, err := p.storage.fetchPodNetwork(p.id)
	if err == nil {
		p.networkNS = networkNS
	}
	state, err := p.storage.fetchPodState(p.id)
	if err == nil && state.State != "" {
		p.state = state
		return p, nil
	}
	if err := p.agent.createPod(p); err != nil {
		return nil, err
	}
	if err := p.attachDevices(); err != nil {
		return nil, err
	}
	if err := p.setPodState(StateReady); err != nil {
		return nil, err
	}
	return p, nil
}
func newPod(podConfig PodConfig) (*Pod, error) {
	if podConfig.valid() == false {
		return nil, fmt.Errorf("Invalid pod configuration")
	}
	agent := newAgent(podConfig.AgentType)
	hypervisor, err := newHypervisor(podConfig.HypervisorType)
	if err != nil {
		return nil, err
	}
	network := newNetwork(podConfig.NetworkModel)
	p := &Pod{
		id:              podConfig.ID,
		hypervisor:      hypervisor,
		agent:           agent,
		storage:         &filesystem{},
		network:         network,
		config:          &podConfig,
		volumes:         podConfig.Volumes,
		runPath:         filepath.Join(runStoragePath, podConfig.ID),
		configPath:      filepath.Join(configStoragePath, podConfig.ID),
		state:           State{},
		annotationsLock: &sync.RWMutex{},
		wg:              &sync.WaitGroup{},
	}
	if err := p.storage.createAllResources(*p); err != nil {
		return nil, err
	}
	if err := p.hypervisor.init(p); err != nil {
		p.storage.deletePodResources(p.id, nil)
		return nil, err
	}
	if err := p.hypervisor.createPod(podConfig); err != nil {
		p.storage.deletePodResources(p.id, nil)
		return nil, err
	}
	agentConfig := newAgentConfig(podConfig)
	if err := p.agent.init(p, agentConfig); err != nil {
		p.storage.deletePodResources(p.id, nil)
		return nil, err
	}
	return p, nil
}
func (p *Pod) storePod() error {
	err := p.storage.storePodResource(p.id, configFileType, *(p.config))
	if err != nil {
		return err
	}
	for _, container := range p.containers {
		err = p.storage.storeContainerResource(p.id, container.id, configFileType, *(container.config))
		if err != nil {
			return err
		}
	}
	return nil
}
func fetchPod(podID string) (pod *Pod, err error) {
	if podID == "" {
		return nil, errNeedPodID
	}
	fs := filesystem{}
	config, err := fs.fetchPodConfig(podID)
	if err != nil {
		return nil, err
	}
	pod, err = createPod(config)
	if err != nil {
		return nil, fmt.Errorf("failed to create pod with config %+v: %v", config, err)
	}
	if err := pod.newContainers(); err != nil {
		return nil, err
	}
	return pod, nil
}
func (p *Pod) findContainer(containerID string) (*Container, error) {
	if p == nil {
		return nil, errNeedPod
	}
	if containerID == "" {
		return nil, errNeedContainerID
	}
	for _, c := range p.containers {
		if containerID == c.id {
			return c, nil
		}
	}
	return nil, fmt.Errorf("Could not find the container %q from the pod %q containers list",
		containerID, p.id)
}
func (p *Pod) removeContainer(containerID string) error {
	if p == nil {
		return errNeedPod
	}
	if containerID == "" {
		return errNeedContainerID
	}
	for idx, c := range p.containers {
		if containerID == c.id {
			p.containers = append(p.containers[:idx], p.containers[idx+1:]...)
			return nil
		}
	}
	return fmt.Errorf("Could not remove the container %q from the pod %q containers list",
		containerID, p.id)
}