Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions pkg/provider/vsphere/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
InfraKit Instance Plugin - VMware vCenter/vSphere
===============================

This plugin allows Docker InfraKit to automate the provisioning of Virtual Machine instances.

### Current State
- InfraKit will provision from LinuxKit `.iso` files that can be uploaded using the `$ linuxkit push vcenter <args> file.iso` command.
- Provisioning, Scaling and Destroying
- An InfraKit Group will create a VMware vCenter folder that will hold all VM instances that are tied to that group.
- On vSphere it will use the `annotation` field to hold the InfraKit group and config SHA.
- Environment variables can be used with the plugin for VMware vCenter configuration:
- `VCURL` = URL for VMware vCenter/vSphere `https://User:Pass@X.X.X.X/sdk`
- `VCNETWORK` = Name of network e.g. `VM Network`
- `VCDATASTORE` = Default Datastore used for new VM Instances
- `VCHOST` = Name of the main vSphere host that will be used.
- The following JSON parameters provide VM Instance configuration:

```
"Properties": {
"Datastore" : "datastore1",
"Network" : "VM Network",
"Hostname" : "localhost.localdomain",
"isoPath" : "linuxkit/linuxkit.iso",
"CPUs" : "1",
"MEM" : "512",
"vmPrefix" : "lk",
"powerOn" : true
}

```
- Moved to `pkg/providers/vsphere`


## To Do
- Investigate error messages, when using vSphere instead of VMware vCenter
- VMware Template support `.vmtx`
- `Makefile` needs updating



43 changes: 43 additions & 0 deletions pkg/provider/vsphere/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"os"

log "github.com/Sirupsen/logrus"
"github.com/docker/infrakit/pkg/cli"
instance_plugin "github.com/docker/infrakit/pkg/rpc/instance"
"github.com/spf13/cobra"
)

func main() {

cmd := &cobra.Command{
Use: os.Args[0],
Short: "VMware vSphere instance plugin",
}

// This will hold the configuration that is used to communicate with VMware vCenter or vSphere
var newVCenter vCenter

name := cmd.Flags().String("name", "instance-vsphere", "Plugin name to advertise for discovery")
logLevel := cmd.Flags().Int("log", cli.DefaultLogLevel, "Logging level. 0 is least verbose. Max is 5")

// Attributes of the VMware vCenter Server to connect to
newVCenter.vCenterURL = cmd.Flags().String("url", os.Getenv("VCURL"), "URL of VMware vCenter in the format of https://username:password@VCaddress/sdk")
newVCenter.dsName = cmd.Flags().String("datastore", os.Getenv("VCDATASTORE"), "The name of the DataStore to host the VM")
newVCenter.networkName = cmd.Flags().String("network", os.Getenv("VCNETWORK"), "The network label the VM will use")
newVCenter.vSphereHost = cmd.Flags().String("hostname", os.Getenv("VCHOST"), "The server that will run the VM")

cmd.Run = func(c *cobra.Command, args []string) {
cli.SetLogLevel(*logLevel)
cli.RunPlugin(*name, instance_plugin.PluginServer(NewVSphereInstancePlugin(&newVCenter)))
}

cmd.AddCommand(cli.VersionCommand())

err := cmd.Execute()
if err != nil {
log.Error(err)
os.Exit(1)
}
}
194 changes: 194 additions & 0 deletions pkg/provider/vsphere/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
package main

import (
"context"
"fmt"
"math/rand"
"time"

"github.com/docker/infrakit/pkg/spi"
"github.com/docker/infrakit/pkg/spi/instance"
"github.com/docker/infrakit/pkg/types"

log "github.com/Sirupsen/logrus"
)

// Spec is just whatever that can be unmarshalled into a generic JSON map
type Spec map[string]interface{}

func init() {
rand.Seed(time.Now().UTC().UnixNano())
}

type plugin struct {
ctx context.Context
vC *vCenter
vCenterInternals *vcInternal
}

