vagrant-vcloud 0.1.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 (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE +20 -0
  5. data/README.md +80 -0
  6. data/Rakefile +17 -0
  7. data/example_box/README.md +13 -0
  8. data/example_box/Vagrantfile +6 -0
  9. data/example_box/metadata.json +1 -0
  10. data/lib/vagrant-vcloud.rb +65 -0
  11. data/lib/vagrant-vcloud/action.rb +226 -0
  12. data/lib/vagrant-vcloud/action/announce_ssh_exec.rb +17 -0
  13. data/lib/vagrant-vcloud/action/build_vapp.rb +197 -0
  14. data/lib/vagrant-vcloud/action/connect_vcloud.rb +68 -0
  15. data/lib/vagrant-vcloud/action/destroy.rb +69 -0
  16. data/lib/vagrant-vcloud/action/disconnect_vcloud.rb +33 -0
  17. data/lib/vagrant-vcloud/action/forward_ports.rb +127 -0
  18. data/lib/vagrant-vcloud/action/handle_nat_port_collisions.rb +129 -0
  19. data/lib/vagrant-vcloud/action/inventory_check.rb +156 -0
  20. data/lib/vagrant-vcloud/action/is_created.rb +36 -0
  21. data/lib/vagrant-vcloud/action/is_paused.rb +22 -0
  22. data/lib/vagrant-vcloud/action/is_running.rb +22 -0
  23. data/lib/vagrant-vcloud/action/message_already_running.rb +17 -0
  24. data/lib/vagrant-vcloud/action/message_cannot_suspend.rb +17 -0
  25. data/lib/vagrant-vcloud/action/message_not_created.rb +17 -0
  26. data/lib/vagrant-vcloud/action/message_will_not_destroy.rb +17 -0
  27. data/lib/vagrant-vcloud/action/power_off.rb +33 -0
  28. data/lib/vagrant-vcloud/action/power_on.rb +46 -0
  29. data/lib/vagrant-vcloud/action/read_ssh_info.rb +69 -0
  30. data/lib/vagrant-vcloud/action/read_state.rb +59 -0
  31. data/lib/vagrant-vcloud/action/resume.rb +33 -0
  32. data/lib/vagrant-vcloud/action/suspend.rb +33 -0
  33. data/lib/vagrant-vcloud/action/sync_folders.rb +82 -0
  34. data/lib/vagrant-vcloud/action/unmap_port_forwardings.rb +75 -0
  35. data/lib/vagrant-vcloud/config.rb +132 -0
  36. data/lib/vagrant-vcloud/driver/base.rb +459 -0
  37. data/lib/vagrant-vcloud/driver/meta.rb +151 -0
  38. data/lib/vagrant-vcloud/driver/version_5_1.rb +1669 -0
  39. data/lib/vagrant-vcloud/errors.rb +62 -0
  40. data/lib/vagrant-vcloud/model/forwarded_port.rb +64 -0
  41. data/lib/vagrant-vcloud/plugin.rb +78 -0
  42. data/lib/vagrant-vcloud/provider.rb +41 -0
  43. data/lib/vagrant-vcloud/util/compile_forwarded_ports.rb +31 -0
  44. data/lib/vagrant-vcloud/version.rb +5 -0
  45. data/locales/en.yml +55 -0
  46. data/vagrant-vcloud.gemspec +34 -0
  47. metadata +273 -0
@@ -0,0 +1,17 @@
1
+ module VagrantPlugins
2
+ module VCloud
3
+ module Action
4
+ class AnnounceSSHExec < Vagrant::Action::Builtin::SSHExec
5
+ def initialize(app, env)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ sshInfo = env[:machine].ssh_info
11
+ env[:ui].success("External IP for #{env[:machine].name}: #{sshInfo[:host]}")
12
+ super
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,197 @@
1
+ require "securerandom"
2
+ require "etc"
3
+ require "netaddr"
4
+
5
+ module VagrantPlugins
6
+ module VCloud
7
+ module Action
8
+ class BuildVApp
9
+ def initialize(app, env)
10
+ @app = app
11
+ @logger = Log4r::Logger.new("vagrant_vcloud::action::build_vapp")
12
+ end
13
+
14
+ def call(env)
15
+
16
+ # FIXME: we need to find a way to clean things up when a SIGINT get
17
+ # called... see env[:interrupted] in the vagrant code
18
+
19
+ cfg = env[:machine].provider_config
20
+ cnx = cfg.vcloud_cnx.driver
21
+ vmName = env[:machine].name
22
+
23
+ if !cfg.ip_subnet.nil?
24
+
25
+ @logger.debug("Input address: #{cfg.ip_subnet}")
26
+
27
+ begin
28
+ cidr = NetAddr::CIDR.create(cfg.ip_subnet)
29
+ rescue NetAddr::ValidationError
30
+ raise Errors::InvalidSubnet, :message => cfg.ip_subnet
31
+ end
32
+ if cidr.bits > 30
33
+ @logger.debug("Subnet too small!")
34
+ raise Errors::SubnetTooSmall, :message => cfg.ip_subnet
35
+ end
36
+
37
+ rangeAddresses = cidr.range(0)
38
+
39
+ @logger.debug("Range: #{rangeAddresses}")
40
+
41
+ rangeAddresses.shift # Delete the "network" address from the range.
42
+ gatewayIp = rangeAddresses.shift # Retrieve the first usable IP, to be used as a gateway.
43
+ rangeAddresses.reverse! # Reverse the array in place.
44
+ rangeAddresses.shift # Delete the "broadcast" address from the range.
45
+ rangeAddresses.reverse! # Reverse back the array.
46
+
47
+ @logger.debug("Gateway IP: #{gatewayIp.to_s}")
48
+ @logger.debug("Netmask: #{cidr.wildcard_mask}")
49
+ @logger.debug("IP Pool: #{rangeAddresses.first}-#{rangeAddresses.last}")
50
+
51
+ network_options = {
52
+ :name => "Vagrant-vApp-Net",
53
+ :gateway => gatewayIp.to_s,
54
+ :netmask => cidr.wildcard_mask,
55
+ :start_address => rangeAddresses.first,
56
+ :end_address => rangeAddresses.last,
57
+ :fence_mode => "natRouted",
58
+ :ip_allocation_mode => "POOL",
59
+ :parent_network => cfg.vdc_network_id,
60
+ :enable_firewall => "false",
61
+ :dns1 => "8.8.8.8", # FIXME: We should let the user choose DNS servers and then
62
+ :dns2 => "8.8.4.4" # fall back to Google's if they're not specified.
63
+ }
64
+
65
+ else
66
+
67
+ # No IP subnet specified, reverting to defaults
68
+ network_options = {
69
+ :name => "Vagrant-vApp-Net",
70
+ :gateway => "10.1.1.1",
71
+ :netmask => "255.255.255.0",
72
+ :start_address => "10.1.1.2",
73
+ :end_address => "10.1.1.254",
74
+ :fence_mode => "natRouted",
75
+ :ip_allocation_mode => "POOL",
76
+ :parent_network => cfg.vdc_network_id,
77
+ :enable_firewall => "false",
78
+ :dns1 => "8.8.8.8",
79
+ :dns2 => "8.8.4.4"
80
+ }
81
+
82
+ end
83
+
84
+ if env[:machine].get_vapp_id.nil?
85
+
86
+ env[:ui].info("Building vApp...")
87
+
88
+ compose = cnx.compose_vapp_from_vm(
89
+ cfg.vdc_id,
90
+ "Vagrant-#{Etc.getlogin}-#{Socket.gethostname.downcase}-#{SecureRandom.hex(4)}",
91
+ "vApp created by #{Etc.getlogin} running on #{Socket.gethostname.downcase} using vagrant-vcloud on #{Time.now.strftime("%B %d, %Y")}",
92
+ {
93
+ vmName => cfg.catalog_item[:vms_hash][env[:machine].box.name.to_s][:id]
94
+ },
95
+ network_options
96
+ )
97
+ @logger.debug("Launched Compose vApp")
98
+ # Wait for the task to finish.
99
+ wait = cnx.wait_task_completion(compose[:task_id])
100
+
101
+ if !wait[:errormsg].nil?
102
+ raise Errors::ComposeVAppError, :message => wait[:errormsg]
103
+ end
104
+
105
+
106
+ # Fetch thenewly created vApp ID
107
+ vAppId = compose[:vapp_id]
108
+
109
+ # putting the vApp Id in a globally reachable var and file.
110
+ env[:machine].vappid = vAppId
111
+
112
+ # Fetching new vApp object to check stuff.
113
+ newVApp = cnx.get_vapp(vAppId)
114
+
115
+ # FIXME: Add a lot of error handling for each step here !
116
+
117
+ if newVApp
118
+ env[:ui].success("vApp #{newVApp[:name]} created successfully!")
119
+
120
+ # Add the vm id as machine.id
121
+ newVMProperties = newVApp[:vms_hash].fetch(vmName)
122
+ env[:machine].id = newVMProperties[:id]
123
+
124
+ ### SET GUEST CONFIG
125
+ #env[:ui].info("Setting Guest Customization on ID: [#{vmName}] of vApp [#{newVApp[:name]}]")
126
+ setCustom = cnx.set_vm_guest_customization(newVMProperties[:id], vmName, {
127
+ :enabled => true,
128
+ :admin_passwd_enabled => false
129
+ })
130
+ cnx.wait_task_completion(setCustom)
131
+
132
+ # @logger.info("Starting VM [#{vmName}] - this will take a while as vShield Edge is getting deployed as well")
133
+ # env[:ui].info("Starting VM [#{vmName}] - this will take a while as vShield Edge is getting deployed as well")
134
+ # poweronVM = cnx.poweron_vm(newVMProperties[:id])
135
+ # cnx.wait_task_completion(poweronVM)
136
+
137
+ else
138
+ env[:ui].error("vApp #{newVApp[:name]} creation failed!")
139
+ raise
140
+ end
141
+ else
142
+ env[:ui].info("Adding VM to existing vApp...")
143
+
144
+ recompose = cnx.recompose_vapp_from_vm(
145
+ env[:machine].get_vapp_id,
146
+ {
147
+ vmName => cfg.catalog_item[:vms_hash][env[:machine].box.name.to_s][:id]
148
+ },
149
+ network_options
150
+ )
151
+
152
+ @logger.info("Waiting for the add to complete ...")
153
+
154
+ # Wait for the task to finish.
155
+ wait = cnx.wait_task_completion(recompose[:task_id])
156
+
157
+ newVApp = cnx.get_vapp(env[:machine].get_vapp_id)
158
+
159
+ # FIXME: Add a lot of error handling for each step here !
160
+
161
+ if newVApp
162
+
163
+ #env[:ui].success("VM #{vmName} added to #{newVApp[:name]} successfully!")
164
+ #@logger.info("VM #{vmName} added to #{newVApp[:name]} successfully!")
165
+
166
+ # Add the vm id as machine.id
167
+ newVMProperties = newVApp[:vms_hash].fetch(vmName)
168
+ env[:machine].id = newVMProperties[:id]
169
+
170
+ ### SET GUEST CONFIG
171
+ #@logger.info("Setting Guest Customization on ID: [#{newVMProperties[:id]}] of vApp [#{newVApp[:name]}]")
172
+ #env[:ui].info("Setting Guest Customization on ID: [#{vmName}] of vApp [#{newVApp[:name]}]")
173
+ setCustom = cnx.set_vm_guest_customization(newVMProperties[:id], vmName, {
174
+ :enabled => true,
175
+ :admin_passwd_enabled => false
176
+ })
177
+ cnx.wait_task_completion(setCustom)
178
+
179
+ # @logger.info("Starting VM [#{vmName}]")
180
+ # env[:ui].info("Starting VM [#{vmName}]")
181
+ # poweronVM = cnx.poweron_vm(newVMProperties[:id])
182
+ # cnx.wait_task_completion(poweronVM)
183
+
184
+ else
185
+
186
+ env[:ui].error("VM #{vmName} add to #{newVApp[:name]} failed!")
187
+ raise
188
+ end
189
+ end
190
+
191
+ @app.call env
192
+
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,68 @@
1
+ #require "vcloud-rest/connection"
2
+ require "log4r"
3
+
4
+ module VagrantPlugins
5
+ module VCloud
6
+ module Action
7
+ class ConnectVCloud
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_vcloud::action::connect_vcloud")
11
+ end
12
+
13
+ def call(env)
14
+ config = env[:machine].provider_config
15
+
16
+ # begin
17
+ # Avoid recreating a new session each time.
18
+ if !config.vcloud_cnx
19
+ @logger.info("Connecting to vCloud Director...")
20
+
21
+ @logger.debug("config.hostname : #{config.hostname}")
22
+ @logger.debug("config.username : #{config.username}")
23
+ @logger.debug("config.password : #{config.password}")
24
+ @logger.debug("config.org_name : #{config.org_name}")
25
+
26
+ # Create the vcloud-rest connection object with the configuration
27
+ # information.
28
+ config.vcloud_cnx = Driver::Meta.new(
29
+ config.hostname,
30
+ config.username,
31
+ config.password,
32
+ config.org_name
33
+ )
34
+
35
+ @logger.info("Logging into vCloud Director...")
36
+ config.vcloud_cnx.login
37
+
38
+ # Check for the vCloud Director authentication token
39
+ if config.vcloud_cnx.driver.auth_key
40
+ @logger.info("Logged in successfully!")
41
+ @logger.debug(
42
+ "x-vcloud-authorization=#{config.vcloud_cnx.driver.auth_key}"
43
+ )
44
+ else
45
+ @logger.info("Login failed in to #{config.hostname}.")
46
+ env[:ui].error("Login failed in to #{config.hostname}.")
47
+ raise
48
+ end
49
+ else
50
+ @logger.info("Already logged in, using current session")
51
+ @logger.debug(
52
+ "x-vcloud-authorization=#{config.vcloud_cnx.driver.auth_key}"
53
+ )
54
+ end
55
+
56
+ @app.call env
57
+
58
+ # rescue Exception => e
59
+ # ### When bad credentials, we get here.
60
+ # @logger.debug("Couldn't connect to vCloud Director: #{e.inspect}")
61
+ # raise VagrantPlugins::VCloud::Errors::VCloudError, :message => e.message
62
+ # end
63
+
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,69 @@
1
+ require "i18n"
2
+
3
+ module VagrantPlugins
4
+ module VCloud
5
+ module Action
6
+ class Destroy
7
+
8
+ def initialize(app, env)
9
+ @app = app
10
+ @logger = Log4r::Logger.new("vagrant_vcloud::action::destroy")
11
+ end
12
+
13
+ def call(env)
14
+
15
+ cfg = env[:machine].provider_config
16
+ cnx = cfg.vcloud_cnx.driver
17
+ vAppId = env[:machine].get_vapp_id
18
+ vmId = env[:machine].id
19
+
20
+ cfg.org = cnx.get_organization_by_name(cfg.org_name)
21
+ cfg.vdc_id = cnx.get_vdc_id_by_name(cfg.org, cfg.vdc_name)
22
+
23
+ testvApp = cnx.get_vapp(vAppId)
24
+
25
+ @logger.debug("Number of VMs in the vApp: #{testvApp[:vms_hash].count}")
26
+
27
+ if testvApp[:vms_hash].count == 1
28
+ env[:ui].info("Single VM left in the vApp, destroying the vApp...")
29
+
30
+ if cfg.vdc_edge_gateway_ip && cfg.vdc_edge_gateway
31
+ env[:ui].info("Removing mapping for ip #{cfg.vdc_edge_gateway_ip} on Edge #{cfg.vdc_edge_gateway}.")
32
+ @logger.debug("Deleting Edge Gateway rules - vdc id: #{cfg.vdc_id}")
33
+ edge_remove = cnx.remove_edge_gateway_rules(cfg.vdc_edge_gateway, cfg.vdc_id, cfg.vdc_edge_gateway_ip, vAppId)
34
+ cnx.wait_task_completion(edge_remove)
35
+ end
36
+
37
+ env[:ui].info("Powering off vApp...")
38
+ vAppStopTask = cnx.poweroff_vapp(vAppId)
39
+ vAppStopWait = cnx.wait_task_completion(vAppStopTask)
40
+
41
+ if !vAppStopWait[:errormsg].nil?
42
+ raise Errors::StopVAppError, :message => vAppStopWait[:errormsg]
43
+ end
44
+
45
+ env[:ui].info("Destroying vApp...")
46
+ vAppDeleteTask = cnx.delete_vapp(vAppId)
47
+ @logger.debug("vApp Delete task id #{vAppDeleteTask}")
48
+ cnx.wait_task_completion(vAppDeleteTask)
49
+
50
+
51
+ # FIXME: Look into this.
52
+ ####env[:machine].provider.driver.delete
53
+ env[:machine].id=nil
54
+ env[:machine].vappid=nil
55
+ else
56
+ env[:ui].info("Destroying VM...")
57
+ vmDeleteTask = cnx.delete_vm(vmId)
58
+ @logger.debug("VM Delete task id #{vmDeleteTask}")
59
+ cnx.wait_task_completion(vmDeleteTask)
60
+ env[:machine].id=nil
61
+ end
62
+
63
+ @app.call env
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,33 @@
1
+ module VagrantPlugins
2
+ module VCloud
3
+ module Action
4
+ class DisconnectVCloud
5
+ def initialize(app, env)
6
+ @app = app
7
+ @logger = Log4r::Logger.new("vagrant_vcloud::action::disconnect_vcloud")
8
+ end
9
+
10
+ def call(env)
11
+ begin
12
+ @logger.info("Disconnecting from vCloud Director...")
13
+
14
+ # Fetch the global vCloud Director connection handle
15
+ cnx = env[:machine].provider_config.vcloud_cnx.driver
16
+
17
+ # Delete the current vCloud Director Session
18
+ cnx.logout
19
+
20
+ # If session key doesn't exist, we are disconnected
21
+ if !cnx.auth_key
22
+ @logger.info("Disconnected from vCloud Director successfully!")
23
+ end
24
+
25
+ rescue Exception => e
26
+ #raise a properly namespaced error for Vagrant
27
+ raise Errors::VCloudError, :message => e.message
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,127 @@
1
+ module VagrantPlugins
2
+ module VCloud
3
+ module Action
4
+ class ForwardPorts
5
+ include Util::CompileForwardedPorts
6
+
7
+ def initialize(app, env)
8
+ @app = app
9
+ @logger = Log4r::Logger.new("vagrant_vcloud::action::forward_ports")
10
+ end
11
+
12
+ #--------------------------------------------------------------
13
+ # Execution
14
+ #--------------------------------------------------------------
15
+ def call(env)
16
+ @env = env
17
+
18
+ # Get the ports we're forwarding
19
+ env[:forwarded_ports] ||= compile_forwarded_ports(env[:machine].config)
20
+
21
+ @logger.debug("WE'RE GOING TO FORWARD THIS!: #{@env[:forwarded_ports]}")
22
+
23
+ forward_ports
24
+
25
+ @app.call(env)
26
+ end
27
+
28
+ def forward_ports
29
+ ports = []
30
+
31
+ # interfaces = @env[:machine].provider.driver.read_network_interfaces
32
+
33
+ cfg = @env[:machine].provider_config
34
+ cnx = cfg.vcloud_cnx.driver
35
+ vmName = @env[:machine].name
36
+ vAppId = @env[:machine].get_vapp_id
37
+
38
+ cfg.org = cnx.get_organization_by_name(cfg.org_name)
39
+ cfg.vdc_network_id = cfg.org[:networks][cfg.vdc_network_name]
40
+
41
+ @logger.debug("Getting VM info...")
42
+ vm = cnx.get_vapp(vAppId)
43
+ vmInfo = vm[:vms_hash][vmName.to_sym]
44
+
45
+
46
+ @env[:forwarded_ports].each do |fp|
47
+ message_attributes = {
48
+ :guest_port => fp.guest_port,
49
+ :host_port => fp.host_port
50
+ }
51
+
52
+ # Assuming the only reason to establish port forwarding is
53
+ # because the VM is using Virtualbox NAT networking. Host-only
54
+ # bridged networking don't require port-forwarding and establishing
55
+ # forwarded ports on these attachment types has uncertain behaviour.
56
+ @env[:ui].info("Forwarding Ports: VM port #{fp.guest_port} -> vShield Edge port #{fp.host_port}")
57
+
58
+ # Verify we have the network interface to attach to
59
+ # if !interfaces[fp.adapter]
60
+ # raise Vagrant::Errors::ForwardPortAdapterNotFound,
61
+ # :adapter => fp.adapter.to_s,
62
+ # :guest => fp.guest_port.to_s,
63
+ # :host => fp.host_port.to_s
64
+ # end
65
+
66
+ # Port forwarding requires the network interface to be a NAT interface,
67
+ # so verify that that is the case.
68
+ # if interfaces[fp.adapter][:type] != :nat
69
+ # @env[:ui].info(I18n.t("vagrant.actions.vm.forward_ports.non_nat",
70
+ # message_attributes))
71
+ # next
72
+ # end
73
+
74
+ # Add the options to the ports array to send to the driver later
75
+ ports << {
76
+ :guestip => fp.guest_ip,
77
+ :nat_internal_port => fp.guest_port,
78
+ :hostip => fp.host_ip,
79
+ :nat_external_port => fp.host_port,
80
+ :name => fp.id,
81
+ :nat_protocol => fp.protocol.upcase,
82
+ :vapp_scoped_local_id => vmInfo[:vapp_scoped_local_id]
83
+ }
84
+ end
85
+
86
+ if !ports.empty?
87
+ # We only need to forward ports if there are any to forward
88
+
89
+ @logger.debug("Here's what we should pass to the driver method: #{ports.inspect}")
90
+ @logger.debug("here's our network id #{cfg.vdc_network_id}")
91
+ # @env[:machine].provider.driver.forward_ports(ports)
92
+
93
+ # newvapp[:vms_hash].each do |key, value|
94
+
95
+ # nat_rules << { :nat_external_port => j.to_s, :nat_internal_port => "873", :nat_protocol => "UDP", :vm_scoped_local_id => value[:vapp_scoped_local_id]}
96
+ # j += 1
97
+
98
+ ### Here we apply the nat_rules to the vApp we just built
99
+
100
+ # puts "### Applying Port Forwarding NAT Rules"
101
+
102
+ addports = cnx.add_vapp_port_forwarding_rules(
103
+ vAppId,
104
+ "Vagrant-vApp-Net",
105
+ {
106
+ :fence_mode => "natRouted",
107
+ :parent_network => cfg.vdc_network_id,
108
+ :nat_policy_type => "allowTraffic",
109
+ :nat_rules => ports
110
+ })
111
+
112
+ wait = cnx.wait_task_completion(addports)
113
+
114
+ if !wait[:errormsg].nil?
115
+ raise Errors::ComposeVAppError, :message => wait[:errormsg]
116
+ end
117
+
118
+
119
+ end
120
+
121
+
122
+
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end