ibm-cloud-sdk 0.1.4 → 0.1.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 181a2894e2d8045bea0d2a33cf81570480eee1f668017b8ade96b1801d0465b2
4
- data.tar.gz: 5399f7e3e4f4b483a72e673d351605cb1f8bb09f216e5fd1a9439742f736aedf
3
+ metadata.gz: dc39c6125bcaf6730a73477c76e7e40d2eb131cf6ca34466537d65f615ed8e6a
4
+ data.tar.gz: ac29b18c76bff0ed290878e12007f1bf639654ed239ce7c27e99431acde25a17
5
5
  SHA512:
6
- metadata.gz: 237fd30c5dd4efa622de5be57a2df9e2285dcabc3d15f415d6efb6bec31b36254cbaf6c3cb32a6d8b7113b7e8709e4eddee64736515030e5e3227694dc464b4e
7
- data.tar.gz: ed36bdf032519bc35c1563f62fe279f6744b3f25b97fef4358ebd689958a48a17a5a1eafbf85f72a3c62e372dfb764b35463cc292eede788b3ad127170664ced
6
+ metadata.gz: 845d945f1e0722745858a2256decc3fd73628fd172ba88a8e49a51a7edbf06418965cc609566288e31c2965ff88f2eff33f7691628bd33ef26da0309827c5058
7
+ data.tar.gz: ee6c2c63c3472db99d9d773d77e045180594958b0ee4627b964f64365e1ea6a07c7a3159706ef326d9b87702a97218d7648c057737b14e4afc02bf4f40ae6c5f
@@ -1,6 +1,29 @@
1
1
  # Changelog
2
2
  All notable changes to the gem ibm-cloud-sdk-ruby will be documented here.
3
3
 
4
+ ## v0.1.9 - 2020-10-02
5
+ - Fix PowerVS Volume attach/detach calls
6
+
7
+ ## v0.1.8 - 2020-10-01
8
+ - Add second level instances
9
+
10
+ ## v0.1.7 - 2020-09-28
11
+ - Added Logging in IBM Cloud
12
+ - Add VCR to vpc spec
13
+ - Add exception when status of response is not in 200 range or 404
14
+ - Power IaaS Update docstrings, VM actions volumes
15
+
16
+ ## v0.1.6 - 2020-09-23
17
+ - Add PowerIaaS method to get instance info
18
+ - Return region specific PowerVS storage types
19
+ - Move VPC instance into instances and add initialization method.
20
+
21
+ ## v0.1.5 - 2020-09-21
22
+ - Added Enumerable based pagination support
23
+ - Move instance profiles
24
+ - Improve resource lookup by GUID
25
+ - Add support to create a PowerIaas volume
26
+
4
27
  ## v0.1.4 - 2020-09-17
5
28
  - Added support for the IBM Virtual Private Cloud (VPC) service
6
29
 
data/Gemfile CHANGED
@@ -5,3 +5,5 @@ gemspec
5
5
 
6
6
  gem "rake", "~> 12.0"
7
7
  gem "rspec", "~> 3.0"
8
+ gem 'vcr'
9
+ gem 'webmock'
@@ -8,6 +8,7 @@ require "ibm/cloud/sdk/power_iaas"
8
8
  require "ibm/cloud/sdk/resource_controller"
9
9
  require "ibm/cloud/sdk/version"
10
10
  require "ibm/cloud/sdk/vpc/cloud_sdk"
11
+ require "ibm/cloud/sdk/logging"
11
12
 
12
13
  module IBM
13
14
  module Cloud
@@ -0,0 +1,21 @@
1
+ require_relative 'null_logger'
2
+
3
+ module IBM
4
+ module Cloud
5
+ module SDK
6
+ class << self
7
+ attr_writer :logger
8
+ end
9
+
10
+ def self.logger
11
+ @logger ||= NullLogger.new
12
+ end
13
+
14
+ module Logging
15
+ def logger
16
+ IBM::Cloud::SDK.logger
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ require "logger"
2
+
3
+ module IBM
4
+ module Cloud
5
+ module SDK
6
+ class NullLogger < Logger
7
+ def initialize(*_args)
8
+ end
9
+
10
+ def add(*_args, &_block)
11
+ end
12
+
13
+ def debug?
14
+ false
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,11 @@
1
+ require_relative 'logging'
2
+
1
3
  module IBM
2
4
  module Cloud
3
5
  module SDK
4
6
  class PowerIaas < BaseService
7
+ include Logging
8
+
5
9
  # Create an API Client object for the Power IaaS service
6
10
  #
7
11
  # @param region [String] the IBM Power Cloud instance region
@@ -15,12 +19,23 @@ module IBM
15
19
  @region = region
16
20
  @token = token
17
21
  @tenant = tenant
22
+ RestClient.log = logger
18
23
  end
19
24
 
25
+ # Get the API service Endpoint URL
26
+ #
27
+ # @return [String] Endpoint URL
20
28
  def endpoint
21
29
  "https://#{region.sub(/-\d$/, '')}.power-iaas.cloud.ibm.com/pcloud/v1"
22
30
  end
23
31
 
32
+ # Get Power Cloud Instance information
33
+ #
34
+ # @return [Hash] CloudInstance
35
+ def get_pcloud_instance
36
+ get("cloud-instances/#{guid}")
37
+ end
38
+
24
39
  # Get all PVM instances in an IBM Power Cloud instance
25
40
  #
26
41
  # @return [Array<Hash>] all PVM Instances for this instance
@@ -34,12 +49,15 @@ module IBM
34
49
 
35
50
  # Get an IBM Power Cloud PVM instance
36
51
  #
37
- # @param pvm_instance_id [String] the PVM instance ID
52
+ # @param pvm_instance_id [String] PVM instance ID
38
53
  # @return [Hash] PVM Instances
39
54
  def get_pvm_instance(instance_id)
40
55
  get("cloud-instances/#{guid}/pvm-instances/#{instance_id}")
41
56
  end
42
57
 
58
+ # Perform 'start' action on a PVMInstance
59
+ #
60
+ # @param pvm_instance_id [String] PVM instance ID
43
61
  def start_pvm_instance(instance_id)
