PageRenderTime 287ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/pkg/cloudprovider/providers/vsphere/vsphere.go

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