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
}
createPod creates a pod from a pod description, the containers list, the hypervisor
and the agent passed through the Config structure.
It will create and store the pod structure, and then ask the hypervisor
to physically create that pod i.e. starts a VM for that pod to eventually
be started.
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
}