44
62
  post(
45
63
  "cloud-instances/#{guid}/pvm-instances/#{instance_id}/action",
@@ -47,6 +65,9 @@ module IBM
47
65
  )
48
66
  end
49
67
 
68
+ # Perform 'stop' action on a PVMInstance
69
+ #
70
+ # @param pvm_instance_id [String] PVM instance ID
50
71
  def stop_pvm_instance(instance_id)
51
72
  post(
52
73
  "cloud-instances/#{guid}/pvm-instances/#{instance_id}/action",
@@ -54,6 +75,22 @@ module IBM
54
75
  )
55
76
  end
56
77
 
78
+ # Perform 'immediate-shutdown' action on a PVMInstance
79
+ #
80
+ # @param pvm_instance_id [String] PVM instance ID
81
+ def immediate_shutdown_pvm_instance(instance_id)
82
+ post(
83
+ "cloud-instances/#{guid}/pvm-instances/#{instance_id}/action",
84
+ {"action" => "immediate-shutdown"}.to_json
85
+ )
86
+ end
87
+
88
+ # Perform 'reboot' action on a PVMInstance
89
+ #
90
+ # This action has been deprecated and replaced by 'soft-reboot'
91
+ # and 'hard-reboot'
92
+ #
93
+ # @param pvm_instance_id [String] PVM instance ID
57
94
  def reboot_pvm_instance(instance_id)
58
95
  post(
59
96
  "cloud-instances/#{guid}/pvm-instances/#{instance_id}/action",
@@ -61,10 +98,47 @@ module IBM
61
98
  )
62
99
  end
63
100
 
101
+ # Perform 'soft-reboot' action on a PVMInstance
102
+ #
103
+ # @param pvm_instance_id [String] PVM instance ID
104
+ def soft_reboot_pvm_instance(instance_id)
105
+ post(
106
+ "cloud-instances/#{guid}/pvm-instances/#{instance_id}/action",
107
+ {"action" => "soft-reboot"}.to_json
108
+ )
109
+ end
110
+
111
+ # Perform 'hard-reboot' action on a PVMInstance
112
+ #
113
+ # @param pvm_instance_id [String] PVM instance ID
114
+ def hard_reboot_pvm_instance(instance_id)
115
+ post(
116
+ "cloud-instances/#{guid}/pvm-instances/#{instance_id}/action",
117
+ {"action" => "hard-reboot"}.to_json
118
+ )
119
+ end
120
+
121
+ # Perform 'reset-state' action on a PVMInstance
122
+ #
123
+ # @param pvm_instance_id [String] PVM instance ID
124
+ def reset_state_pvm_instance(instance_id)
125
+ post(
126
+ "cloud-instances/#{guid}/pvm-instances/#{instance_id}/action",
127
+ {"action" => "reset-state"}.to_json
128
+ )
129
+ end
130
+
131
+ # Create a new PVM instance
132
+ #
133
+ # @param instance_hash [Hash] New instance attributes
134
+ # @return [Hash] PVMInstance
64
135
  def create_pvm_instance(instance_hash)
65
136
  post("cloud-instances/#{guid}/pvm-instances", instance_hash.to_json)
66
137
  end
67
138
 
139
+ # Delete a PVM instance
140
+ #
141
+ # @param pvm_instance_id [String] PVM instance ID
68
142
  def delete_pvm_instance(instance_id)
69
143
  delete("cloud-instances/#{guid}/pvm-instances/#{instance_id}")
70
144
  end
@@ -82,7 +156,7 @@ module IBM
82
156
 
83
157
  # Get an IBM Power Cloud image
84
158
  #
85
- # @param image_id [String] The ID of an Image
159
+ # @param image_id [String] Image ID
86
160
  # @return [Hash] Image
87
161
  def get_image(image_id)
88
162
  get("cloud-instances/#{guid}/images/#{image_id}")
@@ -90,6 +164,9 @@ module IBM
90
164
  nil
91
165
  end
92
166
 
167
+ # Delete an image from a cloud instance
168
+ #
169
+ # @param image_id [String] Image ID
93
170
  def delete_image(image_id)
94
171
  delete("cloud-instances/#{guid}/images/#{image_id}")
95
172
  end
@@ -107,7 +184,7 @@ module IBM
107
184
 
108
185
  # Get a specific volume
109
186
  #
110
- # @param volume_id [String] The ID of a volume
187
+ # @param volume_id [String] Image ID
111
188
  # @return [Hash] Volume
112
189
  def get_volume(volume_id)
113
190
  get("cloud-instances/#{guid}/volumes/#{volume_id}")
@@ -115,11 +192,35 @@ module IBM
115
192
 
116
193
  # Delete a volume
117
194
  #
118
- # @param volume_id [String] The ID of a volume
195
+ # @param volume_id [String] Volume ID
119
196
  def delete_volume(volume_id)
120
197
  delete("cloud-instances/#{guid}/volumes/#{volume_id}")
121
198
  end
122
199
 
200
+ # Create a volume
201
+ #
202
+ # @param volume_hash [Hash] New volume attributes
203
+ # @return [Hash] Volume
204
+ def create_volume(volume_hash)
205
+ post("cloud-instances/#{guid}/volumes", volume_hash.to_json)
206
+ end
207
+
208
+ # Attach a volume
209
+ #
210
+ # @param pvm_instance_id [String] PVM Instance ID
211
+ # @param volume_id [String] Volume ID
212
+ def attach_volume(pvm_instance_id, volume_id)
213
+ post("cloud-instances/#{guid}/pvm-instances/#{pvm_instance_id}/volumes/#{volume_id}", {})
214
+ end
215
+
216
+ # Detach a volume
217
+ #
218
+ # @param pvm_instance_id [String] PVM Instance ID
219
+ # @param volume_id [String] Volume ID
220
+ def detach_volume(pvm_instance_id, volume_id)
221
+ delete("cloud-instances/#{guid}/pvm-instances/#{pvm_instance_id}/volumes/#{volume_id}")
222
+ end
223
+
123
224
  # Get all networks in an IBM Power Cloud instance
