kitchen-vcenter 1.5.0 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31833a2dfb60dba469a3c03aa8261cc4639760770cb33b913909950009e5603b
4
- data.tar.gz: c0c663f9b4ac33fdc505dab121ba33112d22b7cc9df59213a1aa1858c1191aa4
3
+ metadata.gz: 4830a5da83f0ac1eba8ce606f4151ff369058478452776699f45b52277bd4943
4
+ data.tar.gz: c7761ff930c8c78194dafe5c5ea7b55e4a27b1db992f4f1c678a66308cf75bb2
5
5
  SHA512:
6
- metadata.gz: 4c5ef3e005c6f281b651c197a46a1bb84d38c3261973d5dc909d1924afd398a8c4debc2746f0de3f84d5e2dcd294a3e0537fb8df4210733abd9e7eb94ff9a40c
7
- data.tar.gz: 66bc5bcb9263cbd8ab91757555f32daa26b0b2148c792ab1dd62613053bab7efdfa83673d6afbcc0e97621b393d7fb2f3339b853856f958d158f718cc16f43af
6
+ metadata.gz: 4986789d6c04264fcbf426176c3453427cf8a3f4b8cc951efe77a7b4d353b10aa20570c63f59b33294992f8a889b38b49454a25257ae6722a4431bb332272f4a
7
+ data.tar.gz: 3335539aeb36bd96b4e044c774501bee318ab1130a89cbb46fd319af83ee2d27952a9e8d232f3a1170b6baf196ee63cf6fd08bd952c920733d4993baffe8ea97
@@ -20,5 +20,5 @@
20
20
  # The main kitchen-vcenter module
21
21
  module KitchenVcenter
22
22
  # The version of this version of test-kitchen we assume enterprises want.
23
- VERSION = "1.5.0"
23
+ VERSION = "2.0.0"
24
24
  end
@@ -18,15 +18,8 @@
18
18
  #
19
19
 
20
20
  require "kitchen"
21
- require "rbvmomi"
22
- require "sso"
23
- require "base"
24
- require "lookup_service_helper"
25
- require "vapi"
26
- require "com/vmware/cis"
27
- require "com/vmware/cis/tagging"
28
- require "com/vmware/vcenter"
29
- require "com/vmware/vcenter/vm"
21
+ require "vsphere-automation-cis"
22
+ require "vsphere-automation-vcenter"
30
23
  require "support/clone_vm"
31
24
  require "securerandom"
32
25
  require "uri"
@@ -37,7 +30,7 @@ module Kitchen
37
30
  module Driver
38
31
  # Extends the Base class for vCenter
39
32
  class Vcenter < Kitchen::Driver::Base
40
- attr_accessor :connection_options, :ipaddress, :vapi_config, :session_svc, :session_id
33
+ attr_accessor :connection_options, :ipaddress, :api_client
41
34
 
42
35
  required_config :vcenter_username
43
36
  required_config :vcenter_password
@@ -53,7 +46,6 @@ module Kitchen
53
46
  default_config :resource_pool, nil
54
47
  default_config :clone_type, :full
55
48
  default_config :cluster, nil
56
- default_config :lookup_service_host, nil
57
49
  default_config :network_name, nil
58
50
  default_config :tags, nil
59
51
 
@@ -72,7 +64,6 @@ module Kitchen
72
64
  # @todo This does not allow to specify cluster AND pool yet
73
65
  unless config[:cluster].nil?
74
66
  cluster = get_cluster(config[:cluster])
75
- # @todo Check for active hosts, to avoid "A specified parameter was not correct: spec.pool"
76
67
  config[:resource_pool] = cluster.resource_pool
77
68
  else
78
69
  # Find the first resource pool on any cluster
@@ -111,30 +102,38 @@ module Kitchen
111
102
  }
112
103
 
113
104
  # Create an object from which the clone operation can be called
114
- clone_obj = Support::CloneVm.new(connection_options, options)
115
- state[:hostname] = clone_obj.clone
116
- state[:vm_name] = config[:vm_name]
105
+ new_vm = Support::CloneVm.new(connection_options, options)
106
+ new_vm.clone
107
+
108
+ state[:hostname] = new_vm.ip
109
+ state[:vm_name] = new_vm.name
117
110
 
118
111
  unless config[:tags].nil? || config[:tags].empty?
112
+ tag_api = VSphereAutomation::CIS::TaggingTagApi.new(api_client)
113
+ vm_tags = tag_api.list.value
114
+ raise format("No configured tags found on VCenter, but %s specified", config[:tags].to_s) if vm_tags.empty?
115
+
119
116
  valid_tags = {}
120
- vm_tags = Com::Vmware::Cis::Tagging::Tag.new(vapi_config)
121
- vm_tags.list.each do |uid|
122
- tag = vm_tags.get(uid)
123
- valid_tags[tag.name] = tag.id
117
+ vm_tags.each do |uid|
118
+ tag = tag_api.get(uid)
119
+
120
+ valid_tags[tag.value.name] = tag.value.id if tag.is_a? VSphereAutomation::CIS::CisTaggingTagResult
124
121
  end
125
122
 
126
123
  # Error out on undefined tags
127
124
  invalid = config[:tags] - valid_tags.keys
128
125
  raise format("Specified tag(s) %s not valid", invalid.join(",")) unless invalid.empty?
129
-
130
- tag_service = Com::Vmware::Cis::Tagging::TagAssociation.new(vapi_config)
131
-
132
- # calls needs a DynamicID object which we construct from type and mobID
133
- mobid = get_vm(config[:vm_name]).vm
134
- dynamic_id = Com::Vmware::Vapi::Std::DynamicID.new(type: "VirtualMachine", id: mobid)
135
-
126
+ tag_service = VSphereAutomation::CIS::TaggingTagAssociationApi.new(api_client)
136
127
  tag_ids = config[:tags].map { |name| valid_tags[name] }
137
- tag_service.attach_multiple_tags_to_object(dynamic_id, tag_ids)
128
+
129
+ request_body = {
130
+ object_id: {
131
+ id: get_vm(config[:vm_name]).vm,
132
+ type: "VirtualMachine",
133
+ },
134
+ tag_ids: tag_ids,
135
+ }
136
+ tag_service.attach_multiple_tags_to_object(request_body)
138
137
  end
