infrakit: Move the hyperkit instance plugin into the source directory

- The tools directory ideally should not contain source code
- Removes double vendoring of packagages
- Makes it easer to hook the build into the top-level Makefile

Eventually, the plugin should be moved to the infrakit repo.

Signed-off-by: Rolf Neugebauer <rolf.neugebauer@docker.com>
This commit is contained in:
Rolf Neugebauer
2017-03-25 12:41:22 +01:00
parent 1c0a86caee
commit 6a29d153f5
418 changed files with 23393 additions and 2389 deletions

View File

@@ -0,0 +1,30 @@
{
"ID": "cattle",
"Properties": {
"Allocation": {
"Size": 1
},
"Instance": {
"Plugin": "instance-hyperkit",
"Properties": {
"Moby": "../../moby",
"Disk" : 512,
"CPUs" : 2,
"Memory" : 1024
}
},
"Flavor": {
"Plugin": "flavor-vanilla",
"Properties": {
"Init": [
"test1",
"test2"
],
"Tags": {
"tier": "sample",
"project": "infrakit"
}
}
}
}
}

View File

@@ -0,0 +1,221 @@
package main
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path"
log "github.com/Sirupsen/logrus"
"github.com/docker/hyperkit/go"
"github.com/docker/infrakit/pkg/spi/instance"
"github.com/docker/infrakit/pkg/types"
)
// NewHyperKitPlugin creates an instance plugin for hyperkit.
func NewHyperKitPlugin(vmDir, hyperkit, vpnkitSock string) instance.Plugin {
return &hyperkitPlugin{VMDir: vmDir,
HyperKit: hyperkit,
VPNKitSock: vpnkitSock,
}
}
type hyperkitPlugin struct {
// VMDir is the path to a directory where per VM state is kept
VMDir string
// Hyperkit is the path to the hyperkit executable
HyperKit string
// VPNKitSock is the path to the VPNKit Unix domain socket.
VPNKitSock string
}
// Validate performs local validation on a provision request.
func (p hyperkitPlugin) Validate(req *types.Any) error {
return nil
}
// Provision creates a new instance.
func (p hyperkitPlugin) Provision(spec instance.Spec) (*instance.ID, error) {
var properties map[string]interface{}
if spec.Properties != nil {
if err := spec.Properties.Decode(&properties); err != nil {
return nil, fmt.Errorf("Invalid instance properties: %s", err)
}
}
if properties["Moby"] == nil {
return nil, errors.New("Property 'Moby' must be set")
}
if properties["CPUs"] == nil {
properties["CPUs"] = 1
}
if properties["Memory"] == nil {
properties["Memory"] = 512
}
if properties["Disk"] == nil {
properties["Disk"] = 256
}
instanceDir, err := ioutil.TempDir(p.VMDir, "infrakit-")
if err != nil {
return nil, err
}
id := instance.ID(path.Base(instanceDir))
// Start a HyperKit instance
h, err := hyperkit.New(p.HyperKit, instanceDir, p.VPNKitSock, "")
if err != nil {
return nil, err
}
h.Kernel = properties["Moby"].(string) + "-bzImage"
h.Initrd = properties["Moby"].(string) + "-initrd.img"
h.CPUs = int(properties["CPUs"].(float64))
h.Memory = int(properties["Memory"].(float64))
h.DiskSize = int(properties["Disk"].(float64))
h.UserData = spec.Init
h.Console = hyperkit.ConsoleFile
err = h.Start("console=ttyS0")
if err != nil {
return nil, err
}
log.Info("Started new VM: ", id)
tagData, err := types.AnyValue(spec.Tags)
if err != nil {
return nil, err
}
if err := ioutil.WriteFile(path.Join(instanceDir, "tags"), tagData.Bytes(), 0644); err != nil {
return nil, err
}
return &id, nil
}
// Label labels the instance
func (p hyperkitPlugin) Label(instance instance.ID, labels map[string]string) error {
instanceDir := path.Join(p.VMDir, string(instance))
tagFile := path.Join(instanceDir, "tags")
buff, err := ioutil.ReadFile(tagFile)
if err != nil {
return err
}
tags := map[string]string{}
err = types.AnyBytes(buff).Decode(&tags)
if err != nil {
return err
}
for k, v := range labels {
tags[k] = v
}
encoded, err := types.AnyValue(tags)
if err != nil {
return err
}
return ioutil.WriteFile(tagFile, encoded.Bytes(), 0644)
}
// Destroy terminates an existing instance.
func (p hyperkitPlugin) Destroy(id instance.ID) error {
log.Info("Destroying VM: ", id)
instanceDir := path.Join(p.VMDir, string(id))
_, err := os.Stat(instanceDir)
if err != nil {
if os.IsNotExist(err) {
return errors.New("Instance does not exist")
}
}
h, err := hyperkit.FromState(instanceDir)
if err != nil {
return err
}
err = h.Stop()
if err != nil {
return err
}
err = h.Remove(false)
if err != nil {
return err
}
return nil
}
// DescribeInstances returns descriptions of all instances matching all of the provided tags.
func (p hyperkitPlugin) DescribeInstances(tags map[string]string) ([]instance.Description, error) {
files, err := ioutil.ReadDir(p.VMDir)
if err != nil {
return nil, err
}
descriptions := []instance.Description{}
for _, file := range files {
if !file.IsDir() {
continue
}
instanceDir := path.Join(p.VMDir, file.Name())
tagData, err := ioutil.ReadFile(path.Join(instanceDir, "tags"))
if err != nil {
if os.IsNotExist(err) {
continue
}
return nil, err
}
instanceTags := map[string]string{}
if err := types.AnyBytes(tagData).Decode(&instanceTags); err != nil {
return nil, err
}
allMatched := true
for k, v := range tags {
value, exists := instanceTags[k]
if !exists || v != value {
allMatched = false
break
}
}
if allMatched {
var logicalID *instance.LogicalID
id := instance.ID(file.Name())
h, err := hyperkit.FromState(instanceDir)
if err != nil {
log.Warningln("Could not get instance data. Id: ", id)
p.Destroy(id)
continue
}
if !h.IsRunning() {
log.Warningln("Instance is not running. Id: ", id)
p.Destroy(id)
continue
}
lid := instance.LogicalID(h.Pid)
logicalID = &lid
descriptions = append(descriptions, instance.Description{
ID: id,
LogicalID: logicalID,
Tags: instanceTags,
})
}
}
return descriptions, nil
}