124
225
  #
125
226
  # @return [Array<Hash>] all networks for this IBM Power Cloud instance
@@ -132,7 +233,7 @@ module IBM
132
233
 
133
234
  # Get an IBM Power Cloud network
134
235
  #
135
- # @param network_id [String] the network ID
236
+ # @param network_id [String] Network ID
136
237
  # @return [Hash] Network
137
238
  def get_network(network_id)
138
239
  get("cloud-instances/#{guid}/networks/#{network_id}")
@@ -146,42 +247,64 @@ module IBM
146
247
  end
147
248
 
148
249
  # Get a storage types list in IBM Power Cloud.
149
- # note: this mehod to be refactored under the common
250
+ # note: this method to be refactored under the common
150
251
  # IBM::Cloud::SDK::PowerIaas.endpoint when the rest api become available.
151
252
  #
152
- # @return [Hash] StorageType
253
+ # @return [Array<Hash>] StorageType
153
254
  def get_storage_types
154
- JSON.parse(RestClient.get("https://#{region.sub(/-\d$/, '')}.power-iaas.cloud.ibm.com/broker/v1/storage-types", headers))
255
+ JSON.parse(RestClient.get("https://#{region.sub(/-\d$/, '')}.power-iaas.cloud.ibm.com/broker/v1/storage-types", headers))[region]
155
256
  end
156
257
 
258
+ # Create a new network
259
+ #
260
+ # @param network_hash [Hash] New network attributes
261
+ # @return [Hash] Network
157
262
  def create_network(network_hash)
158
263
  post("cloud-instances/#{guid}/networks", network_hash.to_json)
159
264
  end
160
265
 
266
+ # Delete a network
267
+ #
268
+ # @param network_id [String] Network ID
161
269
  def delete_network(network_id)
162
270
  delete("cloud-instances/#{guid}/networks/#{network_id}")
163
271
  end
164
272
 
273
+ # Get all ports for a network
274
+ #
275
+ # @param network_id [String] Network ID
276
+ # @return [Array<Hash>] NetworkPort
165
277
  def get_network_ports(network_id)
166
278
  get("cloud-instances/#{guid}/networks/#{network_id}/ports")["ports"]
167
279
  end
168
280
 
281
+ # List the tenant's SSH Keys
282
+ #
283
+ # @return [Array<Hash>] SSHKey
169
284
  def get_ssh_keys
170
285
  get("tenants/#{tenant}")["sshKeys"]
171
286
  end
172
287
 
288
+ # Add a new SSH key to the tenant
289
+ #
290
+ # @param name [String] User defined name for the SSH key
291
+ # @param sshkey [String] SSH RSA key
292
+ # @return [Hash] SSHKey
173
293
  def create_key_pair(name, sshkey)
174
294
  payload = {"name" => name, "sshkey" => sshkey}
175
295
  post("tenants/#{tenant}/sshkeys", payload.to_json)
176
296
  end
177
297
 
298
+ # Delete SSH key from the tenant
299
+ #
300
+ # @param sshkey_name [String] SSH Key name
178
301
  def delete_key_pair(name)
179
302
  delete("tenants/#{tenant}/sshkeys/#{name}")
180
303
  end
181
304
 
182
305
  # Get an SAP profile
183
306
  #
184
- # @param sap_profile_id [String] The ID of an SAP profile
307
+ # @param sap_profile_id [String] SAP Profile ID
185
308
  # @return [Hash] SAP profile
186
309
  def get_sap_profile(sap_profile_id)
187
310
  get("cloud-instances/#{guid}/sap/#{sap_profile_id}")
@@ -204,7 +327,7 @@ module IBM
204
327
  # instance is the standard 'PVMInstance' type and can be accessed via
205
328
  # the existing *_pvm_instance methods.
206
329
  #
207
- # @param sap_profile_id [String] The ID of an SAP profile
330
+ # @param sap_profile_id [String] SAP Profile ID
208
331
  # @return [Hash] SAP profile
209
332
  def create_sap_pvm_instance(instance_hash)
210
333
  post("cloud-instances/#{guid}/sap", instance_hash.to_json)
@@ -2,6 +2,7 @@ module IBM
2
2
  module Cloud
3
3
  module SDK
4
4
  class ResourceController < BaseService
5
+ require "ibm/cloud/sdk/resource_controller/resource"
5
6
  def endpoint
6
7
  "https://resource-controller.cloud.ibm.com/v2"
7
8
  end
@@ -10,15 +11,8 @@ module IBM
10
11
  @token = token
11
12
  end
12
13
 
13
- def get_resources
14
- resources = get("resource_instances")["resources"] || []
15
-
16
- require "ibm/cloud/sdk/resource_controller/resource"
17
- resources.map { |instance| Resource.new(instance) }
18
- end
19
-
20
14
  def get_resource(guid)
21
- get_resources.detect { |resource| resource.guid == guid }
15
+ Resource.new(get("resource_instances/#{guid}"))
22
16
  end
23
17
 
24
18
  private
@@ -1,7 +1,7 @@
1
1
  module IBM
2
2
  module Cloud
3
3
  module SDK
4
- VERSION = "0.1.4"
4
+ VERSION = "0.1.9"
5
5
  end
6
6
  end
7
7
  end
@@ -4,11 +4,13 @@
4
4
  require_relative 'vpc/base_vpc'
5
5
  require_relative 'vpc/base_collection'
6
6
  require_relative 'vpc/base_instance'
7
+ require_relative 'vpc/exceptions'
7
8
 
8
9
  require_relative 'vpc/floatingips'
9
10
  require_relative 'vpc/flowlogcollectors'
10
11
  require_relative 'vpc/ike_policies'
11
12
  require_relative 'vpc/images'
13
+ require_relative 'vpc/instance_profiles'
12
14
  require_relative 'vpc/instances'
13
15
  require_relative 'vpc/ipsec_policies'
14
16
  require_relative 'vpc/keys'
@@ -32,17 +34,16 @@ module IBM
32
34
  # Create an API Client object for the VPC IaaS service
