github.com/emc-advanced-dev/unik@v0.0.0-20190717152701-a58d3e8e33b7/pkg/providers/vsphere/vsphereclient/client.go (about)

     1  package vsphereclient
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/url"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	"github.com/sirupsen/logrus"
    11  	"github.com/emc-advanced-dev/pkg/errors"
    12  	"github.com/solo-io/unik/pkg/types"
    13  	unikutil "github.com/solo-io/unik/pkg/util"
    14  	"github.com/vmware/govmomi"
    15  	"github.com/vmware/govmomi/find"
    16  	"golang.org/x/net/context"
    17  )
    18  
    19  type VsphereClient struct {
    20  	u  *url.URL
    21  	ds string
    22  	dc string
    23  }
    24  
    25  func NewVsphereClient(u *url.URL, datastore, datacenter string) *VsphereClient {
    26  	return &VsphereClient{
    27  		u:  u,
    28  		ds: datastore,
    29  		dc: datacenter,
    30  	}
    31  }
    32  
    33  func (vc *VsphereClient) newGovmomiClient() (*govmomi.Client, error) {
    34  	c, err := govmomi.NewClient(context.TODO(), vc.u, true)
    35  	if err != nil {
    36  		return nil, errors.New("creating new govmovi client", err)
    37  	}
    38  	return c, nil
    39  }
    40  
    41  func (vc *VsphereClient) newGovmomiFinder() (*find.Finder, error) {
    42  	c, err := vc.newGovmomiClient()
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	f := find.NewFinder(c.Client, true)
    47  
    48  	// Find one and only datacenter
    49  	dc, err := f.DefaultDatacenter(context.TODO())
    50  	if err != nil {
    51  		return nil, errors.New("finding default datacenter", err)
    52  	}
    53  
    54  	// Make future calls local to this datacenter
    55  	f.SetDatacenter(dc)
    56  	return f, nil
    57  }
    58  
    59  func (vc *VsphereClient) GetVmByUuid(uuid string) (*VirtualMachine, error) {
    60  
    61  	container := unikutil.NewContainer("vsphere-client")
    62  	args := []string{
    63  		"govc",
    64  		"vm.info",
    65  		"-k",
    66  		"-u", formatUrl(vc.u),
    67  		"--json",
    68  		"--vm.uuid=" + uuid,
    69  	}
    70  	logrus.WithField("command", args).Debugf("running command")
    71  	out, err := container.CombinedOutput(args...)
    72  	if err != nil {
    73  		return nil, errors.New("failed running govc vm.info "+uuid, err)
    74  	}
    75  	var vm VmInfo
    76  	if err := json.Unmarshal(out, &vm); err != nil {
    77  		return nil, errors.New("unmarshalling json: "+string(out), err)
    78  	}
    79  	if len(vm.VirtualMachines) < 1 {
    80  		return nil, errors.New("returned virtualmachines had len 0; does vm exist? "+string(out), nil)
    81  	}
    82  	return &vm.VirtualMachines[0], nil
    83  }
    84  
    85  func (vc *VsphereClient) GetVm(name string) (*VirtualMachine, error) {
    86  
    87  	container := unikutil.NewContainer("vsphere-client")
    88  	args := []string{
    89  		"govc",
    90  		"vm.info",
    91  		"-k",
    92  		"-u", formatUrl(vc.u),
    93  		"--json",
    94  		name,
    95  	}
    96  	logrus.WithField("command", args).Debugf("running command")
    97  	out, err := container.CombinedOutput(args...)
    98  	if err != nil {
    99  		return nil, errors.New("failed running govc vm.info "+name, err)
   100  	}
   101  	var vm VmInfo
   102  	if err := json.Unmarshal(out, &vm); err != nil {
   103  		return nil, errors.New("unmarshalling json: "+string(out), err)
   104  	}
   105  	if len(vm.VirtualMachines) < 1 {
   106  		return nil, errors.New("returned virtualmachines had len 0; does vm exist? "+string(out), nil)
   107  	}
   108  	return &vm.VirtualMachines[0], nil
   109  }
   110  
   111  func (vc *VsphereClient) GetVmIp(vmName string) (string, error) {
   112  	vm, err := vc.GetVm(vmName)
   113  	if err != nil {
   114  		return "", errors.New("getting vsphere vm", err)
   115  	}
   116  	return vm.Guest.IPAddress, nil
   117  }
   118  
   119  func (vc *VsphereClient) CreateVm(vmName string, memoryMb int, networkType types.VsphereNetworkType, networkLabel string) error {
   120  
   121  	container := unikutil.NewContainer("vsphere-client")
   122  	args := []string{
   123  		"govc",
   124  		"vm.create",
   125  		"-k",
   126  		"-u", formatUrl(vc.u),
   127  		"--force=true",
   128  		fmt.Sprintf("--m=%v", memoryMb),
   129  		"--on=false",
   130  		"-ds", vc.ds,
   131  		fmt.Sprintf("-net.adapter=%s", networkType),
   132  	}
   133  	if networkLabel != "" {
   134  		args = append(args, fmt.Sprintf("-net=%s", networkLabel))
   135  	}
   136  	args = append(args, vmName)
   137  
   138  	if err := container.Run(args...); err != nil {
   139  		return errors.New("failed running govc vm.create "+vmName, err)
   140  	}
   141  	return nil
   142  }
   143  
   144  func (vc *VsphereClient) DestroyVm(vmName string) error {
   145  
   146  	container := unikutil.NewContainer("vsphere-client")
   147  	args := []string{
   148  		"govc",
   149  		"vm.destroy",
   150  		"-k",
   151  		"-u", formatUrl(vc.u),
   152  		vmName,
   153  	}
   154  	if err := container.Run(args...); err != nil {
   155  		return errors.New("failed running govc vm.destroy "+vmName, err)
   156  	}
   157  	return nil
   158  }
   159  
   160  func (vc *VsphereClient) Mkdir(folder string) error {
   161  
   162  	container := unikutil.NewContainer("vsphere-client")
   163  	args := []string{
   164  		"govc",
   165  		"datastore.mkdir",
   166  		"-ds", vc.ds,
   167  		"-k",
   168  		"-u", formatUrl(vc.u),
   169  		folder,
   170  	}
   171  	if err := container.Run(args...); err != nil {
   172  		logrus.WithError(err).Warnf("failed running govc datastore.mkdir " + folder)
   173  	}
   174  	return nil
   175  }
   176  
   177  func (vc *VsphereClient) Rmdir(folder string) error {
   178  
   179  	container := unikutil.NewContainer("vsphere-client")
   180  	args := []string{
   181  		"govc",
   182  		"datastore.rm",
   183  		"-ds", vc.ds,
   184  		"-k",
   185  		"-u", formatUrl(vc.u),
   186  		folder,
   187  	}
   188  	if err := container.Run(args...); err != nil {
   189  		return errors.New("failed running govc datastore.rm "+folder, err)
   190  	}
   191  	return nil
   192  }
   193  
   194  func (vc *VsphereClient) ImportVmdk(vmdkPath, remoteFolder string) error {
   195  	vmdkFolder, err := filepath.Abs(filepath.Dir(vmdkPath))
   196  	if err != nil {
   197  		return errors.New("getting aboslute path for "+vmdkFolder, err)
   198  	}
   199  
   200  	container := unikutil.NewContainer("vsphere-client").WithVolume(vmdkFolder, vmdkFolder)
   201  	args := []string{
   202  		"govc",
   203  		"import.vmdk",
   204  		"-ds", vc.ds,
   205  		"-k",
   206  		"-u", formatUrl(vc.u),
   207  		vmdkPath,
   208  		remoteFolder,
   209  	}
   210  	if err := container.Run(args...); err != nil {
   211  		return errors.New("failed running govc import.vmdk "+remoteFolder, err)
   212  	}
   213  	return nil
   214  }
   215  
   216  func (vc *VsphereClient) UploadFile(srcFile, dest string) error {
   217  	srcDir := filepath.Dir(srcFile)
   218  
   219  	container := unikutil.NewContainer("vsphere-client").WithVolume(srcDir, srcDir)
   220  	args := []string{
   221  		"govc",
   222  		"datastore.upload",
   223  		"-ds", vc.ds,
   224  		"-k",
   225  		"-u", formatUrl(vc.u),
   226  		srcFile,
   227  		dest,
   228  	}
   229  	if err := container.Run(args...); err != nil {
   230  		return errors.New("failed running govc datastore.upload", err)
   231  	}
   232  	return nil
   233  }
   234  
   235  func (vc *VsphereClient) DownloadFile(remoteFile, localFile string) error {
   236  	localDir := filepath.Dir(localFile)
   237  
   238  	container := unikutil.NewContainer("vsphere-client").WithVolume(localDir, localDir)
   239  	args := []string{
   240  		"govc",
   241  		"datastore.download",
   242  		"-ds", vc.ds,
   243  		"-k",
   244  		"-u", formatUrl(vc.u),
   245  		remoteFile,
   246  		localFile,
   247  	}
   248  	if err := container.Run(args...); err != nil {
   249  		return errors.New("failed running govc datastore.upload", err)
   250  	}
   251  	return nil
   252  }
   253  
   254  func (vc *VsphereClient) CopyVmdk(src, dest string) error {
   255  	password, _ := vc.u.User.Password()
   256  
   257  	container := unikutil.NewContainer("vsphere-client")
   258  	args := []string{
   259  		"java",
   260  		"-jar",
   261  		"/vsphere-client.jar",
   262  		"CopyVirtualDisk",
   263  		vc.u.String(),
   264  		vc.u.User.Username(),
   265  		password,
   266  		vc.dc,
   267  		"[" + vc.ds + "] " + src,
   268  		"[" + vc.ds + "] " + dest,
   269  	}
   270  	if err := container.Run(args...); err != nil {
   271  		return errors.New("failed running vsphere-client.jar CopyVirtualDisk "+src+" "+dest, err)
   272  	}
   273  	return nil
   274  }
   275  
   276  func (vc *VsphereClient) CopyFile(src, dest string) error {
   277  	password, _ := vc.u.User.Password()
   278  	container := unikutil.NewContainer("vsphere-client")
   279  	args := []string{
   280  		"java",
   281  		"-jar",
   282  		"/vsphere-client.jar",
   283  		"CopyFile",
   284  		vc.u.String(),
   285  		vc.u.User.Username(),
   286  		password,
   287  		vc.dc,
   288  		"[" + vc.ds + "] " + src,
   289  		"[" + vc.ds + "] " + dest,
   290  	}
   291  	if err := container.Run(args...); err != nil {
   292  		lastSlash := strings.LastIndex(dest, "/")
   293  		directory := "/"
   294  		file := dest[lastSlash+1:]
   295  		if lastSlash != -1 {
   296  			directory += dest[0:lastSlash]
   297  			file = dest[lastSlash+1:]
   298  		}
   299  		files, err := vc.Ls(directory)
   300  		if err != nil {
   301  			return errors.New("failed running vsphere-client.jar CopyFile "+src+" "+dest, err)
   302  		}
   303  		if !unikutil.StringInSlice(file, files) {
   304  			return errors.New("failed running vsphere-client.jar CopyFile "+src+" "+dest, err)
   305  		}
   306  	}
   307  	return nil
   308  }
   309  
   310  func (vc *VsphereClient) Ls(dir string) ([]string, error) {
   311  
   312  	container := unikutil.NewContainer("vsphere-client")
   313  	args := []string{
   314  		"govc",
   315  		"datastore.ls",
   316  		"-ds", vc.ds,
   317  		"-k",
   318  		"-u", formatUrl(vc.u),
   319  		dir,
   320  	}
   321  	out, err := container.Output(args...)
   322  	if err != nil {
   323  		return nil, errors.New("failed running govc datastore.ls "+dir, err)
   324  	}
   325  	split := strings.Split(string(out), "\n")
   326  	contents := []string{}
   327  	for _, content := range split {
   328  		if content != "" {
   329  			contents = append(contents, content)
   330  		}
   331  	}
   332  	return contents, nil
   333  }
   334  
   335  func (vc *VsphereClient) PowerOnVm(vmName string) error {
   336  
   337  	container := unikutil.NewContainer("vsphere-client")
   338  	args := []string{
   339  		"govc",
   340  		"vm.power",
   341  		"--on=true",
   342  		"-k",
   343  		"-u", formatUrl(vc.u),
   344  		vmName,
   345  	}
   346  	if err := container.Run(args...); err != nil {
   347  		return errors.New("failed running govc vm.power (on)", err)
   348  	}
   349  	return nil
   350  }
   351  
   352  func (vc *VsphereClient) PowerOffVm(vmName string) error {
   353  
   354  	container := unikutil.NewContainer("vsphere-client")
   355  	args := []string{
   356  		"govc",
   357  		"vm.power",
   358  		"--off=true",
   359  		"-k",
   360  		"-u", formatUrl(vc.u),
   361  		vmName,
   362  	}
   363  	if err := container.Run(args...); err != nil {
   364  		return errors.New("failed running govc vm.power (off)", err)
   365  	}
   366  	return nil
   367  }
   368  
   369  func (vc *VsphereClient) AttachDisk(vmName, vmdkPath string, controllerKey int, deviceType types.StorageDriver) error {
   370  	password, _ := vc.u.User.Password()
   371  
   372  	container := unikutil.NewContainer("vsphere-client")
   373  	args := []string{
   374  		"java",
   375  		"-jar",
   376  		"/vsphere-client.jar",
   377  		"VmAttachDisk",
   378  		vc.u.String(),
   379  		vc.u.User.Username(),
   380  		password,
   381  		vmName,
   382  		"[" + vc.ds + "] " + vmdkPath,
   383  		string(deviceType),
   384  		fmt.Sprintf("%v", controllerKey),
   385  	}
   386  	if err := container.Run(args...); err != nil {
   387  		return errors.New("failed running vsphere-client.jar AttachVmdk", err)
   388  	}
   389  	return nil
   390  }
   391  
   392  func (vc *VsphereClient) DetachDisk(vmName string, controllerKey int, deviceType types.StorageDriver) error {
   393  	password, _ := vc.u.User.Password()
   394  
   395  	container := unikutil.NewContainer("vsphere-client")
   396  	args := []string{
   397  		"java",
   398  		"-jar",
   399  		"/vsphere-client.jar",
   400  		"VmDetachDisk",
   401  		vc.u.String(),
   402  		vc.u.User.Username(),
   403  		password,
   404  		vmName,
   405  		string(deviceType),
   406  		fmt.Sprintf("%v", controllerKey),
   407  	}
   408  	if err := container.Run(args...); err != nil {
   409  		return errors.New("failed running vsphere-client.jar DetachVmdk", err)
   410  	}
   411  	return nil
   412  }
   413  
   414  func formatUrl(u *url.URL) string {
   415  	return "https://" + strings.TrimPrefix(strings.TrimPrefix(u.String(), "http://"), "https://")
   416  }