139
138
  end
140
139
 
@@ -146,18 +145,20 @@ module Kitchen
146
145
 
147
146
  save_and_validate_parameters
148
147
  connect
148
+
149
149
  vm = get_vm(state[:vm_name])
150
+ unless vm.nil?
151
+ vm_api = VSphereAutomation::VCenter::VMApi.new(api_client)
150
152
 
151
- vm_obj = Com::Vmware::Vcenter::VM.new(vapi_config)
153
+ # shut the machine down if it is running
154
+ if vm.power_state == "POWERED_ON"
155
+ power = VSphereAutomation::VCenter::VmPowerApi.new(api_client)
156
+ power.stop(vm.vm)
157
+ end
152
158
 
153
- # shut the machine down if it is running
154
- if vm.power_state.value == "POWERED_ON"
155
- power = Com::Vmware::Vcenter::Vm::Power.new(vapi_config)
156
- power.stop(vm.vm)
159
+ # delete the vm
160
+ vm_api.delete(vm.vm)
157
161
  end
158
-
159
- # delete the vm
160
- vm_obj.delete(vm.vm)
161
162
  end
162
163
 
163
164
  private
@@ -195,22 +196,20 @@ module Kitchen
195
196
  #
196
197
  # @param [name] name is the name of the datacenter
197
198
  def datacenter_exists?(name)
198
- filter = Com::Vmware::Vcenter::Datacenter::FilterSpec.new(names: Set.new([name]))
199
- dc_obj = Com::Vmware::Vcenter::Datacenter.new(vapi_config)
200
- dc = dc_obj.list(filter)
199
+ dc_api = VSphereAutomation::VCenter::DatacenterApi.new(api_client)
200
+ dcs = dc_api.list({ filter_names: name }).value
201
201
 
202
- raise format("Unable to find data center: %s", name) if dc.empty?
202
+ raise format("Unable to find data center: %s", name) if dcs.empty?
203
203
  end
204
204
 
205
205
  # Checks if a network exists or not
206
206
  #
207
207
  # @param [name] name is the name of the Network
208
208
  def network_exists?(name)
209
- net_obj = Com::Vmware::Vcenter::Network.new(vapi_config)
210
- filter = Com::Vmware::Vcenter::Network::FilterSpec.new(names: Set.new([name]))
211
- net = net_obj.list(filter)
209
+ net_api = VSphereAutomation::VCenter::NetworkApi.new(api_client)
210
+ nets = net_api.list({ filter_names: name }).value
212
211
 
213
- raise format("Unable to find target network: %s", name) if net.empty?
212
+ raise format("Unable to find target network: %s", name) if nets.empty?
214
213
  end
215
214
 
216
215
  # Validates the host name of the server you can connect to
@@ -218,56 +217,58 @@ module Kitchen
218
217
  # @param [name] name is the name of the host
219
218
  def get_host(name)
220
219
  # create a host object to work with
221
- host_obj = Com::Vmware::Vcenter::Host.new(vapi_config)
220
+ host_api = VSphereAutomation::VCenter::HostApi.new(api_client)
222
221
 
223
222
  if name.nil?
224
- host = host_obj.list
223
+ hosts = host_api.list.value
225
224
  else
226
- filter = Com::Vmware::Vcenter::Host::FilterSpec.new(names: Set.new([name]))
227
- host = host_obj.list(filter)
225
+ hosts = host_api.list({ filter_names: name }).value
228
226
  end
229
227
 
230
- raise format("Unable to find target host: %s", name) if host.empty?
228
+ raise format("Unable to find target host: %s", name) if hosts.empty?
231
229
 
232
- host[0]
230
+ hosts.first
233
231
  end
234
232
 
235
233
  # Gets the folder you want to create the VM
236
234
  #
237
235
  # @param [name] name is the name of the folder
238
236
  def get_folder(name)
239
- # Create a filter to ensure that only the named folder is returned
240
- filter = Com::Vmware::Vcenter::Folder::FilterSpec.new(names: Set.new([name]))
241
- folder_obj = Com::Vmware::Vcenter::Folder.new(vapi_config)
242
- folder = folder_obj.list(filter)
237
+ folder_api = VSphereAutomation::VCenter::FolderApi.new(api_client)
238
+ folders = folder_api.list({ filter_names: name }).value
243
239
 
244
- raise format("Unable to find folder: %s", name) if folder.empty?
240
+ raise format("Unable to find folder: %s", name) if folders.empty?
245
241
 
246
- folder[0].folder
242
+ folders.first.folder
247
243
  end
248
244
 
249
245
  # Gets the name of the VM you are creating
250
246
  #
251
247
  # @param [name] name is the name of the VM
252
248
  def get_vm(name)
253
- filter = Com::Vmware::Vcenter::VM::FilterSpec.new(names: Set.new([name]))
254
- vm_obj = Com::Vmware::Vcenter::VM.new(vapi_config)
255
- vm_obj.list(filter)[0]
249
+ vm_api = VSphereAutomation::VCenter::VMApi.new(api_client)
250
+ vms = vm_api.list({ filter_names: name }).value
251
+
252
+ vms.first
256
253
  end
257
254
 
258
255
  # Gets the info of the cluster
259
256
  #
260
257
  # @param [name] name is the name of the Cluster
261
258
  def get_cluster(name)
262
- cl_obj = Com::Vmware::Vcenter::Cluster.new(vapi_config)
259
+ cluster_api = VSphereAutomation::VCenter::ClusterApi.new(api_client)
260
+ clusters = cluster_api.list({ filter_names: name }).value
263
261
 
264
- # @todo: Use Cluster::FilterSpec to only get the cluster which was asked
265
- # filter = Com::Vmware::Vcenter::Cluster::FilterSpec.new(clusters: Set.new(['...']))
266
- clusters = cl_obj.list.select { |cluster| cluster.name == name }
267
262
  raise format("Unable to find Cluster: %s", name) if clusters.empty?
268
263
 
269
- cluster_id = clusters[0].cluster
270
- cl_obj.get(cluster_id)
264
+ cluster_id = clusters.first.cluster
265
+
266
+ host_api = VSphereAutomation::VCenter::HostApi.new(api_client)
267
+ hosts = host_api.list({ filter_clusters: cluster_id, connection_states: "CONNECTED" }).value
268
+
269
+ raise format("Unable to find active host in cluster %s", name) if hosts.empty?
270
+
271
+ cluster_api.get(cluster_id).value
271
272
  end