33
35
  #
34
36
  # @param region [String] the IBM Power Cloud instance region
35
- # @param token [IAMtoken] the IBM Cloud IAM Token object
36
- # @param logger [Logger] an instance of an instanciated logger.
37
- def initialize(region, api_key, logger: nil)
37
+ # @param connection [IBM::Cloud::SDK::VPC::Connection] A connection object.
38
+ # @param logger [Logger] An instance of an instanciated logger.
39
+ def initialize(region, connection, logger: nil)
38
40
  @region = region
39
- @api_key = api_key
40
- @token = api_key
41
+ @connection = connection
41
42
 
42
- @logger = logger || Logger.new($stdout)
43
+ @logger = logger || Logger.new($stdout, level: :warn)
43
44
  end
44
45
 
45
- attr_reader :token, :logger
46
+ attr_reader :connection, :logger
46
47
  attr_accessor :region
47
48
 
48
49
  # The Region API endpoint.
@@ -67,6 +68,10 @@ module IBM
67
68
  VPC::Images.new(self)
68
69
  end
69
70
 
71
+ def instance_profiles
72
+ VPC::InstanceProfiles.new(self)
73
+ end
74
+
70
75
  def instances
71
76
  VPC::Instances.new(self)
72
77
  end
@@ -1,14 +1,20 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
+ require_relative('base_mixins/has_child')
5
+
4
6
  module IBM
5
7
  module Cloud
6
8
  module SDK
7
9
  # Container that encapsulates the VPC API.
8
10
  class BaseCollection < BaseVPC
11
+ # This class is used as a base for collection APIs.
12
+ # @param parent [Object] The parent instance in the API chain.
13
+ # @param endpoint [string] A path from the parent to the desired endpoint. In most cases is should be 1 word.
14
+ # @param array_key [string] The key that the API response holds the endpoint data. When nil the endpoint will be used.
15
+ # @param child_class [Object] The Object to be used when instanciating the single instance for this class.
9
16
  def initialize(parent, endpoint, array_key: nil, child_class: nil)
10
17
  # Setup empty base instance variables.
11
- @data = nil
12
18
  @params = nil
13
19
 
14
20
  array_key ||= endpoint
@@ -17,50 +23,83 @@ module IBM
17
23
  @array_key ||= array_key
18
24
  @instance ||= child_class
19
25
 
26
+ (class << self; include ChildMixin; end) if child_class
27
+
20
28
  super(parent, endpoint)
21
29
  end
22
30
 
31
+ # A chainable method to set query filters on the collection.
32
+ # @example vpc.images.params(limit: 1).all
33
+ #
34
+ # @param start [String] A server-supplied token determining what resource to start the page on.
35
+ # @param limit [Integer] The number of resources to return on a page allowed values are between 1 and 100
36
+ # @param resource_group [String] Filters the collection to resources within one of the resource groups identified in a comma-separated list of resource group identifiers
37
+ # @return [BaseCollection] This class with the param instance variable set.
38
+ def params(start: nil, limit: nil, resource_group: nil)
39
+ @params = {}
40
+ @params[:start] = start if start
41
+ @params[:limit] = limit if limit
42
+ @params[:resource_group] = resource_group if resource_group
43
+ self
44
+ end
45
+
23
46
  # Retrieve the collection from the cloud.
47
+ # @return [IBM::Cloud::SDK::VPC::Response] The http response object.
24
48
  def fetch
25
49
  @data ||= get(params: @params)
26
- @data
27
50
  end
28
51
 
52
+ # Get an iterable for the resource collection.
53
+ # @return [Enumerator] Use standard each, next idioms.
29
54
  def all
30
- response = fetch.subkey(@array_key)
31
- return response if response.is_a?(Array)
55
+ each_resource(url)
56
+ end
32
57
 
33
- raise "#{self.class}.#{__method__} Expecting response to be an Array not a #{response.class}"
58
+ # Fetch all data and return in an array.
59
+ # @return [Array] Hashes of the returned data.
60
+ def data
61
+ all.to_a
34
62
  end
35
63
 
36
- def params(start: nil, limit: nil, resource_group: nil)
37
- @params = {}
38
- @params['start'] = start if start
39
- @params['limit'] = limit if limit
40
- @params['resource_group'] = resource_group if resource_group
41
- self
64
+ # Determine if the collection has a total_count key in its response.
65
+ # @return [Boolean]
66
+ def has_count?
67
+ fetch.json&.key?(:total_count)
42
68
  end
43
69
 
70
+ # Get the total count if it exists in the response. Returns nil otherwise.
71
+ # @return [Integer] The total count reuturned by the server.
44
72
  def count
45
- fetch.subkey('total_count')
73
+ fetch.json&.fetch(:total_count, nil)
46
74
  end
47
75
 
48
- def limit
49
- fetch.subkey('limit')
76
+ # A generic post method to create a resource on the collection.
77
+ # @param payload [Hash] A hash of parameters to send to the server.
78
+ # @param payload_type [String] One of the following options json, form, or body.
79
+ # @return [IBM::Cloud::SDK::VPC::Response] The http response object.
80
+ def create(payload, payload_type = 'json')
81
+ adhoc(method: 'post', payload_type: payload_type, payload: payload)
50
82
  end
51
83
 
52
- def instance(id)
53
- @instance.new(self, id)
54
- end
84
+ private
55
85
 
56
- def next
57
- fetch.subkey('next')
58
- rescue RuntimeError
59
- nil
60
- end
86
+ # Create a generator that removes the need for pagination.
87
+ def each_resource(url, &block)
88
+ return enum_for(:each_resource, url) unless block_given?
89
+ return unless url
90
+
91
+ response = @connection.adhoc('get', url, metadata(@params)).json
92
+ resources = response.fetch(@array_key.to_sym)
93
+
94
+ resources&.each do |value|
95
+ yield value
96
+ end
97
+ return unless response.key?(:next)
98
+
99
+ next_url = response.dig(:next, :href)
100
+ return unless next_url
61
101
 
