vagrant-vcloudair 0.5.0

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 (53) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +34 -0
  3. data/.rubocop.yml +34 -0
  4. data/Gemfile +7 -0
  5. data/LICENSE +21 -0
  6. data/README.md +109 -0
  7. data/lib/vagrant-vcloudair.rb +63 -0
  8. data/lib/vagrant-vcloudair/action.rb +298 -0
  9. data/lib/vagrant-vcloudair/action/announce_ssh_exec.rb +22 -0
  10. data/lib/vagrant-vcloudair/action/build_vapp.rb +235 -0
  11. data/lib/vagrant-vcloudair/action/connect_vcloud.rb +54 -0
  12. data/lib/vagrant-vcloudair/action/destroy_vapp.rb +54 -0
  13. data/lib/vagrant-vcloudair/action/destroy_vm.rb +37 -0
  14. data/lib/vagrant-vcloudair/action/disconnect_vcloud.rb +31 -0
  15. data/lib/vagrant-vcloudair/action/forward_ports.rb +132 -0
  16. data/lib/vagrant-vcloudair/action/handle_nat_port_collisions.rb +153 -0
  17. data/lib/vagrant-vcloudair/action/inventory_check.rb +210 -0
  18. data/lib/vagrant-vcloudair/action/is_bridged.rb +29 -0
  19. data/lib/vagrant-vcloudair/action/is_created.rb +35 -0
  20. data/lib/vagrant-vcloudair/action/is_last_vm.rb +31 -0
  21. data/lib/vagrant-vcloudair/action/is_paused.rb +20 -0
  22. data/lib/vagrant-vcloudair/action/is_running.rb +20 -0
  23. data/lib/vagrant-vcloudair/action/message_already_running.rb +16 -0
  24. data/lib/vagrant-vcloudair/action/message_cannot_suspend.rb +16 -0
  25. data/lib/vagrant-vcloudair/action/message_not_created.rb +16 -0
  26. data/lib/vagrant-vcloudair/action/message_not_running.rb +16 -0
  27. data/lib/vagrant-vcloudair/action/message_will_not_destroy.rb +21 -0
  28. data/lib/vagrant-vcloudair/action/power_off.rb +33 -0
  29. data/lib/vagrant-vcloudair/action/power_off_vapp.rb +40 -0
  30. data/lib/vagrant-vcloudair/action/power_on.rb +39 -0
  31. data/lib/vagrant-vcloudair/action/read_ssh_info.rb +153 -0
  32. data/lib/vagrant-vcloudair/action/read_state.rb +51 -0
  33. data/lib/vagrant-vcloudair/action/resume.rb +25 -0
  34. data/lib/vagrant-vcloudair/action/suspend.rb +25 -0
  35. data/lib/vagrant-vcloudair/action/unmap_port_forwardings.rb +74 -0
  36. data/lib/vagrant-vcloudair/cap/forwarded_ports.rb +38 -0
  37. data/lib/vagrant-vcloudair/cap/public_address.rb +18 -0
  38. data/lib/vagrant-vcloudair/cap/rdp_info.rb +18 -0
  39. data/lib/vagrant-vcloudair/cap/winrm_info.rb +15 -0
  40. data/lib/vagrant-vcloudair/command.rb +285 -0
  41. data/lib/vagrant-vcloudair/config.rb +205 -0
  42. data/lib/vagrant-vcloudair/driver/base.rb +643 -0
  43. data/lib/vagrant-vcloudair/driver/meta.rb +202 -0
  44. data/lib/vagrant-vcloudair/driver/version_5_1.rb +2019 -0
  45. data/lib/vagrant-vcloudair/errors.rb +77 -0
  46. data/lib/vagrant-vcloudair/model/forwarded_port.rb +66 -0
  47. data/lib/vagrant-vcloudair/plugin.rb +111 -0
  48. data/lib/vagrant-vcloudair/provider.rb +41 -0
  49. data/lib/vagrant-vcloudair/util/compile_forwarded_ports.rb +34 -0
  50. data/lib/vagrant-vcloudair/version.rb +5 -0
  51. data/locales/en.yml +169 -0
  52. data/vagrant-vcloudair.gemspec +33 -0
  53. metadata +266 -0