// NewVSphereInstancePlugin will take the cmdline/env configuration
func NewVSphereInstancePlugin(vc *vCenter) instance.Plugin {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Attempt to log in to VMware vCenter and return the internal variables required
internals, err := vCenterConnect(vc)
if err != nil {
fmt.Printf("%v", err)
}
return &plugin{
ctx: ctx,
vC: vc,
vCenterInternals: &internals,
}
}

// Info returns a vendor specific name and version
func (p *plugin) VendorInfo() *spi.VendorInfo {
return &spi.VendorInfo{
InterfaceSpec: spi.InterfaceSpec{
Name: "infrakit-instance-vSphere",
Version: "0.6.0",
},
URL: "https://github.com/docker/infrakit",
}
}

// ExampleProperties returns the properties / config of this plugin
func (p *plugin) ExampleProperties() *types.Any {
any, err := types.AnyValue(Spec{
"exampleString": "a_string",
"exampleBool": true,
"exampleInt": 1,
})
if err != nil {
return nil
}
return any
}

// Validate performs local validation on a provision request.
func (p *plugin) Validate(req *types.Any) error {
log.Debugln("validate", req.String())

spec := Spec{}
if err := req.Decode(&spec); err != nil {
return err
}

log.Debugln("Validated:", spec)
return nil
}

// Provision creates a new instance based on the spec.
func (p *plugin) 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)
}
}

newInstance, err := parseParameters(properties, p)
if err != nil {
log.Errorf("Error: \n%v", err)
return nil, err
}

err = setInternalStructures(p.vC, p.vCenterInternals)
if err != nil {
log.Errorf("Error: \n%v", err)
return nil, err
}

if *p.vC.networkName != "" {
findNetwork(p.vC, p.vCenterInternals)
}

// Use the VMware plugin data in order to provision a new VM server
vmName := instance.ID(fmt.Sprintf(newInstance.vmPrefix+"-%d", rand.Int63()))
if spec.Tags != nil {
log.Infof("Adding %s to Group %v", string(vmName), spec.Tags["infrakit.group"])
}

if err != nil {
return nil, err
}
newInstance.vmName = string(vmName)
err = createNewVMInstance(p, &newInstance, spec)
if err != nil {
return &vmName, err
}
return &vmName, nil
}

// Label labels the instance
func (p *plugin) Label(instance instance.ID, labels map[string]string) error {

// fp := filepath.Join(p.Dir, string(instance))
// buff, err := afero.ReadFile(p.fs, fp)
// if err != nil {
// return err
// }
// instanceData := fileInstance{}
// err = json.Unmarshal(buff, &instanceData)
// if err != nil {
// return err
// }

// if instanceData.Description.Tags == nil {
// instanceData.Description.Tags = map[string]string{}
// }
// for k, v := range labels {
// instanceData.Description.Tags[k] = v
// }

// buff, err = json.MarshalIndent(instanceData, "", "")
// log.Debugln("label:", instance, "data=", string(buff), "err=", err)
// if err != nil {
// return err
// }
return nil
}

// Destroy terminates an existing instance.
func (p *plugin) Destroy(instance instance.ID, context instance.Context) error {
log.Infof("Currently running %s on instance: %v", context, instance)
deleteVM(p, string(instance))
return nil
}

// DescribeInstances returns descriptions of all instances matching all of the provided tags.
// TODO - need to define the fitlering of tags => AND or OR of matches?
func (p *plugin) DescribeInstances(tags map[string]string, properties bool) ([]instance.Description, error) {

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

log.Debugln("describe-instances", tags)
results := []instance.Description{}

groupName := tags["infrakit.group"]
instances, err := findGroupInstances(p, groupName)
if err != nil {
log.Debugf("%v", err)
}
if len(instances) == 0 {
log.Warnln("No Instances found")
}

for _, vmInstance := range instances {
configSHA := returnDataFromAnnotation(ctx, vmInstance, "sha")
tags["infrakit.config_sha"] = configSHA

results = append(results, instance.Description{
ID: instance.ID(vmInstance.Name()),
LogicalID: nil,
Tags: tags,
})
}

return results, nil
}
Loading