62
- def create(payload)
63
- post(payload)
102
+ each_resource(next_url, &block)
64
103
  end
65
104
  end
66
105
  end
@@ -7,7 +7,7 @@ module IBM
7
7
  # Container that encapsulates the VPC API.
8
8
  class BaseInstance < BaseVPC
9
9
  def details
10
- get.hash
10
+ get.hash_response
11
11
  end
12
12
 
13
13
  def update(payload)
@@ -0,0 +1,27 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module IBM
5
+ module Cloud
6
+ module SDK
7
+ # Access a specific instance by either id or name depending on API.
8
+ module ChildMixin
9
+ # Get an instance of the collection object.
10
+ # @param id [String] ID of Name to search on depending on API.
11
+ # @return [] The instance object.
12
+ def instance(id)
13
+ @instance.new(self, id)
14
+ end
15
+
16
+ # Return the first_instance returned from a collection get.
17
+ def first_instance
18
+ result = params(limit: 1).all.first
19
+ return nil unless result
20
+ return nil unless result.key?(:id)
21
+
22
+ instance(result.fetch(:id))
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -8,14 +8,14 @@ module IBM
8
8
  class BaseVPC
9
9
  def initialize(parent, endpoint = nil)
10
10
  @endpoint = parent.url(endpoint)
11
- @token = parent.token
11
+ @connection = parent.connection
12
12
  @logger = parent.logger
13
13
  end
14
14
 
15
- attr_reader :endpoint, :token, :logger
15
+ attr_reader :endpoint, :connection, :logger
16
16
 
17
17
  def adhoc(method: 'get', path: nil, params: {}, payload_type: 'json', payload: {})
18
- @token.adhoc(method.to_sym, url(path), metadata(params, payload_type, payload))
18
+ @connection.adhoc(method.to_sym, url(path), metadata(params, payload_type, payload))
19
19
  end
20
20
 
21
21
  def get(path: nil, params: {})
@@ -23,7 +23,7 @@ module IBM
23
23
  end
24
24
 
25
25
  def post(payload = {}, path: nil, params: {}, type: 'json')
26
- adhoc(method: 'post', path: path, params: params, payload: payload)
26
+ adhoc(method: 'post', path: path, params: params, payload: payload, payload_type: type)
27
27
  end
28
28
 
29
29
  def put(payload = {}, path: nil, params: {})
@@ -12,7 +12,7 @@ module IBM
12
12
  @logger ||= Logger.new($stdout, level: :warn)
13
13
 
14
14
  @client = HTTP.use(http_options(options))
15
- @token = IBM::Cloud::SDK::VPC::Connection.new(api_key, logger: @logger, client: @client)
15
+ @connection = IBM::Cloud::SDK::VPC::Connection.new(api_key, logger: @logger, client: @client)
16
16
  end
17
17
 
18
18
  def http_options(options = {})
@@ -24,10 +24,10 @@ module IBM
24
24
  )
25
25
  end
26
26
 
27
- attr_reader :logger, :token
27
+ attr_reader :logger, :connection
28
28
 
29
29
  def vpc(region = 'us-east')
30
- IBM::Cloud::SDK::Vpc.new(region, @token, logger: @logger)
30
+ IBM::Cloud::SDK::Vpc.new(region, @connection, logger: @logger)
31
31
  end
32
32
  end
33
- end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module IBM
4
+ module Cloud
5
+ module SDK
6
+ module VPC
7
+ # Module to contain all custom exception classes.
8
+ module Exceptions
9
+ # An exception for http with a response attribute.
10
+ # @param response [IBM::Cloud::SDK::VPC::Response] The original response object.
11
+ # @param msg [String] A human readable message.
12
+ class ExceptionWithResponse < RuntimeError
13
+ def initialize(response, msg)
14
+ @response = response
15
+ super(msg)
16
+ end
17
+ # @return [IBM::Cloud::SDK::VPC::Response] The response
18
+ attr_reader :response
19
+ end
20
+
21
+ # An exception for http status errors with a response attribute.
22
+ # @param response [IBM::Cloud::SDK::VPC::Response] The original response object.
23
+ class HttpStatusError < ExceptionWithResponse
24
+ def initialize(response)
25
+ msg = "Invalid status #{response.code} for url \"#{response.url}\", #{response.reason}. #{response.body}"
26
+ super(response, msg)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -8,8 +8,10 @@ module IBM
8
8
  module Cloud
9
9
  module SDK
10
10
  module VPC
11
-
12
- # Contols tokens.
11
+ # The Connection object to be used for all HTTP requests.
12
+ # @param api_key [String] The API Key to be used for this account.
13
+ # @param logger [Logger] An instantiated logger instance.
14
+ # @param client [HTTP::Client] An instantiated HTTP client.
13
15
  class Connection
14
16
  def initialize(api_key, logger: nil, client: nil)
15
17
  @api_key = api_key
@@ -20,17 +22,36 @@ module IBM
20
22
 
21
23
  attr_reader :client
22
24
 
25
+ # Send a HTTP request. Checks the validity of the response.
26
+ # @param verb [String] THe HTTP verb to use for this request.
27
+ # @param uri [String] The Full URL to send.
28
+ # @option opts [Hash] :params Parameters for URL encoding parameters.
29
+ # @option opts [Hash] :json Used when sending a hash as application/json content type.
30
+ # @option opts [Hash] :form Used when sending a hash as a form.
31
+ # @option opts [Hash] :headers Used to modify headers for request.
32
+ # @return [IBM::Cloud::SDK::VPC::Response] Wrapped response to query.
33
+ # @raise [IBM::Cloud::SDK::VPC::Exceptions::HttpStatusError] Response code is not either in 200-series or 404.
23
34
  def adhoc(verb, uri, opts = {})
24
- response = @client.auth(@token.authorization_header).request(verb.to_sym, uri, opts)
35
+ unverified_request(verb, uri, opts).raise_for_status?
36
+ end
37
+
38
+ # Send a HTTP request. Don't do any validation checks.
39
+ # @see :adhoc for options.
40
+ def unverified_request(verb, uri, opts = {})
41
+ response = @client.auth(@token.authorization_header).request(verb.to_s.downcase.to_sym, uri, opts)
25
42
  Response.new(response)
