Skip to content
This repository has been archived by the owner on Apr 3, 2018. It is now read-only.

Commit

Permalink
virtcontainers: Initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
  • Loading branch information
Samuel Ortiz committed Oct 17, 2016
1 parent dbccf33 commit 8fbd5de
Show file tree
Hide file tree
Showing 12 changed files with 2,917 additions and 0 deletions.
92 changes: 92 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
[![Go Report Card](https://goreportcard.com/badge/github.com/sameo/virtcontainers)](https://goreportcard.com/report/github.com/sameo/virtcontainers)

# VirtContainers

VirtContainers is a Go package for building hardware virtualized container runtimes.

## Scope

VirtContainers is not a container runtime implementation, but aims at factorizing
hardware virtualization code in order to build VM based container runtimes.

The few existing VM based container runtimes (Clear Containers, RunV, Rkt
kvm stage 1) all share the same hardware virtualization semantics but use different
code bases to implement them. VirtContainers goal is to factorize this code into
a common Go library.

Ideally VM based container runtime implementations would become translation layers
from the runtime specification they implement to the VirtContainers API.

## Out of scope

Implementing yet another container runtime is out of VirtContainers scope. Any tools
or executables provided with VirtContainers are only provided for demonstration or
testing purposes.

## Design

### Goals

VirtContainers is a container specification agnostic Go package and thus tries to
abstract the various container runtime specifications (OCI, AppC and CRI) and present
that as its high level API.

### Pods

The VirtContainers execution unit is a Pod, i.e. VirtContainers callers start pods
where containers will be running.

Virtcontainers creates a pod by starting a virtual machine and setting the pod up within
that environment. Starting a pod means launching all containers with the VM pod runtime
environment.

### Hypervisors

The virtcontainers package relies on hypervisors to start and stop virtual machine where
pods will be running. An hypervisor is defined by an Hypervisor interface implementation,
and the default implementation is the QEMU one.

### Agents

During the lifecycle of a container, the runtime running on the host needs to interact with
the virtual machine guest OS in order to start new commands to be executed as part of a given
container workload, set new networking routes or interfaces, fetch a container standard or
error output, and so on.
There are many existing and potential solutions to resolve that problem and virtcontainers abstract
this through the Agent interface.

## API

The high level VirtContainers API is the following one:

### Pod API

* `CreatePod(podConfig PodConfig)` creates a Pod.
The Pod is prepared and will run into a virtual machine. It is not started, i.e. the VM is not running after `CreatePod()` is called.

* `DeletePod(podID string)` deletes a Pod.
The function will fail if the Pod is running. In that case `StopPod()` needs to be called first.

* `StartPod(podID string)` starts an already created Pod.

* `StopPod(podID string)` stops an already running Pod.

* `ListPod()` lists all running Pods on the host.

* `EnterPod(cmd Cmd)` enters a Pod root filesystem and runs a given command.

* `PodStatus(podID string)` returns a detailed Pod status.

### Container API

* `CreateContainer(podID string, container ContainerConfig)` creates a Container on a given Pod.

* `DeleteContainer(containerID string)` deletes a Container from a Pod. If the container is running it needs to be stopped first.

* `StartContainer(containerID string)` starts an already created container.

* `StopContainer(containerID string)` stops an already running container.

* `EnterContainer(containerID string, cmd Cmd)` enters an already running container and runs a given command.

* `ContainerStatus(containerID string)` returns a detailed container status.
130 changes: 130 additions & 0 deletions agent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package virtcontainers

import (
"fmt"

"github.com/mitchellh/mapstructure"
)

// AgentType describes the type of guest agent a Pod should run.
type AgentType string

const (
// NoopAgentType is the No-Op agent.
NoopAgentType AgentType = "noop"

// SSHdAgent is the SSH daemon agent.
SSHdAgent = "sshd"

// HyperstartAgent is the Hyper hyperstart agent.
HyperstartAgent = "hyperstart"
)

// Set sets an agent type based on the input string.
func (agentType *AgentType) Set(value string) error {
switch value {
case "noop":
*agentType = NoopAgentType
return nil
case "sshd":
*agentType = SSHdAgent
return nil
case "hyperstart":
*agentType = HyperstartAgent
return nil
default:
return fmt.Errorf("Unknown agent type %s", value)
}
}

// String converts an agent type to a string.
func (agentType *AgentType) String() string {
switch *agentType {
case NoopAgentType:
return string(NoopAgentType)
case SSHdAgent:
return string(SSHdAgent)
case HyperstartAgent:
return string(HyperstartAgent)
default:
return ""
}
}

// newAgent returns an agent from an agent type.
func newAgent(agentType AgentType) (agent, error) {
switch agentType {
case NoopAgentType:
return &noopAgent{}, nil
case SSHdAgent:
return &sshd{}, nil
case HyperstartAgent:
return &hyper{}, nil
default:
return &noopAgent{}, nil
}
}

// newAgentConfig returns an agent config from a generic PodConfig interface.
func newAgentConfig(config PodConfig) interface{} {
switch config.AgentType {
case NoopAgentType:
return nil
case SSHdAgent:
var sshdConfig SshdConfig
err := mapstructure.Decode(config.AgentConfig, &sshdConfig)
if err != nil {
return err
}
return sshdConfig
case HyperstartAgent:
var hyperConfig HyperConfig
err := mapstructure.Decode(config.AgentConfig, &hyperConfig)
if err != nil {
return err
}
return hyperConfig
default:
return nil
}
}

// Agent is the virtcontainers agent interface.
// Agents are running in the guest VM and handling
// communications between the host and guest.
type agent interface {
// init is used to pass agent specific configuration to the agent implementation.
// agent implementations also will typically start listening for agent events from
// init().
// After init() is called, agent implementations should be initialized and ready
// to handle all other Agent interface methods.
init(config interface{}, hypervisor hypervisor) error

// start will start the agent on the host.
start() error

// exec will tell the agent to run a command in an already running container.
exec(podID string, contID string, cmd Cmd) error

// StartPod will tell the agent to start all containers related to the Pod.
startPod(config PodConfig) error

// StopPod will tell the agent to stop all containers related to the Pod.
stopPod(config PodConfig) error
}
164 changes: 164 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
//
// Copyright (c) 2016 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

package virtcontainers

import (
"fmt"
"os"
"text/tabwriter"
)

// CreatePod is the virtcontainers pod creation entry point.
// CreatePod creates a pod and its containers. It does not start them.
func CreatePod(podConfig PodConfig) (*Pod, error) {
// Create the pod.
p, err := createPod(podConfig)
if err != nil {
return nil, err
}

// Store it.
err = p.storePod()
if err != nil {
return nil, err
}

return p, nil
}

// DeletePod is the virtcontainers pod deletion entry point.
// DeletePod will stop an already running container and then delete it.
func DeletePod(podID string) (*Pod, error) {
// Fetch the pod from storage and create it.
p, err := fetchPod(podID)
if err != nil {
return nil, err
}

// Delete it.
err = p.delete()
if err != nil {
return nil, err
}

return p, nil
}

// StartPod is the virtcontainers pod starting entry point.
// StartPod will talk to the given hypervisor to start an existing
// pod and all its containers.
// It returns the pod ID.
func StartPod(podID string) (*Pod, error) {
// Fetch the pod from storage and create it.
p, err := fetchPod(podID)
if err != nil {
return nil, err
}

// Start it.
err = p.start()
if err != nil {
p.delete()
return nil, err
}

return p, nil
}

// StopPod is the virtcontainers pod stopping entry point.
// StopPod will talk to the given agent to stop an existing pod and destroy all containers within that pod.
func StopPod(podID string) (*Pod, error) {
// Fetch the pod from storage and create it.
p, err := fetchPod(podID)
if err != nil {
return nil, err
}

// Stop it.
err = p.stop()
if err != nil {
p.delete()
return nil, err
}

return p, nil
}

// RunPod is the virtcontainers pod running entry point.
// RunPod creates a pod and its containers and then it starts them.
func RunPod(podConfig PodConfig) (*Pod, error) {
// Create the pod.
p, err := createPod(podConfig)
if err != nil {
return nil, err
}

// Store it.
err = p.storePod()
if err != nil {
return nil, err
}

// Start it.
err = p.start()
if err != nil {
p.delete()
return nil, err
}

return p, nil
}

var listFormat = "%s\t%s\t%s\t%s\n"

// ListPod is the virtcontainers pod listing entry point.
func ListPod() error {
dir, err := os.Open(configStoragePath)
if err != nil {
return err
}

defer dir.Close()

pods, err := dir.Readdirnames(0)
if err != nil {
return err
}

fs := filesystem{}

w := tabwriter.NewWriter(os.Stdout, 2, 8, 1, '\t', 0)
fmt.Fprintf(w, listFormat, "POD ID", "STATE", "HYPERVISOR", "AGENT")

for _, p := range pods {
config, err := fs.fetchConfig(p)
if err != nil {
continue
}

state, err := fs.fetchState(p)
if err != nil {
continue
}

fmt.Fprintf(w, listFormat,
config.ID, state.State, config.HypervisorType, config.AgentType)
}

w.Flush()
return nil
}
Loading

0 comments on commit 8fbd5de

Please sign in to comment.