vmware-vra 2.6.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -1
  3. data/CHANGELOG.md +35 -2
  4. data/README.md +91 -141
  5. data/Rakefile +1 -12
  6. data/lib/vra/catalog.rb +39 -8
  7. data/lib/vra/catalog_base.rb +62 -0
  8. data/lib/vra/catalog_item.rb +29 -75
  9. data/lib/vra/catalog_source.rb +116 -0
  10. data/lib/vra/catalog_type.rb +56 -0
  11. data/lib/vra/client.rb +62 -53
  12. data/lib/vra/deployment.rb +155 -0
  13. data/lib/vra/deployment_request.rb +117 -0
  14. data/lib/vra/{resources.rb → deployments.rb} +26 -17
  15. data/lib/vra/exceptions.rb +2 -2
  16. data/lib/vra/http.rb +20 -7
  17. data/lib/vra/request.rb +28 -36
  18. data/lib/vra/request_parameters.rb +14 -13
  19. data/lib/vra/resource.rb +33 -203
  20. data/lib/vra/version.rb +2 -2
  21. data/lib/vra.rb +15 -12
  22. data/spec/catalog_item_spec.rb +64 -222
  23. data/spec/catalog_source_spec.rb +178 -0
  24. data/spec/catalog_spec.rb +112 -72
  25. data/spec/catalog_type_spec.rb +114 -0
  26. data/spec/client_spec.rb +272 -227
  27. data/spec/deployment_request_spec.rb +192 -0
  28. data/spec/deployment_spec.rb +227 -0
  29. data/spec/deployments_spec.rb +80 -0
  30. data/spec/fixtures/resource/sample_catalog_item.json +18 -0
  31. data/spec/fixtures/resource/sample_catalog_item_2.json +18 -0
  32. data/spec/fixtures/resource/sample_catalog_source.json +20 -0
  33. data/spec/fixtures/resource/sample_catalog_type.json +49 -0
  34. data/spec/fixtures/resource/sample_dep_actions.json +58 -0
  35. data/spec/fixtures/resource/sample_dep_request.json +19 -0
  36. data/spec/fixtures/resource/sample_dep_resource.json +112 -0
  37. data/spec/fixtures/resource/sample_deployment.json +26 -0
  38. data/spec/fixtures/resource/sample_entitlements.json +25 -0
  39. data/spec/http_spec.rb +63 -61
  40. data/spec/request_spec.rb +62 -68
  41. data/spec/resource_spec.rb +71 -390
  42. data/spec/spec_helper.rb +10 -4
  43. data/vmware-vra.gemspec +3 -5
  44. metadata +44 -36
  45. data/.travis.yml +0 -14
  46. data/Jenkinsfile +0 -31
  47. data/lib/vra/catalog_request.rb +0 -126
  48. data/lib/vra/requests.rb +0 -41
  49. data/spec/catalog_request_spec.rb +0 -267
  50. data/spec/requests_spec.rb +0 -60
  51. data/spec/resources_spec.rb +0 -71
@@ -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) 2015 Chef Software, Inc.
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
- class CatalogItem
25
- attr_reader :id, :client
26
- def initialize(client, opts)
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
- if @id.nil? && @catalog_item_data.nil?
32
- raise ArgumentError, "must supply an id or a catalog item data hash"
33
- end
28
+ attr_reader :project_id
34
29
 
35
- if !@id.nil? && !@catalog_item_data.nil?
36
- raise ArgumentError, "must supply an id OR a catalog item data hash, not both"
37
- end
30
+ def initialize(client, opts = {})
31
+ super
32
+ @project_id = opts[:project_id]
33
+ validate!
38
34
 
39
- if @catalog_item_data.nil?
35
+ if @data.nil?
40
36
  fetch_catalog_item
41
37
  else
42
- @id = @catalog_item_data["id"]
38
+ @id = @data['id']
43
39
  end
44
40
  end
45
41
 
