vra-restapi 1.5.2

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.
@@ -0,0 +1,61 @@
1
+ #
2
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'json'
20
+
21
+ module Vra
22
+ module Exception
23
+ class DuplicateItemsDetected < RuntimeError; end
24
+ class NotFound < RuntimeError; end
25
+ class RequestError < RuntimeError; end
26
+ class Unauthorized < RuntimeError; end
27
+
28
+ class HTTPError < RuntimeError
29
+ attr_accessor :klass, :code, :body, :errors, :path
30
+ def initialize(opts={})
31
+ @code = opts[:code]
32
+ @body = opts[:body]
33
+ @path = opts[:path]
34
+ @klass = opts[:klass]
35
+ @errors = []
36
+
37
+ parse_errors
38
+ end
39
+
40
+ def parse_errors
41
+ begin
42
+ if @body.nil?
43
+ return
44
+ end
45
+ data = JSON.parse(@body)
46
+ rescue JSON::ParserError => e
47
+ return
48
+ end
49
+
50
+ return if data.nil?
51
+ return unless data['errors'].respond_to?(:each)
52
+
53
+ data['errors'].each do |error|
54
+ @errors << error['systemMessage']
55
+ end
56
+ end
57
+ end
58
+
59
+ class HTTPNotFound < HTTPError; end
60
+ end
61
+ end
@@ -0,0 +1,97 @@
1
+ #
2
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'json'
20
+
21
+ module Vra
22
+ class Request
23
+ attr_reader :client, :id
24
+ def initialize(client, id)
25
+ @client = client
26
+ @id = id
27
+
28
+ @request_data = nil
29
+ @status = nil
30
+ @completion_state = nil
31
+ @completion_details = nil
32
+ end
33
+
34
+ def refresh
35
+ @request_data = JSON.parse(client.http_get!("/catalog-service/api/consumer/requests/#{@id}"))
36
+ rescue Vra::Exception::HTTPNotFound
37
+ raise Vra::Exception::NotFound, "request ID #{@id} is not found"
38
+ end
39
+
40
+ def refresh_if_empty
41
+ refresh if request_empty?
42
+ end
43
+
44
+ def request_empty?
45
+ @request_data.nil?
46
+ end
47
+
48
+ def status
49
+ refresh_if_empty
50
+ return if request_empty?
51
+
52
+ @request_data['phase']
53
+ end
54
+
55
+ def completed?
56
+ successful? || failed?
57
+ end
58
+
59
+ def successful?
60
+ status == 'SUCCESSFUL'
61
+ end
62
+
63
+ def failed?
64
+ status == 'FAILED'
65
+ end
66
+
67
+ def completion_state
68
+ refresh_if_empty
69
+ return if request_empty?
70
+
71
+ @request_data['requestCompletion']['requestCompletionState']
72
+ end
73
+
74
+ def completion_details
75
+ refresh_if_empty
76
+ return if request_empty?
77
+
78
+ @request_data['requestCompletion']['completionDetails']
79
+ end
80
+
81
+ def resources
82
+ resources = []
83
+
84
+ begin
85
+ request_resources = client.http_get_paginated_array!("/catalog-service/api/consumer/requests/#{@id}/resources")
86
+ rescue Vra::Exception::HTTPNotFound
87
+ raise Vra::Exception::NotFound, "resources for request ID #{@id} are not found"
88
+ end
89
+
90
+ request_resources.each do |resource|
91
+ resources << Vra::Resource.new(client, data: resource)
92
+ end
93
+
94
+ resources
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,67 @@
1
+ #
2
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ module Vra
20
+ class RequestParameters
21
+ def initialize
22
+ @entries = {}
23
+ end
24
+
25
+ def set(key, type, value)
26
+ @entries[key] = Vra::RequestParameter.new(key, type, value)
27
+ end
28
+
29
+ def delete(key)
30
+ @entries.delete(key)
31
+ end
32
+
33
+ def all_entries
34
+ @entries.values
35
+ end
36
+ end
37
+
38
+ class RequestParameter
39
+ attr_accessor :key, :type, :value
40
+ def initialize(key, type, value)
41
+ @key = key
42
+ @type = type
43
+ @value = value
44
+ end
45
+
46
+ def to_h
47
+ {
48
+ 'key' => @key,
49
+ 'value' => {
50
+ 'type' => @type,
51
+ 'value' => format_value
52
+ }
53
+ }
54
+ end
55
+
56
+ def format_value
57
+ case @type
58
+ when 'integer'
59
+ @value.to_i
60
+ when 'string'
61
+ @value.to_s
62
+ else
63
+ @value.to_s
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ #
2
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ module Vra
20
+ class Requests
21
+ def initialize(client)
22
+ @client = client
23
+ end
24
+
25
+ def all_requests
26
+ requests = []
27
+
28
+ items = @client.http_get_paginated_array!('/catalog-service/api/consumer/requests')
29
+ items.each do |item|
30
+ requests << Vra::Request.new(@client, item['id'])
31
+ end
32
+
33
+ requests
34
+ end
35
+
36
+ def by_id(id)
37
+ Vra::Request.new(@client, id)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,234 @@
1
+ #
2
+ # Author:: Chef Partner Engineering (<partnereng@chef.io>)
3
+ # Copyright:: Copyright (c) 2015 Chef Software, Inc.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+
19
+ require 'json'
20
+
21
+ module Vra
22
+ # rubocop:disable ClassLength
23
+ class Resource
24
+ attr_reader :client, :id, :resource_data
25
+
26
+ def initialize(client, opts)
27
+ @client = client
28
+ @id = opts[:id]
29
+ @resource_data = opts[:data]
30
+ @resource_actions = []
31
+
32
+ if @id.nil? && @resource_data.nil?
33
+ raise ArgumentError, 'must supply an id or a resource data hash'
34
+ end
35
+
36
+ if ! @id.nil? && ! @resource_data.nil?
37
+ raise ArgumentError, 'must supply an id OR a resource data hash, not both'
38
+ end
39
+
40
+ if @resource_data.nil?
41
+ fetch_resource_data
42
+ else
43
+ @id = @resource_data['id']
44
+ end
45
+ end
46
+
47
+ def fetch_resource_data
48
+ @resource_data = JSON.parse(client.http_get!("/catalog-service/api/consumer/resources/#{@id}"))
49
+ rescue Vra::Exception::HTTPNotFound
50
+ raise Vra::Exception::NotFound, "resource ID #{@id} does not exist"
51
+ end
52
+ alias refresh fetch_resource_data
53
+
54
+ def name
55
+ resource_data['name']
56
+ end
57
+
58
+ def description
59
+ resource_data['description']
60
+ end
61
+
62
+ def status
63
+ resource_data['status']
64
+ end
65
+
66
+ def vm?
67
+ %w(Infrastructure.Virtual Infrastructure.Cloud).include?(resource_data['resourceTypeRef']['id'])
68
+ end
69
+
70
+ def tenant_id
71
+ resource_data['organization']['tenantRef']
72
+ end
73
+
74
+ def tenant_name
75
+ resource_data['organization']['tenantLabel']
76
+ end
77
+
78
+ def subtenant_id
79
+ resource_data['organization']['subtenantRef']
80
+ end
81
+
82
+ def subtenant_name
83
+ resource_data['organization']['subtenantLabel']
84
+ end
85
+
86
+ def catalog_id
87
+ resource_data['catalogItem']['id']
88
+ end
89
+
90
+ def catalog_name
91
+ resource_data['catalogItem']['label']
92
+ end
93
+
94
+ def owner_ids
95
+ resource_data['owners'].map { |x| x['ref'] }
96
+ end
97
+
98
+ def owner_names
99
+ resource_data['owners'].map { |x| x['value'] }
100
+ end
101
+
102
+ def machine_status
103
+ status = resource_data['resourceData']['entries'].find { |x| x['key'] == 'MachineStatus' }
104
+ raise 'No MachineStatus entry available for resource' if status.nil?
105
+
106
+ status['value']['value']
107
+ end
108
+
109
+ def machine_on?
110
+ machine_status == 'On'
111
+ end
112
+
113
+ def machine_off?
114
+ machine_status == 'Off'
115
+ end
116
+
117
+ def machine_turning_on?
118
+ machine_status == 'TurningOn' || machine_status == 'MachineActivated'
119
+ end
120
+
121
+ def machine_turning_off?
122
+ %w(TurningOff ShuttingDown).include?(machine_status)
123
+ end
124
+
125
+ def machine_in_provisioned_state?
126
+ machine_status == 'MachineProvisioned'
127
+ end
128
+
129
+ def network_interfaces
130
+ return unless vm?
131
+
132
+ network_list = resource_data['resourceData']['entries'].find { |x| x['key'] == 'NETWORK_LIST' }
133
+ return if network_list.nil?
134
+
135
+ network_list['value']['items'].each_with_object([]) do |item, nics|
136
+ nic = {}
137
+ item['values']['entries'].each do |entry|
138
+ key = entry['key']
139
+ value = entry['value']['value']
140
+ nic[key] = value
141
+ end
142
+
143
+ nics << nic
144
+ end
145
+ end
146
+
147
+ def ip_addresses
148
+ return if !vm? || network_interfaces.nil?
149
+
150
+ addrs = []
151
+ network_interfaces.each do |nic|
152
+ next unless nic.key?('NETWORK_ADDRESS')
153
+ addrs << nic['NETWORK_ADDRESS']
154
+ end
155
+
156
+ addrs
157
+ end
158
+
159
+ def actions
160
+ # if this Resource instance was created with data from a "all_resources" fetch,
161
+ # it is likely missing operations data because the vRA API is not pleasant sometimes.
162
+ fetch_resource_data if resource_data['operations'].nil?
163
+
164
+ resource_data['operations']
165
+ end
166
+
167
+ def action_id_by_name(name)
168
+ return if actions.nil?
169
+
170
+ action = actions.find { |x| x['name'] == name }
171
+ return if action.nil?
172
+
173
+ action['id']
174
+ end
175
+
176
+ def destroy
177
+ action_id = action_id_by_name('Destroy')
178
+ raise Vra::Exception::NotFound, "No destroy action found for resource #{@id}" if action_id.nil?
179
+
180
+ submit_action_request(action_id)
181
+ end
182
+
183
+ def shutdown
184
+ action_id = action_id_by_name('Shutdown')
185
+ raise Vra::Exception::NotFound, "No shutdown action found for resource #{@id}" if action_id.nil?
186
+
187
+ submit_action_request(action_id)
188
+ end
189
+
190
+ def poweroff
191
+ action_id = action_id_by_name('Power Off')
192
+ raise Vra::Exception::NotFound, "No power-off action found for resource #{@id}" if action_id.nil?
193
+
194
+ submit_action_request(action_id)
195
+ end
196
+
197
+ def poweron
198
+ action_id = action_id_by_name('Power On')
199
+ raise Vra::Exception::NotFound, "No power-on action found for resource #{@id}" if action_id.nil?
200
+
201
+ submit_action_request(action_id)
202
+ end
203
+
204
+ def action_request_payload(action_id)
205
+ {
206
+ '@type' => 'ResourceActionRequest',
207
+ 'resourceRef' => {
208
+ 'id' => @id
209
+ },
210
+ 'resourceActionRef' => {
211
+ 'id' => action_id
212
+ },
213
+ 'organization' => {
214
+ 'tenantRef' => tenant_id,
215
+ 'tenantLabel' => tenant_name,
216
+ 'subtenantRef' => subtenant_id,
217
+ 'subtenantLabel' => subtenant_name
218
+ },
219
+ 'state' => 'SUBMITTED',
220
+ 'requestNumber' => 0,
221
+ 'requestData' => {
222
+ 'entries' => []
223
+ }
224
+ }
225
+ end
226
+
227
+ def submit_action_request(action_id)
228
+ payload = action_request_payload(action_id).to_json
229
+ response = client.http_post('/catalog-service/api/consumer/requests', payload)
230
+ request_id = response.headers[:location].split('/')[-1]
231
+ Vra::Request.new(client, request_id)
232
+ end
233
+ end
234
+ end