knife-vcenter 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/{LICENSE.txt → LICENSE} +0 -0
- data/lib/base.rb +8 -3
- data/lib/chef/knife/cloud/vcenter_service.rb +117 -81
- data/lib/chef/knife/cloud/vcenter_service_helpers.rb +15 -3
- data/lib/chef/knife/cloud/vcenter_service_options.rb +18 -17
- data/lib/chef/knife/vcenter_cluster_list.rb +19 -13
- data/lib/chef/knife/vcenter_datacenter_list.rb +19 -13
- data/lib/chef/knife/vcenter_host_list.rb +28 -19
- data/lib/chef/knife/vcenter_vm_clone.rb +39 -28
- data/lib/chef/knife/vcenter_vm_create.rb +26 -21
- data/lib/chef/knife/vcenter_vm_delete.rb +15 -10
- data/lib/chef/knife/vcenter_vm_list.rb +31 -21
- data/lib/chef/knife/vcenter_vm_show.rb +12 -13
- data/lib/knife-vcenter/version.rb +4 -2
- data/lib/lookup_service_helper.rb +421 -427
- data/lib/sso.rb +213 -218
- data/lib/support/clone_vm.rb +4 -4
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/vcenter_vm_list_spec.rb +21 -22
- metadata +6 -58
- data/.github/ISSUE_TEMPLATE.md +0 -22
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -14
- data/.gitignore +0 -21
- data/.rubocop.yml +0 -18
- data/.travis.yml +0 -16
- data/CHANGELOG.md +0 -34
- data/Gemfile +0 -3
- data/README.md +0 -219
- data/Rakefile +0 -20
- data/knife-vcenter.gemspec +0 -37
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,31 +17,36 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
20
|
+
require "chef/knife"
|
21
|
+
require "chef/knife/cloud/server/delete_options"
|
22
|
+
require "chef/knife/cloud/server/delete_command"
|
23
|
+
require "chef/knife/cloud/vcenter_service"
|
24
|
+
require "chef/knife/cloud/vcenter_service_helpers"
|
25
|
+
require "chef/knife/cloud/vcenter_service_options"
|
26
26
|
|
27
27
|
class Chef
|
28
28
|
class Knife
|
29
29
|
class Cloud
|
30
|
+
# Extends the SeverDeleteCommand for specifically vCenter
|
30
31
|
class VcenterVmDelete < ServerDeleteCommand
|
31
32
|
include ServerDeleteOptions
|
32
33
|
include VcenterServiceOptions
|
33
34
|
include VcenterServiceHelpers
|
34
35
|
|
35
|
-
banner
|
36
|
+
banner "knife vcenter vm delete NAME [NAME] (options)"
|
36
37
|
|
37
38
|
# rubocop:disable Style/GuardClause
|
39
|
+
# Validates the parameters to make sure we're good.
|
40
|
+
#
|
38
41
|
def validate_params!
|
39
42
|
if @name_args.empty?
|
40
|
-
ui.error(
|
43
|
+
ui.error("You must supply the name of the virtual machine to delete.")
|
41
44
|
exit(1) if @name_args.empty?
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
48
|
+
# Executes the command against vCenter and the Chef Server
|
49
|
+
#
|
45
50
|
def execute_command
|
46
51
|
@name_args.each do |name|
|
47
52
|
service.delete_vm(name)
|
@@ -51,4 +56,4 @@ class Chef
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
end
|
54
|
-
end
|
59
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,50 +17,60 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
20
|
+
require "chef/knife"
|
21
|
+
require "chef/knife/cloud/server/list_command"
|
22
|
+
require "chef/knife/cloud/server/list_options"
|
23
|
+
require "chef/knife/cloud/vcenter_service"
|
24
|
+
require "chef/knife/cloud/vcenter_service_helpers"
|
25
|
+
require "chef/knife/cloud/vcenter_service_options"
|
26
26
|
|
27
27
|
class Chef
|
28
|
+
# The main knife class
|
28
29
|
class Knife
|
30
|
+
# The main cloud class from knife-cloud
|
29
31
|
class Cloud
|
32
|
+
# Extends the ServerListCommand for specific vCenter
|
30
33
|
class VcenterVmList < Chef::Knife::Cloud::ServerListCommand
|
31
34
|
include VcenterServiceHelpers
|
32
35
|
include VcenterServiceOptions
|
33
36
|
|
34
|
-
banner
|
37
|
+
banner "knife vcenter vm list"
|
35
38
|
|
39
|
+
# Sets up the columns for listing out and sorts by name
|
40
|
+
#
|
36
41
|
def before_exec_command
|
37
42
|
@columns_with_info = [
|
38
|
-
{ label:
|
39
|
-
{ label:
|
40
|
-
{ label:
|
41
|
-
{ label:
|
42
|
-
{ label:
|
43
|
+
{ label: "ID", key: "vm" },
|
44
|
+
{ label: "Name", key: "name" },
|
45
|
+
{ label: "Power State", key: "power_state", value_callback: method(:format_power_status) },
|
46
|
+
{ label: "CPU Count", key: "cpu_count" },
|
47
|
+
{ label: "RAM Size (MB)", key: "memory_size_MiB", value_callback: method(:format_memory_value) }
|
43
48
|
]
|
44
49
|
|
45
|
-
@sort_by_field =
|
50
|
+
@sort_by_field = "name"
|
46
51
|
end
|
47
52
|
|
53
|
+
# Sets the color for the different status of the machines
|
54
|
+
#
|
48
55
|
def format_power_status(status)
|
49
56
|
status_check = status.value
|
50
57
|
status_color = case status_check
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
58
|
+
when "POWERED_OFF"
|
59
|
+
:red
|
60
|
+
when "POWERED_ON"
|
61
|
+
:green
|
62
|
+
when "SUSPENDED"
|
63
|
+
:yellow
|
57
64
|
end
|
58
65
|
|
59
66
|
ui.color(status.value, status_color)
|
60
67
|
end
|
61
68
|
|
69
|
+
# Formats the memory value
|
70
|
+
#
|
71
|
+
# @param [Object] value takes the number and formats it how you need it to
|
62
72
|
def format_memory_value(value)
|
63
|
-
value.to_s.reverse.gsub(/...(?=.)/,'\&,').reverse
|
73
|
+
value.to_s.reverse.gsub(/...(?=.)/, '\&,').reverse
|
64
74
|
end
|
65
75
|
end
|
66
76
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,32 +17,31 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
23
|
-
require
|
24
|
-
require
|
25
|
-
require
|
20
|
+
require "chef/knife"
|
21
|
+
require "chef/knife/cloud/server/show_options"
|
22
|
+
require "chef/knife/cloud/server/show_command"
|
23
|
+
require "chef/knife/cloud/vcenter_service"
|
24
|
+
require "chef/knife/cloud/vcenter_service_helpers"
|
25
|
+
require "chef/knife/cloud/vcenter_service_options"
|
26
26
|
|
27
27
|
class Chef
|
28
28
|
class Knife
|
29
29
|
class Cloud
|
30
|
+
# Extends the SeverShowCommand to do specific things for vCenter
|
30
31
|
class VcenterVmShow < ServerShowCommand
|
31
32
|
include ServerShowOptions
|
32
33
|
include VcenterServiceOptions
|
33
34
|
include VcenterServiceHelpers
|
34
35
|
|
35
|
-
banner
|
36
|
-
|
37
|
-
# rubocop:disable Style/GuardClause
|
36
|
+
banner "knife vcenter vm show NAME (options)"
|
38
37
|
def validate_params!
|
39
38
|
if @name_args.empty?
|
40
|
-
ui.error(
|
39
|
+
ui.error("You must supply the name of the virtual machine to display.")
|
41
40
|
exit(1) if @name_args.empty?
|
42
41
|
end
|
43
42
|
|
44
43
|
if @name_args.size > 1
|
45
|
-
ui.error(
|
44
|
+
ui.error("You may only supply one virtual machine name")
|
46
45
|
exit 1
|
47
46
|
end
|
48
47
|
|
@@ -51,4 +50,4 @@ class Chef
|
|
51
50
|
end
|
52
51
|
end
|
53
52
|
end
|
54
|
-
end
|
53
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
#
|
3
3
|
# Author:: Chef Partner Engineering (<partnereng@chef.io>)
|
4
|
-
# Copyright:: Copyright (c) 2017 Chef Software, Inc.
|
4
|
+
# Copyright:: Copyright (c) 2017-2018 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -17,6 +17,8 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
+
# Provisions machines in vCenter
|
20
21
|
module KnifeVcenter
|
21
|
-
|
22
|
+
# The version of this amazing Gem, you should <3 it.
|
23
|
+
VERSION = "2.0.1"
|
22
24
|
end
|
@@ -1,463 +1,457 @@
|
|
1
1
|
# Copyright 2014-2017 VMware, Inc. All Rights Reserved.
|
2
2
|
# SPDX-License-Identifier: MIT
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
4
|
+
require "savon"
|
5
|
+
require "nokogiri"
|
6
|
+
require "base"
|
7
7
|
# require 'sample/framework/sample_base'
|
8
8
|
|
9
9
|
# Utility class that helps use the lookup service.
|
10
10
|
class LookupServiceHelper
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
#
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
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.empty?
|
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
|
+
|
66
|
+
result = find_vapi_urls
|
67
|
+
raise "VAPI URLs not found" unless result && !result.empty?
|
68
|
+
|
69
|
+
result[node_id]
|
70
|
+
end
|
71
|
+
|
72
|
+
# Finds all the vim service endpoint URLs
|
73
|
+
# In a MxN setup where there are more than one management node;
|
74
|
+
# this method returns more than one URL
|
75
|
+
#
|
76
|
+
# @return [Hash] vim service endpoint URLs in a dictionary where
|
77
|
+
# the key is the node_id and the value is the service URL.
|
78
|
+
def find_vim_urls
|
79
|
+
find_service_url(product = "com.vmware.cis",
|
80
|
+
service = "vcenterserver",
|
81
|
+
endpoint = "com.vmware.vim",
|
82
|
+
protocol = "vmomi")
|
83
|
+
end
|
84
|
+
|
85
|
+
# Finds the vim service endpoint URL of a management node
|
86
|
+
#
|
87
|
+
# @param node_id [String] The UUID of the management node.
|
88
|
+
# @return [String] vim service endpoint URL of a management node or
|
89
|
+
# nil if no vim endpoint is found.
|
90
|
+
def find_vim_url(node_id)
|
91
|
+
raise "node_id is required" if node_id.nil?
|
92
|
+
|
93
|
+
result = find_vim_urls
|
94
|
+
raise "VIM URLs not found" unless result && !result.empty?
|
95
|
+
|
96
|
+
result[node_id]
|
97
|
+
end
|
98
|
+
|
99
|
+
# Finds all the spbm service endpoint URLs
|
100
|
+
# In a MxN setup where there are more than one management node;
|
101
|
+
# this method returns more than one URL
|
102
|
+
#
|
103
|
+
# @return [Hash] spbm service endpoint URLs in a dictionary where
|
104
|
+
# the key is the node_id and the value is the service URL.
|
105
|
+
def find_vim_pbm_urls
|
106
|
+
find_service_url(product = "com.vmware.vim.sms",
|
107
|
+
service = "sms",
|
108
|
+
endpoint = "com.vmware.vim.pbm",
|
109
|
+
protocol = "https")
|
110
|
+
end
|
111
|
+
|
112
|
+
# Finds the spbm service endpoint URL of a management node
|
113
|
+
#
|
114
|
+
# @param node_id [String] The UUID of the management node.
|
115
|
+
# @return [String] spbm service endpoint URL of a management node or
|
116
|
+
# nil if no spbm endpoint is found.
|
117
|
+
def find_vim_pbm_url(node_id)
|
118
|
+
raise "node_id is required" if node_id.nil?
|
119
|
+
|
120
|
+
result = find_vim_pbm_urls
|
121
|
+
raise "PBM URLs not found" unless result && !result.empty?
|
122
|
+
|
123
|
+
result[node_id]
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get the management node id from the instance name
|
127
|
+
#
|
128
|
+
# @param instance_name [String] The instance name of the management node
|
129
|
+
# @return [String] The UUID of the management node or
|
130
|
+
# nil is no management node is found by the given instance name
|
131
|
+
def get_mgmt_node_id(instance_name)
|
132
|
+
raise "instance_name is required" if instance_name.nil?
|
133
|
+
result = find_mgmt_nodes()
|
134
|
+
raise "Management nodes not found" unless result && result.size > 0
|
135
|
+
result[instance_name]
|
136
|
+
end
|
137
|
+
|
138
|
+
def get_mgmt_node_instance_name(node_id)
|
139
|
+
raise "node_id is required" if node_id.nil?
|
140
|
+
|
141
|
+
result = find_mgmt_nodes
|
142
|
+
raise "Management nodes not found" unless result && !result.empty?
|
143
|
+
|
144
|
+
result.each { |k, v| return k if v == node_id }
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
|
148
|
+
# Finds the instance name and UUID of the management node for M1xN1 or
|
149
|
+
# when the PSC and management services all reside on a single node.
|
150
|
+
def get_default_mgmt_node
|
151
|
+
result = find_mgmt_nodes
|
152
|
+
raise "Management nodes not found" unless result && !result.empty?
|
153
|
+
|
154
|
+
# WHY: raise MultipleManagementNodeException.new if result.size > 1
|
155
|
+
[result.keys[0], result.values[0]]
|
156
|
+
end
|
157
|
+
|
158
|
+
# Finds all the management nodes
|
159
|
+
#
|
160
|
+
# @return [Hash] management node instance name and node id (UUID) in a dictionary.
|
161
|
+
def find_mgmt_nodes
|
162
|
+
# assert self.serviceRegistration is not None
|
163
|
+
list = List.new(client, "com.vmware.cis", "vcenterserver",
|
164
|
+
"vmomi", "com.vmware.vim")
|
165
|
+
|
166
|
+
list.invoke
|
167
|
+
list.get_instance_names
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
|
172
|
+
# Finds a service URL with the given attributes.
|
173
|
+
def find_service_url(product, service, endpoint, protocol)
|
174
|
+
# assert serviceRegistration is not None
|
175
|
+
list = List.new(client, product, service, protocol, endpoint)
|
176
|
+
|
177
|
+
list.invoke
|
178
|
+
list.get_service_endpoints
|
179
|
+
end
|
180
|
+
|
181
|
+
# Gets or creates the Savon client instance.
|
182
|
+
def client
|
183
|
+
@client ||= Savon.client do |globals|
|
184
|
+
# see: http://savonrb.com/version2/globals.html
|
185
|
+
globals.wsdl wsdl_url
|
186
|
+
globals.endpoint soap_url
|
187
|
+
|
188
|
+
globals.strip_namespaces false
|
189
|
+
globals.env_namespace :S
|
190
|
+
|
191
|
+
# set like this so https connection does not fail
|
192
|
+
# TODO: find an acceptable solution for production
|
193
|
+
globals.ssl_verify_mode :none
|
194
|
+
|
195
|
+
# dev/debug settings
|
196
|
+
# globals.pretty_print_xml ENV['DEBUG_SOAP']
|
197
|
+
# globals.log ENV['DEBUG_SOAP']
|
192
198
|
end
|
199
|
+
end
|
193
200
|
end
|
194
201
|
|
195
|
-
|
196
202
|
# @abstract Base class for invocable service calls.
|
197
203
|
class Invocable
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
204
|
+
attr_reader :operation, :client, :response
|
205
|
+
|
206
|
+
# Constructs a new instance.
|
207
|
+
# @param operation [Symbol] the operation name
|
208
|
+
# @param client [Savon::Client] the client
|
209
|
+
def initialize(operation, client)
|
210
|
+
@operation = operation
|
211
|
+
@client = client
|
212
|
+
end
|
213
|
+
|
214
|
+
# Invokes the service call represented by this type.
|
215
|
+
def invoke
|
216
|
+
request = request_xml.to_s
|
217
|
+
Base.log.debug(request)
|
218
|
+
@response = client.call(operation, xml: request)
|
219
|
+
Base.log.debug(response)
|
220
|
+
self # for chaining with new
|
221
|
+
end
|
222
|
+
|
223
|
+
# Builds the request XML content.
|
224
|
+
def request_xml
|
225
|
+
builder = Builder::XmlMarkup.new
|
226
|
+
builder.instruct!(:xml, encoding: "UTF-8")
|
227
|
+
|
228
|
+
builder.tag!("S:Envelope",
|
229
|
+
"xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/") do |envelope|
|
230
|
+
envelope.tag!("S:Body") do |body|
|
231
|
+
body_xml(body)
|
232
|
+
end
|
216
233
|
end
|
234
|
+
builder.target!
|
235
|
+
end
|
217
236
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
builder.tag!("S:Envelope",
|
224
|
-
"xmlns:S" => "http://schemas.xmlsoap.org/soap/envelope/") do |envelope|
|
225
|
-
envelope.tag!("S:Body") do |body|
|
226
|
-
body_xml(body)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
builder.target!
|
230
|
-
end
|
237
|
+
# Builds the body portion of the request XML content.
|
238
|
+
# Specific service operations must override this method.
|
239
|
+
def body_xml
|
240
|
+
raise "abstract method not implemented!"
|
241
|
+
end
|
231
242
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
raise 'abstract method not implemented!'
|
236
|
-
end
|
243
|
+
# Gets the response XML content.
|
244
|
+
def response_xml
|
245
|
+
raise "illegal state: response not set yet" if response.nil?
|
237
246
|
|
238
|
-
|
239
|
-
|
240
|
-
raise 'illegal state: response not set yet' if response.nil?
|
241
|
-
@response_xml ||= Nokogiri::XML(response.to_xml)
|
242
|
-
end
|
247
|
+
@response_xml ||= Nokogiri::XML(response.to_xml)
|
248
|
+
end
|
243
249
|
|
244
|
-
|
245
|
-
|
246
|
-
|
250
|
+
def response_hash
|
251
|
+
@response_hash ||= response.to_hash
|
252
|
+
end
|
247
253
|
end
|
248
254
|
|
249
255
|
# Encapsulates the list operation of the lookup service.
|
250
256
|
class List < Invocable
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
etype.tag!("type") do |t|
|
302
|
-
t << @endpoint
|
303
|
-
end
|
304
|
-
end
|
305
|
-
end
|
257
|
+
# Constructs a new instance.
|
258
|
+
def initialize(client, product, service, protocol, endpoint)
|
259
|
+
super(:list, client)
|
260
|
+
|
261
|
+
@product = product
|
262
|
+
@service = service
|
263
|
+
@protocol = protocol
|
264
|
+
@endpoint = endpoint
|
265
|
+
end
|
266
|
+
|
267
|
+
# <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
|
268
|
+
# <S:Body>
|
269
|
+
# <List xmlns="urn:lookup">
|
270
|
+
# <_this type="LookupServiceRegistration">ServiceRegistration</_this>
|
271
|
+
# <filterCriteria>
|
272
|
+
# <serviceType>
|
273
|
+
# <product>com.vmware.cis</product>
|
274
|
+
# <type>cs.identity</type>
|
275
|
+
# </serviceType>
|
276
|
+
# <endpointType>
|
277
|
+
# <protocol>wsTrust</protocol>
|
278
|
+
# <type>com.vmware.cis.cs.identity.sso</type>
|
279
|
+
# </endpointType>
|
280
|
+
# </filterCriteria>
|
281
|
+
# </List>
|
282
|
+
# </S:Body>
|
283
|
+
# </S:Envelope>
|
284
|
+
def body_xml(body)
|
285
|
+
body.tag!("List", "xmlns" => "urn:lookup") do |list|
|
286
|
+
# TODO: use the copy that was retrieved on startup?
|
287
|
+
list.tag!("_this",
|
288
|
+
"type" => "LookupServiceRegistration") do |this|
|
289
|
+
this << "ServiceRegistration"
|
290
|
+
end
|
291
|
+
list.tag!("filterCriteria") do |criteria|
|
292
|
+
criteria.tag!("serviceType") do |stype|
|
293
|
+
stype.tag!("product") do |p|
|
294
|
+
p << @product
|
295
|
+
end
|
296
|
+
stype.tag!("type") do |t|
|
297
|
+
t << @service
|
298
|
+
end
|
299
|
+
end
|
300
|
+
criteria.tag!("endpointType") do |etype|
|
301
|
+
etype.tag!("protocol") do |p|
|
302
|
+
p << @protocol
|
303
|
+
end
|
304
|
+
etype.tag!("type") do |t|
|
305
|
+
t << @endpoint
|
306
|
+
end
|
306
307
|
end
|
308
|
+
end
|
307
309
|
end
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
=
|
315
|
-
<ListResponse xmlns="urn:lookup">
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
</ListResponse>
|
346
|
-
=
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
result[node_id] = entry[:service_endpoints][:url]
|
354
|
-
}
|
355
|
-
Base.log.debug "List: result = #{result}"
|
356
|
-
return result
|
310
|
+
end
|
311
|
+
|
312
|
+
# Gets the service endpoint information from the response.
|
313
|
+
# Support for MxN.
|
314
|
+
# @return [Hash] a hash where the key is NodeId and the Value is a Service URL
|
315
|
+
def get_service_endpoints
|
316
|
+
result = {}
|
317
|
+
# <ListResponse xmlns="urn:lookup">
|
318
|
+
# <returnval>
|
319
|
+
# <serviceVersion>2.0</serviceVersion>
|
320
|
+
# <vendorNameResourceKey/>
|
321
|
+
# <vendorNameDefault/>
|
322
|
+
# <vendorProductInfoResourceKey/>
|
323
|
+
# <vendorProductInfoDefault/>
|
324
|
+
# <serviceEndpoints>
|
325
|
+
# <url>https://pa-rdinfra3-vm7-dhcp5583.eng.vmware.com/sts/STSService/vsphere.local</url>
|
326
|
+
# <endpointType>
|
327
|
+
# <protocol>wsTrust</protocol>
|
328
|
+
# <type>com.vmware.cis.cs.identity.sso</type>
|
329
|
+
# </endpointType>
|
330
|
+
# <sslTrust>
|
331
|
+
# ...
|
332
|
+
# </sslTrust>
|
333
|
+
# </serviceEndpoints>
|
334
|
+
# <serviceNameResourceKey/>
|
335
|
+
# <serviceNameDefault/>
|
336
|
+
# <serviceDescriptionResourceKey/>
|
337
|
+
# <serviceDescriptionDefault/>
|
338
|
+
# <ownerId>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com@vsphere.local</ownerId>
|
339
|
+
# <serviceType>
|
340
|
+
# <product>com.vmware.cis</product>
|
341
|
+
# <type>cs.identity</type>
|
342
|
+
# </serviceType>
|
343
|
+
# <nodeId/>
|
344
|
+
# <serviceId>6a8a5058-5d3d-4d42-bb5e-383b91c8732e</serviceId>
|
345
|
+
# <siteId>default-first-site</siteId>
|
346
|
+
# </returnval>
|
347
|
+
# </ListResponse>
|
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]
|
357
355
|
end
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
Base.log.debug "List: result = #{result}"
|
394
|
-
return result
|
356
|
+
Base.log.debug "List: result = #{result}"
|
357
|
+
result
|
358
|
+
end
|
359
|
+
|
360
|
+
def get_instance_names
|
361
|
+
result = {}
|
362
|
+
# <serviceAttributes>
|
363
|
+
# <key>com.vmware.cis.cm.GroupInternalId</key>
|
364
|
+
# <value>com.vmware.vim.vcenter</value>
|
365
|
+
# </serviceAttributes>
|
366
|
+
# <serviceAttributes>
|
367
|
+
# <key>com.vmware.cis.cm.ControlScript</key>
|
368
|
+
# <value>vmware-vpxd.sh</value>
|
369
|
+
# </serviceAttributes>
|
370
|
+
# <serviceAttributes>
|
371
|
+
# <key>com.vmware.cis.cm.HostId</key>
|
372
|
+
# <value>906477a1-24c6-4d48-9e99-55ef962878f7</value>
|
373
|
+
# </serviceAttributes>
|
374
|
+
# <serviceAttributes>
|
375
|
+
# <key>com.vmware.vim.vcenter.instanceName</key>
|
376
|
+
# <value>pa-rdinfra3-vm7-dhcp5583.eng.vmware.com</value>
|
377
|
+
# </serviceAttributes>
|
378
|
+
Base.log.debug "List: response_hash = #{response_hash}"
|
379
|
+
return_val = response_hash[:list_response][:returnval]
|
380
|
+
return_val = [return_val] if return_val.is_a? Hash
|
381
|
+
return_val.each do |entry|
|
382
|
+
node_id = entry[:node_id]
|
383
|
+
# TODO: is it possible there be 0 or 1 attrs? if so, deal with it.
|
384
|
+
attrs = entry[:service_attributes]
|
385
|
+
Base.log.debug "List: attrs=#{attrs}"
|
386
|
+
attrs.each do |attr|
|
387
|
+
if attr[:key] == "com.vmware.vim.vcenter.instanceName"
|
388
|
+
result[attr[:value]] = node_id
|
389
|
+
end
|
390
|
+
end
|
395
391
|
end
|
392
|
+
Base.log.debug "List: result = #{result}"
|
393
|
+
result
|
394
|
+
end
|
396
395
|
end
|
397
396
|
|
398
397
|
# Encapsulates the RetrieveServiceContent operation of the lookup service.
|
399
398
|
class RetrieveServiceContent < Invocable
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
rsc.tag!("_this", "type" => "LookupServiceInstance") do |this|
|
418
|
-
this << "ServiceInstance"
|
419
|
-
end
|
420
|
-
end
|
421
|
-
end
|
422
|
-
|
423
|
-
=begin
|
424
|
-
...
|
425
|
-
<RetrieveServiceContentResponse xmlns="urn:lookup">
|
426
|
-
<returnval>
|
427
|
-
<lookupService type="LookupLookupService">lookupService</lookupService>
|
428
|
-
<serviceRegistration type="LookupServiceRegistration">ServiceRegistration</serviceRegistration>
|
429
|
-
<deploymentInformationService type="LookupDeploymentInformationService">deploymentInformationService</deploymentInformationService>
|
430
|
-
<l10n type="LookupL10n">l10n</l10n>
|
431
|
-
</returnval>
|
432
|
-
</RetrieveServiceContentResponse>
|
433
|
-
...
|
434
|
-
=end
|
435
|
-
def get_service_registration
|
436
|
-
Base.log.debug "RetrieveServiceContent: response_hash = #{response_hash}"
|
437
|
-
return_val = response_hash[:retrieve_service_content_response][:returnval]
|
438
|
-
result = return_val[:service_registration]
|
439
|
-
Base.log.debug "RetrieveServiceContent: result = #{result}"
|
440
|
-
result
|
399
|
+
# Constructs a new instance.
|
400
|
+
def initialize(client)
|
401
|
+
super(:retrieve_service_content, client)
|
402
|
+
end
|
403
|
+
|
404
|
+
# <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
|
405
|
+
# <S:Body>
|
406
|
+
# <RetrieveServiceContent xmlns="urn:lookup">
|
407
|
+
# <_this type="LookupServiceInstance">ServiceInstance</_this>
|
408
|
+
# </RetrieveServiceContent>
|
409
|
+
# </S:Body>
|
410
|
+
# </S:Envelope>
|
411
|
+
def body_xml(body)
|
412
|
+
body.tag!("RetrieveServiceContent", "xmlns" => "urn:lookup") do |rsc|
|
413
|
+
rsc.tag!("_this", "type" => "LookupServiceInstance") do |this|
|
414
|
+
this << "ServiceInstance"
|
415
|
+
end
|
441
416
|
end
|
417
|
+
end
|
418
|
+
|
419
|
+
# ...
|
420
|
+
# <RetrieveServiceContentResponse xmlns="urn:lookup">
|
421
|
+
# <returnval>
|
422
|
+
# <lookupService type="LookupLookupService">lookupService</lookupService>
|
423
|
+
# <serviceRegistration type="LookupServiceRegistration">ServiceRegistration</serviceRegistration>
|
424
|
+
# <deploymentInformationService type="LookupDeploymentInformationService">deploymentInformationService</deploymentInformationService>
|
425
|
+
# <l10n type="LookupL10n">l10n</l10n>
|
426
|
+
# </returnval>
|
427
|
+
# </RetrieveServiceContentResponse>
|
428
|
+
# ...
|
429
|
+
def get_service_registration
|
430
|
+
Base.log.debug "RetrieveServiceContent: response_hash = #{response_hash}"
|
431
|
+
return_val = response_hash[:retrieve_service_content_response][:returnval]
|
432
|
+
result = return_val[:service_registration]
|
433
|
+
Base.log.debug "RetrieveServiceContent: result = #{result}"
|
434
|
+
result
|
435
|
+
end
|
442
436
|
end
|
443
437
|
|
444
|
-
class MultipleManagementNodeException <
|
438
|
+
class MultipleManagementNodeException < RuntimeError
|
445
439
|
end
|
446
440
|
|
447
441
|
# main: quick self tester
|
448
|
-
if
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
442
|
+
if $PROGRAM_NAME == __FILE__
|
443
|
+
Base.log.level = Logger::DEBUG if ENV["DEBUG"]
|
444
|
+
sample = SelfTestSample.new
|
445
|
+
sample.ls_ip = ARGV[0] || "10.67.245.207"
|
446
|
+
# MXN: sample.ls_ip = '10.160.42.83'
|
447
|
+
# MXN: sample.ls_ip = '10.160.35.191'
|
448
|
+
# MAYBE: sample.main() # for arg parsing
|
449
|
+
ls_helper = LookupServiceHelper.new(sample)
|
450
|
+
ls_helper.connect
|
451
|
+
puts "***************************************"
|
452
|
+
puts "SSO URL: #{ls_helper.find_sso_url}"
|
453
|
+
puts "VAPI URL: #{ls_helper.find_vapi_urls}"
|
454
|
+
puts "VIM URL: #{ls_helper.find_vim_urls}"
|
455
|
+
puts "PBM URL: #{ls_helper.find_vim_pbm_urls}"
|
456
|
+
puts "Mgmt Nodes: #{ls_helper.find_mgmt_nodes}"
|
463
457
|
end
|