vmware-vra 2.6.1 → 3.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 +5 -5
- data/.gitignore +3 -1
- data/CHANGELOG.md +35 -2
- data/README.md +91 -141
- data/Rakefile +1 -12
- data/lib/vra/catalog.rb +39 -8
- data/lib/vra/catalog_base.rb +62 -0
- data/lib/vra/catalog_item.rb +29 -75
- data/lib/vra/catalog_source.rb +116 -0
- data/lib/vra/catalog_type.rb +56 -0
- data/lib/vra/client.rb +62 -53
- data/lib/vra/deployment.rb +155 -0
- data/lib/vra/deployment_request.rb +117 -0
- data/lib/vra/{resources.rb → deployments.rb} +26 -17
- data/lib/vra/exceptions.rb +2 -2
- data/lib/vra/http.rb +20 -7
- data/lib/vra/request.rb +28 -36
- data/lib/vra/request_parameters.rb +14 -13
- data/lib/vra/resource.rb +33 -203
- data/lib/vra/version.rb +2 -2
- data/lib/vra.rb +15 -12
- data/spec/catalog_item_spec.rb +64 -222
- data/spec/catalog_source_spec.rb +178 -0
- data/spec/catalog_spec.rb +112 -72
- data/spec/catalog_type_spec.rb +114 -0
- data/spec/client_spec.rb +272 -227
- data/spec/deployment_request_spec.rb +192 -0
- data/spec/deployment_spec.rb +227 -0
- data/spec/deployments_spec.rb +80 -0
- data/spec/fixtures/resource/sample_catalog_item.json +18 -0
- data/spec/fixtures/resource/sample_catalog_item_2.json +18 -0
- data/spec/fixtures/resource/sample_catalog_source.json +20 -0
- data/spec/fixtures/resource/sample_catalog_type.json +49 -0
- data/spec/fixtures/resource/sample_dep_actions.json +58 -0
- data/spec/fixtures/resource/sample_dep_request.json +19 -0
- data/spec/fixtures/resource/sample_dep_resource.json +112 -0
- data/spec/fixtures/resource/sample_deployment.json +26 -0
- data/spec/fixtures/resource/sample_entitlements.json +25 -0
- data/spec/http_spec.rb +63 -61
- data/spec/request_spec.rb +62 -68
- data/spec/resource_spec.rb +71 -390
- data/spec/spec_helper.rb +10 -4
- data/vmware-vra.gemspec +3 -5
- metadata +44 -36
- data/.travis.yml +0 -14
- data/Jenkinsfile +0 -31
- data/lib/vra/catalog_request.rb +0 -126
- data/lib/vra/requests.rb +0 -41
- data/spec/catalog_request_spec.rb +0 -267
- data/spec/requests_spec.rb +0 -60
- data/spec/resources_spec.rb +0 -71
data/lib/vra/catalog_item.rb
CHANGED
@@ -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)
|
4
|
+
# Copyright:: Copyright (c) 2022 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,114 +17,68 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require "ffi_yajl"
|
20
|
+
require "ffi_yajl" unless defined?(FFI_Yajl)
|
21
21
|
require "vra/catalog"
|
22
22
|
|
23
23
|
module Vra
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@client = client
|
28
|
-
@id = opts[:id]
|
29
|
-
@catalog_item_data = opts[:data]
|
24
|
+
# Class that represents the Catalog Item
|
25
|
+
class CatalogItem < Vra::CatalogBase
|
26
|
+
INDEX_URL = '/catalog/api/admin/items'
|
30
27
|
|
31
|
-
|
32
|
-
raise ArgumentError, "must supply an id or a catalog item data hash"
|
33
|
-
end
|
28
|
+
attr_reader :project_id
|
34
29
|
|
35
|
-
|
36
|
-
|
37
|
-
|
30
|
+
def initialize(client, opts = {})
|
31
|
+
super
|
32
|
+
@project_id = opts[:project_id]
|
33
|
+
validate!
|
38
34
|
|
39
|
-
if @
|
35
|
+
if @data.nil?
|
40
36
|
fetch_catalog_item
|
41
37
|
else
|
42
|
-
@id = @
|
38
|
+
@id = @data['id']
|
43
39
|
end
|
44
40
|
end
|
45
41
|
|
46
42
|
def fetch_catalog_item
|
47
|
-
@
|
43
|
+
@data = client.get_parsed("/catalog/api/admin/items/#{id}")
|
48
44
|
rescue Vra::Exception::HTTPNotFound
|
49
45
|
raise Vra::Exception::NotFound, "catalog ID #{id} does not exist"
|
50
46
|
end
|
51
47
|
|
52
48
|
def name
|
53
|
-
|
49
|
+
data['name']
|
54
50
|
end
|
55
51
|
|
56
52
|
def description
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
def status
|
61
|
-
@catalog_item_data["status"]
|
53
|
+
data['description']
|
62
54
|
end
|
63
55
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
@catalog_item_data["organization"]
|
56
|
+
def source_id
|
57
|
+
data['sourceId']
|
68
58
|
end
|
69
59
|
|
70
|
-
def
|
71
|
-
|
60
|
+
def source_name
|
61
|
+
data['sourceName']
|
72
62
|
end
|
73
63
|
|
74
|
-
def
|
75
|
-
|
64
|
+
def source
|
65
|
+
@source ||= Vra::CatalogSource.new(client, id: source_id)
|
76
66
|
end
|
77
67
|
|
78
|
-
def
|
79
|
-
|
68
|
+
def type
|
69
|
+
@type ||= Vra::CatalogType.new(client, data: data['type'])
|
80
70
|
end
|
81
71
|
|
82
|
-
def
|
83
|
-
|
72
|
+
def icon_id
|
73
|
+
data['iconId']
|
84
74
|
end
|
85
75
|
|
86
|
-
def
|
87
|
-
|
76
|
+
def entitle!(opts = {})
|
77
|
+
super(opts.merge(type: 'CatalogItemIdentifier'))
|
88
78
|
end
|
89
79
|
|
90
|
-
|
91
|
-
|
92
|
-
# @return [String] - returns a json string of the catalog template
|
93
|
-
def self.dump_template(client, id)
|
94
|
-
response = client.http_get("/catalog-service/api/consumer/entitledCatalogItems/#{id}/requests/template")
|
95
|
-
response.body
|
96
|
-
end
|
97
|
-
|
98
|
-
# @param client [Vra::Client] - a vra client object
|
99
|
-
# @param id [String] - the id of the catalog item
|
100
|
-
# @param filename [String] - the name of the file you want to output the template to
|
101
|
-
# if left blank, will default to the id of the item
|
102
|
-
# @note outputs the catalog template to a file in serialized format
|
103
|
-
def self.write_template(client, id, filename = nil)
|
104
|
-
filename ||= "#{id}.json"
|
105
|
-
begin
|
106
|
-
contents = dump_template(client, id)
|
107
|
-
data = JSON.parse(contents)
|
108
|
-
pretty_contents = JSON.pretty_generate(data)
|
109
|
-
File.write(filename, pretty_contents)
|
110
|
-
return filename
|
111
|
-
rescue Vra::Exception::HTTPError => e
|
112
|
-
raise e
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# @param [Vra::Client] - a vra client object
|
117
|
-
# @param [String] - the directory path to write the files to
|
118
|
-
# @param [Boolean] - set to true if you wish the file name to be the id of the catalog item
|
119
|
-
# @return [Array[String]] - a array of all the files that were generated
|
120
|
-
def self.dump_templates(client, dir_name = "vra_templates", use_id = false)
|
121
|
-
FileUtils.mkdir_p(dir_name) unless File.exist?(dir_name)
|
122
|
-
client.catalog.entitled_items.map do |c|
|
123
|
-
id = use_id ? c.id : c.name.tr(" ", "_")
|
124
|
-
filename = File.join(dir_name, "#{id}.json").downcase
|
125
|
-
write_template(client, c.id, filename)
|
126
|
-
filename
|
127
|
-
end
|
80
|
+
def self.entitle!(client, id)
|
81
|
+
new(client, id: id).entitle!
|
128
82
|
end
|
129
83
|
end
|
130
84
|
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Author:: Ashique Saidalavi (<ashique.saidalavi@progress.com>)
|
4
|
+
# Copyright:: Copyright (c) 2022 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
|
+
require 'ffi_yajl' unless defined?(FFI_Yajl)
|
20
|
+
|
21
|
+
module Vra
|
22
|
+
# Class that represents the Catalog Source
|
23
|
+
class CatalogSource < Vra::CatalogBase
|
24
|
+
INDEX_URL = '/catalog/api/admin/sources'
|
25
|
+
|
26
|
+
# @param client [Vra::Client] - a vra client object
|
27
|
+
# @param opts [Hash] - Contains the either id of the catalog or the data hash
|
28
|
+
# Either one of id or data hash is required, must not supply both
|
29
|
+
def initialize(client, opts)
|
30
|
+
super
|
31
|
+
validate!
|
32
|
+
fetch_data
|
33
|
+
end
|
34
|
+
|
35
|
+
def name
|
36
|
+
data['name']
|
37
|
+
end
|
38
|
+
|
39
|
+
def catalog_type_id
|
40
|
+
data['typeId']
|
41
|
+
end
|
42
|
+
|
43
|
+
def catalog_type
|
44
|
+
@catalog_type ||= Vra::CatalogType.new(client, id: catalog_type_id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def config
|
48
|
+
data['config']
|
49
|
+
end
|
50
|
+
|
51
|
+
def global?
|
52
|
+
data['global'] == true
|
53
|
+
end
|
54
|
+
|
55
|
+
def project_id
|
56
|
+
config['sourceProjectId']
|
57
|
+
end
|
58
|
+
|
59
|
+
def entitle!(opts = {})
|
60
|
+
super(opts.merge(type: 'CatalogSourceIdentifier'))
|
61
|
+
end
|
62
|
+
|
63
|
+
class << self
|
64
|
+
# Method to create a catalog source
|
65
|
+
def create(client, opts)
|
66
|
+
validate_create!(opts)
|
67
|
+
|
68
|
+
response = client.http_post(
|
69
|
+
'/catalog/api/admin/sources',
|
70
|
+
FFI_Yajl::Encoder.encode(create_params(opts)),
|
71
|
+
opts[:skip_auth] || false
|
72
|
+
)
|
73
|
+
|
74
|
+
return false unless response.success?
|
75
|
+
|
76
|
+
new(client, data: FFI_Yajl::Parser.parse(response.body))
|
77
|
+
end
|
78
|
+
|
79
|
+
def entitle!(client, id)
|
80
|
+
new(client, id: id).entitle!
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def validate_create!(opts)
|
86
|
+
%i[name catalog_type_id project_id].each do |arg|
|
87
|
+
raise ArgumentError, "#{arg} param is required to perform the create action" unless opts.key?(arg)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_params(opts)
|
92
|
+
{
|
93
|
+
'name': opts[:name],
|
94
|
+
'typeId': opts[:catalog_type_id],
|
95
|
+
'config': {
|
96
|
+
'sourceProjectId': opts[:project_id]
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def fetch_data
|
105
|
+
fetch_catalog_data && return if data.nil?
|
106
|
+
|
107
|
+
@id = data['id']
|
108
|
+
end
|
109
|
+
|
110
|
+
def fetch_catalog_data
|
111
|
+
@data = client.get_parsed("/catalog/api/admin/sources/#{id}")
|
112
|
+
rescue Vra::Exception::HTTPNotFound
|
113
|
+
raise Vra::Exception::NotFound, "catalog source ID #{id} does not exist"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Author:: Ashique Saidalavi (<ashique.saidalavi@progress.com>)
|
4
|
+
# Copyright:: Copyright (c) 2022 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
|
+
module Vra
|
20
|
+
# Class that represents the Catalog Type
|
21
|
+
class CatalogType < Vra::CatalogBase
|
22
|
+
INDEX_URL = '/catalog/api/types'
|
23
|
+
|
24
|
+
def initialize(client, opts = {})
|
25
|
+
super
|
26
|
+
validate!
|
27
|
+
fetch_data
|
28
|
+
end
|
29
|
+
|
30
|
+
def name
|
31
|
+
data['name']
|
32
|
+
end
|
33
|
+
|
34
|
+
def base_url
|
35
|
+
data['baseUri']
|
36
|
+
end
|
37
|
+
|
38
|
+
def config_schema
|
39
|
+
data['configSchema']
|
40
|
+
end
|
41
|
+
|
42
|
+
def icon_id
|
43
|
+
data['iconId']
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def fetch_data
|
49
|
+
@id = data['id'] and return unless data.nil?
|
50
|
+
|
51
|
+
@data = client.get_parsed("/catalog/api/types/#{id}")
|
52
|
+
rescue Vra::Exception::HTTPNotFound
|
53
|
+
raise Vra::Exception::NotFound, "catalog type ID #{id} does not exist"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/vra/client.rb
CHANGED
@@ -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)
|
4
|
+
# Copyright:: Copyright (c) 2022 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,22 +17,26 @@
|
|
17
17
|
# limitations under the License.
|
18
18
|
#
|
19
19
|
|
20
|
-
require
|
21
|
-
require
|
22
|
-
require
|
20
|
+
require 'ffi_yajl' unless defined?(FFI_Yajl)
|
21
|
+
require 'passwordmasker'
|
22
|
+
require 'vra/http'
|
23
23
|
|
24
24
|
module Vra
|
25
25
|
class Client
|
26
|
+
ACCESS_TOKEN_URL = '/csp/gateway/am/api/login?access_token'
|
27
|
+
ROLES_URL = '/csp/gateway/am/api/loggedin/user/orgs'
|
28
|
+
|
26
29
|
attr_accessor :page_size
|
27
30
|
|
28
31
|
def initialize(opts)
|
29
|
-
@base_url
|
30
|
-
@username
|
31
|
-
@password
|
32
|
-
@tenant
|
33
|
-
@verify_ssl
|
34
|
-
@
|
35
|
-
@
|
32
|
+
@base_url = opts[:base_url]
|
33
|
+
@username = opts[:username]
|
34
|
+
@password = PasswordMasker.new(opts[:password])
|
35
|
+
@tenant = opts[:tenant]
|
36
|
+
@verify_ssl = opts.fetch(:verify_ssl, true)
|
37
|
+
@refresh_token = PasswordMasker.new(nil)
|
38
|
+
@access_token = PasswordMasker.new(nil)
|
39
|
+
@page_size = opts.fetch(:page_size, 20)
|
36
40
|
|
37
41
|
validate_client_options!
|
38
42
|
end
|
@@ -43,15 +47,11 @@ module Vra
|
|
43
47
|
#
|
44
48
|
|
45
49
|
def catalog
|
46
|
-
Vra::Catalog.new(self)
|
47
|
-
end
|
48
|
-
|
49
|
-
def requests(*args)
|
50
|
-
Vra::Requests.new(self, *args)
|
50
|
+
@catalog ||= Vra::Catalog.new(self)
|
51
51
|
end
|
52
52
|
|
53
|
-
def
|
54
|
-
Vra::
|
53
|
+
def deployments
|
54
|
+
@deployments ||= Vra::Deployments.new(self)
|
55
55
|
end
|
56
56
|
|
57
57
|
#########################
|
@@ -59,55 +59,64 @@ module Vra
|
|
59
59
|
# client methods
|
60
60
|
#
|
61
61
|
|
62
|
-
def
|
63
|
-
@
|
62
|
+
def access_token
|
63
|
+
@access_token.value
|
64
|
+
end
|
65
|
+
|
66
|
+
def refresh_token
|
67
|
+
@refresh_token.value
|
68
|
+
end
|
69
|
+
|
70
|
+
def access_token=(value)
|
71
|
+
@access_token.value = value
|
64
72
|
end
|
65
73
|
|
66
|
-
def
|
67
|
-
@
|
74
|
+
def refresh_token=(value)
|
75
|
+
@refresh_token.value = value
|
68
76
|
end
|
69
77
|
|
70
|
-
def
|
78
|
+
def token_params
|
71
79
|
{
|
72
|
-
|
73
|
-
|
74
|
-
|
80
|
+
'username': @username,
|
81
|
+
'password': @password.value,
|
82
|
+
'tenant': @tenant
|
75
83
|
}
|
76
84
|
end
|
77
85
|
|
78
86
|
def request_headers
|
79
|
-
headers
|
80
|
-
headers[
|
81
|
-
headers[
|
82
|
-
headers[
|
87
|
+
headers = {}
|
88
|
+
headers['Accept'] = 'application/json'
|
89
|
+
headers['Content-Type'] = 'application/json'
|
90
|
+
headers['csp-auth-token'] = @access_token.value unless @access_token.value.nil?
|
91
|
+
|
83
92
|
headers
|
84
93
|
end
|
85
94
|
|
86
95
|
def authorize!
|
87
|
-
|
96
|
+
generate_access_token unless authorized?
|
88
97
|
|
89
|
-
raise Vra::Exception::Unauthorized,
|
98
|
+
raise Vra::Exception::Unauthorized, 'Unable to authorize against vRA' unless authorized?
|
90
99
|
end
|
91
100
|
|
92
101
|
def authorized?
|
93
|
-
return false if @
|
102
|
+
return false if @access_token.value.nil?
|
94
103
|
|
95
|
-
response = http_head(
|
96
|
-
response.
|
104
|
+
response = http_head(ROLES_URL, :skip_auth)
|
105
|
+
response.success?
|
97
106
|
end
|
98
107
|
|
99
|
-
def
|
100
|
-
@
|
108
|
+
def generate_access_token
|
109
|
+
@access_token.value = nil
|
101
110
|
validate_client_options!
|
102
111
|
|
103
|
-
response = http_post(
|
104
|
-
FFI_Yajl::Encoder.encode(
|
112
|
+
response = http_post(ACCESS_TOKEN_URL,
|
113
|
+
FFI_Yajl::Encoder.encode(token_params),
|
105
114
|
:skip_auth)
|
106
|
-
unless response.success_ok?
|
107
|
-
raise Vra::Exception::Unauthorized, "Unable to get bearer token: #{response.body}"
|
108
|
-
end
|
115
|
+
raise Vra::Exception::Unauthorized, "Unable to get the access token: #{response.body}" unless response.success_ok?
|
109
116
|
|
110
|
-
|
117
|
+
response_body = FFI_Yajl::Parser.parse(response.body)
|
118
|
+
@access_token.value = response_body['access_token']
|
119
|
+
@refresh_token.value = response_body['refresh_token']
|
111
120
|
end
|
112
121
|
|
113
122
|
def full_url(path)
|
@@ -140,21 +149,26 @@ module Vra
|
|
140
149
|
response.body
|
141
150
|
end
|
142
151
|
|
152
|
+
def http_delete(path, skip_auth = nil)
|
153
|
+
http_fetch(:delete, path, skip_auth)
|
154
|
+
end
|
155
|
+
|
143
156
|
def get_parsed(path)
|
144
157
|
FFI_Yajl::Parser.parse(http_get!(path))
|
145
158
|
end
|
146
159
|
|
147
|
-
def http_get_paginated_array!(path)
|
160
|
+
def http_get_paginated_array!(path, filter = nil)
|
148
161
|
items = []
|
149
|
-
page =
|
150
|
-
base_path = path + "
|
162
|
+
page = 0
|
163
|
+
base_path = path + "?$top=#{page_size}"
|
164
|
+
base_path += "&#{filter}" if filter
|
151
165
|
|
152
166
|
loop do
|
153
|
-
response = get_parsed("#{base_path}
|
167
|
+
response = get_parsed("#{base_path}&$skip=#{page * page_size}")
|
154
168
|
items += response["content"]
|
155
169
|
|
156
|
-
break if page >= response["metadata"]["totalPages"]
|
157
170
|
page += 1
|
171
|
+
break if page >= response["totalPages"]
|
158
172
|
end
|
159
173
|
|
160
174
|
if items.uniq!
|
@@ -218,10 +232,5 @@ module Vra
|
|
218
232
|
rescue URI::InvalidURIError
|
219
233
|
false
|
220
234
|
end
|
221
|
-
|
222
|
-
def fetch_subtenant_items(tenant, subtenant_name)
|
223
|
-
http_get("/identity/api/tenants/#{tenant}/subtenants?%24filter=name+eq+'#{subtenant_name}'")
|
224
|
-
end
|
225
|
-
|
226
235
|
end
|
227
236
|
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
#
|
3
|
+
# Author:: Ashique Saidalavi (<ashique.saidalavi@progress.com>)
|
4
|
+
# Copyright:: Copyright (c) 2022 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 "ffi_yajl" unless defined?(FFI_Yajl)
|
21
|
+
|
22
|
+
module Vra
|
23
|
+
# Class that represents the Deployment Object
|
24
|
+
class Deployment
|
25
|
+
INDEX_URL = '/deployment/api/deployments'
|
26
|
+
|
27
|
+
attr_reader :id
|
28
|
+
|
29
|
+
def initialize(client, opts = {})
|
30
|
+
@client = client
|
31
|
+
@id = opts[:id]
|
32
|
+
@data = opts[:data]
|
33
|
+
validate!
|
34
|
+
|
35
|
+
if @data.nil?
|
36
|
+
refresh
|
37
|
+
elsif @id.nil?
|
38
|
+
@id = @data['id']
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def name
|
43
|
+
@data['name']
|
44
|
+
end
|
45
|
+
|
46
|
+
def description
|
47
|
+
@data['description']
|
48
|
+
end
|
49
|
+
|
50
|
+
def org_id
|
51
|
+
@data['orgId']
|
52
|
+
end
|
53
|
+
|
54
|
+
def blueprint_id
|
55
|
+
@data['blueprintId']
|
56
|
+
end
|
57
|
+
|
58
|
+
def owner
|
59
|
+
@data['ownedBy']
|
60
|
+
end
|
61
|
+
|
62
|
+
def status
|
63
|
+
@data['status']
|
64
|
+
end
|
65
|
+
|
66
|
+
def successful?
|
67
|
+
status == 'CREATE_SUCCESSFUL'
|
68
|
+
end
|
69
|
+
|
70
|
+
def failed?
|
71
|
+
status == 'CREATE_FAILED'
|
72
|
+
end
|
73
|
+
|
74
|
+
def completed?
|
75
|
+
successful? || failed?
|
76
|
+
end
|
77
|
+
|
78
|
+
def actions
|
79
|
+
@actions = client.get_parsed("/deployment/api/deployments/#{id}/actions")
|
80
|
+
end
|
81
|
+
|
82
|
+
def action_id_by_name(action_name)
|
83
|
+
action = actions.find { |x| x['name'] == action_name}
|
84
|
+
return if action.nil?
|
85
|
+
|
86
|
+
action['id']
|
87
|
+
end
|
88
|
+
|
89
|
+
def resources
|
90
|
+
response = client.get_parsed("/deployment/api/deployments/#{id}/resources")
|
91
|
+
|
92
|
+
response['content'].map! { |x| Vra::Resource.new(client, id, data: x) }
|
93
|
+
end
|
94
|
+
|
95
|
+
def resource_by_id(res_id)
|
96
|
+
Vra::Resource.new(client, id, id: res_id)
|
97
|
+
end
|
98
|
+
|
99
|
+
def requests
|
100
|
+
response = client.get_parsed("/deployment/api/deployments/#{id}/requests")
|
101
|
+
|
102
|
+
response['content'].map! { |x| Vra::Request.new(client, id, id: x['id'], data: x) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def refresh
|
106
|
+
@data = client.get_parsed("/deployment/api/deployments/#{id}")
|
107
|
+
rescue Vra::Exception::HTTPNotFound
|
108
|
+
raise Vra::Exception::NotFound, "deployment with ID #{id} does not exist"
|
109
|
+
end
|
110
|
+
|
111
|
+
def destroy(reason = '')
|
112
|
+
action_id = action_id_by_name('Delete')
|
113
|
+
raise Vra::Exception::NotFound, "No destroy action found for resource #{@id}" if action_id.nil?
|
114
|
+
|
115
|
+
submit_action_request(action_id, reason)
|
116
|
+
end
|
117
|
+
|
118
|
+
def power_off(reason = '')
|
119
|
+
action_id = action_id_by_name('PowerOff')
|
120
|
+
raise Vra::Exception::NotFound, "No power-off action found for resource #{@id}" if action_id.nil?
|
121
|
+
|
122
|
+
submit_action_request(action_id, reason)
|
123
|
+
end
|
124
|
+
|
125
|
+
def power_on(reason = nil)
|
126
|
+
action_id = action_id_by_name('PowerOn')
|
127
|
+
raise Vra::Exception::NotFound, "No power-on action found for resource #{@id}" if action_id.nil?
|
128
|
+
|
129
|
+
submit_action_request(action_id, reason)
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
attr_reader :client, :data
|
135
|
+
|
136
|
+
def validate!
|
137
|
+
raise ArgumentError, 'must supply id or data hash' if @id.nil? && @data.nil?
|
138
|
+
end
|
139
|
+
|
140
|
+
def submit_action_request(action_id, reason)
|
141
|
+
response = client.http_post!("/deployment/api/deployments/#{id}/requests",
|
142
|
+
FFI_Yajl::Encoder.encode(submit_action_payload(action_id, reason)))
|
143
|
+
|
144
|
+
Vra::Request.new(client, id, data: FFI_Yajl::Parser.parse(response))
|
145
|
+
end
|
146
|
+
|
147
|
+
def submit_action_payload(action_id, reason)
|
148
|
+
{
|
149
|
+
"actionId": action_id,
|
150
|
+
"inputs": {},
|
151
|
+
"reason": reason
|
152
|
+
}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|