272
273
 
273
274
  # Gets the name of the resource pool
@@ -276,92 +277,47 @@ module Kitchen
276
277
  # @param [name] name is the name of the ResourcePool
277
278
  def get_resource_pool(name)
278
279
  # Create a resource pool object
279
- rp_obj = Com::Vmware::Vcenter::ResourcePool.new(vapi_config)
280
+ rp_api = VSphereAutomation::VCenter::ResourcePoolApi.new(api_client)
280
281
 
281
282
  # If no name has been set, use the first resource pool that can be found,
282
283
  # otherwise try to find by given name
283
284
  if name.nil?
284
285
  # Remove default pool for first pass (<= 1.2.1 behaviour to pick first user-defined pool found)
285
- resource_pool = rp_obj.list.delete_if { |pool| pool.name == "Resources" }
286
- debug("Search of all resource pools found: " + resource_pool.map { |pool| pool.name }.to_s)
286
+ resource_pools = rp_api.list.value.delete_if { |pool| pool.name == "Resources" }
287
+ debug("Search of all resource pools found: " + resource_pools.map { |pool| pool.name }.to_s)
287
288
 
288
289
  # Revert to default pool, if no user-defined pool found (> 1.2.1 behaviour)
289
290
  # (This one might not be found under some circumstances by the statement above)
290
- return get_resource_pool("Resources") if resource_pool.empty?
291
+ return get_resource_pool("Resources") if resource_pools.empty?
291
292
  else
292
- # create a filter to find the named resource pool
293
- filter = Com::Vmware::Vcenter::ResourcePool::FilterSpec.new(names: Set.new([name]))
294
- resource_pool = rp_obj.list(filter)
295
- debug("Search for resource pools found: " + resource_pool.map { |pool| pool.name }.to_s)
293
+ resource_pools = rp_api.list({ filter_names: name }).value
294
+ debug("Search for resource pools found: " + resource_pools.map { |pool| pool.name }.to_s)
296
295
  end
297
296
 
298
- raise format("Unable to find Resource Pool: %s", name) if resource_pool.empty?
297
+ raise format("Unable to find Resource Pool: %s", name) if resource_pools.empty?
299
298
 
300
- resource_pool[0].resource_pool
301
- end
302
-
303
- # Get location of lookup service
304
- def lookup_service_host
305
- # Allow manual overrides
306
- return config[:lookup_service_host] unless config[:lookup_service_host].nil?
307
-
308
- # Retrieve SSO service via RbVmomi, which is always co-located with the Lookup Service.
309
- vim = RbVmomi::VIM.connect @connection_options
310
- vim_settings = vim.serviceContent.setting.setting
311
- sso_url = vim_settings.select { |o| o.key == "config.vpxd.sso.sts.uri" }&.first&.value
312
-
313
- # Configuration fallback, if no SSO URL found for some reason
314
- ls_host = sso_url.nil? ? config[:vcenter_host] : URI.parse(sso_url).host
315
- debug("Using Lookup Service at: " + ls_host)
316
-
317
- ls_host
318
- end
319
-
320
- # Get vCenter FQDN
321
- def vcenter_host
322
- # Retrieve SSO service via RbVmomi, which is always co-located with the Lookup Service.
323
- vim = RbVmomi::VIM.connect @connection_options
324
- vim_settings = vim.serviceContent.setting.setting
325
-
326
- vim_settings.select { |o| o.key == "VirtualCenter.FQDN" }.first.value
299
+ resource_pools.first.resource_pool
327
300
  end
328
301
 
329
302
  # The main connect method
330
303
  #
331
304
  def connect
332
- # Configure the connection to vCenter
333
- lookup_service_helper = LookupServiceHelper.new(lookup_service_host)
334
- vapi_urls = lookup_service_helper.find_vapi_urls
335
- debug("Found vAPI endpoints: [" + vapi_urls.to_s + "]")
336
-
337
- vim_urls = lookup_service_helper.find_vim_urls
338
- debug("Found VIM endpoints: [" + vim_urls.to_s + "]")
339
-
340
- node_id = vim_urls.select { |id, url| url.include? vcenter_host }.keys.first
341
- debug("NodeID of vCenter " + config[:vcenter_host] + " is " + node_id.to_s)
342
-
343
- vapi_url = lookup_service_helper.find_vapi_url(node_id)
344
- debug("vAPI Endpoint for vCenter is " + vapi_url)
345
-
346
- # Create the VAPI config object
347
- ssl_options = {}
348
- ssl_options[:verify] = config[:vcenter_disable_ssl_verify] ? :none : :peer
349
- @vapi_config = VAPI::Bindings::VapiConfig.new(vapi_url, ssl_options)
350
-
351
- # get the SSO url
352
- sso_url = lookup_service_helper.find_sso_url
353
- sso = SSO::Connection.new(sso_url).login(config[:vcenter_username], config[:vcenter_password])
354
- token = sso.request_bearer_token
355
- vapi_config.set_security_context(
356
- VAPI::Security.create_saml_bearer_security_context(token.to_s)
357
- )
358
-
359
- # Login and get the session information
360
- @session_svc = Com::Vmware::Cis::Session.new(vapi_config)
361
- @session_id = session_svc.create
362
- vapi_config.set_security_context(
363
- VAPI::Security.create_session_security_context(session_id)
364
- )
305
+ configuration = VSphereAutomation::Configuration.new.tap do |c|
306
+ c.host = config[:vcenter_host]
307
+ c.username = config[:vcenter_username]
308
+ c.password = config[:vcenter_password]
309
+ c.scheme = "https"
310
+ c.verify_ssl = config[:vcenter_disable_ssl_verify] ? false : true
311
+ c.verify_ssl_host = config[:vcenter_disable_ssl_verify] ? false : true
312
+ end
313
+
314
+ @api_client = VSphereAutomation::ApiClient.new(configuration)
315
+ api_client.default_headers["Authorization"] = configuration.basic_auth_token
316
+
317
+ session_api = VSphereAutomation::CIS::SessionApi.new(api_client)
318
+ session_id = session_api.create("").value
319
+
320
+ api_client.default_headers["vmware-api-session-id"] = session_id
365
321
  end