26
43
  end
27
44
 
45
+ # Get bearer token string for clients not using the adhoc method.
28
46
  def authorization_header
29
47
  @token.authorization_header
30
48
  end
31
49
  end
32
50
 
33
- # Get a token.
51
+ # The IAM token manager.
52
+ # @param api_key [String] The API Key to be used for this account.
53
+ # @param logger [Logger] An instantiated logger instance.
54
+ # @param client [HTTP::Client] An instantiated HTTP client.
34
55
  class Token
35
56
  def initialize(api_key, logger: nil, client: nil)
36
57
  @api_key = api_key
@@ -39,6 +60,9 @@ module IBM
39
60
  @data = fetch
40
61
  end
41
62
 
63
+ # Retrieve a new access_token from IAM.
64
+ # @return [IBM::Cloud::SDK::VPC::Response] Wrapped response to query.
65
+ # @raise [IBM::Cloud::SDK::VPC::Exceptions::HttpStatusError] Response code is not either in 200-series or 404.
42
66
  def fetch
43
67
  payload = {
44
68
  form: {
@@ -47,14 +71,20 @@ module IBM
47
71
  }
48
72
  }
49
73
  response = HTTP.post('https://iam.cloud.ibm.com/identity/token', payload)
50
- @data = Response.new(response).json
74
+ @data = Response.new(response).raise_for_status?.json
51
75
  end
52
76
 
77
+ # Check to see if the access_token is expired. Fetch a new token if none exists.
78
+ # @return [IBM::Cloud::SDK::VPC::Response] Wrapped response to query.
79
+ # @raise [IBM::Cloud::SDK::VPC::Exceptions::HttpStatusError] Response code is not either in 200-series or 404.
53
80
  def expired?
54
81
  fetch unless @data
55
82
  @data.fetch(:expiration).to_i <= Time.now.to_i + 600
56
83
  end
57
84
 
85
+ # Get a Bearer token string. Before returning check to see if token is expired.
86
+ # @return [String] The Bearer token header used in subsequent requests.
87
+ # @raise [IBM::Cloud::SDK::VPC::Exceptions::HttpStatusError] Response code is not either in 200-series or 404.
58
88
  def authorization_header
59
89
  fetch if expired?
60
90
  "#{@data.fetch(:token_type)} #{@data.fetch(:access_token)}"
@@ -8,80 +8,124 @@ module IBM
8
8
  module SDK
9
9
  module VPC
10
10
  # Encapsulate the HTTP response.
11
+ # @param response [HTTP::Response] The HTTP response object.
11
12
  class Response
12
13
  def initialize(response)
13
14
  @response = response
14
15
  end
15
16
 
17
+ # The raw HTTP response.
18
+ # @return [HTTP::Response]
16
19
  attr_reader :response
17
20
 
18
21
  # Return the response in a hash or array.
22
+ # @return [Hash] When response is a hash.
23
+ # @return [Array] When response is an array.
24
+ # @raise [Exceptions::ExceptionWithResponse] Contents of body is not properly formatted json.
19
25
  def json
20
26
  JSON.parse(body, symbolize_names: true)
21
27
  rescue StandardError
22
- raise "Error while parsing response body. #{response.body}"
28
+ raise Exceptions::ExceptionWithResponse.new(self, "#{url} Error while parsing response body. #{response.body}")
23
29
  end
24
30
 
25
31
  # Return the raw response string.
32
+ # @return [String]
33
+ # @return [nil] Response does not have body method.
26
34
  def body
27
- response.body.to_s
35
+ response&.body.to_s
28
36
  end
29
37
 
30
38
  # Return the response code.
39
+ # @return [Integer] Response has code method.
40
+ # @return [nil] Response does not have code method.
31
41
  def code
32
- response.code
42
+ response&.code
33
43
  end
34
44
 
45
+ alias status code
46
+
35
47
  # Return the raw connection object.
48
+ # @return [HTTP::Connection]
49
+ # @return [nil] Response does not have a connection method.
36
50
  def connection
37
- response.connection
51
+ response&.connection
52
+ end
53
+
54
+ # Chainable method to verify the status code. Raise an exception for non 200-series or 404 status codes.
55
+ # @return [Response] Allows for method to be chainable.
56
+ # @raise [Exceptions::HttpStatusError] Raise if status checks failed.
57
+ def raise_for_status?
58
+ return self if (200..299).include?(code)
59
+ return self if code == 404
60
+
61
+ raise Exceptions::HttpStatusError.new(self)
38
62
  end
39
63
 
40
64
  # Return the content type of the response.
65
+ # @return [String] The mimetype of the response.
66
+ # @return [nil] Response does not have response method that responds to mime_type.
41
67
  def content_type
42
- response.response.mime_type
68
+ response&.response&.mime_type
43
69
  end
44
70
 
45
71
  # Return the textual reason.
72
+ # @return [String] HTTP Reason
73
+ # @return [nil] Response does not have reaspn method that responds.
46
74
  def reason
47
- response.reason
75
+ response&.reason
48
76
  end
49
77
 
50
78
  # Return the sent url as a string.
79
+ # @return [String] Full URL sent
80
+ # @return [nil] Response does not have response method that responds to mime_type.
51
81
  def url
52
- response.uri.to_s
82
+ response&.uri.to_s
53
83
  end
54
84
 
55
85
  # Return the sent url as a URI class.
86
+ # @see https://github.com/httprb/http/blob/master/lib/http/uri.rb URI Class doc.
87
+ # @return [HTTP::URI]
88
+ # @return [nil] Response does not have response method that responds to mime_type.
56
89
  def uri
57
- response.uri
90
+ response&.uri
58
91
  end
59
92
 
60
93
  # Verify that the json response is a hash.
94
+ # @return [Hash] Response from JSON
95
+ # @raise [RuntimeError] JSON object is not a Hash.
61
96
  def hash_response
62
97
  check_object(Hash)
63
98
  end
64
99
 
