vagrant-vsphere 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE.txt +24 -0
  4. data/README.md +151 -0
  5. data/Rakefile +17 -0
  6. data/example_box/metadata.json +3 -0
  7. data/lib/vSphere/action/clone.rb +83 -0
  8. data/lib/vSphere/action/close_vsphere.rb +24 -0
  9. data/lib/vSphere/action/connect_vsphere.rb +25 -0
  10. data/lib/vSphere/action/destroy.rb +38 -0
  11. data/lib/vSphere/action/get_ssh_info.rb +38 -0
  12. data/lib/vSphere/action/get_state.rb +46 -0
  13. data/lib/vSphere/action/is_created.rb +16 -0
  14. data/lib/vSphere/action/is_running.rb +20 -0
  15. data/lib/vSphere/action/message_already_created.rb +18 -0
  16. data/lib/vSphere/action/message_not_created.rb +18 -0
  17. data/lib/vSphere/action/message_not_running.rb +18 -0
  18. data/lib/vSphere/action/power_off.rb +28 -0
  19. data/lib/vSphere/action/power_on.rb +31 -0
  20. data/lib/vSphere/action/sync_folders.rb +65 -0
  21. data/lib/vSphere/action.rb +151 -0
  22. data/lib/vSphere/config.rb +37 -0
  23. data/lib/vSphere/errors.rb +11 -0
  24. data/lib/vSphere/plugin.rb +30 -0
  25. data/lib/vSphere/provider.rb +39 -0
  26. data/lib/vSphere/util/machine_helpers.rb +15 -0
  27. data/lib/vSphere/util/vim_helpers.rb +37 -0
  28. data/lib/vSphere/version.rb +5 -0
  29. data/lib/vagrant-vsphere.rb +18 -0
  30. data/locales/en.yml +61 -0
  31. data/spec/action_spec.rb +116 -0
  32. data/spec/clone_spec.rb +32 -0
  33. data/spec/connect_vsphere_spec.rb +24 -0
  34. data/spec/destroy_spec.rb +31 -0
  35. data/spec/get_ssh_info_spec.rb +31 -0
  36. data/spec/get_state_spec.rb +54 -0
  37. data/spec/is_created_spec.rb +29 -0
  38. data/spec/spec_helper.rb +97 -0
  39. data/vSphere.gemspec +28 -0
  40. metadata +205 -0
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *~
2
+ .vagrant/*
3
+ Vagrantfile
4
+ pkg/*
5
+ *.box
6
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ # We depend on Vagrant for development, but we don't add it as a
7
+ # gem dependency because we expect to be installed within the
8
+ # Vagrant environment itself using `vagrant plugin`.
9
+ gem 'vagrant', :git => 'git://github.com/mitchellh/vagrant.git'
10
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2013 Regents of the University of Colorado
2
+
3
+ This software was developed by the National Snow and Ice Data Center with funding from multiple sources.
4
+
5
+ MIT License
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ "Software"), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # Vagrant vSphere Provider
2
+
3
+ This is a [Vagrant](http://www.vagrantup.com) 1.2+ plugin that adds a [vSphere](http://pubs.vmware.com/vsphere-50/index.jsp?topic=%2Fcom.vmware.wssdk.apiref.doc_50%2Fright-pane.html)
4
+ provider to Vagrant, allowing Vagrant to control and provision machines using VMware. New machines are created from virtual machines or templates which must be configured prior to using using this provider.
5
+
6
+ This provider is built on top of the [RbVmomi](https://github.com/vmware/rbvmomi) Ruby interface to the vSphere API.
7
+
8
+ ## Requirements
9
+ * Vagrant 1.2+
10
+ * VMware + vSphere API
11
+ * Ruby 1.9+
12
+ * libxml2, libxml2-dev, libxslt, libxslt-dev
13
+
14
+ ## Building the gem
15
+
16
+ The gem needs to be built before the provider can be added to Vagrant:
17
+
18
+ ```
19
+ gem build vSphere.gemspec
20
+ ```
21
+
22
+ ## Installation
23
+
24
+ Install using standard Vagrant plugin method:
25
+
26
+ ```
27
+ $ vagrant plugin install vagrant-vsphere
28
+ ```
29
+
30
+ This command needs to be run in vagrant-vsphere build directory so that vagrant can find the gem.
31
+
32
+ ### Potential Intallation Problems
33
+
34
+ The requirements for [Nokogiri](http://nokogiri.org/) must be installed before the plugin can be installed. See Nokogiri's [tutorial](http://nokogiri.org/tutorials/installing_nokogiri.html) for
35
+ detailed instructions.
36
+
37
+ The plugin forces use of Nokogiri 1.5.10 to prevent conflicts with older versions of system libraries, specifically zlib.
38
+
39
+ ## Usage
40
+
41
+ After installing the plugin, you must create a vSphere box. The example_box directory contains a metadata.json file
42
+ that can be used to create a dummy box with the command:
43
+
44
+ ```
45
+ $ tar cvzf dummy.box ./metadata.json
46
+ ```
47
+
48
+ This can be installed using the standard Vagrant methods or specified in the Vagrantfile.
49
+
50
+ After creating the dummy box, make a Vagrantfile that looks like the following:
51
+
52
+ ```ruby
53
+ Vagrant.configure("2") do |config|
54
+ config.vm.box = 'dummy'
55
+ config.vm.box_url = './example_box/dummy.box'
56
+
57
+ config.vm.provider :vsphere do |vsphere|
58
+ vsphere.host = 'HOST NAME OF YOUR VSPHERE INSTANCE'
59
+ vsphere.compute_resource_name = 'YOUR COMPUTE RESOURCE'
60
+ vsphere.resource_pool_name = 'YOUR RESOURCE POOL'
61
+ vsphere.template_name = 'YOUR VM TEMPLATE'
62
+ vsphere.name = 'NEW VM NAME'
63
+ vsphere.user = 'YOUR VMWARE USER'
64
+ vsphere.password = 'YOUR VMWARE PASSWORD'
65
+ end
66
+ end
67
+ ```
68
+
69
+ And then run `vagrant up --provider=vsphere`.
70
+
71
+ ### Custom Box
72
+
73
+ The bulk of this configuration can be included as part of a custom box. See the [Vagrant documentation](http://docs.vagrantup.com/v2/boxes.html)
74
+ and the Vagrant [AWS provider](https://github.com/mitchellh/vagrant-aws/tree/master/example_box) for more information and an example.
75
+
76
+ ### Supported Commands
77
+
78
+ Currently the only implemented actions are `up`, `halt`, `destroy`, and `ssh`.
79
+
80
+ `up` supports provisioning of the new VM with the standard Vagrant provisioners.
81
+
82
+
83
+ ## Configuration
84
+
85
+ This provider has the following settings, all are required unless noted:
86
+
87
+ * `host` - IP or name for the vSphere API
88
+ * `insecure` - _Optional_ verify SSL certificate from the host
89
+ * `user' - user name for connecting to vSphere
90
+ * `password` - password for connecting to vSphere
91
+ * `data_center_name` - _Optional_ datacenter containing the computed resource, the template and where the new VM will be created, if not specified the first datacenter found will be used
92
+ * `compute_resource_name` - _Required if cloning from template_ the name of the host containing the resource pool for the new VM
93
+ * `resource_pool_name` - _Required if cloning from template_ the resource pool for the new VM
94
+ * `clone_from_vm` - _Optional_ use a virtual machine instead of a template as the source for the cloning operation
95
+ * `template_name` - the VM or VM template to clone
96
+ * `name` - name of the new VM
97
+ * `customization_spec_name` - _Optional_ customization spec for the new VM
98
+ * `data_store_name` - _Optional_ the datastore where the VM will be located
99
+
100
+ ### Cloning from a VM rather than a template
101
+
102
+ To clone from an existing VM rather than a template, set `clone_from_vm` to true. If this value is set, `compute_resource_name` and `resource_pool_name` not required.
103
+
104
+ ### Setting a static IP address
105
+
106
+ To set a static IP, add a private network to your vagrant file:
107
+
108
+ ```ruby
109
+ config.vm.network 'private_network', ip: '192.168.50.4'
110
+ ```
111
+
112
+ The IP address will only be set if a customization spec name is given. The customization spec must have network adapter settings configured. For each private network specified, there needs to be a corresponding network adapter in the customization spec. An error will be thrown if there are more networks than adapters.
113
+
114
+ ## Version History
115
+ * 0.0.1
116
+ * Initial release
117
+ * 0.1.0
118
+ * Add folder syncing with guest OS
119
+ * Add provisoning
120
+ * 0.2.0
121
+ * Merge halt action from [catharsis](https://github.com/catharsis)
122
+ * 0.3.0
123
+ * Lock Nokogiri version at 1.5.10 to prevent library conflicts
124
+ * Add support for customization specs
125
+ * 0.4.0
126
+ * Add support for specifying datastore location for new VMs
127
+ * 0.5.0
128
+ * Allow setting static ip addresses using Vagrant private networks
129
+ * Allow cloning from VM or template
130
+
131
+ ## Versioning
132
+
133
+ This plugin follows the principles of [Semantic Versioning 2.0.0](http://semver.org/)
134
+
135
+ ## Contributing
136
+
137
+ 1. Fork it
138
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
139
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
140
+ 4. Push to the branch (`git push origin my-new-feature`)
141
+ 5. Create new Pull Request
142
+
143
+ ## License
144
+
145
+ GI-Cat Driver is licensed under the MIT license. See [LICENSE.txt][license].
146
+
147
+ [license]: https://raw.github.com/nsidc/vagrant-vsphere/master/LICENSE.txt
148
+
149
+ ## Credit
150
+
151
+ This software was developed by the National Snow and Ice Data Center with funding from multiple sources.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'rspec/core/rake_task'
4
+
5
+ # Immediately sync all stdout so that tools like buildbot can
6
+ # immediately load in the output.
7
+ $stdout.sync = true
8
+ $stderr.sync = true
9
+
10
+ # Change to the directory of this file.
11
+ Dir.chdir(File.expand_path('../', __FILE__))
12
+
13
+ Bundler::GemHelper.install_tasks
14
+
15
+ RSpec::Core::RakeTask.new
16
+
17
+ task :default => 'spec'
@@ -0,0 +1,3 @@
1
+ {
2
+ "provider": "vSphere"
3
+ }
@@ -0,0 +1,83 @@
1
+ require 'rbvmomi'
2
+ require 'i18n'
3
+ require 'vSphere/util/vim_helpers'
4
+ require 'vSphere/util/machine_helpers'
5
+
6
+ module VagrantPlugins
7
+ module VSphere
8
+ module Action
9
+ class Clone
10
+ include Util::VimHelpers
11
+ include Util::MachineHelpers
12
+
13
+ def initialize(app, env)
14
+ @app = app
15
+ end
16
+
17
+ def call(env)
18
+ config = env[:machine].provider_config
19
+ connection = env[:vSphere_connection]
20
+ machine = env[:machine]
21
+
22
+ dc = get_datacenter connection, machine
23
+ template = dc.find_vm config.template_name
24
+
25
+ raise Error::VSphereError, :message => I18n.t('errors.missing_template') if template.nil?
26
+
27
+ begin
28
+ location = RbVmomi::VIM.VirtualMachineRelocateSpec
29
+ location[:pool] = get_resource_pool(connection, machine) unless config.clone_from_vm
30
+
31
+ datastore = get_datastore connection, machine
32
+ location[:datastore] = datastore unless datastore.nil?
33
+
34
+ spec = RbVmomi::VIM.VirtualMachineCloneSpec :location => location, :powerOn => true, :template => false
35
+
36
+ customization = get_customization_spec_info_by_name connection, machine
37
+ spec[:customization] = configure_networks(customization.spec, machine) unless customization.nil?
38
+
39
+ env[:ui].info I18n.t('vsphere.creating_cloned_vm')
40
+ env[:ui].info " -- #{config.clone_from_vm ? "Source" : "Template"} VM: #{config.template_name}"
41
+ env[:ui].info " -- Name: #{config.name}"
42
+
43
+ new_vm = template.CloneVM_Task(:folder => template.parent, :name => config.name, :spec => spec).wait_for_completion
44
+ rescue Exception => e
45
+ puts e.message
46
+ raise Errors::VSphereError, :message => e.message
47
+ end
48
+
49
+ #TODO: handle interrupted status in the environment, should the vm be destroyed?
50
+
51
+ machine.id = new_vm.config.uuid
52
+
53
+ # wait for SSH to be available
54
+ wait_for_ssh env
55
+
56
+ env[:ui].info I18n.t('vsphere.vm_clone_success')
57
+
58
+ @app.call env
59
+ end
60
+
61
+ private
62
+
63
+ def configure_networks(spec, machine)
64
+ customization_spec = spec.clone
65
+
66
+ # find all the configured private networks
67
+ private_networks = machine.config.vm.networks.find_all { |n| n[0].eql? :private_network }
68
+ return customization_spec if private_networks.nil?
69
+
70
+ # make sure we have enough NIC settings to override with the private network settings
71
+ raise Error::VSphereError, :message => I18n.t('errors.too_many_private_networks') if private_networks.length > customization_spec.nicSettingMap.length
72
+
73
+ # assign the private network IP to the NIC
74
+ private_networks.each_index do |idx|
75
+ customization_spec.nicSettingMap[idx].adapter.ip.ipAddress = private_networks[idx][1][:ip]
76
+ end
77
+
78
+ customization_spec
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,24 @@
1
+ require 'rbvmomi'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Action
6
+ class CloseVSphere
7
+ def initialize(app, env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ begin
13
+ env[:vSphere_connection].close
14
+ @app.call env
15
+ rescue Exception => e
16
+ puts e
17
+ #raise a properly namespaced error for Vagrant
18
+ raise Errors::VSphereError, :message => e.message
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,25 @@
1
+ require 'rbvmomi'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Action
6
+ class ConnectVSphere
7
+ def initialize(app, env)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ config = env[:machine].provider_config
13
+
14
+ begin
15
+ env[:vSphere_connection] = RbVmomi::VIM.connect host: config.host, user: config.user, password: config.password, insecure: config.insecure
16
+ @app.call env
17
+ rescue Exception => e
18
+ puts e.backtrace
19
+ raise VagrantPlugins::VSphere::Errors::VSphereError, :message => e.message
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ require 'rbvmomi'
2
+ require 'i18n'
3
+ require 'vSphere/util/vim_helpers'
4
+
5
+ module VagrantPlugins
6
+ module VSphere
7
+ module Action
8
+ class Destroy
9
+ include Util::VimHelpers
10
+
11
+ def initialize(app, env)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ destroy_vm env
17
+ env[:machine].id = nil
18
+
19
+ @app.call env
20
+ end
21
+
22
+ private
23
+
24
+ def destroy_vm(env)
25
+ vm = get_vm_by_uuid env[:vSphere_connection], env[:machine]
26
+ return if vm.nil?
27
+
28
+ begin
29
+ env[:ui].info I18n.t('vsphere.destroy_vm')
30
+ vm.Destroy_Task.wait_for_completion
31
+ rescue Exception => e
32
+ raise Errors::VSphereError, :message => e.message
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'rbvmomi'
2
+ require 'vSphere/util/vim_helpers'
3
+
4
+ module VagrantPlugins
5
+ module VSphere
6
+ module Action
7
+ class GetSshInfo
8
+ include Util::VimHelpers
9
+
10
+
11
+ def initialize(app, env)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ env[:machine_ssh_info] = get_ssh_info(env[:vSphere_connection], env[:machine])
17
+
18
+ @app.call env
19
+ end
20
+
21
+ private
22
+
23
+ def get_ssh_info(connection, machine)
24
+ return nil if machine.id.nil?
25
+
26
+ vm = get_vm_by_uuid connection, machine
27
+
28
+ return nil if vm.nil?
29
+
30
+ return {
31
+ :host => vm.guest.ipAddress,
32
+ :port => 22
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,46 @@
1
+ require 'rbvmomi'
2
+ require 'vSphere/util/vim_helpers'
3
+
4
+ module VagrantPlugins
5
+ module VSphere
6
+ module Action
7
+ class GetState
8
+ include Util::VimHelpers
9
+
10
+ # the three possible values of a vSphere VM's power state
11
+ POWERED_ON = 'poweredOn'
12
+ POWERED_OFF = 'poweredOff'
13
+ SUSPENDED = 'suspended'
14
+
15
+ def initialize(app, env)
16
+ @app = app
17
+ end
18
+
19
+ def call(env)
20
+ env[:machine_state_id] = get_state(env[:vSphere_connection], env[:machine])
21
+
22
+ @app.call env
23
+ end
24
+
25
+ private
26
+
27
+ def get_state(connection, machine)
28
+ return :not_created if machine.id.nil?
29
+
30
+ vm = get_vm_by_uuid connection, machine
31
+
32
+ if vm.nil?
33
+ return :not_created
34
+ end
35
+
36
+ if vm.runtime.powerState.eql?(POWERED_ON)
37
+ :running
38
+ else
39
+ # If the VM is powered off or suspended, we consider it to be powered off. A power on command will either turn on or resume the VM
40
+ :poweroff
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ module VagrantPlugins
2
+ module VSphere
3
+ module Action
4
+ class IsCreated
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ env[:result] = env[:machine].state.id != :not_created
11
+ @app.call env
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ require 'vSphere/util/machine_helpers'
2
+
3
+ module VagrantPlugins
4
+ module VSphere
5
+ module Action
6
+ class IsRunning
7
+ include Util::MachineHelpers
8
+
9
+ def initialize(app, env)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ env[:result] = env[:machine].state.id == :running
15
+ @app.call env
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -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 MessageAlreadyCreated
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,28 @@
1
+ require 'rbvmomi'
2
+ require 'i18n'
3
+ require 'vSphere/util/vim_helpers'
4
+
5
+ module VagrantPlugins
6
+ module VSphere
7
+ module Action
8
+ class PowerOff
9
+ include Util::VimHelpers
10
+
11
+ def initialize(app, env)
12
+ @app = app
13
+ end
14
+
15
+ def call(env)
16
+ vm = get_vm_by_uuid env[:vSphere_connection], env[:machine]
17
+
18
+ unless vm.nil?
19
+ env[:ui].info I18n.t('vsphere.power_off_vm')
20
+ vm.PowerOffVM_Task.wait_for_completion
21
+ end
22
+
23
+ @app.call env
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,31 @@
1
+ require 'rbvmomi'
2
+ require 'i18n'
3
+ require 'vSphere/util/vim_helpers'
4
+ require 'vSphere/util/machine_helpers'
5
+
6
+ module VagrantPlugins
7
+ module VSphere
8
+ module Action
9
+ class PowerOn
10
+ include Util::VimHelpers
11
+ include Util::MachineHelpers
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
+ vm.PowerOnVM_Task.wait_for_completion
22
+
23
+ # wait for SSH to be available
24
+ wait_for_ssh env
25
+
26
+ @app.call env
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end