366
322
  end
367
323
  end
@@ -2,10 +2,11 @@ require "rbvmomi"
2
2
 
3
3
  class Support
4
4
  class CloneVm
5
- attr_reader :vim, :options
5
+ attr_reader :vim, :options, :vm, :name, :path
6
6
 
7
7
  def initialize(conn_opts, options)
8
8
  @options = options
9
+ @name = options[:name]
9
10
 
10
11
  # Connect to vSphere
11
12
  @vim ||= RbVmomi::VIM.connect conn_opts
@@ -83,7 +84,7 @@ class Support
83
84
  # @todo not working yet
84
85
  # relocate_spec.folder = dest_folder
85
86
  clone_spec = RbVmomi::VIM.VirtualMachineInstantCloneSpec(location: relocate_spec,
86
- name: options[:name])
87
+ name: name)
87
88
 
88
89
  task = src_vm.InstantClone_Task(spec: clone_spec)
89
90
  else
@@ -91,24 +92,27 @@ class Support
91
92
  powerOn: options[:poweron],
92
93
  template: false)
93
94
 
94
- task = src_vm.CloneVM_Task(spec: clone_spec, folder: dest_folder, name: options[:name])
95
+ task = src_vm.CloneVM_Task(spec: clone_spec, folder: dest_folder, name: name)
95
96
  end
96
97
  task.wait_for_completion
97
98
 
98
99
  # get the IP address of the machine for bootstrapping
99
100
  # machine name is based on the path, e.g. that includes the folder
100
- name = options[:folder].nil? ? options[:name] : format("%s/%s", options[:folder][:name], options[:name])
101
- new_vm = dc.find_vm(name)
101
+ @path = options[:folder].nil? ? name : format("%s/%s", options[:folder][:name], name)
102
+ @vm = dc.find_vm(path)
102
103
 
103
- if new_vm.nil?
104
- puts format("Unable to find machine: %s", name)
104
+ if vm.nil?
105
+ puts format("Unable to find machine: %s", path)
105
106
  else
106
107
  puts "Waiting for network interfaces to become available..."
107
- sleep 2 while new_vm.guest.net.empty? || !new_vm.guest.ipAddress
108
- new_vm.guest.net[0].ipConfig.ipAddress.detect do |addr|
109
- addr.origin != "linklayer"
110
- end.ipAddress
108
+ sleep 2 while vm.guest.net.empty? || !vm.guest.ipAddress
111
109
  end
112
110
  end
111
+
112
+ def ip
113
+ vm.guest.net[0].ipConfig.ipAddress.detect do |addr|
114
+ addr.origin != "linklayer"
115
+ end.ipAddress
116
+ end
113
117
  end
114
118
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kitchen-vcenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chef Software
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-12 00:00:00.000000000 Z
11
+ date: 2019-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rbvmomi
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '6.6'
61
+ version: '0.1'
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '6.6'
68
+ version: '0.1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '1.7'
75
+ version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '1.7'
82
+ version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rake
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -102,11 +102,8 @@ extensions: []
102
102
  extra_rdoc_files: []
103
103
  files:
104
104
  - LICENSE
105
- - lib/base.rb
106
105
  - lib/kitchen-vcenter/version.rb
107
106
  - lib/kitchen/driver/vcenter.rb
108
- - lib/lookup_service_helper.rb
109
- - lib/sso.rb
110
107
  - lib/support/clone_vm.rb
111
108
  homepage: https://github.com/chef/kitchen-vcenter
112
109
  licenses:
@@ -127,8 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
124
  - !ruby/object:Gem::Version
128
125
  version: '0'
129
126
  requirements: []
130
- rubyforge_project:
131
- rubygems_version: 2.7.6
127
+ rubygems_version: 3.0.2
132
128
  signing_key:
133
129
  specification_version: 4
134
130
  summary: Test Kitchen driver for VMare vCenter