65
100
  # Verify that the json response is an array.
101
+ # @return [Array] Response from JSON
102
+ # @raise [RuntimeError] JSON object is not a Array.
66
103
  def array_response
67
104
  check_object(Array)
68
105
  end
69
106
 
70
107
  # Find a subkey within the returned response.
108
+ # @param key [String] Name of a first level key.
109
+ # @return [Any] Response from JSON
110
+ # @raise [RuntimeError] JSON object is not a Array.
71
111
  def subkey(key)
72
112
  ret = hash_response
73
113
  sym_key = key.to_sym
74
114
  return ret.fetch(sym_key) if ret.key?(sym_key)
75
115
 
76
- raise "Key not found in #{ret}."
116
+ msg = "Key #{key} not found in #{ret}."
117
+ raise Exceptions::ExceptionWithResponse.new(self, msg)
77
118
  end
78
119
 
79
120
  # Check to see if the returned object is the expected object.
121
+ # @param obj [Object] The object to test the response against.
122
+ # @raise [Exceptions::ExceptionWithResponse] Parsed JSON is not the expecte class.
80
123
  def check_object(obj)
81
124
  ret = json
82
125
  return ret if ret.instance_of?(obj)
83
126
 
84
- raise "Expected #{obj} in response for #{url}. The returned object is a #{ret.class}."
127
+ msg = "Expected #{obj} in response for #{url}. The returned object is a #{ret.class}."
128
+ raise Exceptions::ExceptionWithResponse.new(self, msg)
85
129
  end
86
130
  end
87
131
  end
@@ -5,7 +5,7 @@ module IBM
5
5
  module Cloud
6
6
  module SDK
7
7
  module VPC
8
- module INSTANCES
8
+ module INSTANCE
9
9
  # Actions for an instance.
10
10
  class Actions < BaseCollection
11
11
  def initialize(parent)
@@ -5,7 +5,7 @@ module IBM
5
5
  module Cloud
6
6
  module SDK
7
7
  module VPC
8
- module INSTANCES
8
+ module INSTANCE
9
9
  # Get a Floating IP.
10
10
  class FloatingIps < BaseCollection
11
11
  def initialize(parent)
@@ -7,41 +7,16 @@ module IBM
7
7
  module Cloud
8
8
  module SDK
9
9
  module VPC
10
- module INSTANCES
10
+ module INSTANCE
11
11
  # All netowrk interfaces.
12
- class NetworkInterfaces < BaseVPC
12
+ class NetworkInterfaces < BaseCollection
13
13
  def initialize(parent)
14
- super(parent, 'network_interfaces')
15
- end
16
-
17
- def all
18
- get.subkey('network_interfaces')
19
- # get
20
- end
21
-
22
- def update(payload)
23
- post(payload)
24
- end
25
-
26
- def instance(id)
27
- NetworkInterface.new(self, id)
14
+ super(parent, 'network_interfaces', child_class: NetworkInterface)
28
15
  end
29
16
  end
30
17
 
31
18
  # A single network insterface.
32
- class NetworkInterface < BaseVPC
33
- def remove
34
- delete
35
- end
36
-
37
- def details
38
- get
39
- end
40
-
41
- def update(payload)
42
- patch(payload)
43
- end
44
-
19
+ class NetworkInterface < BaseInstance
45
20
  def floating_ips
46
21
  FloatingIps.new(self)
47
22
  end
@@ -5,39 +5,16 @@ module IBM
5
5
  module Cloud
6
6
  module SDK
7
7
  module VPC
8
- module INSTANCES
8
+ module INSTANCE
9
9
  # Get all attached volumes.
10
- class VolumeAttachments < BaseVPC
10
+ class VolumeAttachments < BaseCollection
11
11
  def initialize(parent)
12
- super(parent, 'volume_attachments')
13
- end
14
-
15
- def all
16
- get
17
- end
18
-
19
- def create(payload)
20
- post(payload)
21
- end
22
-
23
- def instance(id)
24
- VolumeAttachment.new(self, id)
12
+ super(parent, 'volume_attachments', child_class: VolumeAttachment)
25
13
  end
26
14
  end
27
15
 
28
16
  # A single attached volume.
29
- class VolumeAttachment < BaseVPC
30
- def details
31
- get
32
- end
33
-
34
- def update(payload)
35
- patch(payload)
36
- end
37
-
38
- def remove
39
- delete
40
- end
17
+ class VolumeAttachment < BaseInstance
41
18
  end
42
19
  end
43
20
  end
@@ -0,0 +1,21 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module IBM
5
+ module Cloud
6
+ module SDK
7
+ module VPC
8
+ # Work with multiple profiles.
9
+ class InstanceProfiles < BaseCollection
10
+ def initialize(parent)
11
+ super(parent, 'instance/profiles', child_class: Profile, array_key: 'profiles')
12
+ end
13
+ end
14
+
15
+ # Get a single profile.
16
+ class Profile < BaseInstance
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,7 +1,9 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
- require_relative('instance')
4
+ require_relative 'instance/actions'
5
+ require_relative 'instance/network_interfaces'
6
+ require_relative 'instance/volume_attachments'
5
7
 
6
8
  module IBM
7
9
  module Cloud
@@ -11,7 +13,45 @@ module IBM
11
13
  # Work with multiple VM instances.
12
14
  class Instances < BaseCollection
13
15
  def initialize(parent)
