This repository has been archived by the owner on Apr 3, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
- Loading branch information
Samuel Ortiz
committed
Oct 17, 2016
1 parent
dbccf33
commit 8fbd5de
Showing
12 changed files
with
2,917 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
Oops, something went wrong.