djo-vagrant-vsphere 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.bumpversion.cfg +11 -0
  3. data/.gitignore +8 -0
  4. data/.rubocop.yml +13 -0
  5. data/.rubocop_todo.yml +80 -0
  6. data/.travis.yml +11 -0
  7. data/CHANGELOG.md +250 -0
  8. data/DEVELOPMENT.md +67 -0
  9. data/Gemfile +16 -0
  10. data/LICENSE.txt +24 -0
  11. data/README.md +310 -0
  12. data/Rakefile +20 -0
  13. data/example_box/metadata.json +3 -0
  14. data/lib/vSphere/action.rb +195 -0
  15. data/lib/vSphere/action/clone.rb +239 -0
  16. data/lib/vSphere/action/close_vsphere.rb +22 -0
  17. data/lib/vSphere/action/connect_vsphere.rb +29 -0
  18. data/lib/vSphere/action/destroy.rb +41 -0
  19. data/lib/vSphere/action/get_ssh_info.rb +37 -0
  20. data/lib/vSphere/action/get_state.rb +41 -0
  21. data/lib/vSphere/action/is_created.rb +16 -0
  22. data/lib/vSphere/action/is_running.rb +16 -0
  23. data/lib/vSphere/action/message_already_created.rb +18 -0
  24. data/lib/vSphere/action/message_not_created.rb +18 -0
  25. data/lib/vSphere/action/message_not_running.rb +18 -0
  26. data/lib/vSphere/action/power_off.rb +40 -0
  27. data/lib/vSphere/action/power_on.rb +28 -0
  28. data/lib/vSphere/cap/public_address.rb +15 -0
  29. data/lib/vSphere/config.rb +60 -0
  30. data/lib/vSphere/errors.rb +11 -0
  31. data/lib/vSphere/plugin.rb +44 -0
  32. data/lib/vSphere/provider.rb +39 -0
  33. data/lib/vSphere/util/vim_helpers.rb +91 -0
  34. data/lib/vSphere/util/vm_helpers.rb +39 -0
  35. data/lib/vSphere/version.rb +5 -0
  36. data/lib/vagrant-vsphere.rb +18 -0
  37. data/locales/en.yml +64 -0
  38. data/spec/action_spec.rb +162 -0
  39. data/spec/clone_spec.rb +102 -0
  40. data/spec/connect_vsphere_spec.rb +26 -0
  41. data/spec/destroy_spec.rb +31 -0
  42. data/spec/get_ssh_info_spec.rb +31 -0
  43. data/spec/get_state_spec.rb +55 -0
  44. data/spec/is_created_spec.rb +29 -0
  45. data/spec/power_off_spec.rb +35 -0
  46. data/spec/spec_helper.rb +147 -0
  47. data/vSphere.gemspec +30 -0
  48. data/vsphere_screenshot.png +0 -0
  49. metadata +212 -0