14
- super(parent, 'instances', child_class: INSTANCES::Instance)
16
+ super(parent, 'instances', child_class: Instance)
17
+ end
18
+
19
+ # A chainable method to set query filters on the collection.
20
+ # @example vpc.images.params(limit: 1).all
21
+ #
22
+ # @param start [String] A server-supplied token determining what resource to start the page on.
23
+ # @param limit [Integer] The number of resources to return on a page allowed values are between 1 and 100
24
+ # @param name [String] Filters the collection to resources with the exact specified name
25
+ # @param vpc_id [String] Filters the collection to resources in the VPC with the specified identifier
26
+ # @param vpc_crn [String] Filters the collection to resources in the VPC with the specified CRN
27
+ # @param vpc_name [String] Filters the collection to resources in the VPC with the exact specified name
28
+ # @return [BaseCollection] This class with the param instance variable set.
29
+ def params(start: nil, limit: nil, name: nil, vpc_id: nil, vpc_crn: nil, vpc_name: nil)
30
+ super(start: start, limit: limit)
31
+ @params['name'] = name if name
32
+ @params['vpc.id'] = vpc_id if vpc_id
33
+ @params['vpc.crn'] = vpc_crn if vpc_crn
34
+ @params['vpc.name'] = vpc_name if vpc_name
35
+ self
36
+ end
37
+ end
38
+
39
+ # Work with a single instance.
40
+ class Instance < BaseInstance
41
+ def actions
42
+ INSTANCE::Actions.new(self)
43
+ end
44
+
45
+ def network_interfaces
46
+ INSTANCE::NetworkInterfaces.new(self)
47
+ end
48
+
49
+ def volume_attachments
50
+ INSTANCE::VolumeAttachments.new(self)
51
+ end
52
+
53
+ def initialization
54
+ adhoc(method: 'get', path: 'initialization').json
15
55
  end
16
56
  end
17
57
  end
@@ -27,7 +27,7 @@ module IBM
27
27
  end
28
28
 
29
29
  # A single zone.
30
- class Zone < BaseVPC
30
+ class Zone < BaseInstance
31
31
  end
32
32
  end
33
33
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ibm-cloud-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - IBM Cloud Developers
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-17 00:00:00.000000000 Z
11
+ date: 2020-10-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client
@@ -60,6 +60,8 @@ files:
60
60
  - lib/ibm/cloud/sdk/base_service.rb
61
61
  - lib/ibm/cloud/sdk/iam.rb
62
62
  - lib/ibm/cloud/sdk/iam/token.rb
63
+ - lib/ibm/cloud/sdk/logging.rb
64
+ - lib/ibm/cloud/sdk/null_logger.rb
63
65
  - lib/ibm/cloud/sdk/power_iaas.rb
64
66
  - lib/ibm/cloud/sdk/resource_controller.rb
65
67
  - lib/ibm/cloud/sdk/resource_controller/resource.rb
@@ -67,20 +69,21 @@ files:
67
69
  - lib/ibm/cloud/sdk/vpc.rb
68
70
  - lib/ibm/cloud/sdk/vpc/base_collection.rb
69
71
  - lib/ibm/cloud/sdk/vpc/base_instance.rb
72
+ - lib/ibm/cloud/sdk/vpc/base_mixins/has_child.rb
70
73
  - lib/ibm/cloud/sdk/vpc/base_vpc.rb
71
74
  - lib/ibm/cloud/sdk/vpc/cloud_sdk.rb
75
+ - lib/ibm/cloud/sdk/vpc/exceptions.rb
72
76
  - lib/ibm/cloud/sdk/vpc/floatingips.rb
73
77
  - lib/ibm/cloud/sdk/vpc/flowlogcollectors.rb
74
78
  - lib/ibm/cloud/sdk/vpc/helpers/connection.rb
75
79
  - lib/ibm/cloud/sdk/vpc/helpers/response.rb
76
80
  - lib/ibm/cloud/sdk/vpc/ike_policies.rb
77
81
  - lib/ibm/cloud/sdk/vpc/images.rb
78
- - lib/ibm/cloud/sdk/vpc/instance.rb
79
82
  - lib/ibm/cloud/sdk/vpc/instance/actions.rb
80
83
  - lib/ibm/cloud/sdk/vpc/instance/floating_ips.rb
81
84
  - lib/ibm/cloud/sdk/vpc/instance/network_interfaces.rb
82
- - lib/ibm/cloud/sdk/vpc/instance/profiles.rb
83
85
  - lib/ibm/cloud/sdk/vpc/instance/volume_attachments.rb
86
+ - lib/ibm/cloud/sdk/vpc/instance_profiles.rb
84
87
  - lib/ibm/cloud/sdk/vpc/instances.rb
85
88
  - lib/ibm/cloud/sdk/vpc/ipsec_policies.rb
86
89
  - lib/ibm/cloud/sdk/vpc/keys.rb
@@ -109,7 +112,7 @@ licenses:
109
112
  - '"Apache-2.0"'
110
113
  metadata:
111
114
  homepage_uri: https://github.com/IBM-Cloud/ibm-cloud-sdk-ruby
112
- changelog_uri: https://github.com/IBM-Cloud/ibm-cloud-sdk-ruby/blob/v0.1.4/CHANGELOG.md
115
+ changelog_uri: https://github.com/IBM-Cloud/ibm-cloud-sdk-ruby/blob/v0.1.9/CHANGELOG.md
113
116
  post_install_message:
114
117
  rdoc_options: []
115
118
  require_paths:
@@ -1,36 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- require_relative 'instance/actions'
5
- require_relative 'instance/network_interfaces'
6
- require_relative 'instance/volume_attachments'
7
- require_relative 'instance/profiles'
8
-
9
- module IBM
10
- module Cloud
11
- module SDK
12
- module VPC
13
- module INSTANCES
14
- # Work with a single instance.
15
- class Instance < BaseInstance
16
- def actions
17
- Actions.new(self)
18
- end
19
-
20
- def network_interfaces
21
- NetworkInterfaces.new(self)
22
- end
23
-
24
- def volume_attachments
25
- VolumeAttachments.new(self)
26
- end
27
-
28
- def profiles
29
- Profiles.new(self)
30
- end
31
- end
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,34 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- module IBM
5
- module Cloud
6
- module SDK
7
- module VPC
8
- module INSTANCES
9
- # Work with multiple profiles.
10
- class Profiles < BaseVPC
11
- def initialize(parent)
12
- super(parent, 'instance/profiles')
13
- end
14
-
15
- def all
16
- get
17
- end
18
-
19
- def instance(name)
20
- Profile.new(self, name)
21
- end
22
- end
23
-
24
- # Get a single profile.
25
- class Profile < BaseVPC
26
- def details
27
- get
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
34
- end