data/lib/base.rb DELETED
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
- #
3
- # Author:: Chef Partner Engineering (<partnereng@chef.io>)
4
- # Copyright:: Copyright (c) 2017 Chef Software, Inc.
5
- # License:: Apache License, Version 2.0
6
- #
7
- # Licensed under the Apache License, Version 2.0 (the "License");
8
- # you may not use this file except in compliance with the License.
9
- # You may obtain a copy of the License at
10
- #
11
- # http://www.apache.org/licenses/LICENSE-2.0
12
- #
13
- # Unless required by applicable law or agreed to in writing, software
14
- # distributed under the License is distributed on an "AS IS" BASIS,
15
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- # See the License for the specific language governing permissions and
17
- # limitations under the License.
18
- #
19
-
20
- require "logger"
21
-
22
- module Base
23
- attr_accessor :log
24
-
25
- def self.log
26
- @log ||= init_logger
27
- end
28
-
29
- def self.init_logger
30
- log = Logger.new(STDOUT)
31
- log.progname = "Knife VCenter"
32
- log.level = Logger::INFO
33
- log
34
- end
35
- end
@@ -1,464 +0,0 @@
1
- # Copyright 2014-2017 VMware, Inc. All Rights Reserved.
2
- # SPDX-License-Identifier: MIT
3
-
4
- require "savon"
5
- require "nokogiri"
6
- require "base"
7
- # require 'sample/framework/sample_base'
8
-
9
- # Utility class that helps use the lookup service.
10
- class LookupServiceHelper
11
- attr_reader :sample, :wsdl_url, :soap_url
12
- attr_reader :serviceRegistration
13
-
14
- # Constructs a new instance.
15
- # @param [Object] host the associated sample, which provides access
16
- # to the configuration properties of the sample
17
- def initialize(host)
18
- @soap_url = format("https://%s/lookupservice/sdk", host)
19
- @wsdl_url = format("https://%s/lookupservice/wsdl/lookup.wsdl", host)
20
- end
21
-
22
- # Connects to the lookup service.
23
- def connect
24
- rsc = RetrieveServiceContent.new(client).invoke
25
- @serviceRegistration = rsc.get_service_registration
26
- Base.log.info "service registration = #{serviceRegistration}"
27
- end
28
-
29
- # Finds the SSO service URL.
30
- # In a MxN setup where there are more than one PSC nodes;
31
- # This method returns the first SSO service endpoint URL
32
- # as returned by the lookup service.
33
- #
34
- # @return [String] SSO Service endpoint URL.
35
- def find_sso_url
36
- result = find_service_url(product = "com.vmware.cis",
37
- service = "cs.identity",
38
- endpoint = "com.vmware.cis.cs.identity.sso",
39
- protocol = "wsTrust")
40
- raise "SSO URL not found" unless result && result.size > 0
41
-
42
- result.values[0]
43
- end
44
-
45
- # Finds all the vAPI service endpoint URLs.
46
- # In a MxN setup where there are more than one management node;
47
- # this method returns more than one URL
48
- #
49
- # @return [Hash] vapi service endpoint URLs in a dictionary
50
- # where the key is the node_id and the value is the service URL.
51
- def find_vapi_urls
52
- find_service_url(product = "com.vmware.cis",
53
- service = "cs.vapi",
54
- endpoint = "com.vmware.vapi.endpoint",
55
- protocol = "vapi.json.https.public")
56
- end
57
-
58
- # Finds the vapi service endpoint URL of a management node.
59
- #
60
- # @param node_id [String] The UUID of the management node.
61
- # @return [String] vapi service endpoint URL of a management node or
62
- # nil if no vapi endpoint is found.
63
- def find_vapi_url(node_id)
64
- raise "node_id is required" if node_id.nil?
65
- result = find_vapi_urls()
66
- raise "VAPI URLs not found" unless result && result.size > 0
67
- result[node_id]
68
- end
69
-
70
- # Finds all the vim service endpoint URLs
71
- # In a MxN setup where there are more than one management node;
72
- # this method returns more than one URL
73
- #
74
- # @return [Hash] vim service endpoint URLs in a dictionary where
75
- # the key is the node_id and the value is the service URL.
76
- def find_vim_urls
77
- find_service_url(product = "com.vmware.cis",
78
- service = "vcenterserver",
79
- endpoint = "com.vmware.vim",
80
- protocol = "vmomi")
81
- end
82
-
83
- # Finds the vim service endpoint URL of a management node
84
- #
85
- # @param node_id [String] The UUID of the management node.
86
- # @return [String] vim service endpoint URL of a management node or
87
- # nil if no vim endpoint is found.
88
- def find_vim_url(node_id)
89
- raise "node_id is required" if node_id.nil?
90
- result = find_vim_urls()
91
- raise "VIM URLs not found" unless result && result.size > 0
92
- result[node_id]
93
- end
94
-
95
- # Finds all the spbm service endpoint URLs
96
- # In a MxN setup where there are more than one management node;
97
- # this method returns more than one URL
98
- #
99
- # @return [Hash] spbm service endpoint URLs in a dictionary where
100
- # the key is the node_id and the value is the service URL.
101
- def find_vim_pbm_urls
102
- find_service_url(product = "com.vmware.vim.sms",
103
- service = "sms",
104
- endpoint = "com.vmware.vim.pbm",
105
- protocol = "https")
106
- end
107
-
108
- # Finds the spbm service endpoint URL of a management node
109
- #
110
- # @param node_id [String] The UUID of the management node.
111
- # @return [String] spbm service endpoint URL of a management node or
112
- # nil if no spbm endpoint is found.
113
- def find_vim_pbm_url(node_id)
114
- raise "node_id is required" if node_id.nil?
115
- result = find_vim_pbm_urls()
116
- raise "PBM URLs not found" unless result && result.size > 0
117
- result[node_id]
118
- end
119
-
120
- # Get the management node id from the instance name
121
- #
122
- # @param instance_name [String] The instance name of the management node
123
- # @return [String] The UUID of the management node or
124
- # nil is no management node is found by the given instance name
125
- def get_mgmt_node_id(instance_name)
126
- raise "instance_name is required" if instance_name.nil?
127
-
128
- result = find_mgmt_nodes
129
- raise "Management nodes not found" unless result && !result.empty?
130
-
131
- result[instance_name]
132
- end
133
-
134
- def get_mgmt_node_instance_name(node_id)
135
- raise "node_id is required" if node_id.nil?
136
-
137
- result = find_mgmt_nodes
138
- raise "Management nodes not found" unless result && !result.empty?
139
-
140
- result.each { |k, v| return k if v == node_id }
141
- nil
142
- end
143
-
144
- # Finds the instance name and UUID of the management node for M1xN1 or
145
- # when the PSC and management services all reside on a single node.
146
- def get_default_mgmt_node
147
- result = find_mgmt_nodes
148
- raise "Management nodes not found" unless result && !result.empty?
149
-
150
- # WHY: raise MultipleManagementNodeException.new if result.size > 1
151
- [result.keys[0], result.values[0]]
152
- end
153
-
154
- # Finds all the management nodes
155
- #
156
- # @return [Hash] management node instance name and node id (UUID) in a dictionary.
157
- def find_mgmt_nodes
158
- # assert self.serviceRegistration is not None
159
- list = List.new(client, "com.vmware.cis", "vcenterserver",
160
- "vmomi", "com.vmware.vim")
161
-
162
- list.invoke
163
- list.get_instance_names
164
- end
165
-
166
- private
167
-
168
- # Finds a service URL with the given attributes.
169
- def find_service_url(product, service, endpoint, protocol)
170
- # assert serviceRegistration is not None
171
- list = List.new(client, product, service, protocol, endpoint)
172
-
173
- list.invoke
174
- list.get_service_endpoints
175
- end
176
-
177
- # Gets or creates the Savon client instance.
178
- def client
179
- @client ||= Savon.client do |globals|
180
- # see: http://savonrb.com/version2/globals.html
181
- globals.wsdl wsdl_url
182
- globals.endpoint soap_url
183
-
184
- globals.strip_namespaces false
185
- globals.env_namespace :S
186
-
187
- # set like this so https connection does not fail
188
- # TODO: find an acceptable solution for production
189
- globals.ssl_verify_mode :none
190
-
191
- # dev/debug settings
192
- # globals.pretty_print_xml ENV['DEBUG_SOAP']
193
- # globals.log ENV['DEBUG_SOAP']
194
- end
195
- end
196
- end
197
-
198
- # @abstract Base class for invocable service calls.
199
- class Invocable
200
- attr_reader :operation, :client, :response
201
-
202
- # Constructs a new instance.
203
- # @param operation [Symbol] the operation name
204
- # @param client [Savon::Client] the client
205
- def initialize(operation, client)
206
- @operation = operation
207
- @client = client
208
- end
209
-
210
- # Invokes the service call represented by this type.
211
- def invoke
212
- request = request_xml.to_s
213
- Base.log.debug(request)
214
- @response = client.call(operation, xml: request)
215
- Base.log.debug(response)
216
- self # for chaining with new
217
- end
218
-
219
- # Builds the request XML content.
220
- def request_xml
221
- builder = Builder::XmlMarkup.new
222
- builder.instruct!(:xml, encoding: "UTF-8")
223
-
224
- builder.tag!("S:Envelope",
225
- "xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/") do |envelope|
226
- envelope.tag!("S:Body") do |body|
227
- body_xml(body)
228
- end
229
- end
230
- builder.target!
231
- end
232
-
233
- # Builds the body portion of the request XML content.
234
- # Specific service operations must override this method.
235
- def body_xml
236
- raise "abstract method not implemented!"
237
- end
238
-
239
- # Gets the response XML content.
240
- def response_xml
241
- raise "illegal state: response not set yet" if response.nil?
242
-
243
- @response_xml ||= Nokogiri::XML(response.to_xml)
244
- end
245
-
246
- def response_hash
247
- @response_hash ||= response.to_hash
248
- end
249
- end
250
-
251
- # Encapsulates the list operation of the lookup service.
252
- class List < Invocable
253
- # Constructs a new instance.
254
- def initialize(client, product, service, protocol, endpoint)
255
- super(:list, client)
256
-
257
- @product = product
258
- @service = service
259
- @protocol = protocol
260
- @endpoint = endpoint
261
- end
262
-
263
- =begin
264
- <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
265
- <S:Body>
266
- <List xmlns="urn:lookup">
267
- <_this type="LookupServiceRegistration">ServiceRegistration</_this>
268
- <filterCriteria>
269
- <serviceType>
270
- <product>com.vmware.cis</product>
271
- <type>cs.identity</type>
272
- </serviceType>
273
- <endpointType>
274
- <protocol>wsTrust</protocol>
275
- <type>com.vmware.cis.cs.identity.sso</type>
276
- </endpointType>
277
- </filterCriteria>
278
- </List>
279
- </S:Body>
280
- </S:Envelope>
281
- =end
282
- def body_xml(body)
283
- body.tag!("List", "xmlns" => "urn:lookup") do |list|
284
- # TODO: use the copy that was retrieved on startup?
285
- list.tag!("_this",
286
- "type" => "LookupServiceRegistration") do |this|
287
- this << "ServiceRegistration"
288
- end
289
- list.tag!("filterCriteria") do |criteria|
290
- criteria.tag!("serviceType") do |stype|
291
- stype.tag!("product") do |p|
292
- p << @product
293
- end
294
- stype.tag!("type") do |t|
295
- t << @service
296
- end
297
- end
298
- criteria.tag!("endpointType") do |etype|
299
- etype.tag!("protocol") do |p|
300
- p << @protocol
301
- end
302
- etype.tag!("type") do |t|
303
- t << @endpoint
304
- end
305
- end
306
- end
307
- end
308
- end
309
-
310
- # Gets the service endpoint information from the response.
311
- # Support for MxN.
312
- # @return [Hash] a hash where the key is NodeId and the Value is a Service URL
313
- def get_service_endpoints
314
- result = {}
315
- =begin
316
- <ListResponse xmlns="urn:lookup">
317
- <returnval>
318
- <serviceVersion>2.0</serviceVersion>
319
- <vendorNameResourceKey/>
320
- <vendorNameDefault/>
321
- <vendorProductInfoResourceKey/>
322
- <vendorProductInfoDefault/>
323
- <serviceEndpoints>
324
- <url>https://pa-rdinfra3-vm7-dhcp5583.eng.vmware.com/sts/STSService/vsphere.local</url>
325
- <endpointType>
326
- <protocol>wsTrust</protocol>
327
- <type>com.vmware.cis.cs.identity.sso</type>
328
- </endpointType>
329
- <sslTrust>
330
- ...
331
- </sslTrust>
332
- </serviceEndpoints>
333
- <serviceNameResourceKey/>
334
- <serviceNameDefault/>
335
- <serviceDescriptionResourceKey/>
336
- <serviceDescriptionDefault/>
337
- <ownerId>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com@vsphere.local</ownerId>
338
- <serviceType>
339
- <product>com.vmware.cis</product>
340
- <type>cs.identity</type>
341
- </serviceType>
342
- <nodeId/>
343
- <serviceId>6a8a5058-5d3d-4d42-bb5e-383b91c8732e</serviceId>
344
- <siteId>default-first-site</siteId>
345
- </returnval>
346
- </ListResponse>
347
- =end
348
- Base.log.debug "List: response_hash = #{response_hash}"
349
- return_val = response_hash[:list_response][:returnval]
350
- return_val = [return_val] if return_val.is_a? Hash
351
- return_val.each do |entry|
352
- # FYI: the node_id is sometimes null, so use the service_id in this case
353
- node_id = entry[:node_id] || entry[:service_id]
354
- result[node_id] = entry[:service_endpoints][:url]
355
- end
356
- Base.log.debug "List: result = #{result}"
357
- result
358
- end
359
-
360
- def get_instance_names
361
- result = {}
362
- =begin
363
- <serviceAttributes>
364
- <key>com.vmware.cis.cm.GroupInternalId</key>
365
- <value>com.vmware.vim.vcenter</value>
366
- </serviceAttributes>
367
- <serviceAttributes>
368
- <key>com.vmware.cis.cm.ControlScript</key>
369
- <value>vmware-vpxd.sh</value>
370
- </serviceAttributes>
371
- <serviceAttributes>
372
- <key>com.vmware.cis.cm.HostId</key>
373
- <value>906477a1-24c6-4d48-9e99-55ef962878f7</value>
374
- </serviceAttributes>
375
- <serviceAttributes>
376
- <key>com.vmware.vim.vcenter.instanceName</key>
377
- <value>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com</value>
378
- </serviceAttributes>
379
- =end
380
- Base.log.debug "List: response_hash = #{response_hash}"
381
- return_val = response_hash[:list_response][:returnval]
382
- return_val = [return_val] if return_val.is_a? Hash
383
- return_val.each do |entry|
384
- node_id = entry[:node_id]
385
- # TODO: is it possible there be 0 or 1 attrs? if so, deal with it.
386
- attrs = entry[:service_attributes]
387
- Base.log.debug "List: attrs=#{attrs}"
388
- attrs.each do |attr|
389
- if attr[:key] == "com.vmware.vim.vcenter.instanceName"
390
- result[attr[:value]] = node_id
391
- end
392
- end
393
- end
394
- Base.log.debug "List: result = #{result}"
395
- result
396
- end
397
- end
398
-
399
- # Encapsulates the RetrieveServiceContent operation of the lookup service.
400
- class RetrieveServiceContent < Invocable
401
-
402
- # Constructs a new instance.
403
- def initialize(client)
404
- super(:retrieve_service_content, client)
405
- end
406
-
407
- =begin
408
- <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
409
- <S:Body>
410
- <RetrieveServiceContent xmlns="urn:lookup">
411
- <_this type="LookupServiceInstance">ServiceInstance</_this>
412
- </RetrieveServiceContent>
413
- </S:Body>
414
- </S:Envelope>
415
- =end
416
- def body_xml(body)
417
- body.tag!("RetrieveServiceContent", "xmlns" => "urn:lookup") do |rsc|
418
- rsc.tag!("_this", "type" => "LookupServiceInstance") do |this|
419
- this << "ServiceInstance"
420
- end
421
- end
422
- end
423
-
424
- =begin
425
- ...
426
- <RetrieveServiceContentResponse xmlns="urn:lookup">
427
- <returnval>
428
- <lookupService type="LookupLookupService">lookupService</lookupService>
429
- <serviceRegistration type="LookupServiceRegistration">ServiceRegistration</serviceRegistration>
430
- <deploymentInformationService type="LookupDeploymentInformationService">deploymentInformationService</deploymentInformationService>
431
- <l10n type="LookupL10n">l10n</l10n>
432
- </returnval>
433
- </RetrieveServiceContentResponse>
434
- ...
435
- =end
436
- def get_service_registration
437
- Base.log.debug "RetrieveServiceContent: response_hash = #{response_hash}"
438
- return_val = response_hash[:retrieve_service_content_response][:returnval]
439
- result = return_val[:service_registration]
440
- Base.log.debug "RetrieveServiceContent: result = #{result}"
441
- result
442
- end
443
- end
444
-
445
- class MultipleManagementNodeException < RuntimeError
446
- end
447
-
448
- # main: quick self tester
449
- if __FILE__ == $0
450
- Base.log.level = Logger::DEBUG if ENV["DEBUG"]
451
- sample = SelfTestSample.new
452
- sample.ls_ip = ARGV[0] || "10.67.245.207"
453
- # MXN: sample.ls_ip = '10.160.42.83'
454
- # MXN: sample.ls_ip = '10.160.35.191'
455
- # MAYBE: sample.main() # for arg parsing
456
- ls_helper = LookupServiceHelper.new(sample)
457
- ls_helper.connect
458
- puts "***************************************"
459
- puts "SSO URL: #{ls_helper.find_sso_url}"
460
- puts "VAPI URL: #{ls_helper.find_vapi_urls}"
461
- puts "VIM URL: #{ls_helper.find_vim_urls}"
462
- puts "PBM URL: #{ls_helper.find_vim_pbm_urls}"
463
- puts "Mgmt Nodes: #{ls_helper.find_mgmt_nodes}"
464
- end
data/lib/sso.rb DELETED
@@ -1,268 +0,0 @@
1
- # Copyright 2014-2017 VMware, Inc. All Rights Reserved.
2
- # SPDX-License-Identifier: MIT
3
-
4
- require "savon"
5
- require "nokogiri"
6
- require "date"
7
- require "securerandom"
8
-
9
- # A little utility library for VMware SSO.
10
- # For now, this is not a general purpose library that covers all
11
- # the interfaces of the SSO service.
12
- # Specifically, the support is limited to the following:
13
- # * request bearer token.
14
- module SSO
15
- # The XML date format.
16
- DATE_FORMAT = "%FT%T.%LZ".freeze
17
-
18
- # The XML namespaces that are required: SOAP, WSDL, et al.
19
- NAMESPACES = {
20
- "xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/",
21
- "xmlns:wst" => "http://docs.oasis-open.org/ws-sx/ws-trust/200512",
22
- "xmlns:u" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
23
- "xmlns:x" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
24
- }.freeze
25
-
26
- # Provides the connection details for the SSO service.
27
- class Connection
28
- attr_accessor :sso_url, :wsdl_url, :username, :password
29
-
30
- # Creates a new instance.
31
- def initialize(sso_url, wsdl_url = nil)
32
- self.sso_url = sso_url
33
- self.wsdl_url = wsdl_url || "#{sso_url}?wsdl"
34
- end
35
-
36
- # Login with the given credentials.
37
- # Note: this does not invoke a login action, but rather stores the
38
- # credentials for use later.
39
- def login(username, password)
40
- self.username = username
41
- self.password = password
42
- self # enable builder pattern
43
- end
44
-
45
- # Gets (or creates) the Savon client instance.
46
- def client
47
- # construct and init the client proxy
48
- @client ||= Savon.client do |globals|
49
- # see: http://savonrb.com/version2/globals.html
50
- globals.wsdl wsdl_url
51
- globals.endpoint sso_url
52
-
53
- globals.strip_namespaces false
54
- globals.env_namespace :S
55
-
56
- # set like this so https connection does not fail
57
- # TODO: find an acceptable solution for production
58
- globals.ssl_verify_mode :none
59
-
60
- # dev/debug settings
61
- # globals.pretty_print_xml ENV['DEBUG_SOAP']
62
- # globals.log ENV['DEBUG_SOAP']
63
- end
64
- end
65
-
66
- # Invokes the request bearer token operation.
67
- # @return [SamlToken]
68
- def request_bearer_token
69
- rst = RequestSecurityToken.new(client, username, password)
70
- rst.invoke
71
- rst.saml_token
72
- end
73
- end
74
-
75
- # @abstract Base class for invocable service calls.
76
- class SoapInvocable
77
- attr_reader :operation, :client, :response
78
-
79
- # Constructs a new instance.
80
- # @param operation [Symbol] the SOAP operation name (in Symbol form)
81
- # @param client [Savon::Client] the client
82
- def initialize(operation, client)
83
- @operation = operation
84
- @client = client
85
- end
86
-
87
- # Invokes the service call represented by this type.
88
- def invoke
89
- request = request_xml.to_s
90
- puts "request = #{request}" if ENV["DEBUG"]
91
- @response = client.call(operation, xml: request)
92
- puts "response = #{response}" if ENV["DEBUG"]
93
- self # for chaining with new
94
- end
95
-
96
- # Builds the request XML content.
97
- def request_xml
98
- builder = Builder::XmlMarkup.new
99
- builder.instruct!(:xml, encoding: "UTF-8")
100
-
101
- builder.tag!("S:Envelope", NAMESPACES) do |envelope|
102
- if has_header?
103
- envelope.tag!("S:Header") do |header|
104
- header_xml(header)
105
- end
106
- end
107
- envelope.tag!("S:Body") do |body|
108
- body_xml(body)
109
- end
110
- end
111
- builder.target!
112
- end
113
-
114
- def has_header?
115
- true
116
- end
117
-
118
- # Builds the header portion of the SOAP request.
119
- # Specific service operations must override this method.
120
- def header_xml(_header)
121
- raise "abstract method not implemented!"
122
- end
123
-
124
- # Builds the body portion of the SOAP request.
125
- # Specific service operations must override this method.
126
- def body_xml(_body)
127
- raise "abstract method not implemented!"
128
- end
129
-
130
- # Gets the response XML content.
131
- def response_xml
132
- raise "illegal state: response not set yet" if response.nil?
133
-
134
- @response_xml ||= Nokogiri::XML(response.to_xml)
135
- end
136
-
137
- def response_hash
138
- @response_hash ||= response.to_hash
139
- end
140
- end
141
-
142
- # Encapsulates an issue operation that requests a security token
143
- # from the SSO service.
144
- class RequestSecurityToken < SoapInvocable
145
-
146
- attr_accessor :request_type, :delegatable
147
-
148
- # Constructs a new instance.
149
- def initialize(client, username, password, hours = 2)
150
- super(:issue, client)
151
-
152
- @username = username
153
- @password = password
154
- @hours = hours
155
-
156
- # TODO: these things should be configurable, so we can get
157
- # non-delegatable tokens, HoK tokens, etc.
158
- @request_type = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue"
159
- @delegatable = true
160
- end
161
-
162
- def now
163
- @now ||= Time.now.utc.to_datetime
164
- end
165
-
166
- def created
167
- @created ||= now.strftime(DATE_FORMAT)
168
- end
169
-
170
- def future
171
- @future ||= now + (2 / 24.0) # days (for DateTime math)
172
- end
173
-
174
- def expires
175
- @expires ||= future.strftime(DATE_FORMAT)
176
- end
177
-
178
- # Builds the header XML for the SOAP request.
179
- def header_xml(header)
180
- id = "uuid-" + SecureRandom.uuid
181
-
182
- # header.tag!("x:Security", "x:mustUnderstand" => "1") do |security|
183
- header.tag!("x:Security") do |security|
184
- security.tag!("u:Timestamp", "u:Id" => "_0") do |timestamp|
185
- timestamp.tag!("u:Created") do |element|
186
- element << created
187
- end
188
- timestamp.tag!("u:Expires") do |element|
189
- element << expires
190
- end
191
- end
192
-
193
- security.tag!("x:UsernameToken", "u:Id" => id) do |utoken|
194
- utoken.tag!("x:Username") do |element|
195
- element << @username
196
- end
197
- utoken.tag!("x:Password") do |element|
198
- element << @password
199
- end
200
- end
201
- end
202
- end
203
-
204
- # Builds the body XML for the SOAP request.
205
- def body_xml(body)
206
- body.tag!("wst:RequestSecurityToken") do |rst|
207
- rst.tag!("wst:RequestType") do |element|
208
- element << request_type
209
- end
210
- rst.tag!("wst:Delegatable") do |element|
211
- element << delegatable.to_s
212
- end
213
- =begin
214
- #TODO: we don't seem to need this, but I'm leaving this
215
- #here for now as a reminder.
216
- rst.tag!("wst:Lifetime") do |lifetime|
217
- lifetime.tag!("u:Created") do |element|
218
- element << created
219
- end
220
- lifetime.tag!("u:Expires") do |element|
221
- element << expires
222
- end
223
- end
224
- =end
225
- end
226
- end
227
-
228
- # Gets the saml_token from the SOAP response body.
229
- # @return [SamlToken] the requested SAML token
230
- def saml_token
231
- assertion = response_xml.at_xpath("//saml2:Assertion",
232
- "saml2" => "urn:oasis:names:tc:SAML:2.0:assertion")
233
- SamlToken.new(assertion)
234
- end
235
- end
236
-
237
- # Holds a SAML token.
238
- class SamlToken
239
- attr_reader :xml
240
-
241
- # Creates a new instance.
242
- def initialize(xml)
243
- @xml = xml
244
- end
245
-
246
- # TODO: add some getters for interesting content
247
-
248
- def to_s
249
- esc_token = xml.to_xml(indent: 0, encoding: "UTF-8")
250
- esc_token = esc_token.delete("\n")
251
- esc_token
252
- end
253
- end
254
- end
255
-
256
- # main: quick self tester
257
- if __FILE__ == $0
258
- cloudvm_ip = ARGV[0]
259
- cloudvm_ip ||= "10.20.17.0"
260
- # cloudvm_ip ||= "10.67.245.207"
261
- sso_url = "https://#{cloudvm_ip}/sts/STSService/vsphere.local"
262
- wsdl_url = "#{sso_url}?wsdl"
263
- sso = SSO::Connection.new(sso_url, wsdl_url)
264
- # sso.login("administrator@vsphere.local", "Admin!23")
265
- sso.login("root", "vmware")
266
- token = sso.request_bearer_token
267
- puts token.to_s
268
- end