PageRenderTime 123ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/k8s.io/kubernetes/pkg/cloudprovider/providers/vsphere/vsphere.go

https://gitlab.com/github-cloud-corporation/bootkube
Go | 802 lines | 578 code | 130 blank | 94 comment | 176 complexity | cf9f4aa2dec1384fe896ff777a83fc4e MD5 | raw file
  1. /*
  2. Copyright 2016 The Kubernetes Authors All rights reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package vsphere
  14. import (
  15. "bytes"
  16. "errors"
  17. "fmt"
  18. "io"
  19. "net/url"
  20. "os/exec"
  21. "path"
  22. "strings"
  23. "github.com/vmware/govmomi"
  24. "github.com/vmware/govmomi/find"
  25. "github.com/vmware/govmomi/object"
  26. "github.com/vmware/govmomi/property"
  27. "github.com/vmware/govmomi/vim25/mo"
  28. "github.com/vmware/govmomi/vim25/types"
  29. "golang.org/x/net/context"
  30. "gopkg.in/gcfg.v1"
  31. "github.com/golang/glog"
  32. "k8s.io/kubernetes/pkg/api"
  33. "k8s.io/kubernetes/pkg/cloudprovider"
  34. "k8s.io/kubernetes/pkg/util/runtime"
  35. )
  36. const ProviderName = "vsphere"
  37. const ActivePowerState = "poweredOn"
  38. const DefaultDiskController = "scsi"
  39. const DefaultSCSIControllerType = "lsilogic-sas"
  40. // Controller types that are currently supported for hot attach of disks
  41. // lsilogic driver type is currently not supported because,when a device gets detached
  42. // it fails to remove the device from the /dev path (which should be manually done)
  43. // making the subsequent attaches to the node to fail.
  44. // TODO: Add support for lsilogic driver type
  45. var supportedSCSIControllerType = []string{"lsilogic-sas", "pvscsi"}
  46. var ErrNoDiskUUIDFound = errors.New("No disk UUID found")
  47. var ErrNoDiskIDFound = errors.New("No vSphere disk ID found")
  48. var ErrNoDevicesFound = errors.New("No devices found")
  49. // VSphere is an implementation of cloud provider Interface for VSphere.
  50. type VSphere struct {
  51. cfg *VSphereConfig
  52. // InstanceID of the server where this VSphere object is instantiated.
  53. localInstanceID string
  54. }
  55. type VSphereConfig struct {
  56. Global struct {
  57. User string `gcfg:"user"`
  58. Password string `gcfg:"password"`
  59. VCenterIP string `gcfg:"server"`
  60. VCenterPort string `gcfg:"port"`
  61. InsecureFlag bool `gcfg:"insecure-flag"`
  62. Datacenter string `gcfg:"datacenter"`
  63. Datastore string `gcfg:"datastore"`
  64. WorkingDir string `gcfg:"working-dir"`
  65. }
  66. Network struct {
  67. PublicNetwork string `gcfg:"public-network"`
  68. }
  69. Disk struct {
  70. SCSIControllerType string `dcfg:"scsicontrollertype"`
  71. }
  72. }
  73. func readConfig(config io.Reader) (VSphereConfig, error) {
  74. if config == nil {
  75. err := fmt.Errorf("no vSphere cloud provider config file given")
  76. return VSphereConfig{}, err
  77. }
  78. var cfg VSphereConfig
  79. err := gcfg.ReadInto(&cfg, config)
  80. return cfg, err
  81. }
  82. func init() {
  83. cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) {
  84. cfg, err := readConfig(config)
  85. if err != nil {
  86. return nil, err
  87. }
  88. return newVSphere(cfg)
  89. })
  90. }
  91. func readInstanceID(cfg *VSphereConfig) (string, error) {
  92. cmd := exec.Command("bash", "-c", `dmidecode -t 1 | grep UUID | tr -d ' ' | cut -f 2 -d ':'`)
  93. var out bytes.Buffer
  94. cmd.Stdout = &out
  95. err := cmd.Run()
  96. if err != nil {
  97. return "", err
  98. }
  99. if out.Len() == 0 {
  100. return "", fmt.Errorf("unable to retrieve Instance ID")
  101. }
  102. // Create context
  103. ctx, cancel := context.WithCancel(context.Background())
  104. defer cancel()
  105. // Create vSphere client
  106. c, err := vsphereLogin(cfg, ctx)
  107. if err != nil {
  108. return "", err
  109. }
  110. defer c.Logout(ctx)
  111. // Create a new finder
  112. f := find.NewFinder(c.Client, true)
  113. // Fetch and set data center
  114. dc, err := f.Datacenter(ctx, cfg.Global.Datacenter)
  115. if err != nil {
  116. return "", err
  117. }
  118. f.SetDatacenter(dc)
  119. s := object.NewSearchIndex(c.Client)
  120. svm, err := s.FindByUuid(ctx, dc, strings.ToLower(strings.TrimSpace(out.String())), true, nil)
  121. var vm mo.VirtualMachine
  122. err = s.Properties(ctx, svm.Reference(), []string{"name"}, &vm)
  123. if err != nil {
  124. return "", err
  125. }
  126. return vm.Name, nil
  127. }
  128. func newVSphere(cfg VSphereConfig) (*VSphere, error) {
  129. id, err := readInstanceID(&cfg)
  130. if err != nil {
  131. return nil, err
  132. }
  133. if cfg.Disk.SCSIControllerType == "" {
  134. cfg.Disk.SCSIControllerType = DefaultSCSIControllerType
  135. } else if !checkControllerSupported(cfg.Disk.SCSIControllerType) {
  136. glog.Errorf("%v is not a supported SCSI Controller type. Please configure 'lsilogic-sas' OR 'pvscsi'", cfg.Disk.SCSIControllerType)
  137. return nil, errors.New("Controller type not supported. Please configure 'lsilogic-sas' OR 'pvscsi'")
  138. }
  139. if cfg.Global.WorkingDir != "" {
  140. cfg.Global.WorkingDir = path.Clean(cfg.Global.WorkingDir) + "/"
  141. }
  142. vs := VSphere{
  143. cfg: &cfg,
  144. localInstanceID: id,
  145. }
  146. return &vs, nil
  147. }
  148. func checkControllerSupported(ctrlType string) bool {
  149. for _, c := range supportedSCSIControllerType {
  150. if ctrlType == c {
  151. return true
  152. }
  153. }
  154. return false
  155. }
  156. func vsphereLogin(cfg *VSphereConfig, ctx context.Context) (*govmomi.Client, error) {
  157. // Parse URL from string
  158. u, err := url.Parse(fmt.Sprintf("https://%s:%s/sdk", cfg.Global.VCenterIP, cfg.Global.VCenterPort))
  159. if err != nil {
  160. return nil, err
  161. }
  162. // set username and password for the URL
  163. u.User = url.UserPassword(cfg.Global.User, cfg.Global.Password)
  164. // Connect and log in to ESX or vCenter
  165. c, err := govmomi.NewClient(ctx, u, cfg.Global.InsecureFlag)
  166. if err != nil {
  167. return nil, err
  168. }
  169. return c, nil
  170. }
  171. func getVirtualMachineByName(cfg *VSphereConfig, ctx context.Context, c *govmomi.Client, name string) (*object.VirtualMachine, error) {
  172. // Create a new finder
  173. f := find.NewFinder(c.Client, true)
  174. // Fetch and set data center
  175. dc, err := f.Datacenter(ctx, cfg.Global.Datacenter)
  176. if err != nil {
  177. return nil, err
  178. }
  179. f.SetDatacenter(dc)
  180. vmRegex := cfg.Global.WorkingDir + name
  181. // Retrieve vm by name
  182. //TODO: also look for vm inside subfolders
  183. vm, err := f.VirtualMachine(ctx, vmRegex)
  184. if err != nil {
  185. return nil, err
  186. }
  187. return vm, nil
  188. }
  189. func getVirtualMachineManagedObjectReference(ctx context.Context, c *govmomi.Client, vm *object.VirtualMachine, field string, dst interface{}) error {
  190. collector := property.DefaultCollector(c.Client)
  191. // Retrieve required field from VM object
  192. err := collector.RetrieveOne(ctx, vm.Reference(), []string{field}, dst)
  193. if err != nil {
  194. return err
  195. }
  196. return nil
  197. }
  198. func getInstances(cfg *VSphereConfig, ctx context.Context, c *govmomi.Client, filter string) ([]string, error) {
  199. f := find.NewFinder(c.Client, true)
  200. dc, err := f.Datacenter(ctx, cfg.Global.Datacenter)
  201. if err != nil {
  202. return nil, err
  203. }
  204. f.SetDatacenter(dc)
  205. vmRegex := cfg.Global.WorkingDir + filter
  206. //TODO: get all vms inside subfolders
  207. vms, err := f.VirtualMachineList(ctx, vmRegex)
  208. if err != nil {
  209. return nil, err
  210. }
  211. var vmRef []types.ManagedObjectReference
  212. for _, vm := range vms {
  213. vmRef = append(vmRef, vm.Reference())
  214. }
  215. pc := property.DefaultCollector(c.Client)
  216. var vmt []mo.VirtualMachine
  217. err = pc.Retrieve(ctx, vmRef, []string{"name", "summary"}, &vmt)
  218. if err != nil {
  219. return nil, err
  220. }
  221. var vmList []string
  222. for _, vm := range vmt {
  223. if vm.Summary.Runtime.PowerState == ActivePowerState {
  224. vmList = append(vmList, vm.Name)
  225. } else if vm.Summary.Config.Template == false {
  226. glog.Warningf("VM %s, is not in %s state", vm.Name, ActivePowerState)
  227. }
  228. }
  229. return vmList, nil
  230. }
  231. type Instances struct {
  232. cfg *VSphereConfig
  233. localInstanceID string
  234. }
  235. // Instances returns an implementation of Instances for vSphere.
  236. func (vs *VSphere) Instances() (cloudprovider.Instances, bool) {
  237. return &Instances{vs.cfg, vs.localInstanceID}, true
  238. }
  239. // List is an implementation of Instances.List.
  240. func (i *Instances) List(filter string) ([]string, error) {
  241. ctx, cancel := context.WithCancel(context.Background())
  242. defer cancel()
  243. c, err := vsphereLogin(i.cfg, ctx)
  244. if err != nil {
  245. return nil, err
  246. }
  247. defer c.Logout(ctx)
  248. vmList, err := getInstances(i.cfg, ctx, c, filter)
  249. if err != nil {
  250. return nil, err
  251. }
  252. glog.V(3).Infof("Found %s instances matching %s: %s",
  253. len(vmList), filter, vmList)
  254. return vmList, nil
  255. }
  256. // NodeAddresses is an implementation of Instances.NodeAddresses.
  257. func (i *Instances) NodeAddresses(name string) ([]api.NodeAddress, error) {
  258. addrs := []api.NodeAddress{}
  259. // Create context
  260. ctx, cancel := context.WithCancel(context.Background())
  261. defer cancel()
  262. // Create vSphere client
  263. c, err := vsphereLogin(i.cfg, ctx)
  264. if err != nil {
  265. return nil, err
  266. }
  267. defer c.Logout(ctx)
  268. vm, err := getVirtualMachineByName(i.cfg, ctx, c, name)
  269. if err != nil {
  270. return nil, err
  271. }
  272. var mvm mo.VirtualMachine
  273. err = getVirtualMachineManagedObjectReference(ctx, c, vm, "guest.net", &mvm)
  274. if err != nil {
  275. return nil, err
  276. }
  277. // retrieve VM's ip(s)
  278. for _, v := range mvm.Guest.Net {
  279. var addressType api.NodeAddressType
  280. if i.cfg.Network.PublicNetwork == v.Network {
  281. addressType = api.NodeExternalIP
  282. } else {
  283. addressType = api.NodeInternalIP
  284. }
  285. for _, ip := range v.IpAddress {
  286. api.AddToNodeAddresses(&addrs,
  287. api.NodeAddress{
  288. Type: addressType,
  289. Address: ip,
  290. },
  291. )
  292. }
  293. }
  294. return addrs, nil
  295. }
  296. func (i *Instances) AddSSHKeyToAllInstances(user string, keyData []byte) error {
  297. return errors.New("unimplemented")
  298. }
  299. func (i *Instances) CurrentNodeName(hostname string) (string, error) {
  300. return i.localInstanceID, nil
  301. }
  302. // ExternalID returns the cloud provider ID of the specified instance (deprecated).
  303. func (i *Instances) ExternalID(name string) (string, error) {
  304. // Create context
  305. ctx, cancel := context.WithCancel(context.Background())
  306. defer cancel()
  307. // Create vSphere client
  308. c, err := vsphereLogin(i.cfg, ctx)
  309. if err != nil {
  310. return "", err
  311. }
  312. defer c.Logout(ctx)
  313. vm, err := getVirtualMachineByName(i.cfg, ctx, c, name)
  314. if err != nil {
  315. return "", err
  316. }
  317. var mvm mo.VirtualMachine
  318. err = getVirtualMachineManagedObjectReference(ctx, c, vm, "summary", &mvm)
  319. if err != nil {
  320. return "", err
  321. }
  322. if mvm.Summary.Runtime.PowerState == ActivePowerState {
  323. return vm.InventoryPath, nil
  324. }
  325. if mvm.Summary.Config.Template == false {
  326. glog.Warningf("VM %s, is not in %s state", name, ActivePowerState)
  327. } else {
  328. glog.Warningf("VM %s, is a template", name)
  329. }
  330. return "", cloudprovider.InstanceNotFound
  331. }
  332. // InstanceID returns the cloud provider ID of the specified instance.
  333. func (i *Instances) InstanceID(name string) (string, error) {
  334. // Create context
  335. ctx, cancel := context.WithCancel(context.Background())
  336. defer cancel()
  337. // Create vSphere client
  338. c, err := vsphereLogin(i.cfg, ctx)
  339. if err != nil {
  340. return "", err
  341. }
  342. defer c.Logout(ctx)
  343. vm, err := getVirtualMachineByName(i.cfg, ctx, c, name)
  344. var mvm mo.VirtualMachine
  345. err = getVirtualMachineManagedObjectReference(ctx, c, vm, "summary", &mvm)
  346. if err != nil {
  347. return "", err
  348. }
  349. if mvm.Summary.Runtime.PowerState == ActivePowerState {
  350. return "/" + vm.InventoryPath, nil
  351. }
  352. if mvm.Summary.Config.Template == false {
  353. glog.Warning("VM %s, is not in %s state", name, ActivePowerState)
  354. } else {
  355. glog.Warning("VM %s, is a template", name)
  356. }
  357. return "", cloudprovider.InstanceNotFound
  358. }
  359. func (i *Instances) InstanceType(name string) (string, error) {
  360. return "", nil
  361. }
  362. func (vs *VSphere) Clusters() (cloudprovider.Clusters, bool) {
  363. return nil, true
  364. }
  365. // ProviderName returns the cloud provider ID.
  366. func (vs *VSphere) ProviderName() string {
  367. return ProviderName
  368. }
  369. // LoadBalancer returns an implementation of LoadBalancer for vSphere.
  370. func (vs *VSphere) LoadBalancer() (cloudprovider.LoadBalancer, bool) {
  371. return nil, false
  372. }
  373. // Zones returns an implementation of Zones for Google vSphere.
  374. func (vs *VSphere) Zones() (cloudprovider.Zones, bool) {
  375. glog.V(4).Info("Claiming to support Zones")
  376. return vs, true
  377. }
  378. func (vs *VSphere) GetZone() (cloudprovider.Zone, error) {
  379. glog.V(4).Infof("Current zone is %v", vs.cfg.Global.Datacenter)
  380. return cloudprovider.Zone{Region: vs.cfg.Global.Datacenter}, nil
  381. }
  382. // Routes returns a false since the interface is not supported for vSphere.
  383. func (vs *VSphere) Routes() (cloudprovider.Routes, bool) {
  384. return nil, false
  385. }
  386. // ScrubDNS filters DNS settings for pods.
  387. func (vs *VSphere) ScrubDNS(nameservers, searches []string) (nsOut, srchOut []string) {
  388. return nameservers, searches
  389. }
  390. func getVirtualMachineDevices(cfg *VSphereConfig, ctx context.Context, c *govmomi.Client, name string) (*object.VirtualMachine, object.VirtualDeviceList, *object.Datastore, error) {
  391. // Create a new finder
  392. f := find.NewFinder(c.Client, true)
  393. // Fetch and set data center
  394. dc, err := f.Datacenter(ctx, cfg.Global.Datacenter)
  395. if err != nil {
  396. return nil, nil, nil, err
  397. }
  398. f.SetDatacenter(dc)
  399. // Find datastores
  400. ds, err := f.Datastore(ctx, cfg.Global.Datastore)
  401. if err != nil {
  402. return nil, nil, nil, err
  403. }
  404. vmRegex := cfg.Global.WorkingDir + name
  405. vm, err := f.VirtualMachine(ctx, vmRegex)
  406. if err != nil {
  407. return nil, nil, nil, err
  408. }
  409. // Get devices from VM
  410. vmDevices, err := vm.Device(ctx)
  411. if err != nil {
  412. return nil, nil, nil, err
  413. }
  414. return vm, vmDevices, ds, nil
  415. }
  416. //cleaning up the controller
  417. func cleanUpController(newSCSIController types.BaseVirtualDevice, vmDevices object.VirtualDeviceList, vm *object.VirtualMachine, ctx context.Context) error {
  418. ctls := vmDevices.SelectByType(newSCSIController)
  419. if len(ctls) < 1 {
  420. return ErrNoDevicesFound
  421. }
  422. newScsi := ctls[len(ctls)-1]
  423. err := vm.RemoveDevice(ctx, true, newScsi)
  424. if err != nil {
  425. return err
  426. }
  427. return nil
  428. }
  429. // Attaches given virtual disk volume to the compute running kubelet.
  430. func (vs *VSphere) AttachDisk(vmDiskPath string, nodeName string) (diskID string, diskUUID string, err error) {
  431. // Create context
  432. ctx, cancel := context.WithCancel(context.Background())
  433. defer cancel()
  434. // Create vSphere client
  435. c, err := vsphereLogin(vs.cfg, ctx)
  436. if err != nil {
  437. return "", "", err
  438. }
  439. defer c.Logout(ctx)
  440. // Find virtual machine to attach disk to
  441. var vSphereInstance string
  442. if nodeName == "" {
  443. vSphereInstance = vs.localInstanceID
  444. } else {
  445. vSphereInstance = nodeName
  446. }
  447. // Get VM device list
  448. vm, vmDevices, ds, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
  449. if err != nil {
  450. return "", "", err
  451. }
  452. var diskControllerType = vs.cfg.Disk.SCSIControllerType
  453. // find SCSI controller of particular type from VM devices
  454. var diskController = getSCSIController(vmDevices, diskControllerType)
  455. var newSCSICreated = false
  456. var newSCSIController types.BaseVirtualDevice
  457. // creating a scsi controller as there is none found of controller type defined
  458. if diskController == nil {
  459. glog.V(4).Infof("Creating a SCSI controller of %v type", diskControllerType)
  460. newSCSIController, err := vmDevices.CreateSCSIController(diskControllerType)
  461. if err != nil {
  462. runtime.HandleError(fmt.Errorf("error creating new SCSI controller: %v", err))
  463. return "", "", err
  464. }
  465. configNewSCSIController := newSCSIController.(types.BaseVirtualSCSIController).GetVirtualSCSIController()
  466. hotAndRemove := true
  467. configNewSCSIController.HotAddRemove = &hotAndRemove
  468. configNewSCSIController.SharedBus = types.VirtualSCSISharing(types.VirtualSCSISharingNoSharing)
  469. // add the scsi controller to virtual machine
  470. err = vm.AddDevice(context.TODO(), newSCSIController)
  471. if err != nil {
  472. glog.V(3).Infof("cannot add SCSI controller to vm - %v", err)
  473. // attempt clean up of scsi controller
  474. if vmDevices, err := vm.Device(ctx); err == nil {
  475. cleanUpController(newSCSIController, vmDevices, vm, ctx)
  476. }
  477. return "", "", err
  478. }
  479. // verify scsi controller in virtual machine
  480. vmDevices, err = vm.Device(ctx)
  481. if err != nil {
  482. //cannot cleanup if there is no device list
  483. return "", "", err
  484. }
  485. diskController = getSCSIController(vmDevices, vs.cfg.Disk.SCSIControllerType)
  486. if diskController == nil {
  487. glog.Errorf("cannot find SCSI controller in VM - %v", err)
  488. // attempt clean up of scsi controller
  489. cleanUpController(newSCSIController, vmDevices, vm, ctx)
  490. return "", "", err
  491. }
  492. newSCSICreated = true
  493. }
  494. disk := vmDevices.CreateDisk(diskController, ds.Reference(), vmDiskPath)
  495. backing := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
  496. backing.DiskMode = string(types.VirtualDiskModeIndependent_persistent)
  497. // Attach disk to the VM
  498. err = vm.AddDevice(ctx, disk)
  499. if err != nil {
  500. glog.Errorf("cannot attach disk to the vm - %v", err)
  501. if newSCSICreated {
  502. cleanUpController(newSCSIController, vmDevices, vm, ctx)
  503. }
  504. return "", "", err
  505. }
  506. vmDevices, err = vm.Device(ctx)
  507. if err != nil {
  508. if newSCSICreated {
  509. cleanUpController(newSCSIController, vmDevices, vm, ctx)
  510. }
  511. return "", "", err
  512. }
  513. devices := vmDevices.SelectByType(disk)
  514. if len(devices) < 1 {
  515. if newSCSICreated {
  516. cleanUpController(newSCSIController, vmDevices, vm, ctx)
  517. }
  518. return "", "", ErrNoDevicesFound
  519. }
  520. // get new disk id
  521. newDevice := devices[len(devices)-1]
  522. deviceName := devices.Name(newDevice)
  523. // get device uuid
  524. diskUUID, err = getVirtualDiskUUID(newDevice)
  525. if err != nil {
  526. if newSCSICreated {
  527. cleanUpController(newSCSIController, vmDevices, vm, ctx)
  528. }
  529. vs.DetachDisk(deviceName, vSphereInstance)
  530. return "", "", err
  531. }
  532. return deviceName, diskUUID, nil
  533. }
  534. func getSCSIController(vmDevices object.VirtualDeviceList, scsiType string) *types.VirtualController {
  535. // get virtual scsi controller of passed argument type
  536. for _, device := range vmDevices {
  537. devType := vmDevices.Type(device)
  538. if devType == scsiType {
  539. if c, ok := device.(types.BaseVirtualController); ok {
  540. return c.GetVirtualController()
  541. }
  542. }
  543. }
  544. return nil
  545. }
  546. func getVirtualDiskUUID(newDevice types.BaseVirtualDevice) (string, error) {
  547. vd := newDevice.GetVirtualDevice()
  548. if b, ok := vd.Backing.(*types.VirtualDiskFlatVer2BackingInfo); ok {
  549. uuidWithNoHypens := strings.Replace(b.Uuid, "-", "", -1)
  550. return strings.ToLower(uuidWithNoHypens), nil
  551. }
  552. return "", ErrNoDiskUUIDFound
  553. }
  554. func getVirtualDiskID(volPath string, vmDevices object.VirtualDeviceList) (string, error) {
  555. // filter vm devices to retrieve disk ID for the given vmdk file
  556. for _, device := range vmDevices {
  557. if vmDevices.TypeName(device) == "VirtualDisk" {
  558. d := device.GetVirtualDevice()
  559. if b, ok := d.Backing.(types.BaseVirtualDeviceFileBackingInfo); ok {
  560. fileName := b.GetVirtualDeviceFileBackingInfo().FileName
  561. if fileName == volPath {
  562. return vmDevices.Name(device), nil
  563. }
  564. }
  565. }
  566. }
  567. return "", ErrNoDiskIDFound
  568. }
  569. // Detaches given virtual disk volume from the compute running kubelet.
  570. func (vs *VSphere) DetachDisk(volPath string, nodeName string) error {
  571. // Create context
  572. ctx, cancel := context.WithCancel(context.Background())
  573. defer cancel()
  574. // Create vSphere client
  575. c, err := vsphereLogin(vs.cfg, ctx)
  576. if err != nil {
  577. return err
  578. }
  579. defer c.Logout(ctx)
  580. // Find VM to detach disk from
  581. var vSphereInstance string
  582. if nodeName == "" {
  583. vSphereInstance = vs.localInstanceID
  584. } else {
  585. vSphereInstance = nodeName
  586. }
  587. vm, vmDevices, _, err := getVirtualMachineDevices(vs.cfg, ctx, c, vSphereInstance)
  588. if err != nil {
  589. return err
  590. }
  591. diskID, err := getVirtualDiskID(volPath, vmDevices)
  592. if err != nil {
  593. glog.Warningf("disk ID not found for %v ", volPath)
  594. return err
  595. }
  596. // Remove disk from VM
  597. device := vmDevices.Find(diskID)
  598. if device == nil {
  599. return fmt.Errorf("device '%s' not found", diskID)
  600. }
  601. err = vm.RemoveDevice(ctx, true, device)
  602. if err != nil {
  603. return err
  604. }
  605. return nil
  606. }
  607. // Create a volume of given size (in KiB).
  608. func (vs *VSphere) CreateVolume(name string, size int, tags *map[string]string) (volumePath string, err error) {
  609. // Create context
  610. ctx, cancel := context.WithCancel(context.Background())
  611. defer cancel()
  612. // Create vSphere client
  613. c, err := vsphereLogin(vs.cfg, ctx)
  614. if err != nil {
  615. return "", err
  616. }
  617. defer c.Logout(ctx)
  618. // Create a new finder
  619. f := find.NewFinder(c.Client, true)
  620. // Fetch and set data center
  621. dc, err := f.Datacenter(ctx, vs.cfg.Global.Datacenter)
  622. f.SetDatacenter(dc)
  623. // Create a virtual disk manager
  624. vmDiskPath := "[" + vs.cfg.Global.Datastore + "] " + name + ".vmdk"
  625. virtualDiskManager := object.NewVirtualDiskManager(c.Client)
  626. // Create specification for new virtual disk
  627. vmDiskSpec := &types.FileBackedVirtualDiskSpec{
  628. VirtualDiskSpec: types.VirtualDiskSpec{
  629. AdapterType: (*tags)["adapterType"],
  630. DiskType: (*tags)["diskType"],
  631. },
  632. CapacityKb: int64(size),
  633. }
  634. // Create virtual disk
  635. task, err := virtualDiskManager.CreateVirtualDisk(ctx, vmDiskPath, dc, vmDiskSpec)
  636. if err != nil {
  637. return "", err
  638. }
  639. err = task.Wait(ctx)
  640. if err != nil {
  641. return "", err
  642. }
  643. return vmDiskPath, nil
  644. }
  645. // Deletes a volume given volume name.
  646. func (vs *VSphere) DeleteVolume(vmDiskPath string) error {
  647. // Create context
  648. ctx, cancel := context.WithCancel(context.Background())
  649. defer cancel()
  650. // Create vSphere client
  651. c, err := vsphereLogin(vs.cfg, ctx)
  652. if err != nil {
  653. return err
  654. }
  655. defer c.Logout(ctx)
  656. // Create a new finder
  657. f := find.NewFinder(c.Client, true)
  658. // Fetch and set data center
  659. dc, err := f.Datacenter(ctx, vs.cfg.Global.Datacenter)
  660. f.SetDatacenter(dc)
  661. // Create a virtual disk manager
  662. virtualDiskManager := object.NewVirtualDiskManager(c.Client)
  663. // Delete virtual disk
  664. task, err := virtualDiskManager.DeleteVirtualDisk(ctx, vmDiskPath, dc)
  665. if err != nil {
  666. return err
  667. }
  668. return task.Wait(ctx)
  669. }