@@ -0,0 +1,25 @@
1
+ module VagrantPlugins
2
+ module VCloudAir
3
+ module Action
4
+ class Resume
5
+ def initialize(app, env)
6
+ @app = app
7
+ @logger = Log4r::Logger.new('vagrant_vcloudair::action::resume')
8
+ end
9
+
10
+ def call(env)
11
+ cfg = env[:machine].provider_config
12
+ cnx = cfg.vcloudair_cnx.driver
13
+
14
+ vm_id = env[:machine].id
15
+
16
+ env[:ui].info(I18n.t(vagrant_vcloudair.vm.poweron_vm))
17
+ task_id = cnx.poweron_vm(vm_id)
18
+ cnx.wait_task_completion(task_id)
19
+
20
+ @app.call env
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module VagrantPlugins
2
+ module VCloudAir
3
+ module Action
4
+ class Suspend
5
+ def initialize(app, env)
6
+ @app = app
7
+ @logger = Log4r::Logger.new('vagrant_vcloudair::action::suspend')
8
+ end
9
+
10
+ def call(env)
11
+ cfg = env[:machine].provider_config
12
+ cnx = cfg.vcloudair_cnx.driver
13
+
14
+ vm_id = env[:machine].id
15
+
16
+ env[:ui].info(I18n.t('vagrant_vcloudair.vm.suspend_vm'))
17
+ task_id = cnx.suspend_vm(vm_id)
18
+ cnx.wait_task_completion(task_id)
19
+
20
+ @app.call env
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,74 @@
1
+ require 'set'
2
+
3
+ module VagrantPlugins
4
+ module VCloudAir
5
+ module Action
6
+ # This middleware class will detect and handle collisions with
7
+ # forwarded ports, whether that means raising an error or repairing
8
+ # them automatically.
9
+ #
10
+ # Parameters it takes from the environment hash:
11
+ #
12
+ # * `:port_collision_repair` - If true, it will attempt to repair
13
+ # port collisions. If false, it will raise an exception when
14
+ # there is a collision.
15
+ #
16
+ # * `:port_collision_extra_in_use` - An array of ports that are
17
+ # considered in use.
18
+ #
19
+ # * `:port_collision_remap` - A hash remapping certain host ports
20
+ # to other host ports.
21
+ #
22
+ class UnmapPortForwardings
23
+ def initialize(app, env)
24
+ @app = app
25
+ @logger = Log4r::Logger.new(
26
+ 'vagrant_vcloudair::action::unmap_port_forwardings'
27
+ )
28
+ end
29
+
30
+ def call(env)
31
+ cfg = env[:machine].provider_config
32
+ cnx = cfg.vcloudair_cnx.driver
33
+ vapp_id = env[:machine].get_vapp_id
34
+ vm_name = env[:machine].name
35
+
36
+ cfg.org = cnx.get_organization_by_name(cfg.vdc_name)
37
+ cfg.vdc_network_id = cfg.org[:networks][cfg.vdc_network_name]
38
+
39
+ @logger.debug('Getting vApp information...')
40
+ vm = cnx.get_vapp(vapp_id)
41
+ myhash = vm[:vms_hash][vm_name.to_sym]
42
+ @logger.debug('Getting port forwarding rules...')
43
+ rules = cnx.get_vapp_port_forwarding_rules(vapp_id)
44
+
45
+ unless myhash.nil?
46
+ # FIXME: not familiar with this syntax (tsugliani)
47
+ new_rule_set = rules.select {
48
+ |h| !myhash[:vapp_scoped_local_id].include? h[:vapp_scoped_local_id]
49
+ }
50
+
51
+ @logger.debug("OUR NEW RULE SET, PURGED: #{new_rule_set}")
52
+
53
+ remove_ports = cnx.set_vapp_port_forwarding_rules(
54
+ vapp_id,
55
+ 'Vagrant-vApp-Net',
56
+ :fence_mode => 'natRouted',
57
+ :parent_network => cfg.vdc_network_id,
58
+ :nat_policy_type => 'allowTraffic',
59
+ :nat_rules => new_rule_set
60
+ )
61
+
62
+ wait = cnx.wait_task_completion(remove_ports)
63
+
64
+ unless wait[:errormsg].nil?
65
+ fail Errors::ComposeVAppError, :message => wait[:errormsg]
66
+ end
67
+ end
68
+
69
+ @app.call(env)
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,38 @@
1
+ module VagrantPlugins
2
+ module VCloudAir
3
+ module Cap
4
+ module ForwardedPorts
5
+ # Reads the forwarded ports that currently exist on the machine
6
+ # itself. This raises an exception if the machine isn't running.
7
+ #
8
+ # This also may not match up with configured forwarded ports, because
9
+ # Vagrant auto port collision fixing may have taken place.
10
+ #
11
+ # @return [Hash<Integer, Integer>] Host => Guest port mappings.
12
+ def self.forwarded_ports(machine)
13
+ result = {}
14
+
15
+ cfg = machine.provider_config
16
+ cnx = cfg.vcloudair_cnx.driver
17
+ vapp_id = machine.get_vapp_id
18
+ vm_name = machine.name
19
+ vm = cnx.get_vapp(vapp_id)
20
+ myhash = vm[:vms_hash][vm_name.to_sym]
21
+
22
+ return if vm.nil?
23
+
24
+ if cfg.network_bridge.nil?
25
+ rules = cnx.get_vapp_port_forwarding_rules(vapp_id)
26
+
27
+ rules.each do |rule|
28
+ if rule[:vapp_scoped_local_id] == myhash[:vapp_scoped_local_id]
29
+ result[rule[:nat_external_port].to_i] = rule[:nat_internal_port].to_i
30
+ end
31
+ end
32
+ end
33
+ result
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ module VagrantPlugins
2
+ module VCloudAir
3
+ module Cap
4
+ module PublicAddress
5
+ def self.public_address(machine)
6
+ # Initial try for vagrant share feature.
7
+ # It seems ssh_info[:port] is given automatically.
8
+ # I think this feature was built planning that the port forwarding
9
+ # and networking was done on the vagrant machine, which isn't the
10
+ # case in vagrant-vcloudair
11
+
12
+ ssh_info = machine.ssh_info
13
+ ssh_info[:host]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ module VagrantPlugins
2
+ module VCloudAir
3
+ module Cap
4
+ module RDP
5
+
6
+ # Reads the RDP forwarded port that currently exists on the machine
7
+ # itself. This raises an exception if the machine isn't running.
8
+ # @return [Hash<Integer, Integer>] Host => Guest port mappings.
9
+ def self.rdp_info(machine)
10
+ env = machine.action('read_rdp_info')
11
+ env[:machine_ssh_info]
12
+ end
13
+
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,15 @@
1
+ module VagrantPlugins
2
+ module VCloudAir
3
+ module Cap
4
+ module WinRM
5
+ # Reads the WinRM forwarded port that currently exists on the machine
6
+ # itself. This raises an exception if the machine isn't running.
7
+ # @return [Hash<Integer, Integer>] Host => Guest port mappings.
8
+ def self.winrm_info(machine)
9
+ env = machine.action('read_winrm_info')
10
+ env[:machine_ssh_info]
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,285 @@
1
+ require 'awesome_print'
2
+ require 'terminal-table'
3
+
4
+ module VagrantPlugins
5
+ module VCloudAir
6
+ # This Class exposes an additional 'vcloudair' namespace within the vagrant
7
+ # command.
8
+ class Command < Vagrant.plugin('2', :command)
9
+ def self.synopsis
10
+ 'namespace to interact with vCloud Air specifics [vCloud Air provider]'
11
+ end
12
+
13
+ def command_vcloud_status(cfg, vapp_id)
14
+ # Set our handlers to the driver and objects
15
+
16
+ puts 'Fetching vCloud Air status...'
17
+ cnx = cfg.vcloudair_cnx.driver
18
+ vapp = cnx.get_vapp(vapp_id)
19
+
20
+ organization = cnx.get_organization_by_name(cfg.vdc_name)
21
+ cfg.vdc_id = cnx.get_vdc_id_by_name(organization, cfg.vdc_name)
22
+
23
+ # Create a new table for the general information
24
+ table = Terminal::Table.new
25
+ table.title = "Vagrant vCloud Air Status : #{cfg.hostname}"
26
+
27
+ table << ['Organization Name', cfg.vdc_name]
28
+ table << ['Organization vDC Name', cfg.vdc_name]
29
+ table << ['Organization vDC ID', cfg.vdc_id]
30
+ table << ['Organization vDC Network Name', cfg.vdc_network_name]
31
+ table << ['Organization vDC Edge Gateway Name',
32
+ cfg.vdc_edge_gateway] unless cfg.vdc_edge_gateway.nil?
33
+ table << ['Organization vDC Edge IP',
34
+ cfg.vdc_edge_gateway_ip] unless cfg.vdc_edge_gateway_ip.nil?
35
+ table << :separator
36
+ table << ['vApp Name', vapp[:name]]
37
+ table << ['vAppID', vapp_id]
38
+
39
+ vapp[:vms_hash].each do |vm|
40
+ # This should be checked indivudually
41
+ # When 1 VM is destroyed, ID is still populated, should be cleaned.
42
+ table << ["-> #{vm[0]}", vm[1][:id]]
43
+ end
44
+
45
+ # Print the General Information Table
46
+ puts table
47
+ end
48
+
49
+ def command_vcloud_network(cfg, vapp_id, ssh_host)
50
+ # FIXME: this needs to be fixed to accomodate the bridged scenario
51
+ # potentially showing only the assigned IPs in the VMs
52
+
53
+ puts 'Fetching vCloud Air network settings ...'
54
+ cnx = cfg.vcloudair_cnx.driver
55
+ vapp = cnx.get_vapp(vapp_id)
56
+
57
+ organization = cnx.get_organization_by_name(cfg.vdc_name)
58
+ cfg.vdc_id = cnx.get_vdc_id_by_name(organization, cfg.vdc_name)
59
+
60
+ if !cfg.network_bridge.nil?
61
+ # Create a new table for the network information
62
+ network_table = Terminal::Table.new
63
+ network_table.title = 'Network Map'
64
+
65
+ network_table << ['VM Name', 'IP Address', 'Connection']
66
+ network_table << :separator
67
+
68
+ vapp[:vms_hash].each do |vm|
69
+ network_table << [vm[0], vm[1][:addresses][0], 'Direct']
70
+ end
71
+ else
72
+ vapp_edge_ip = cnx.get_vapp_edge_public_ip(vapp_id)
73
+ vapp_edge_rules = cnx.get_vapp_port_forwarding_rules(vapp_id)
74
+ edge_gateway_rules = cnx.get_edge_gateway_rules(cfg.vdc_edge_gateway,
75
+ cfg.vdc_id)
76
+
77
+ # Create a new table for the network information
78
+ network_table = Terminal::Table.new
79
+ network_table.title = 'Vagrant vCloud Air Network Map'
80
+
81
+ network_table << ['VM Name', 'Destination NAT Mapping', 'Enabled']
82
+ network_table << :separator
83
+
84
+ # Fetching Destination NAT Rules for each vApp/Edge/VM/Mapping
85
+ vapp_edge_rules.each do |vapp_edge_rule|
86
+ edge_gateway_rule = edge_gateway_rules.find {|r|
87
+ (r[:rule_type] == 'DNAT' &&
88
+ r[:original_ip] == cfg.vdc_edge_gateway_ip &&
89
+ r[:translated_ip] == vapp_edge_ip)}
90
+
91
+ # Loop on every VM in the vApp
92
+ vapp[:vms_hash].each do |vm|
93
+ # Only Map valid vAppEdge scope to VM scope
94
+ vm_scope = vm[1][:vapp_scoped_local_id]
95
+ vapp_edge_scope = vapp_edge_rule[:vapp_scoped_local_id]
96
+
97
+ if vm_scope == vapp_edge_scope
98
+ # Generate DNAT Mappings for the valid machines
99
+ # If rules don't match, you will not see them !
100
+ if edge_gateway_rule
101
+ # DNAT rule from edge to vapp to vm
102
+ connect_host = nil
103
+
104
+ # Add support for config.ssh.host
105
+ if ssh_host
106
+ connect_host = "#{ssh_host}:" +
107
+ "#{vapp_edge_rule[:nat_external_port]}" +
108
+ ' -> ' +
109
+ "#{cfg.vdc_edge_gateway_ip}:" +
110
+ "#{vapp_edge_rule[:nat_external_port]}"
111
+ else
112
+ connect_host = "#{cfg.vdc_edge_gateway_ip}:" +
113
+ "#{vapp_edge_rule[:nat_external_port]}"
114
+ end
115
+
116
+ network_table << [
117
+ "#{vm[0]}",
118
+ "#{connect_host}" +
119
+ " -> #{vapp_edge_ip}:" +
120
+ "#{vapp_edge_rule[:nat_external_port]}" +
121
+ " -> #{vm[1][:addresses][0]}:" +
122
+ "#{vapp_edge_rule[:nat_internal_port]}",
123
+ edge_gateway_rule[:is_enabled]
124
+ ]
125
+ else
126
+ # DNAT rule only from vapp to vm
127
+ network_table << [
128
+ "#{vm[0]}",
129
+ "#{vapp_edge_ip}:" +
130
+ "#{vapp_edge_rule[:nat_external_port]}" +
131
+ " -> #{vm[1][:addresses][0]}:" +
132
+ "#{vapp_edge_rule[:nat_internal_port]}",
133
+ true
134
+ ]
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ # Fetching Source NAT Rules for the vApp
141
+ network_table << :separator
142
+ network_table << ['Network Name', 'Source NAT Mapping', 'Enabled']
143
+ network_table << :separator
144
+
145
+ edge_gateway_rules.each do |edge_gateway_rule|
146
+ # Only check SNAT and src/dst
147
+ if edge_gateway_rule[:rule_type] == 'SNAT' &&
148
+ edge_gateway_rule[:original_ip] == vapp_edge_ip &&
149
+ edge_gateway_rule[:translated_ip] == cfg.vdc_edge_gateway_ip
150
+
151
+ network_table << [
152
+ edge_gateway_rule[:interface_name],
153
+ "#{vapp_edge_ip} -> #{cfg.vdc_edge_gateway_ip}",
154
+ edge_gateway_rule[:is_enabled]
155
+ ]
156
+ end
157
+ end
158
+
159
+ # Fetching Edge Gateway Firewall Rules
160
+ network_table << :separator
161
+ network_table << ['Rule# - Description', 'Firewall Rules', 'Enabled']
162
+ network_table << :separator
163
+ edge_gateway_rules.each do |edge_gateway_rule|
164
+ # Only add firewall rules
165
+ if edge_gateway_rule[:rule_type] == 'Firewall'
166
+ network_table << [
167
+ "#{edge_gateway_rule[:id]} - " +
168
+ "(#{edge_gateway_rule[:description]})",
169
+ "#{edge_gateway_rule[:policy]} " +
170
+ "SRC:#{edge_gateway_rule[:source_ip]}:" +
171
+ "#{edge_gateway_rule[:source_portrange]} to " +
172
+ "DST:#{edge_gateway_rule[:destination_ip]}:" +
173
+ "#{edge_gateway_rule[:destination_portrange]}",
174
+ "#{edge_gateway_rule[:is_enabled]}"
175
+ ]
176
+ end
177
+ end
178
+ end
179
+ # Print the Network Table
180
+ puts network_table
181
+ end
182
+
183
+ def command_vcloud_redeploy_edge_gw(cfg)
184
+ cnx = cfg.vcloudair_cnx.driver
185
+
186
+ organization = cnx.get_organization_by_name(cfg.vdc_name)
187
+ cfg.vdc_id = cnx.get_vdc_id_by_name(organization, cfg.vdc_name)
188
+
189
+ edge_gw_id = cnx.find_edge_gateway_id(cfg.vdc_edge_gateway, cfg.vdc_id)
190
+ task_id = cnx.redeploy_edge_gateway(edge_gw_id)
191
+
192
+ puts "Redeploying #{cfg.vdc_edge_gateway} vShield Edge Gateway... " +
193
+ '(This task can take a few minutes)'
194
+ cnx.wait_task_completion(task_id)
195
+ puts 'Done'
196
+ end
197
+
198
+ def execute
199
+ options = {}
200
+ opts = OptionParser.new do |o|
201
+ o.banner = 'Usage: vagrant vcloud [options]'
202
+
203
+ # We can probably extend this if needed for specific information
204
+ o.on(
205
+ '-n',
206
+ '--network',
207
+ 'Display the vCloud Air network mapping information'
208
+ ) do |f|
209
+ options[:network] = true
210
+ end
211
+
212
+ o.on(
213
+ '-s',
214
+ '--status',
215
+ 'Display the vCloud Air objects IDs'
216
+ ) do |f|
217
+ options[:status] = true
218
+ end
219
+
220
+ o.on(
221
+ '-r',
222
+ '--redeploy-edge-gw',
223
+ 'Redeploy the vCloud Air Edge Gateway'
224
+ ) do |f|
225
+ options[:redeploy_edge_gw] = true
226
+ end
227
+
228
+ end
229
+
230
+ @argv = parse_options(opts)
231
+ return unless @argv
232
+
233
+ # If no arguments, print help
234
+ if options.keys.count() == 0
235
+ puts opts
236
+ exit 1
237
+ end
238
+
239
+ puts 'Initializing vCloud Air provider...'
240
+ # initialize some variables
241
+ ssh_host = nil
242
+ vapp_id = nil
243
+ cfg = nil
244
+
245
+ # Go through the vagrant machines
246
+ with_target_vms(@argv) do |machine|
247
+
248
+ # FIXME/Bug: why does the provider switch to virtualbox when
249
+ # destroying VMs within the the vApp:
250
+ # .vagrant/machines/<machine>/virtualbox Cannot trace why this
251
+ # happens :-( (tsugliani)
252
+ if machine.provider_name != :vcloudair
253
+ # Not a vCloud Air provider, exit with explicit error message
254
+ puts "#{machine.provider_name} provider is incompatible with " +
255
+ 'this command'
256
+ exit 1
257
+ end
258
+
259
+ # Force reloads on objects by fetching the ssh_info
260
+ machine.provider.ssh_info
261
+
262
+ # populate cfg & vApp Id for later use.
263
+ cfg = machine.provider_config
264
+ vapp_id = machine.get_vapp_id
265
+ ssh_host = machine.config.ssh.host
266
+ break
267
+ end
268
+
269
+ # iterate through each option and call the according command.
270
+ options.keys.each do |key|
271
+ case key
272
+ when :status
273
+ command_vcloud_status(cfg, vapp_id)
274
+ when :network
275
+ command_vcloud_network(cfg, vapp_id, ssh_host)
276
+ when :redeploy_edge_gw
277
+ command_vcloud_redeploy_edge_gw(cfg)
278
+ end
279
+ end
280
+
281
+ 0
282
+ end
283
+ end
284
+ end
285
+ end