46
42
  def fetch_catalog_item
47
- @catalog_item_data = client.get_parsed("/catalog-service/api/consumer/catalogItems/#{id}")
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
- @catalog_item_data["name"]
49
+ data['name']
54
50
  end
55
51
 
56
52
  def description
57
- @catalog_item_data["description"]
58
- end
59
-
60
- def status
61
- @catalog_item_data["status"]
53
+ data['description']
62
54
  end
63
55
 
64
- def organization
65
- return {} if @catalog_item_data["organization"].nil?
66
-
67
- @catalog_item_data["organization"]
56
+ def source_id
57
+ data['sourceId']
68
58
  end
69
59
 
70
- def tenant_id
71
- organization["tenantRef"]
60
+ def source_name
61
+ data['sourceName']
72
62
  end
73
63
 
74
- def tenant_name
75
- organization["tenantLabel"]
64
+ def source
65
+ @source ||= Vra::CatalogSource.new(client, id: source_id)
76
66
  end
77
67
 
78
- def subtenant_id
79
- organization["subtenantRef"]
68
+ def type
69
+ @type ||= Vra::CatalogType.new(client, data: data['type'])
80
70
  end
81
71
 
82
- def subtenant_name
83
- organization["subtenantLabel"]
72
+ def icon_id
73
+ data['iconId']
84
74
  end
85
75
 
86
- def blueprint_id
87
- @catalog_item_data["providerBinding"]["bindingId"]
76
+ def entitle!(opts = {})
77
+ super(opts.merge(type: 'CatalogItemIdentifier'))
88
78
  end
89
79
 
90
- # @param [String] - the id of the catalog item
91
- # @param [Vra::Client] - a vra client object
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) 2015 Chef Software, Inc.
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 "ffi_yajl"
21
- require "passwordmasker"
22
- require "vra/http"
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 = opts[:base_url]
30
- @username = opts[:username]
31
- @password = PasswordMasker.new(opts[:password])
32
- @tenant = opts[:tenant]
33
- @verify_ssl = opts.fetch(:verify_ssl, true)
34
- @bearer_token = PasswordMasker.new(nil)
35
- @page_size = opts.fetch(:page_size, 20)
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 resources(*args)
54
- Vra::Resources.new(self, *args)
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 bearer_token
63
- @bearer_token.value
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 bearer_token=(value)
67
- @bearer_token.value = value
74
+ def refresh_token=(value)
75
+ @refresh_token.value = value
68
76
  end
69
77
 
70
- def bearer_token_request_body
78
+ def token_params
71
79
  {
72
- "username" => @username,
73
- "password" => @password.value,
74
- "tenant" => @tenant,
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["Accept"] = "application/json"
81
- headers["Content-Type"] = "application/json"
82
- headers["Authorization"] = "Bearer #{@bearer_token.value}" unless @bearer_token.value.nil?
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
- generate_bearer_token unless authorized?
96
+ generate_access_token unless authorized?
88
97
 
89
- raise Vra::Exception::Unauthorized, "Unable to authorize against vRA" unless authorized?
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 @bearer_token.value.nil?
102
+ return false if @access_token.value.nil?
94
103
 
95
- response = http_head("/identity/api/tokens/#{@bearer_token.value}", :skip_auth)
96
- response.success_no_content?
104
+ response = http_head(ROLES_URL, :skip_auth)
105
+ response.success?
97
106
  end
98
107
 
99
- def generate_bearer_token
100
- @bearer_token.value = nil
108
+ def generate_access_token
109
+ @access_token.value = nil
101
110
  validate_client_options!
102
111
 
103
- response = http_post("/identity/api/tokens",
104
- FFI_Yajl::Encoder.encode(bearer_token_request_body),
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
- @bearer_token.value = FFI_Yajl::Parser.parse(response.body)["id"]
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 = 1
150
- base_path = path + "?limit=#{page_size}"
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}&page=#{page}")
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