vsphere: use vim25.Client directly to support token authentication

This refactor is in support of SAML token authentication: #63209
Avoid use of govmomi.Client as it only supports username+password authentication via SessionManager.Login().
Using vim25.Client directly will allow VCP to add other authentication methods,
such as SessionManager.LoginByToken().
This commit is contained in:
Doug MacEachern 2018-05-05 11:33:53 -07:00
parent f4b2452654
commit 64601373f1
10 changed files with 39 additions and 22 deletions

View File

@ -18,19 +18,19 @@ package vclib
import ( import (
"context" "context"
"fmt" "net"
neturl "net/url" neturl "net/url"
"sync" "sync"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/session" "github.com/vmware/govmomi/session"
"github.com/vmware/govmomi/vim25" "github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/soap"
) )
// VSphereConnection contains information for connecting to vCenter // VSphereConnection contains information for connecting to vCenter
type VSphereConnection struct { type VSphereConnection struct {
GoVmomiClient *govmomi.Client GoVmomiClient *vim25.Client
Username string Username string
Password string Password string
Hostname string Hostname string
@ -59,7 +59,7 @@ func (connection *VSphereConnection) Connect(ctx context.Context) error {
} }
return nil return nil
} }
m := session.NewManager(connection.GoVmomiClient.Client) m := session.NewManager(connection.GoVmomiClient)
userSession, err := m.UserSession(ctx) userSession, err := m.UserSession(ctx)
if err != nil { if err != nil {
glog.Errorf("Error while obtaining user session. err: %+v", err) glog.Errorf("Error while obtaining user session. err: %+v", err)
@ -69,7 +69,7 @@ func (connection *VSphereConnection) Connect(ctx context.Context) error {
return nil return nil
} }
glog.Warningf("Creating new client session since the existing session is not valid or not authenticated") glog.Warningf("Creating new client session since the existing session is not valid or not authenticated")
connection.GoVmomiClient.Logout(ctx)
connection.GoVmomiClient, err = connection.NewClient(ctx) connection.GoVmomiClient, err = connection.NewClient(ctx)
if err != nil { if err != nil {
glog.Errorf("Failed to create govmomi client. err: %+v", err) glog.Errorf("Failed to create govmomi client. err: %+v", err)
@ -78,19 +78,36 @@ func (connection *VSphereConnection) Connect(ctx context.Context) error {
return nil return nil
} }
// Logout calls SessionManager.Logout for the given connection.
func (connection *VSphereConnection) Logout(ctx context.Context) {
m := session.NewManager(connection.GoVmomiClient)
if err := m.Logout(ctx); err != nil {
glog.Errorf("Logout failed: %s", err)
}
}
// NewClient creates a new govmomi client for the VSphereConnection obj // NewClient creates a new govmomi client for the VSphereConnection obj
func (connection *VSphereConnection) NewClient(ctx context.Context) (*govmomi.Client, error) { func (connection *VSphereConnection) NewClient(ctx context.Context) (*vim25.Client, error) {
url, err := neturl.Parse(fmt.Sprintf("https://%s:%s/sdk", connection.Hostname, connection.Port)) url, err := soap.ParseURL(net.JoinHostPort(connection.Hostname, connection.Port))
if err != nil { if err != nil {
glog.Errorf("Failed to parse URL: %s. err: %+v", url, err) glog.Errorf("Failed to parse URL: %s. err: %+v", url, err)
return nil, err return nil, err
} }
url.User = neturl.UserPassword(connection.Username, connection.Password)
client, err := govmomi.NewClient(ctx, url, connection.Insecure) sc := soap.NewClient(url, connection.Insecure)
client, err := vim25.NewClient(ctx, sc)
if err != nil { if err != nil {
glog.Errorf("Failed to create new client. err: %+v", err) glog.Errorf("Failed to create new client. err: %+v", err)
return nil, err return nil, err
} }
m := session.NewManager(client)
err = m.Login(ctx, neturl.UserPassword(connection.Username, connection.Password))
if err != nil {
return nil, err
}
if connection.RoundTripperCount == 0 { if connection.RoundTripperCount == 0 {
connection.RoundTripperCount = RoundTripperDefaultCount connection.RoundTripperCount = RoundTripperDefaultCount
} }

View File

@ -39,7 +39,7 @@ type Datacenter struct {
// GetDatacenter returns the DataCenter Object for the given datacenterPath // GetDatacenter returns the DataCenter Object for the given datacenterPath
// If datacenter is located in a folder, include full path to datacenter else just provide the datacenter name // If datacenter is located in a folder, include full path to datacenter else just provide the datacenter name
func GetDatacenter(ctx context.Context, connection *VSphereConnection, datacenterPath string) (*Datacenter, error) { func GetDatacenter(ctx context.Context, connection *VSphereConnection, datacenterPath string) (*Datacenter, error) {
finder := find.NewFinder(connection.GoVmomiClient.Client, false) finder := find.NewFinder(connection.GoVmomiClient, false)
datacenter, err := finder.Datacenter(ctx, datacenterPath) datacenter, err := finder.Datacenter(ctx, datacenterPath)
if err != nil { if err != nil {
glog.Errorf("Failed to find the datacenter: %s. err: %+v", datacenterPath, err) glog.Errorf("Failed to find the datacenter: %s. err: %+v", datacenterPath, err)
@ -52,7 +52,7 @@ func GetDatacenter(ctx context.Context, connection *VSphereConnection, datacente
// GetAllDatacenter returns all the DataCenter Objects // GetAllDatacenter returns all the DataCenter Objects
func GetAllDatacenter(ctx context.Context, connection *VSphereConnection) ([]*Datacenter, error) { func GetAllDatacenter(ctx context.Context, connection *VSphereConnection) ([]*Datacenter, error) {
var dc []*Datacenter var dc []*Datacenter
finder := find.NewFinder(connection.GoVmomiClient.Client, false) finder := find.NewFinder(connection.GoVmomiClient, false)
datacenters, err := finder.DatacenterList(ctx, "*") datacenters, err := finder.DatacenterList(ctx, "*")
if err != nil { if err != nil {
glog.Errorf("Failed to find the datacenter. err: %+v", err) glog.Errorf("Failed to find the datacenter. err: %+v", err)

View File

@ -47,7 +47,7 @@ func TestDatacenter(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
vc := &VSphereConnection{GoVmomiClient: c} vc := &VSphereConnection{GoVmomiClient: c.Client}
_, err = GetDatacenter(ctx, vc, testNameNotFound) _, err = GetDatacenter(ctx, vc, testNameNotFound)
if err == nil { if err == nil {

View File

@ -45,7 +45,7 @@ func TestDatastore(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
vc := &VSphereConnection{GoVmomiClient: c} vc := &VSphereConnection{GoVmomiClient: c.Client}
dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter) dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter)
if err != nil { if err != nil {

View File

@ -47,7 +47,7 @@ func TestFolder(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
vc := &VSphereConnection{GoVmomiClient: c} vc := &VSphereConnection{GoVmomiClient: c.Client}
dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter) dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter)
if err != nil { if err != nil {

View File

@ -46,7 +46,7 @@ func TestUtils(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
vc := &VSphereConnection{GoVmomiClient: c} vc := &VSphereConnection{GoVmomiClient: c.Client}
dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter) dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter)
if err != nil { if err != nil {

View File

@ -23,9 +23,9 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/vmware/govmomi"
"github.com/vmware/govmomi/object" "github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property" "github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo" "github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types" "github.com/vmware/govmomi/vim25/types"
) )
@ -403,8 +403,8 @@ func (vm *VirtualMachine) deleteController(ctx context.Context, controllerDevice
} }
// RenewVM renews this virtual machine with new client connection. // RenewVM renews this virtual machine with new client connection.
func (vm *VirtualMachine) RenewVM(client *govmomi.Client) VirtualMachine { func (vm *VirtualMachine) RenewVM(client *vim25.Client) VirtualMachine {
dc := Datacenter{Datacenter: object.NewDatacenter(client.Client, vm.Datacenter.Reference())} dc := Datacenter{Datacenter: object.NewDatacenter(client, vm.Datacenter.Reference())}
newVM := object.NewVirtualMachine(client.Client, vm.VirtualMachine.Reference()) newVM := object.NewVirtualMachine(client, vm.VirtualMachine.Reference())
return VirtualMachine{VirtualMachine: newVM, Datacenter: &dc} return VirtualMachine{VirtualMachine: newVM, Datacenter: &dc}
} }

View File

@ -43,7 +43,7 @@ func TestVirtualMachine(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
vc := &VSphereConnection{GoVmomiClient: c} vc := &VSphereConnection{GoVmomiClient: c.Client}
dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter) dc, err := GetDatacenter(ctx, vc, testDefaultDatacenter)
if err != nil { if err != nil {

View File

@ -411,7 +411,7 @@ func newControllerNode(cfg VSphereConfig) (*VSphere, error) {
func logout(vs *VSphere) { func logout(vs *VSphere) {
for _, vsphereIns := range vs.vsphereInstanceMap { for _, vsphereIns := range vs.vsphereInstanceMap {
if vsphereIns.conn.GoVmomiClient != nil { if vsphereIns.conn.GoVmomiClient != nil {
vsphereIns.conn.GoVmomiClient.Logout(context.TODO()) vsphereIns.conn.Logout(context.TODO())
} }
} }

View File

@ -135,7 +135,7 @@ func TestVSphereLogin(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("Failed to connect to vSphere: %s", err) t.Errorf("Failed to connect to vSphere: %s", err)
} }
defer vcInstance.conn.GoVmomiClient.Logout(ctx) defer vcInstance.conn.Logout(ctx)
} }
func TestZones(t *testing.T) { func TestZones(t *testing.T) {