haipa_rest 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +47 -0
- data/lib/haipa_rest.rb +25 -0
- data/lib/haipa_rest/async_operation_status.rb +78 -0
- data/lib/haipa_rest/cloud_error_data.rb +48 -0
- data/lib/haipa_rest/common/configurable.rb +93 -0
- data/lib/haipa_rest/common/default.rb +42 -0
- data/lib/haipa_rest/credentials/application_token_provider.rb +118 -0
- data/lib/haipa_rest/final_state_via.rb +16 -0
- data/lib/haipa_rest/haipa_cli_error.rb +12 -0
- data/lib/haipa_rest/haipa_operation_error.rb +40 -0
- data/lib/haipa_rest/haipa_operation_response.rb +20 -0
- data/lib/haipa_rest/haipa_service_client.rb +304 -0
- data/lib/haipa_rest/polling_state.rb +139 -0
- data/lib/haipa_rest/serialization.rb +43 -0
- data/lib/haipa_rest/typed_error_info.rb +33 -0
- data/lib/haipa_rest/version.rb +8 -0
- metadata +162 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ff597bbe79f2fab568de046de5378015b60b2b756f3ed2b4111786b21f4af208
|
4
|
+
data.tar.gz: f2958344b3891002fdd3241707e8995218e9ede792292c0fe4762c4b6e5396e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d73c9bf85d5082dce938a67e4f0a0eda038e6d57f0496eb7bdaec71c29a4b3e9797d116e1ff9f95ed6301594bc1cb854d55cf379bbde9a27cb022e78b251825e
|
7
|
+
data.tar.gz: aff4f952f9b3678647e1e56c360dc210646237e86dc40a3cf855cff951aedcbbc9da174efa7c86c3b0c17bb0be3946930bcb08bc8098c965f831062a435168b2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2019 dbosoft GmbH
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# Intro
|
2
|
+
|
3
|
+
haipa_rest is a library which supports the Haipa clients generated with Autorest tool. It contains core logic and helper classes for error handling and authentication.
|
4
|
+
Usually it is not supposed to be used as a standalone gem but only as a dependency for generated client gems.
|
5
|
+
|
6
|
+
This project has been forked from the Microsoft Azure ruby client (https://github.com/Azure/azure-sdk-for-ruby)
|
7
|
+
|
8
|
+
# Supported Ruby Versions
|
9
|
+
|
10
|
+
* Ruby 2.0
|
11
|
+
* Ruby 2.1
|
12
|
+
* Ruby 2.2
|
13
|
+
|
14
|
+
Note: x64 Ruby for Windows is known to have some compatibility issues.
|
15
|
+
|
16
|
+
# Installation
|
17
|
+
|
18
|
+
install the appropriate gem:
|
19
|
+
|
20
|
+
```
|
21
|
+
gem install haipa_rest
|
22
|
+
```
|
23
|
+
|
24
|
+
and reference it in your code:
|
25
|
+
|
26
|
+
```Ruby
|
27
|
+
require 'haipa_rest'
|
28
|
+
```
|
29
|
+
|
30
|
+
# Running tests
|
31
|
+
|
32
|
+
haipa_rest has only unit tests which doesn't require any preparation, just run 'rspec' command from the gem directory.
|
33
|
+
|
34
|
+
# Contribution
|
35
|
+
|
36
|
+
To start working on the gem the only additional dev dependecy is required - rspec. After you've added a new feature and all specs pass - you're good to go with PR. But before starting any bug/feature - please make sure you've thoroughly discussed it with repository maintainers. This gem already powers a few SDKs and backward compatibility should taken in account.
|
37
|
+
|
38
|
+
# Adding gem to you generated SDK
|
39
|
+
|
40
|
+
Reference it in the gemfile and also add this line to your client's gemspec file:
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
spec.add_runtime_dependency 'haipa_rest', '~> 0.11.1'
|
44
|
+
```
|
45
|
+
Don't forget to correct the version.
|
46
|
+
|
47
|
+
|
data/lib/haipa_rest.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
require 'ms_rest'
|
6
|
+
require 'haipa_rest/async_operation_status.rb'
|
7
|
+
require 'haipa_rest/Haipa_operation_error.rb'
|
8
|
+
require 'haipa_rest/Haipa_operation_response.rb'
|
9
|
+
require 'haipa_rest/Haipa_service_client.rb'
|
10
|
+
require 'haipa_rest/cloud_error_data.rb'
|
11
|
+
require 'haipa_rest/final_state_via.rb'
|
12
|
+
require 'haipa_rest/credentials/application_token_provider.rb'
|
13
|
+
require 'haipa_rest/polling_state.rb'
|
14
|
+
require 'haipa_rest/serialization.rb'
|
15
|
+
require 'haipa_rest/typed_error_info.rb'
|
16
|
+
require 'haipa_rest/version'
|
17
|
+
require 'haipa_rest/common/configurable'
|
18
|
+
require 'haipa_rest/common/default'
|
19
|
+
|
20
|
+
module Haipa end
|
21
|
+
module Haipa::Client end
|
22
|
+
module Haipa::Client::Serialization end
|
23
|
+
module Haipa::Client::Common end
|
24
|
+
module Haipa::Client::Common::Configurable end
|
25
|
+
module Haipa::Client::Common::Default end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Defines values for AsyncOperationStatus enum.
|
8
|
+
#
|
9
|
+
class AsyncOperationStatus
|
10
|
+
ACCEPTED = 'Accepted'
|
11
|
+
IN_PROGRESS_STATUS = 'InProgress'
|
12
|
+
RUNNING = 'Running'
|
13
|
+
SUCCESS_STATUS = 'Succeeded'
|
14
|
+
FAILED_STATUS = 'Failed'
|
15
|
+
CANCELED_STATUS = 'Canceled'
|
16
|
+
|
17
|
+
ALL_STATUSES = [ACCEPTED, FAILED_STATUS, CANCELED_STATUS, SUCCESS_STATUS, IN_PROGRESS_STATUS, RUNNING]
|
18
|
+
FAILED_STATUSES = [FAILED_STATUS, CANCELED_STATUS]
|
19
|
+
TERMINAL_STATUSES = [FAILED_STATUS, CANCELED_STATUS, SUCCESS_STATUS]
|
20
|
+
|
21
|
+
DEFAULT_DELAY = 30
|
22
|
+
|
23
|
+
# @return [Integer] delay in seconds which should be used for polling for result of async operation.
|
24
|
+
attr_accessor :retry_after
|
25
|
+
|
26
|
+
# @return [Haipa::Client::CloudErrorData] error information about async operation.
|
27
|
+
attr_accessor :error
|
28
|
+
|
29
|
+
# @return [Stirng] status of polling.
|
30
|
+
attr_accessor :status
|
31
|
+
|
32
|
+
#
|
33
|
+
# Checks if given status is terminal one.
|
34
|
+
# @param status [String] status to verify
|
35
|
+
#
|
36
|
+
# @return [Boolean] True if given status is terminal one, false otherwise.
|
37
|
+
def self.is_terminal_status(status)
|
38
|
+
TERMINAL_STATUSES.any? { |st| st.casecmp(status) == 0 }
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Checks if given status is failed one.
|
43
|
+
# @param status [String] status to verify
|
44
|
+
#
|
45
|
+
# @return [Boolean] True if given status is failed one, false otherwise.
|
46
|
+
def self.is_failed_status(status)
|
47
|
+
FAILED_STATUSES.any? { |st| st.casecmp(status) == 0 }
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Checks if given status is successful one.
|
52
|
+
# @param status [String] status to verify
|
53
|
+
#
|
54
|
+
# @return [Boolean] True if given status is successful one, false otherwise.
|
55
|
+
def self.is_successful_status(status)
|
56
|
+
return (status.casecmp(SUCCESS_STATUS) == 0)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Deserializes given hash into AsyncOperationStatus object.
|
61
|
+
# @param object [Hash] object to deserialize.
|
62
|
+
#
|
63
|
+
# @return [AsyncOperationStatus] deserialized object.
|
64
|
+
def self.deserialize_object(object)
|
65
|
+
return if object.nil?
|
66
|
+
output_object = AsyncOperationStatus.new
|
67
|
+
|
68
|
+
output_object.status = object['status']
|
69
|
+
|
70
|
+
output_object.error = CloudErrorData.deserialize_object(object['error'])
|
71
|
+
|
72
|
+
output_object.retry_after = Integer(object['retryAfter']) unless object['retryAfter'].nil?
|
73
|
+
|
74
|
+
output_object
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents keeps aux data about Haipa invalid response.
|
8
|
+
#
|
9
|
+
class CloudErrorData
|
10
|
+
|
11
|
+
# @return [String] the error code parsed from the body of the http error response.
|
12
|
+
attr_accessor :code
|
13
|
+
|
14
|
+
# @return [String] the error message parsed from the body of the http error response.
|
15
|
+
attr_accessor :message
|
16
|
+
|
17
|
+
# @return [String] the error target parsed from the body of the http error response.
|
18
|
+
attr_accessor :target
|
19
|
+
|
20
|
+
# @return [Array<TypedErrorInfo>] the list of additional error info parsed from the body of the http error response.
|
21
|
+
attr_accessor :additionalInfo
|
22
|
+
|
23
|
+
#
|
24
|
+
# Deserializes given hash into CloudErrorData object.
|
25
|
+
# @param object [Hash] object to deserialize.
|
26
|
+
#
|
27
|
+
# @return [CloudErrorData] deserialized object.
|
28
|
+
def self.deserialize_object(object)
|
29
|
+
return if object.nil?
|
30
|
+
output_object = CloudErrorData.new
|
31
|
+
|
32
|
+
output_object.code = object['code']
|
33
|
+
|
34
|
+
output_object.message = object['message']
|
35
|
+
|
36
|
+
output_object.target = object['target']
|
37
|
+
|
38
|
+
unless object['additionalInfo'].nil?
|
39
|
+
output_object.additionalInfo = []
|
40
|
+
object['additionalInfo'].each do |info|
|
41
|
+
output_object.additionalInfo << Haipa::Client::TypedErrorInfo.deserialize_object(info)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
output_object
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
require 'openssl'
|
6
|
+
|
7
|
+
module Haipa::Client::Common
|
8
|
+
# The Haipa::Common::Configurable module provides basic configuration for Haipa activities.
|
9
|
+
module Configurable
|
10
|
+
|
11
|
+
# @return [MsRest::ServiceClientCredentials] credentials to authorize HTTP requests made by the service client.
|
12
|
+
attr_accessor :credentials
|
13
|
+
|
14
|
+
# @return [String] client id.
|
15
|
+
attr_accessor :client_id
|
16
|
+
|
17
|
+
# @return [String] path to client key file
|
18
|
+
attr_accessor :client_key_file
|
19
|
+
|
20
|
+
# @return [String] client key
|
21
|
+
attr_accessor :client_key
|
22
|
+
|
23
|
+
# @return [String] url to identity endpoint.
|
24
|
+
attr_accessor :identity_endpoint
|
25
|
+
|
26
|
+
class << self
|
27
|
+
#
|
28
|
+
# List of configurable keys for {Haipa::Client::Common::Client}.
|
29
|
+
# @return [Array] of option keys.
|
30
|
+
#
|
31
|
+
def keys
|
32
|
+
@keys ||= [:client_id, :client_key_file, :identity_endpoint ]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Set configuration options using a block.
|
38
|
+
#
|
39
|
+
def configure
|
40
|
+
yield self
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Resets the configurable options to provided options or defaults.
|
45
|
+
# This will also creates MsRest::TokenCredentials to be used for subsequent clients.
|
46
|
+
#
|
47
|
+
def reset!(options = {})
|
48
|
+
Haipa::Client::Common::Configurable.keys.each do |key|
|
49
|
+
default_value = Haipa::Client::Common::Default.options[key]
|
50
|
+
instance_variable_set(:"@#{key}", options.fetch(key, default_value))
|
51
|
+
end
|
52
|
+
|
53
|
+
if(options[:client_key].nil?)
|
54
|
+
# The user has not passed in the client key. try to read it from client_key_file
|
55
|
+
self.client_key = OpenSSL::PKey::RSA.new File.read self.client_key_file unless self.client_key_file.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
if(options[:credentials].nil?)
|
59
|
+
# The user has not passed in the credentials. So, the api has to
|
60
|
+
# build the credentials itself.
|
61
|
+
fail ArgumentError, 'client_id is nil' if self.client_id.nil?
|
62
|
+
fail ArgumentError, 'client_key is nil' if self.client_key.nil?
|
63
|
+
fail ArgumentError, 'identity_endpoint is nil' if self.identity_endpoint.nil?
|
64
|
+
|
65
|
+
self.credentials = MsRest::TokenCredentials.new(
|
66
|
+
Haipa::Client::ApplicationTokenProvider.new(
|
67
|
+
self.client_id, self.client_key, self.identity_endpoint))
|
68
|
+
else
|
69
|
+
self.credentials = options[:credentials]
|
70
|
+
end
|
71
|
+
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
75
|
+
def config
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
#
|
82
|
+
# configures configurable options to default values
|
83
|
+
#
|
84
|
+
def setup_default_options
|
85
|
+
opts = {}
|
86
|
+
Haipa::Client::Common::Configurable.keys.map do |key|
|
87
|
+
opts[key] = Haipa::Client::Common::Default.options[key]
|
88
|
+
end
|
89
|
+
|
90
|
+
opts
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client::Common
|
6
|
+
module Default
|
7
|
+
class << self
|
8
|
+
|
9
|
+
#
|
10
|
+
# Default Haipa Client Id.
|
11
|
+
# @return [String] Haipa Client Id.
|
12
|
+
#
|
13
|
+
def client_id
|
14
|
+
ENV['HAIPA_CLIENT_ID']
|
15
|
+
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Default Haipa Client Secret.
|
19
|
+
# @return [String] Haipa Client Secret.
|
20
|
+
#
|
21
|
+
def client_key_file
|
22
|
+
ENV['HAIPA_CLIENT_KEY_FILE']
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# Default Haipa identity endpoint.
|
27
|
+
# @return [String] Haipa identiy endpoint
|
28
|
+
#
|
29
|
+
def identity_endpoint
|
30
|
+
ENV['HAIPA_IDENTITY_ENDPOINT']
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Configuration options.
|
35
|
+
# @return [Hash] Configuration options.
|
36
|
+
#
|
37
|
+
def options
|
38
|
+
Hash[Haipa::Client::Common::Configurable.keys.map { |key| [key, send(key)]}]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
require 'jwt'
|
6
|
+
|
7
|
+
module Haipa::Client
|
8
|
+
#
|
9
|
+
# Class that provides access to authentication token.
|
10
|
+
#
|
11
|
+
class ApplicationTokenProvider < MsRest::TokenProvider
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
TOKEN_ACQUIRE_URL = '{identity_endpoint}/connect/token'
|
16
|
+
DEFAULT_SCHEME = 'Bearer'
|
17
|
+
|
18
|
+
# @return [String] client id.
|
19
|
+
attr_accessor :client_id
|
20
|
+
|
21
|
+
# @return [String] client key
|
22
|
+
attr_accessor :client_key
|
23
|
+
|
24
|
+
# @return [String] url to identity endpoint.
|
25
|
+
attr_accessor :identity_endpoint
|
26
|
+
|
27
|
+
# @return [String] auth token.
|
28
|
+
attr_accessor :token
|
29
|
+
|
30
|
+
# @return [Time] the date when the current token expires.
|
31
|
+
attr_accessor :token_expires_on
|
32
|
+
|
33
|
+
# @return [Integer] the amount of time we refresh token before it expires.
|
34
|
+
attr_reader :expiration_threshold
|
35
|
+
|
36
|
+
# @return [String] the type of token.
|
37
|
+
attr_reader :token_type
|
38
|
+
|
39
|
+
public
|
40
|
+
|
41
|
+
#
|
42
|
+
# Creates and initialize new instance of the ApplicationTokenProvider class.
|
43
|
+
# @param client_id [String] client id.
|
44
|
+
# @param client_key [String] client key.
|
45
|
+
# @param identity_endpoint [String] url of identity endpoint.
|
46
|
+
# @param ca_file [String] path to additional ca file.
|
47
|
+
def initialize(client_id, client_key, identity_endpoint)
|
48
|
+
fail ArgumentError, 'Client id cannot be nil' if client_id.nil?
|
49
|
+
fail ArgumentError, 'Client key cannot be nil' if client_key.nil?
|
50
|
+
fail ArgumentError, 'Identity_endpoint url cannot be nil' if identity_endpoint.nil?
|
51
|
+
|
52
|
+
@client_id = client_id
|
53
|
+
@client_key = client_key
|
54
|
+
@identity_endpoint = identity_endpoint
|
55
|
+
|
56
|
+
@expiration_threshold = 5 * 60
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Returns the string value which needs to be attached
|
61
|
+
# to HTTP request header in order to be authorized.
|
62
|
+
#
|
63
|
+
# @return [String] authentication headers.
|
64
|
+
def get_authentication_header
|
65
|
+
acquire_token if token_expired
|
66
|
+
"#{token_type} #{token}"
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
#
|
72
|
+
# Checks whether token is about to expire.
|
73
|
+
#
|
74
|
+
# @return [Bool] True if token is about to expire, false otherwise.
|
75
|
+
def token_expired
|
76
|
+
@token.nil? || Time.now >= @token_expires_on + expiration_threshold
|
77
|
+
end
|
78
|
+
|
79
|
+
#
|
80
|
+
# Retrieves a new authentication token.
|
81
|
+
#
|
82
|
+
# @return [String] new authentication token.
|
83
|
+
def acquire_token
|
84
|
+
token_acquire_url = TOKEN_ACQUIRE_URL.dup
|
85
|
+
token_acquire_url['{identity_endpoint}'] = @identity_endpoint
|
86
|
+
|
87
|
+
url = URI.parse(token_acquire_url)
|
88
|
+
|
89
|
+
connection = Faraday.new(:url => url, :ssl => MsRest.ssl_options)
|
90
|
+
exp = Time.now.to_i + @expiration_threshold
|
91
|
+
|
92
|
+
payload = { iss: client_id,
|
93
|
+
aud: token_acquire_url,
|
94
|
+
sub: @client_id,
|
95
|
+
exp: exp
|
96
|
+
}
|
97
|
+
|
98
|
+
signed_payload = JWT.encode payload, client_key, 'RS256'
|
99
|
+
|
100
|
+
response = connection.post url.path, {
|
101
|
+
:grant_type => 'client_credentials',
|
102
|
+
:client_id => client_id,
|
103
|
+
:client_assertion_type => 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
|
104
|
+
:client_assertion => signed_payload,
|
105
|
+
:scope => 'compute_api' }
|
106
|
+
|
107
|
+
fail HaipaOperationError,
|
108
|
+
'Couldn\'t login to Haipa, please verify your client id and client key' unless response.status == 200
|
109
|
+
|
110
|
+
response_body = JSON.load(response.body)
|
111
|
+
@token = response_body['access_token']
|
112
|
+
@token_expires_on = Time.now + Integer(response_body['expires_in'])
|
113
|
+
@token_type = response_body['token_type']
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents a final state via of Haipa long running operation.
|
8
|
+
#
|
9
|
+
class FinalStateVia
|
10
|
+
NONE = -1
|
11
|
+
DEFAULT = 0
|
12
|
+
ASYNC_OPERATION = 0
|
13
|
+
LOCATION = 1
|
14
|
+
ORIGINAL_URI = 2
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents an error with the Haipa CLI.
|
8
|
+
#
|
9
|
+
class HaipaCliError < StandardError
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents an Haipa error.
|
8
|
+
#
|
9
|
+
class HaipaOperationError < MsRest::HttpOperationError
|
10
|
+
|
11
|
+
# @return [String] the error message.
|
12
|
+
attr_accessor :error_message
|
13
|
+
|
14
|
+
# @return [String] the error code.
|
15
|
+
attr_accessor :error_code
|
16
|
+
|
17
|
+
#
|
18
|
+
# Creates and initialize new instance of the HaipaOperationError class.
|
19
|
+
# @param [Hash] the HTTP request data (uri, body, headers).
|
20
|
+
# @param [Faraday::Response] the HTTP response object.
|
21
|
+
# @param [String] body the HTTP response body.
|
22
|
+
# @param [String] error message.
|
23
|
+
#
|
24
|
+
def initialize(*args)
|
25
|
+
super(*args)
|
26
|
+
|
27
|
+
# Try to parse @body to find useful error message and code
|
28
|
+
# Body should meet the error condition response requirements for Microsoft REST API Guidelines
|
29
|
+
# https://github.com/Microsoft/api-guidelines/blob/master/Guidelines.md#7102-error-condition-responses
|
30
|
+
begin
|
31
|
+
unless @body.nil?
|
32
|
+
@error_message = @body['error']['message']
|
33
|
+
@error_code = @body['error']['code']
|
34
|
+
@msg = "#{@msg}: #{@error_code}: #{@error_message}"
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents the data received and deserialized from Haipa service.
|
8
|
+
#
|
9
|
+
class HaipaOperationResponse < MsRest::HttpOperationResponse
|
10
|
+
|
11
|
+
# @return [String] identificator of the request.
|
12
|
+
attr_accessor :request_id
|
13
|
+
|
14
|
+
# @return [String] Correlation Id of the request.
|
15
|
+
attr_accessor :correlation_request_id
|
16
|
+
|
17
|
+
# @return [String] Client Request Id of the request.
|
18
|
+
attr_accessor :client_request_id
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,304 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents a point of access to the REST API.
|
8
|
+
#
|
9
|
+
class HaipaServiceClient < MsRest::ServiceClient
|
10
|
+
|
11
|
+
# @return [Integer] execution interval for long running operations.
|
12
|
+
attr_accessor :long_running_operation_retry_timeout
|
13
|
+
|
14
|
+
# @return [String] api version of the Haipa service in string format.
|
15
|
+
attr_accessor :api_version
|
16
|
+
|
17
|
+
def initialize(credentials, options = nil)
|
18
|
+
super(credentials, options)
|
19
|
+
# This is the current default for Haipa services, and content-type
|
20
|
+
# and accept supported by Autorest
|
21
|
+
@request_headers = {
|
22
|
+
'Content-Type' => 'application/json;charset=utf-8',
|
23
|
+
'Accept' => 'application/json'
|
24
|
+
}
|
25
|
+
add_user_agent_information("haipa_rest/#{Haipa::Client::REST_VERSION}")
|
26
|
+
add_user_agent_information("Haipa client for Ruby")
|
27
|
+
end
|
28
|
+
|
29
|
+
#
|
30
|
+
# Retrieves the result of 'POST','DELETE','PUT' or 'PATCH' operation. Performs polling of required.
|
31
|
+
# @param haipa_response [Haipa::Client::HaipaOperationResponse] response from Haipa service.
|
32
|
+
# @param custom_deserialization_block [Proc] custom logic for response deserialization.
|
33
|
+
# @param final_state_via [Haipa::Client::FinalStateVia] Final State via value
|
34
|
+
#
|
35
|
+
# @return [MsRest::HttpOperationResponse] the response.
|
36
|
+
#
|
37
|
+
def get_long_running_operation_result(haipa_response, custom_deserialization_block, final_state_via = FinalStateVia::DEFAULT)
|
38
|
+
check_for_status_code_failure(haipa_response)
|
39
|
+
|
40
|
+
http_method = haipa_response.request.method
|
41
|
+
|
42
|
+
polling_state = PollingState.new(haipa_response, @long_running_operation_retry_timeout)
|
43
|
+
request = haipa_response.request
|
44
|
+
|
45
|
+
if !AsyncOperationStatus.is_terminal_status(polling_state.status)
|
46
|
+
task = Concurrent::TimerTask.new do
|
47
|
+
begin
|
48
|
+
if !polling_state.Haipa_async_operation_header_link.nil?
|
49
|
+
update_state_from_Haipa_async_operation_header(polling_state.get_request(headers: request.headers, base_uri: request.base_uri, user_agent_extended: user_agent_extended), polling_state)
|
50
|
+
elsif !polling_state.location_header_link.nil?
|
51
|
+
update_state_from_location_header(polling_state.get_request(headers: request.headers, base_uri: request.base_uri, user_agent_extended: user_agent_extended), polling_state, custom_deserialization_block, final_state_via)
|
52
|
+
elsif http_method === :put
|
53
|
+
get_request = MsRest::HttpOperationRequest.new(request.base_uri, request.build_path.to_s, :get, {query_params: request.query_params, headers: request.headers, user_agent_extended: user_agent_extended})
|
54
|
+
update_state_from_get_resource_operation(get_request, polling_state, custom_deserialization_block)
|
55
|
+
else
|
56
|
+
task.shutdown
|
57
|
+
if final_state_via == FinalStateVia::LOCATION
|
58
|
+
if !polling_state.response.body.to_s.empty?
|
59
|
+
body = JSON.load(polling_state.response.body)
|
60
|
+
polling_state.resource = custom_deserialization_block.call(body)
|
61
|
+
else
|
62
|
+
fail HaipaOperationError, 'Location header is missing from long running operation'
|
63
|
+
end
|
64
|
+
else
|
65
|
+
fail HaipaOperationError, 'Location header is missing from long running operation'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if AsyncOperationStatus.is_terminal_status(polling_state.status)
|
70
|
+
task.shutdown
|
71
|
+
end
|
72
|
+
rescue Exception => e
|
73
|
+
task.shutdown
|
74
|
+
e
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
polling_delay = polling_state.get_delay
|
79
|
+
polling_delay = 0.1 if polling_delay.nil? || polling_delay == 0
|
80
|
+
|
81
|
+
task.execution_interval = polling_delay
|
82
|
+
task.execute
|
83
|
+
task.wait_for_termination
|
84
|
+
|
85
|
+
polling_error = task.value
|
86
|
+
fail polling_error if polling_error.is_a?(Exception)
|
87
|
+
end
|
88
|
+
|
89
|
+
if AsyncOperationStatus.is_successful_status(polling_state.status)
|
90
|
+
# Process long-running PUT/PATCH
|
91
|
+
if (http_method === :put || http_method === :patch) && polling_state.resource.nil?
|
92
|
+
get_request = MsRest::HttpOperationRequest.new(request.base_uri, request.build_path.to_s, :get, {query_params: request.query_params, headers: request.headers})
|
93
|
+
update_state_from_get_resource_operation(get_request, polling_state, custom_deserialization_block)
|
94
|
+
end
|
95
|
+
|
96
|
+
if final_state_via == FinalStateVia::LOCATION
|
97
|
+
if((http_method === :post || http_method === :delete) && !polling_state.location_header_link.nil?)
|
98
|
+
update_state_from_location_header(polling_state.get_request(headers: request.headers, base_uri: request.base_uri, user_agent_extended: user_agent_extended), polling_state, custom_deserialization_block, final_state_via)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Process long-running POST/DELETE operation with schema defined on success status codes
|
103
|
+
if (http_method === :post || http_method === :delete) && custom_deserialization_block && polling_state.response
|
104
|
+
unless polling_state.response.body.to_s.empty?
|
105
|
+
body = JSON.load(polling_state.response.body)
|
106
|
+
polling_state.resource = custom_deserialization_block.call(body)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
if AsyncOperationStatus.is_failed_status(polling_state.status)
|
112
|
+
fail polling_state.get_operation_error
|
113
|
+
end
|
114
|
+
|
115
|
+
polling_state.get_operation_response
|
116
|
+
end
|
117
|
+
|
118
|
+
#
|
119
|
+
# Verifies for unexpected polling status code
|
120
|
+
# @param haipa_response [Haipa::Client::HaipaOperationResponse] response from Haipa service.
|
121
|
+
#
|
122
|
+
def check_for_status_code_failure(haipa_response)
|
123
|
+
fail MsRest::ValidationError, 'Haipa response cannot be nil' if haipa_response.nil?
|
124
|
+
fail MsRest::ValidationError, 'Haipa response cannot have empty response object' if haipa_response.response.nil?
|
125
|
+
fail MsRest::ValidationError, 'Haipa response cannot have empty request object' if haipa_response.request.nil?
|
126
|
+
|
127
|
+
status_code = haipa_response.response.status
|
128
|
+
http_method = haipa_response.request.method
|
129
|
+
|
130
|
+
fail HaipaOperationError, "Unexpected polling status code from long running operation #{status_code}" unless status_code === 200 || status_code === 202 ||
|
131
|
+
(status_code === 201 && http_method === :put) ||
|
132
|
+
(status_code === 204 && (http_method === :delete || http_method === :post))
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Updates polling state based on location header for PUT HTTP requests.
|
137
|
+
# @param request [MsRest::HttpOperationRequest] The url retrieve data from.
|
138
|
+
# @param polling_state [Haipa::Client::PollingState] polling state to update.
|
139
|
+
# @param custom_deserialization_block [Proc] custom deserialization method for parsing response.
|
140
|
+
#
|
141
|
+
def update_state_from_get_resource_operation(request, polling_state, custom_deserialization_block)
|
142
|
+
result = get_async_with_custom_deserialization(request, custom_deserialization_block)
|
143
|
+
|
144
|
+
fail HaipaOperationError, 'The response from long running operation does not contain a body' if result.response.body.nil? || result.response.body.empty?
|
145
|
+
|
146
|
+
# On non flattened resource, we should find provisioning_state inside 'properties'
|
147
|
+
if result.body.respond_to?(:properties) && result.body.properties.respond_to?(:provisioning_state) && !result.body.properties.provisioning_state.nil?
|
148
|
+
polling_state.status = result.body.properties.provisioning_state
|
149
|
+
# On flattened resource, we should find provisioning_state at the top level
|
150
|
+
elsif result.body.respond_to?(:provisioning_state) && !result.body.provisioning_state.nil?
|
151
|
+
polling_state.status = result.body.provisioning_state
|
152
|
+
else
|
153
|
+
polling_state.status = AsyncOperationStatus::SUCCESS_STATUS
|
154
|
+
end
|
155
|
+
|
156
|
+
error_data = CloudErrorData.new
|
157
|
+
error_data.code = polling_state.status
|
158
|
+
error_data.message = "Long running operation failed with status #{polling_state.status}"
|
159
|
+
|
160
|
+
polling_state.error_data = error_data
|
161
|
+
polling_state.update_response(result.response)
|
162
|
+
polling_state.request = result.request
|
163
|
+
polling_state.resource = result.body
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# Updates polling state based on location header for HTTP requests.
|
168
|
+
# @param request [MsRest::HttpOperationRequest] The url retrieve data from.
|
169
|
+
# @param polling_state [Haipa::Client::PollingState] polling state to update.
|
170
|
+
# @param custom_deserialization_block [Proc] custom deserialization method for parsing response.
|
171
|
+
# @param final_state_via [Haipa::Client::FinalStateVia] Final State via value
|
172
|
+
#
|
173
|
+
def update_state_from_location_header(request, polling_state, custom_deserialization_block, final_state_via = FinalStateVia::DEFAULT)
|
174
|
+
result = get_async_with_custom_deserialization(request, custom_deserialization_block)
|
175
|
+
|
176
|
+
polling_state.update_response(result.response)
|
177
|
+
polling_state.request = result.request
|
178
|
+
status_code = result.response.status
|
179
|
+
http_method = request.method
|
180
|
+
|
181
|
+
if status_code === 202
|
182
|
+
polling_state.status = AsyncOperationStatus::IN_PROGRESS_STATUS
|
183
|
+
elsif status_code === 200 || (status_code === 201 && http_method === :put) ||
|
184
|
+
(status_code === 204 && (http_method === :delete || http_method === :post || http_method === :get))
|
185
|
+
polling_state.status = AsyncOperationStatus::SUCCESS_STATUS
|
186
|
+
|
187
|
+
error_data = CloudErrorData.new
|
188
|
+
error_data.code = polling_state.status
|
189
|
+
error_data.message = "Long running operation failed with status #{polling_state.status}"
|
190
|
+
|
191
|
+
polling_state.error_data = error_data
|
192
|
+
polling_state.resource = result.body
|
193
|
+
elsif final_state_via == FinalStateVia::LOCATION && status_code === 404 && http_method === :delete && !polling_state.Haipa_async_operation_header_link.nil? && !polling_state.location_header_link.nil?
|
194
|
+
polling_state.status = AsyncOperationStatus::SUCCESS_STATUS
|
195
|
+
else
|
196
|
+
fail HaipaOperationError, "The response from long running operation does not have a valid status code. Method: #{http_method}, Status Code: #{status_code}"
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
#
|
201
|
+
# Updates polling state from Haipa async operation header.
|
202
|
+
# @param polling_state [Haipa::Client::PollingState] polling state.
|
203
|
+
#
|
204
|
+
def update_state_from_Haipa_async_operation_header(request, polling_state)
|
205
|
+
result = get_async_with_async_operation_deserialization(request)
|
206
|
+
|
207
|
+
fail HaipaOperationError, 'The response from long running operation does not contain a body' if result.body.nil? || result.body.status.nil?
|
208
|
+
|
209
|
+
polling_state.status = result.body.status
|
210
|
+
polling_state.error_data = result.body.error
|
211
|
+
polling_state.response = result.response
|
212
|
+
polling_state.request = result.request
|
213
|
+
polling_state.resource = nil
|
214
|
+
|
215
|
+
polling_state
|
216
|
+
end
|
217
|
+
|
218
|
+
#
|
219
|
+
# Retrieves data by given URL.
|
220
|
+
# @param request [MsRest::HttpOperationRequest] the URL.
|
221
|
+
# @param custom_deserialization_block [Proc] function to perform deserialization of the HTTP response.
|
222
|
+
#
|
223
|
+
# @return [MsRest::HttpOperationResponse] the response.
|
224
|
+
#
|
225
|
+
def get_async_with_custom_deserialization(request, custom_deserialization_block)
|
226
|
+
result = get_async_common(request)
|
227
|
+
|
228
|
+
if !result.body.nil? && !custom_deserialization_block.nil?
|
229
|
+
begin
|
230
|
+
result.body = custom_deserialization_block.call(result.body)
|
231
|
+
rescue Exception => e
|
232
|
+
fail MsRest::DeserializationError.new("Error occured in deserializing the response", e.message, e.backtrace, http_response.body)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
result
|
237
|
+
end
|
238
|
+
|
239
|
+
#
|
240
|
+
# Retrieves data by given URL.
|
241
|
+
# @param request [MsRest::HttpOperationRequest] the URL.
|
242
|
+
#
|
243
|
+
# @return [MsRest::HttpOperationResponse] the response.
|
244
|
+
#
|
245
|
+
def get_async_with_async_operation_deserialization(request)
|
246
|
+
result = get_async_common(request)
|
247
|
+
|
248
|
+
result.body = AsyncOperationStatus.deserialize_object(result.body)
|
249
|
+
|
250
|
+
result
|
251
|
+
end
|
252
|
+
|
253
|
+
#
|
254
|
+
# Retrieves data by given URL.
|
255
|
+
# @param request [MsRest::HttpOperationRequest] the URL.
|
256
|
+
#
|
257
|
+
# @return [MsRest::HttpOperationResponse] the response.
|
258
|
+
#
|
259
|
+
def get_async_common(request)
|
260
|
+
fail ValidationError, 'Request cannot be nil' if request.nil?
|
261
|
+
|
262
|
+
request.middlewares = [[MsRest::RetryPolicyMiddleware, times: 3, retry: 0.02], [:cookie_jar]]
|
263
|
+
request.headers.merge!({'x-ms-client-request-id' => SecureRandom.uuid}) unless request.headers.key?('x-ms-client-request-id')
|
264
|
+
request.headers.merge!({'Content-Type' => 'application/json'}) unless request.headers.key?('Content-Type')
|
265
|
+
|
266
|
+
# Send Request
|
267
|
+
http_response = request.run_promise do |req|
|
268
|
+
@credentials.sign_request(req) unless @credentials.nil?
|
269
|
+
end.execute.value!
|
270
|
+
|
271
|
+
status_code = http_response.status
|
272
|
+
|
273
|
+
if status_code != 200 && status_code != 201 && status_code != 202 && status_code != 204
|
274
|
+
json_error_data = JSON.load(http_response.body)
|
275
|
+
error_data = CloudErrorData.deserialize_object(json_error_data)
|
276
|
+
|
277
|
+
fail HaipaOperationError.new request, http_response, error_data, "Long running operation failed with status #{status_code}"
|
278
|
+
end
|
279
|
+
|
280
|
+
result = MsRest::HttpOperationResponse.new(request, http_response, http_response.body)
|
281
|
+
|
282
|
+
begin
|
283
|
+
result.body = JSON.load(http_response.body) unless http_response.body.to_s.empty?
|
284
|
+
rescue Exception => e
|
285
|
+
fail MsRest::DeserializationError.new("Error occured in deserializing the response", e.message, e.backtrace, result)
|
286
|
+
end
|
287
|
+
|
288
|
+
result
|
289
|
+
end
|
290
|
+
|
291
|
+
private
|
292
|
+
#
|
293
|
+
# Retrieves a new instance of the HaipaOperationResponse class.
|
294
|
+
# @param [MsRest::HttpOperationRequest] request the HTTP request object.
|
295
|
+
# @param [Faraday::Response] response the HTTP response object.
|
296
|
+
# @param [String] body the HTTP response body.
|
297
|
+
# @return [Haipa::Client::HaipaOperationResponse] the operation response.
|
298
|
+
#
|
299
|
+
def create_response(request, http_response, body = nil)
|
300
|
+
HaipaOperationResponse.new(request, http_response, body)
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents a state of Haipa long running operation.
|
8
|
+
#
|
9
|
+
class PollingState
|
10
|
+
|
11
|
+
# @return [Net::HTTPRequest] the HTTP request.
|
12
|
+
attr_accessor :request
|
13
|
+
|
14
|
+
# @return the resource
|
15
|
+
attr_accessor :resource
|
16
|
+
|
17
|
+
# @return [Net::HTTPResponse] the HTTP response.
|
18
|
+
attr_accessor :response
|
19
|
+
|
20
|
+
# @return [HaipaOperationError] the Haipa error data.
|
21
|
+
attr_accessor :error_data
|
22
|
+
|
23
|
+
# @return [String] the latest value captured from Haipa-AsyncOperation header.
|
24
|
+
attr_accessor :Haipa_async_operation_header_link
|
25
|
+
|
26
|
+
# @return [String] the latest value captured from Location header.
|
27
|
+
attr_accessor :location_header_link
|
28
|
+
|
29
|
+
# @return [String] status of the long running operation.
|
30
|
+
attr_accessor :status
|
31
|
+
|
32
|
+
def initialize(haipa_response, retry_timeout)
|
33
|
+
@retry_timeout = retry_timeout
|
34
|
+
@request = haipa_response.request
|
35
|
+
update_response(haipa_response.response)
|
36
|
+
@resource = haipa_response.body
|
37
|
+
|
38
|
+
case @response.status
|
39
|
+
when 200
|
40
|
+
provisioning_state = get_provisioning_state
|
41
|
+
@status = provisioning_state.nil?? (AsyncOperationStatus::SUCCESS_STATUS):provisioning_state
|
42
|
+
when 201
|
43
|
+
provisioning_state = get_provisioning_state
|
44
|
+
@status = provisioning_state.nil?? (AsyncOperationStatus::IN_PROGRESS_STATUS):provisioning_state
|
45
|
+
when 202
|
46
|
+
@status = AsyncOperationStatus::IN_PROGRESS_STATUS
|
47
|
+
when 204
|
48
|
+
@status = AsyncOperationStatus::SUCCESS_STATUS
|
49
|
+
else
|
50
|
+
@status = AsyncOperationStatus::FAILED_STATUS
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Returns the provisioning status of the resource
|
56
|
+
#
|
57
|
+
# @return [String] provisioning status of the resource
|
58
|
+
def get_provisioning_state
|
59
|
+
# On non flattened resource, we should find provisioning_state inside 'properties'
|
60
|
+
if (!@resource.nil? && @resource.respond_to?(:properties) && @resource.properties.respond_to?(:provisioning_state) && !@resource.properties.provisioning_state.nil?)
|
61
|
+
@resource.properties.provisioning_state
|
62
|
+
# On flattened resource, we should find provisioning_state at the top level
|
63
|
+
elsif !@resource.nil? && @resource.respond_to?(:provisioning_state) && !@resource.provisioning_state.nil?
|
64
|
+
@resource.provisioning_state
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Returns the amount of time in seconds for long running operation polling delay.
|
72
|
+
#
|
73
|
+
# @return [Integer] Amount of time in seconds for long running operation polling delay.
|
74
|
+
def get_delay
|
75
|
+
return @retry_timeout unless @retry_timeout.nil?
|
76
|
+
|
77
|
+
if !response.nil? && !response.headers['Retry-After'].nil?
|
78
|
+
return response.headers['Retry-After'].to_i
|
79
|
+
end
|
80
|
+
|
81
|
+
return AsyncOperationStatus::DEFAULT_DELAY
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Updates the polling state from the fields of given response object.
|
86
|
+
# @param response [Net::HTTPResponse] the HTTP response.
|
87
|
+
def update_response(response)
|
88
|
+
@response = response
|
89
|
+
|
90
|
+
unless response.nil?
|
91
|
+
@Haipa_async_operation_header_link = response.headers['Haipa-AsyncOperation'] unless response.headers['Haipa-AsyncOperation'].nil?
|
92
|
+
@location_header_link = response.headers['Location'] unless response.headers['Location'].nil?
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# returns the Haipa's response.
|
98
|
+
#
|
99
|
+
# @return [Haipa::Client::HaipaOperationResponse] Haipa's response.
|
100
|
+
def get_operation_response
|
101
|
+
haipa_response = HaipaOperationResponse.new(@request, @response, @resource)
|
102
|
+
haipa_response
|
103
|
+
end
|
104
|
+
|
105
|
+
#
|
106
|
+
# Composes and returns cloud error.
|
107
|
+
#
|
108
|
+
# @return [HaipaOperationError] the cloud error.
|
109
|
+
def get_operation_error
|
110
|
+
HaipaOperationError.new @request, @response, @error_data, "Long running operation failed with status #{@status}"
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_request(options = {})
|
114
|
+
link = @Haipa_async_operation_header_link || @location_header_link
|
115
|
+
options[:connection] = create_connection(options[:base_uri])
|
116
|
+
MsRest::HttpOperationRequest.new(nil, link, :get, options)
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
# @return [Integer] retry timeout.
|
122
|
+
attr_accessor :retry_timeout
|
123
|
+
|
124
|
+
attr_accessor :connection
|
125
|
+
|
126
|
+
def create_connection(base_url)
|
127
|
+
@connection ||= Faraday.new(:url => base_url, :ssl => MsRest.ssl_options) do |faraday|
|
128
|
+
[[MsRest::RetryPolicyMiddleware, times: 3, retry: 0.02], [:cookie_jar]].each{ |args| faraday.use(*args) }
|
129
|
+
faraday.adapter Faraday.default_adapter
|
130
|
+
faraday.headers = request.headers
|
131
|
+
logging = ENV['HAIPA_HTTP_LOGGING'] || request.log
|
132
|
+
if logging
|
133
|
+
faraday.response :logger, nil, { :bodies => logging == 'full' }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
# Base module for Haipa Ruby serialization and deserialization.
|
7
|
+
#
|
8
|
+
# Provides methods to serialize Ruby object into Ruby Hash and
|
9
|
+
# to deserialize Ruby Hash into Ruby object.
|
10
|
+
module Serialization
|
11
|
+
include MsRest::Serialization
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
#
|
16
|
+
# Builds serializer
|
17
|
+
#
|
18
|
+
def build_serializer
|
19
|
+
Serialization.new(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Class to handle serialization & deserialization.
|
24
|
+
#
|
25
|
+
class Serialization < MsRest::Serialization::Serialization
|
26
|
+
|
27
|
+
#
|
28
|
+
# Retrieves model of the model_name
|
29
|
+
#
|
30
|
+
# @param model_name [String] Name of the model to retrieve.
|
31
|
+
#
|
32
|
+
def get_model(model_name)
|
33
|
+
begin
|
34
|
+
Object.const_get(@context.class.to_s.split('::')[0...-1].join('::') + "::Models::#{model_name}")
|
35
|
+
rescue NameError
|
36
|
+
# Look into Haipa::Client namespace if model name not found in the models namespace
|
37
|
+
Object.const_get("Haipa::Client::#{model_name}")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa::Client
|
6
|
+
#
|
7
|
+
# Class which represents the error type and information.
|
8
|
+
#
|
9
|
+
class TypedErrorInfo
|
10
|
+
|
11
|
+
# @return [String] the error type parsed from the body of the http error response.
|
12
|
+
attr_accessor :type
|
13
|
+
|
14
|
+
# @return [Object] the error info parsed from the body of the http error response.
|
15
|
+
attr_accessor :info
|
16
|
+
|
17
|
+
#
|
18
|
+
# Deserializes given hash into TypedErrorInfo object.
|
19
|
+
# @param object [Hash] object to deserialize.
|
20
|
+
#
|
21
|
+
# @return [TypedErrorInfo] deserialized object.
|
22
|
+
def self.deserialize_object(object)
|
23
|
+
return if object.nil?
|
24
|
+
output_object = TypedErrorInfo.new
|
25
|
+
|
26
|
+
output_object.type = object['type']
|
27
|
+
|
28
|
+
output_object.info = object['info']
|
29
|
+
|
30
|
+
output_object
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) dbosoft GmbH and Haipa Contributors. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module Haipa end
|
6
|
+
module Haipa::Client
|
7
|
+
REST_VERSION = '0.11.1'
|
8
|
+
end
|
metadata
ADDED
@@ -0,0 +1,162 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: haipa_rest
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.11.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Haipa Contributors
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-08-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: concurrent-ruby
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: unf_ext
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.0.7.2
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.0.7.2
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: faraday
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.9'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.9'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: ms_rest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.7.4
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.7.4
|
111
|
+
description: Haipa Client Library for Ruby.
|
112
|
+
email: package-maintainers@haipa.io
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- LICENSE.txt
|
118
|
+
- README.md
|
119
|
+
- lib/haipa_rest.rb
|
120
|
+
- lib/haipa_rest/async_operation_status.rb
|
121
|
+
- lib/haipa_rest/cloud_error_data.rb
|
122
|
+
- lib/haipa_rest/common/configurable.rb
|
123
|
+
- lib/haipa_rest/common/default.rb
|
124
|
+
- lib/haipa_rest/credentials/application_token_provider.rb
|
125
|
+
- lib/haipa_rest/final_state_via.rb
|
126
|
+
- lib/haipa_rest/haipa_cli_error.rb
|
127
|
+
- lib/haipa_rest/haipa_operation_error.rb
|
128
|
+
- lib/haipa_rest/haipa_operation_response.rb
|
129
|
+
- lib/haipa_rest/haipa_service_client.rb
|
130
|
+
- lib/haipa_rest/polling_state.rb
|
131
|
+
- lib/haipa_rest/serialization.rb
|
132
|
+
- lib/haipa_rest/typed_error_info.rb
|
133
|
+
- lib/haipa_rest/version.rb
|
134
|
+
homepage: https://github.com/haipa/ruby-client
|
135
|
+
licenses:
|
136
|
+
- MIT
|
137
|
+
metadata:
|
138
|
+
bug_tracker_uri: https://github.com/haipa/haipa/issues
|
139
|
+
documentation_uri: https://github.com/haipa/ruby-client
|
140
|
+
homepage_uri: https://github.com/haipa/ruby-client
|
141
|
+
source_code_uri: https://github.com/haipa/ruby-client
|
142
|
+
post_install_message:
|
143
|
+
rdoc_options: []
|
144
|
+
require_paths:
|
145
|
+
- lib
|
146
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: 2.0.0
|
151
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - ">="
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '0'
|
156
|
+
requirements: []
|
157
|
+
rubyforge_project:
|
158
|
+
rubygems_version: 2.7.6
|
159
|
+
signing_key:
|
160
|
+
specification_version: 4
|
161
|
+
summary: Haipa Client Library for Ruby.
|
162
|
+
test_files: []
|