func KillContainer(podID, containerID string, signal syscall.Signal, all bool) error {
	if podID == "" {
		return errNeedPodID
	}
	if containerID == "" {
		return errNeedContainerID
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return err
	}
	c, err := fetchContainer(p, containerID)
	if err != nil {
		return err
	}
	err = c.kill(signal, all)
	if err != nil {
		return err
	}
	return nil
}
KillContainer is the virtcontainers entry point to send a signal
to a container running inside a pod. If all is true, all processes in
the container will be sent the signal.
package virtcontainers
import (
	"os"
	"runtime"
	"syscall"
	"github.com/sirupsen/logrus"
)
func init() {
	runtime.LockOSThread()
}
var virtLog = logrus.FieldLogger(logrus.New())
func SetLogger(logger logrus.FieldLogger) {
	virtLog = logger.WithField("source", "virtcontainers")
}
func CreatePod(podConfig PodConfig) (VCPod, error) {
	return createPodFromConfig(podConfig)
}
func createPodFromConfig(podConfig PodConfig) (*Pod, error) {
	p, err := createPod(podConfig)
	if err != nil {
		return nil, err
	}
	err = p.storePod()
	if err != nil {
		return nil, err
	}
	netNsPath, netNsCreated, err := p.network.init(p.config.NetworkConfig)
	if err != nil {
		return nil, err
	}
	err = p.network.run(netNsPath, func() error {
		return p.config.Hooks.preStartHooks()
	})
	if err != nil {
		return nil, err
	}
	networkNS, err := p.network.add(*p, p.config.NetworkConfig, netNsPath, netNsCreated)
	if err != nil {
		return nil, err
	}
	err = p.storage.storePodNetwork(p.id, networkNS)
	if err != nil {
		return nil, err
	}
	err = p.startVM(netNsPath)
	if err != nil {
		return nil, err
	}
	err = p.startProxy()
	if err != nil {
		return nil, err
	}
	if err := p.startShims(); err != nil {
		return nil, err
	}
	return p, nil
}
func DeletePod(podID string) (VCPod, error) {
	if podID == "" {
		return nil, errNeedPodID
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, err
	}
	networkNS, err := p.storage.fetchPodNetwork(podID)
	if err != nil {
		return nil, err
	}
	if err := p.stopShims(); err != nil {
		return nil, err
	}
	err = p.stopVM()
	if err != nil {
		return nil, err
	}
	if networkNS.NetNsCreated {
		if err := p.network.remove(*p, networkNS); err != nil {
			return nil, err
		}
	}
	err = p.delete()
	if err != nil {
		return nil, err
	}
	if err := p.config.Hooks.postStopHooks(); err != nil {
		return nil, err
	}
	return p, nil
}
func StartPod(podID string) (VCPod, error) {
	if podID == "" {
		return nil, errNeedPodID
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, err
	}
	return startPod(p)
}
func startPod(p *Pod) (*Pod, error) {
	err := p.start()
	if err != nil {
		return nil, err
	}
	if err := p.config.Hooks.postStartHooks(); err != nil {
		return nil, err
	}
	return p, nil
}
func StopPod(podID string) (VCPod, error) {
	if podID == "" {
		return nil, errNeedPod
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, err
	}
	err = p.stop()
	if err != nil {
		p.delete()
		return nil, err
	}
	return p, nil
}
func RunPod(podConfig PodConfig) (VCPod, error) {
	p, err := createPodFromConfig(podConfig)
	if err != nil {
		return nil, err
	}
	lockFile, err := rwLockPod(p.id)
	if err != nil {
		return nil, err
	}
	defer unlockPod(lockFile)
	return startPod(p)
}
func ListPod() ([]PodStatus, error) {
	dir, err := os.Open(configStoragePath)
	if err != nil {
		if os.IsNotExist(err) {
			return []PodStatus{}, nil
		}
		return []PodStatus{}, err
	}
	defer dir.Close()
	podsID, err := dir.Readdirnames(0)
	if err != nil {
		return []PodStatus{}, err
	}
	var podStatusList []PodStatus
	for _, podID := range podsID {
		podStatus, err := StatusPod(podID)
		if err != nil {
			continue
		}
		podStatusList = append(podStatusList, podStatus)
	}
	return podStatusList, nil
}
func StatusPod(podID string) (PodStatus, error) {
	if podID == "" {
		return PodStatus{}, errNeedPodID
	}
	lockFile, err := rLockPod(podID)
	if err != nil {
		return PodStatus{}, err
	}
	pod, err := fetchPod(podID)
	if err != nil {
		unlockPod(lockFile)
		return PodStatus{}, err
	}
	defer pod.wg.Wait()
	defer unlockPod(lockFile)
	var contStatusList []ContainerStatus
	for _, container := range pod.containers {
		contStatus, err := statusContainer(pod, container.id)
		if err != nil {
			return PodStatus{}, err
		}
		contStatusList = append(contStatusList, contStatus)
	}
	podStatus := PodStatus{
		ID:               pod.id,
		State:            pod.state,
		Hypervisor:       pod.config.HypervisorType,
		HypervisorConfig: pod.config.HypervisorConfig,
		Agent:            pod.config.AgentType,
		ContainersStatus: contStatusList,
		Annotations:      pod.config.Annotations,
	}
	return podStatus, nil
}
func CreateContainer(podID string, containerConfig ContainerConfig) (VCPod, VCContainer, error) {
	if podID == "" {
		return nil, nil, errNeedPodID
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return nil, nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, nil, err
	}
	c, err := createContainer(p, containerConfig)
	if err != nil {
		return nil, nil, err
	}
	err = c.storeContainer()
	if err != nil {
		return nil, nil, err
	}
	p.config.Containers = append(p.config.Containers, containerConfig)
	err = p.storage.storePodResource(podID, configFileType, *(p.config))
	if err != nil {
		return nil, nil, err
	}
	return p, c, nil
}
func DeleteContainer(podID, containerID string) (VCContainer, error) {
	if podID == "" {
		return nil, errNeedPodID
	}
	if containerID == "" {
		return nil, errNeedContainerID
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, err
	}
	c, err := fetchContainer(p, containerID)
	if err != nil {
		return nil, err
	}
	err = c.delete()
	if err != nil {
		return nil, err
	}
	for idx, contConfig := range p.config.Containers {
		if contConfig.ID == containerID {
			p.config.Containers = append(p.config.Containers[:idx], p.config.Containers[idx+1:]...)
			break
		}
	}
	err = p.storage.storePodResource(podID, configFileType, *(p.config))
	if err != nil {
		return nil, err
	}
	return c, nil
}
func StartContainer(podID, containerID string) (VCContainer, error) {
	if podID == "" {
		return nil, errNeedPodID
	}
	if containerID == "" {
		return nil, errNeedContainerID
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, err
	}
	c, err := fetchContainer(p, containerID)
	if err != nil {
		return nil, err
	}
	err = c.start()
	if err != nil {
		c.delete()
		return nil, err
	}
	return c, nil
}
func StopContainer(podID, containerID string) (VCContainer, error) {
	if podID == "" {
		return nil, errNeedPodID
	}
	if containerID == "" {
		return nil, errNeedContainerID
	}
	lockFile, err := rwLockPod(podID)
	if err != nil {
		return nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, err
	}
	c, err := fetchContainer(p, containerID)
	if err != nil {
		return nil, err
	}
	err = c.stop()
	if err != nil {
		c.delete()
		return nil, err
	}
	return c, nil
}
func EnterContainer(podID, containerID string, cmd Cmd) (VCPod, VCContainer, *Process, error) {
	if podID == "" {
		return nil, nil, nil, errNeedPodID
	}
	if containerID == "" {
		return nil, nil, nil, errNeedContainerID
	}
	lockFile, err := rLockPod(podID)
	if err != nil {
		return nil, nil, nil, err
	}
	defer unlockPod(lockFile)
	p, err := fetchPod(podID)
	if err != nil {
		return nil, nil, nil, err
	}
	c, err := fetchContainer(p, containerID)
	if err != nil {
		return nil, nil, nil, err
	}
	process, err := c.enter(cmd)
	if err != nil {
		return nil, nil, nil, err
	}
	return p, c, process, nil
}
func StatusContainer(podID, containerID string) (ContainerStatus, error) {
	if podID == "" {
		return ContainerStatus{}, errNeedPodID
	}
	if containerID == "" {
		return ContainerStatus{}, errNeedContainerID
	}
	lockFile, err := rLockPod(podID)
	if err != nil {
		return ContainerStatus{}, err
	}
	pod, err := fetchPod(podID)
	if err != nil {
		unlockPod(lockFile)
		return ContainerStatus{}, err
	}
	defer pod.wg.Wait()
	defer unlockPod(lockFile)
	return statusContainer(pod, containerID)
}
func statusContainer(pod *Pod, containerID string) (ContainerStatus, error) {
	for _, container := range pod.containers {
		if container.id == containerID {
			if (container.state.State == StateRunning ||
				container.state.State == StatePaused) &&
				container.process.Pid > 0 {
				running, err := isShimRunning(container.process.Pid)
				if err != nil {
					return ContainerStatus{}, err
				}
				if !running {
					pod.wg.Add(1)
					go func() {
						defer pod.wg.Done()
						lockFile, err := rwLockPod(pod.id)
						if err != nil {
							return
						}
						defer unlockPod(lockFile)
						if err := container.stop(); err != nil {
							return
						}
					}()
				}
			}
			return ContainerStatus{
				ID:          container.id,
				State:       container.state,
				PID:         container.process.Pid,
				StartTime:   container.process.StartTime,
				RootFs:      container.config.RootFs,
				Annotations: container.config.Annotations,
			}, nil
		}
	}
	return ContainerStatus{}, nil
}