View File

@@ -0,0 +1,89 @@
package main
import (
"encoding/json"
"fmt"
"os"
"os/user"
"path/filepath"
log "github.com/Sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/docker/infrakit/pkg/cli"
"github.com/docker/infrakit/pkg/plugin/metadata"
instance_plugin "github.com/docker/infrakit/pkg/rpc/instance"
metadata_plugin "github.com/docker/infrakit/pkg/rpc/metadata"
instance_spi "github.com/docker/infrakit/pkg/spi/instance"
)
var (
// Version is the build release identifier.
Version = "Unspecified"
// Revision is the build source control revision.
Revision = "Unspecified"
)
func main() {
cmd := &cobra.Command{
Use: os.Args[0],
Short: "HyperKit instance plugin",
}
defaultVMDir := filepath.Join(getHome(), ".infrakit/hyperkit-vms")
name := cmd.Flags().String("name", "instance-hyperkit", "Plugin name to advertise for discovery")
logLevel := cmd.Flags().Int("log", cli.DefaultLogLevel, "Logging level. 0 is least verbose. Max is 5")
vmDir := cmd.Flags().String("vm-dir", defaultVMDir, "Directory where to store VM state")
hyperkit := cmd.Flags().String("hyperkit", "", "Path to HyperKit executable")
vpnkitSock := cmd.Flags().String("vpnkit-sock", "auto", "Path to VPNKit UNIX domain socket")
cmd.RunE = func(c *cobra.Command, args []string) error {
os.MkdirAll(*vmDir, os.ModePerm)
cli.SetLogLevel(*logLevel)
cli.RunPlugin(*name,
instance_plugin.PluginServer(NewHyperKitPlugin(*vmDir, *hyperkit, *vpnkitSock)),
metadata_plugin.PluginServer(metadata.NewPluginFromData(
map[string]interface{}{
"version": Version,
"revision": Revision,
"implements": instance_spi.InterfaceSpec,
},
)),
)
return nil
}
cmd.AddCommand(&cobra.Command{
Use: "version",
Short: "print build version information",
RunE: func(cmd *cobra.Command, args []string) error {
buff, err := json.MarshalIndent(map[string]interface{}{
"version": Version,
"revision": Revision,
}, " ", " ")
if err != nil {
return err
}
fmt.Println(string(buff))
return nil
},
})
if err := cmd.Execute(); err != nil {
log.Error(err)
os.Exit(1)
}
}
func getHome() string {
if usr, err := user.Current(); err == nil {
return usr.HomeDir
}
return os.Getenv("HOME")
}