@@ -0,0 +1,18 @@
1
+ require 'i18n'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Action
6
+ class MessageAlreadyCreated
7
+ def initialize(app, _env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ env[:ui].info I18n.t('vsphere.vm_already_created')
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'i18n'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Action
6
+ class MessageNotCreated
7
+ def initialize(app, _env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ env[:ui].info I18n.t('vsphere.vm_not_created')
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'i18n'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Action
6
+ class MessageNotRunning
7
+ def initialize(app, _env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ env[:ui].info I18n.t('vsphere.vm_not_running')
13
+ @app.call(env)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,40 @@
1
+ require 'rbvmomi'
2
+ require 'i18n'
3
+ require 'vSphere/util/vim_helpers'
4
+ require 'vSphere/util/vm_helpers'
5
+
6
+ module VagrantPlugins
7
+ module VSphere
8
+ module Action
9
+ class PowerOff
10
+ include Util::VimHelpers
11
+ include Util::VmHelpers
12
+
13
+ def initialize(app, _env)
14
+ @app = app
15
+ end
16
+
17
+ def call(env)
18
+ vm = get_vm_by_uuid env[:vSphere_connection], env[:machine]
19
+
20
+ # If the vm is suspended, we need to turn it on so that we can turn it off.
21
+ # This may seem counterintuitive, but the vsphere API documentation states
22
+ # that the Power Off task for a VM will fail if the state is not poweredOn
23
+ # see: https://www.vmware.com/support/developer/vc-sdk/visdk41pubs/ApiReference/vim.VirtualMachine.html#powerOff
24
+ if suspended?(vm)
25
+ env[:ui].info I18n.t('vsphere.power_on_vm')
26
+ power_on_vm(vm)
27
+ end
28
+
29
+ # Powering off is a no-op if we can't find the VM or if it is already off
30
+ unless vm.nil? || powered_off?(vm)
31
+ env[:ui].info I18n.t('vsphere.power_off_vm')
32
+ power_off_vm(vm)
33
+ end
34
+
35
+ @app.call env
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,28 @@
1
+ require 'rbvmomi'
2
+ require 'i18n'
3
+ require 'vSphere/util/vim_helpers'
4
+ require 'vSphere/util/vm_helpers'
5
+
6
+ module VagrantPlugins
7
+ module VSphere
8
+ module Action
9
+ class PowerOn
10
+ include Util::VimHelpers
11
+ include Util::VmHelpers
12
+
13
+ def initialize(app, _env)
14
+ @app = app
15
+ end
16
+
17
+ def call(env)
18
+ vm = get_vm_by_uuid env[:vSphere_connection], env[:machine]
19
+
20
+ env[:ui].info I18n.t('vsphere.power_on_vm')
21
+ power_on_vm(vm)
22
+
23
+ @app.call env
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ module VagrantPlugins
2
+ module VSphere
3
+ module Cap
4
+ module PublicAddress
5
+ def self.public_address(machine)
6
+ return nil if machine.state.id != :running
7
+
8
+ ssh_info = machine.ssh_info
9
+ return nil unless ssh_info
10
+ ssh_info[:host]
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,60 @@
1
+ require 'vagrant'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ class Config < Vagrant.plugin('2', :config)
6
+ attr_accessor :host
7
+ attr_accessor :insecure
8
+ attr_accessor :user
9
+ attr_accessor :password
10
+ attr_accessor :data_center_name
11
+ attr_accessor :compute_resource_name
12
+ attr_accessor :resource_pool_name
13
+ attr_accessor :clone_from_vm
14
+ attr_accessor :template_name
15
+ attr_accessor :name
16
+ attr_accessor :vm_base_path
17
+ attr_accessor :customization_spec_name
18
+ attr_accessor :data_store_name
19
+ attr_accessor :linked_clone
20
+ attr_accessor :proxy_host
21
+ attr_accessor :proxy_port
22
+ attr_accessor :vlan
23
+ attr_accessor :addressType
24
+ attr_accessor :mac
25
+ attr_accessor :memory_mb
26
+ attr_accessor :cpu_count
27
+ attr_accessor :cpu_reservation
28
+ attr_accessor :mem_reservation
29
+
30
+ attr_reader :custom_attributes
31
+
32
+ def initialize
33
+ @custom_attributes = {}
34
+ end
35
+
36
+ def custom_attribute(key, value)
37
+ @custom_attributes[key.to_sym] = value
38
+ end
39
+
40
+ def validate(machine)
41
+ errors = _detected_errors
42
+
43
+ if password == :ask || password.nil?
44
+ self.password = machine.ui.ask('vSphere Password (will be hidden): ', echo: false)
45
+ end
46
+
47
+ # TODO: add blank?
48
+ errors << I18n.t('vsphere.config.host') if host.nil?
49
+ errors << I18n.t('vsphere.config.user') if user.nil?
50
+ errors << I18n.t('vsphere.config.password') if password.nil?
51
+ errors << I18n.t('vsphere.config.template') if template_name.nil?
52
+
53
+ # Only required if we're cloning from an actual template
54
+ errors << I18n.t('vsphere.config.compute_resource') if compute_resource_name.nil? && !clone_from_vm
55
+
56
+ { 'vSphere Provider' => errors }
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,11 @@
1
+ require 'vagrant'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Errors
6
+ class VSphereError < Vagrant::Errors::VagrantError
7
+ error_namespace('vsphere.errors')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,44 @@
1
+ begin
2
+ require 'vagrant'
3
+ rescue LoadError
4
+ raise 'The Vagrant vSphere plugin must be run within Vagrant.'
5
+ end
6
+
7
+ # This is a sanity check to make sure no one is attempting to install
8
+ # this into an early Vagrant version.
9
+ if Vagrant::VERSION < '1.5'
10
+ fail 'The Vagrant vSphere plugin is only compatible with Vagrant 1.5+'
11
+ end
12
+
13
+ module VagrantPlugins
14
+ module VSphere
15
+ class Plugin < Vagrant.plugin('2')
16
+ name 'vsphere'
17
+ description 'Allows Vagrant to manage machines with VMWare vSphere'
18
+
19
+ config(:vsphere, :provider) do
20
+ require_relative 'config'
21
+ Config
22
+ end
23
+
24
+ provider(:vsphere, parallel: true) do
25
+ # TODO: add logging
26
+ setup_i18n
27
+
28
+ # Return the provider
29
+ require_relative 'provider'
30
+ Provider
31
+ end
32
+
33
+ provider_capability('vsphere', 'public_address') do
34
+ require_relative 'cap/public_address'
35
+ Cap::PublicAddress
36
+ end
37
+
38
+ def self.setup_i18n
39
+ I18n.load_path << File.expand_path('locales/en.yml', VSphere.source_root)
40
+ I18n.reload!
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,39 @@
1
+ require 'vagrant'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ class Provider < Vagrant.plugin('2', :provider)
6
+ def initialize(machine)
7
+ @machine = machine
8
+ end
9
+
10
+ def action(name)
11
+ action_method = "action_#{name}"
12
+ return Action.send(action_method) if Action.respond_to?(action_method)
13
+ nil
14
+ end
15
+
16
+ def ssh_info
17
+ env = @machine.action('get_ssh_info')
18
+ env[:machine_ssh_info]
19
+ end
20
+
21
+ def state
22
+ env = @machine.action('get_state')
23
+
24
+ state_id = env[:machine_state_id]
25
+
26
+ short = "vagrant_vsphere.states.short_#{state_id}"
27
+ long = "vagrant_vsphere.states.long_#{state_id}"
28
+
29
+ # Return the MachineState object
30
+ Vagrant::MachineState.new(state_id, short, long)
31
+ end
32
+
33
+ def to_s
34
+ id = @machine.id.nil? ? 'new' : @machine.id
35
+ "vSphere (#{id})"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,91 @@
1
+ require 'rbvmomi'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Util
6
+ module VimHelpers
7
+ def get_datacenter(connection, machine)
8
+ connection.serviceInstance.find_datacenter(machine.provider_config.data_center_name) || fail(Errors::VSphereError, :missing_datacenter)
9
+ end
10
+
11
+ def get_vm_by_uuid(connection, machine)
12
+ get_datacenter(connection, machine).vmFolder.findByUuid machine.id
13
+ end
14
+
15
+ def get_resource_pool(datacenter, machine)
16
+ compute_resource = get_compute_resource(datacenter, machine)
17
+ rp = compute_resource.resourcePool
18
+ unless machine.provider_config.resource_pool_name.nil?
19
+ rp = compute_resource.resourcePool.find(machine.provider_config.resource_pool_name)
20
+ fail Errors::VSphereError, :missing_resource_pool if rp.nil?
21
+ end
22
+ rp
23
+ end
24
+
25
+ def get_compute_resource(datacenter, machine)
26
+ cr = find_clustercompute_or_compute_resource(datacenter, machine.provider_config.compute_resource_name)
27
+ fail Errors::VSphereError, :missing_compute_resource if cr.nil?
28
+ cr
29
+ end
30
+
31
+ def find_clustercompute_or_compute_resource(datacenter, path)
32
+ if path.is_a? String
33
+ es = path.split('/').reject(&:empty?)
34
+ elsif path.is_a? Enumerable
35
+ es = path
36
+ else
37
+ fail "unexpected path class #{path.class}"
38
+ end
39
+ return datacenter.hostFolder if es.empty?
40
+ final = es.pop
41
+
42
+ p = es.inject(datacenter.hostFolder) do |f, e|
43
+ f.find(e, RbVmomi::VIM::Folder) || return
44
+ end
45
+
46
+ begin
47
+ if (x = p.find(final, RbVmomi::VIM::ComputeResource))
48
+ x
49
+ elsif (x = p.find(final, RbVmomi::VIM::ClusterComputeResource))
50
+ x
51
+ end
52
+ rescue Exception
53
+ # When looking for the ClusterComputeResource there seems to be some parser error in RbVmomi Folder.find, try this instead
54
+ x = p.childEntity.find { |x2| x2.name == final }
55
+ if x.is_a?(RbVmomi::VIM::ClusterComputeResource) || x.is_a?(RbVmomi::VIM::ComputeResource)
56
+ x
57
+ else
58
+ puts 'ex unknown type ' + x.to_json
59
+ nil
60
+ end
61
+ end
62
+ end
63
+
64
+ def get_customization_spec_info_by_name(connection, machine)
65
+ name = machine.provider_config.customization_spec_name
66
+ return if name.nil? || name.empty?
67
+
68
+ manager = connection.serviceContent.customizationSpecManager
69
+ fail Errors::VSphereError, :null_configuration_spec_manager if manager.nil?
70
+
71
+ spec = manager.GetCustomizationSpec(name: name)
72
+ fail Errors::VSphereError, :missing_configuration_spec if spec.nil?
73
+
74
+ spec
75
+ end
76
+
77
+ def get_datastore(datacenter, machine)
78
+ name = machine.provider_config.data_store_name
79
+ return if name.nil? || name.empty?
80
+
81
+ # find_datastore uses folder datastore that only lists Datastore and not StoragePod, if not found also try datastoreFolder which contains StoragePod(s)
82
+ datacenter.find_datastore(name) || datacenter.datastoreFolder.traverse(name) || fail(Errors::VSphereError, :missing_datastore)
83
+ end
84
+
85
+ def get_network_by_name(dc, name)
86
+ dc.network.find { |f| f.name == name } || fail(Errors::VSphereError, :missing_vlan)
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,39 @@
1
+ require 'rbvmomi'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Util
6
+ module VmState
7
+ POWERED_ON = 'poweredOn'
8
+ POWERED_OFF = 'poweredOff'
9
+ SUSPENDED = 'suspended'
10
+ end
11
+
12
+ module VmHelpers
13
+ def power_on_vm(vm)
14
+ vm.PowerOnVM_Task.wait_for_completion
15
+ end
16
+
17
+ def power_off_vm(vm)
18
+ vm.PowerOffVM_Task.wait_for_completion
19
+ end
20
+
21
+ def get_vm_state(vm)
22
+ vm.runtime.powerState
23
+ end
24
+
25
+ def powered_on?(vm)
26
+ get_vm_state(vm).eql?(VmState::POWERED_ON)
27
+ end
28
+
29
+ def powered_off?(vm)
30
+ get_vm_state(vm).eql?(VmState::POWERED_OFF)
31
+ end
32
+
33
+ def suspended?(vm)
34
+ get_vm_state(vm).eql?(VmState::SUSPENDED)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,5 @@
1
+ module VagrantPlugins
2
+ module VSphere
3
+ VERSION = '1.6.1'
4
+ end
5
+ end