From 0d7d7fba607b2b6fa4e408ca74c77fbfad0f1e7d Mon Sep 17 00:00:00 2001 From: Abitha Palaniappan Date: Fri, 8 Apr 2016 17:38:26 -0700 Subject: [PATCH] Adding vSphere cloud provider support for Instance List --- .../providers/vsphere/vsphere.go | 84 ++++++++++++++++--- .../providers/vsphere/vsphere_test.go | 36 ++++++-- 2 files changed, 102 insertions(+), 18 deletions(-) diff --git a/pkg/cloudprovider/providers/vsphere/vsphere.go b/pkg/cloudprovider/providers/vsphere/vsphere.go index 43c10c09689..298f6ff3c68 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere.go @@ -23,29 +23,33 @@ import ( "net/url" "github.com/vmware/govmomi" + "github.com/vmware/govmomi/find" + "github.com/vmware/govmomi/property" + "github.com/vmware/govmomi/vim25/mo" + "github.com/vmware/govmomi/vim25/types" "golang.org/x/net/context" "gopkg.in/gcfg.v1" "github.com/golang/glog" - "k8s.io/kubernetes/pkg/cloudprovider" "k8s.io/kubernetes/pkg/api" + "k8s.io/kubernetes/pkg/cloudprovider" ) const ProviderName = "vsphere" // VSphere is an implementation of Interface, LoadBalancer and Instances for vSphere. type VSphere struct { - cfg *VSphereConfig + cfg *VSphereConfig } type VSphereConfig struct { Global struct { - User string `gcfg:"user"` - Password string `gcfg:"password"` - VCenterIp string `gcfg:"server"` - VCenterPort string `gcfg:"port"` - InsecureFlag bool `gcfg:"insecure-flag"` - Datacenter string `gcfg:"datacenter"` + User string `gcfg:"user"` + Password string `gcfg:"password"` + VCenterIp string `gcfg:"server"` + VCenterPort string `gcfg:"port"` + InsecureFlag bool `gcfg:"insecure-flag"` + Datacenter string `gcfg:"datacenter"` } } @@ -72,12 +76,12 @@ func init() { func newVSphere(cfg VSphereConfig) (*VSphere, error) { vs := VSphere{ - cfg: &cfg, + cfg: &cfg, } return &vs, nil } -func vsphereLogin(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, error) { +func vsphereLogin(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, error) { // Parse URL from string u, err := url.Parse(fmt.Sprintf("https://%s:%s/sdk", cfg.Global.VCenterIp, cfg.Global.VCenterPort)) @@ -97,16 +101,72 @@ func vsphereLogin(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, err } type Instances struct { - cfg *VSphereConfig + cfg *VSphereConfig } // Instances returns an implementation of Instances for vSphere. func (vs *VSphere) Instances() (cloudprovider.Instances, bool) { + return &Instances{vs.cfg}, true } +func getInstances(c *govmomi.Client, finder *find.Finder, ctx context.Context, nameFilter string) ([]string, error) { + //TODO: get all vms inside subfolders + vms, err := finder.VirtualMachineList(ctx, nameFilter) + if err != nil { + return nil, err + } + + var vmRef []types.ManagedObjectReference + for _, vm := range vms { + vmRef = append(vmRef, vm.Reference()) + } + + pc := property.DefaultCollector(c.Client) + + var vmt []mo.VirtualMachine + err = pc.Retrieve(ctx, vmRef, []string{"name", "summary"}, &vmt) + if err != nil { + return nil, err + } + + var vmList []string + for _, vm := range vmt { + vmPowerstate := vm.Summary.Runtime.PowerState + if vmPowerstate == "poweredOn" { + vmList = append(vmList, vm.Name) + } + } + return vmList, nil +} + func (i *Instances) List(nameFilter string) ([]string, error) { - return nil, nil + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + c, err := vsphereLogin(i.cfg, ctx) + if err != nil { + fmt.Errorf("Failed to create vSpere client: %s", err) + } + defer c.Logout(ctx) + + fo := find.NewFinder(c.Client, true) + dc, err := fo.Datacenter(ctx, i.cfg.Global.Datacenter) + if err != nil { + glog.Warningf("Failed to find %v", err) + return nil, err + } + + finderObj := fo.SetDatacenter(dc) + vmList, err := getInstances(c, finderObj, ctx, nameFilter) + if err != nil { + return nil, err + } + + glog.V(3).Infof("Found %v instances matching %v: %v", + len(vmList), nameFilter, vmList) + + return vmList, nil } func (i *Instances) NodeAddresses(name string) ([]api.NodeAddress, error) { diff --git a/pkg/cloudprovider/providers/vsphere/vsphere_test.go b/pkg/cloudprovider/providers/vsphere/vsphere_test.go index edd1addc4b9..7f062ac0d29 100644 --- a/pkg/cloudprovider/providers/vsphere/vsphere_test.go +++ b/pkg/cloudprovider/providers/vsphere/vsphere_test.go @@ -17,7 +17,6 @@ limitations under the License. package vsphere import ( - "fmt" "log" "os" "strconv" @@ -28,7 +27,6 @@ import ( ) func configFromEnv() (cfg VSphereConfig, ok bool) { - fmt.Print("inside test") cfg.Global.VCenterIp = os.Getenv("VSPHERE_VCENTER") cfg.Global.VCenterPort = os.Getenv("VSPHERE_VCENTER_PORT") cfg.Global.User = os.Getenv("VSPHERE_USER") @@ -42,8 +40,6 @@ func configFromEnv() (cfg VSphereConfig, ok bool) { cfg.Global.InsecureFlag = InsecureFlag - - ok = (cfg.Global.VCenterIp != "" && cfg.Global.User != "") @@ -59,7 +55,7 @@ func TestReadConfig(t *testing.T) { cfg, err := readConfig(strings.NewReader(` [Global] server = 0.0.0.0 -port = 80 +port = 443 user = user password = password insecure-flag = true @@ -73,7 +69,7 @@ datacenter = us-west t.Errorf("incorrect vcenter ip: %s", cfg.Global.VCenterIp) } - if cfg.Global.VCenterPort != "80" { + if cfg.Global.VCenterPort != "443" { t.Errorf("incorrect vcenter port: %s", cfg.Global.VCenterPort) } @@ -142,3 +138,31 @@ func TestZones(t *testing.T) { t.Fatalf("GetZone() returned wrong region (%s)", zone.Region) } } + +func TestInstances(t *testing.T) { + cfg, ok := configFromEnv() + if !ok { + t.Skipf("No config found in environment") + } + + vs, err := newVSphere(cfg) + if err != nil { + t.Fatalf("Failed to construct/authenticate vSphere: %s", err) + } + + i, ok := vs.Instances() + if !ok { + t.Fatalf("Instances() returned false") + } + + srvs, err := i.List("*") + if err != nil { + t.Fatalf("Instances.List() failed: %s", err) + } + + if len(srvs) == 0 { + t.Fatalf("Instances.List() returned zero servers") + } + t.Logf("Found servers (%d): %s\n", len(srvs), srvs) + +}