Class: MsRestAzure::AzureServiceClient

Inherits:
MsRest::ServiceClient
  • Object
show all
Defined in:
lib/ms_rest_azure/azure_service_client.rb

Overview

Class which represents a point of access to the REST API.

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#api_versionString

Returns api version of the Azure in string format.

Returns:

  • (String)

    api version of the Azure in string format.



15
16
17
# File 'lib/ms_rest_azure/azure_service_client.rb', line 15

def api_version
  @api_version
end

#long_running_operation_retry_timeoutInteger

Returns execution interval for long running operations.

Returns:

  • (Integer)

    execution interval for long running operations.



12
13
14
# File 'lib/ms_rest_azure/azure_service_client.rb', line 12

def long_running_operation_retry_timeout
  @long_running_operation_retry_timeout
end

Instance Method Details

#check_for_status_code_failure(azure_response) ⇒ Object

Verifies for unexpected polling status code

Parameters:



101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/ms_rest_azure/azure_service_client.rb', line 101

def check_for_status_code_failure(azure_response)
  fail MsRest::ValidationError, 'Azure response cannot be nil' if azure_response.nil?
  fail MsRest::ValidationError, 'Azure response cannot have empty response object' if azure_response.response.nil?
  fail MsRest::ValidationError, 'Azure response cannot have empty request object' if azure_response.request.nil?

  status_code = azure_response.response.status
  http_method = azure_response.request.method

  fail AzureOperationError, "Unexpected polling status code from long running operation #{status_code}" unless status_code === 200 || status_code === 202 ||
      (status_code === 201 && http_method === :put) ||
      (status_code === 204 && (http_method === :delete || http_method === :post))
end

#get_async_common(request) ⇒ MsRest::HttpOperationResponse

Retrieves data by given URL.

Parameters:

  • request (MsRest::HttpOperationRequest)

    the URL.

Returns:

  • (MsRest::HttpOperationResponse)

    the response.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# File 'lib/ms_rest_azure/azure_service_client.rb', line 223

def get_async_common(request)
  fail ValidationError, 'Request cannot be nil' if request.nil?

  request.middlewares = [[MsRest::RetryPolicyMiddleware, times: 3, retry: 0.02], [:cookie_jar]]
  request.headers.merge!({'x-ms-client-request-id' => SecureRandom.uuid, 'Content-Type' => 'application/json'})

  # Send Request
  http_response = request.run_promise do |req|
    @credentials.sign_request(req) unless @credentials.nil?
  end.execute.value!

  status_code = http_response.status

  if status_code != 200 && status_code != 201 && status_code != 202 && status_code != 204
    json_error_data = JSON.load(http_response.body)
    error_data = CloudErrorData.deserialize_object(json_error_data)

    fail AzureOperationError.new request, http_response, error_data, "Long running operation failed with status #{status_code}"
  end

  result = MsRest::HttpOperationResponse.new(request, http_response, http_response.body)

  begin
    result.body = JSON.load(http_response.body) unless http_response.body.to_s.empty?
  rescue Exception => e
    fail MsRest::DeserializationError.new("Error occured in deserializing the response", e.message, e.backtrace, result)
  end

  result
end

#get_async_with_async_operation_deserialization(request) ⇒ MsRest::HttpOperationResponse

Retrieves data by given URL.

Parameters:

  • request (MsRest::HttpOperationRequest)

    the URL.

Returns:

  • (MsRest::HttpOperationResponse)

    the response.



211
212
213
214
215
216
# File 'lib/ms_rest_azure/azure_service_client.rb', line 211

def get_async_with_async_operation_deserialization(request)
  result = get_async_common(request)

  result.body = AsyncOperationStatus.deserialize_object(result.body)
  result
end

#get_async_with_custom_deserialization(request, custom_deserialization_block) ⇒ MsRest::HttpOperationResponse

Retrieves data by given URL.

Parameters:

  • request (MsRest::HttpOperationRequest)

    the URL.

  • custom_deserialization_block (Proc)

    function to perform deserialization of the HTTP response.

Returns:

  • (MsRest::HttpOperationResponse)

    the response.



192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/ms_rest_azure/azure_service_client.rb', line 192

def get_async_with_custom_deserialization(request, custom_deserialization_block)
  result = get_async_common(request)

  if !result.body.nil? && !custom_deserialization_block.nil?
    begin
      result.body = custom_deserialization_block.call(result.body)
    rescue Exception => e
      fail MsRest::DeserializationError.new("Error occured in deserializing the response", e.message, e.backtrace, http_response.body)
    end
  end

  result
end

#get_long_running_operation_result(azure_response, custom_deserialization_block) ⇒ MsRest::HttpOperationResponse

Retrieves the result of ‘POST’,‘DELETE’,‘PUT’ or ‘PATCH’ operation. Performs polling of required.

Parameters:

Returns:

  • (MsRest::HttpOperationResponse)

    the response.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/ms_rest_azure/azure_service_client.rb', line 23

def get_long_running_operation_result(azure_response, custom_deserialization_block)
  check_for_status_code_failure(azure_response)

  http_method = azure_response.request.method

  polling_state = PollingState.new(azure_response, @long_running_operation_retry_timeout)
  request = azure_response.request

  if !AsyncOperationStatus.is_terminal_status(polling_state.status)
    task = Concurrent::TimerTask.new do
      begin
        if !polling_state.azure_async_operation_header_link.nil?
          update_state_from_azure_async_operation_header(polling_state.get_request(headers: request.headers, base_uri: request.base_uri), polling_state)
        elsif !polling_state.location_header_link.nil?
          update_state_from_location_header(polling_state.get_request(headers: request.headers, base_uri: request.base_uri), polling_state, custom_deserialization_block)
        elsif http_method === :put
          get_request = MsRest::HttpOperationRequest.new(request.base_uri, request.build_path.to_s, :get, query_params: request.query_params)
          update_state_from_get_resource_operation(get_request, polling_state, custom_deserialization_block)
        else
          task.shutdown
          fail AzureOperationError, 'Location header is missing from long running operation'
        end

        if AsyncOperationStatus.is_terminal_status(polling_state.status)
          task.shutdown
        end
      rescue Exception => e
        task.shutdown
        e
      end
    end

    polling_delay = polling_state.get_delay
    polling_delay = 0.1 if polling_delay.nil? || polling_delay == 0

    task.execution_interval = polling_delay
    task.execute
    task.wait_for_termination

    polling_error = task.value
    fail polling_error if polling_error.is_a?(Exception)
  end

  if (http_method === :put || http_method === :patch) && AsyncOperationStatus.is_successful_status(polling_state.status) && polling_state.resource.nil?
    get_request = MsRest::HttpOperationRequest.new(request.base_uri, request.build_path.to_s, :get, query_params: request.query_params)
    update_state_from_get_resource_operation(get_request, polling_state, custom_deserialization_block)
  end

  if AsyncOperationStatus.is_failed_status(polling_state.status)
    fail polling_state.get_operation_error
  end

  polling_state.get_operation_response
end

#get_post_or_delete_operation_result(azure_response, custom_deserialization_block) ⇒ MsRest::HttpOperationResponse

Retrieves the result of ‘POST’ or ‘DELETE’ operations. Performs polling of required.

Parameters:

Returns:

  • (MsRest::HttpOperationResponse)

    the response.



94
95
96
# File 'lib/ms_rest_azure/azure_service_client.rb', line 94

def get_post_or_delete_operation_result(azure_response, custom_deserialization_block)
  get_long_running_operation_result(azure_response, custom_deserialization_block)
end

#get_put_operation_result(azure_response, custom_deserialization_block) ⇒ MsRest::HttpOperationResponse

Retrieves the result of ‘PUT’ or ‘PATCH’ operation. Performs polling of required.

Parameters:

Returns:

  • (MsRest::HttpOperationResponse)

    the response.



84
85
86
# File 'lib/ms_rest_azure/azure_service_client.rb', line 84

def get_put_operation_result(azure_response, custom_deserialization_block)
  get_long_running_operation_result(azure_response, custom_deserialization_block)
end

#update_state_from_azure_async_operation_header(request, polling_state) ⇒ Object

Updates polling state from Azure async operation header.

Parameters:



174
175
176
177
178
179
180
181
182
183
184
# File 'lib/ms_rest_azure/azure_service_client.rb', line 174

def update_state_from_azure_async_operation_header(request, polling_state)
  result = get_async_with_async_operation_deserialization(request)

  fail AzureOperationError, 'The response from long running operation does not contain a body' if result.body.nil? || result.body.status.nil?

  polling_state.status = result.body.status
  polling_state.error_data = result.body.error
  polling_state.response = result.response
  polling_state.request = result.request
  polling_state.resource = nil
end

#update_state_from_get_resource_operation(request, polling_state, custom_deserialization_block) ⇒ Object

Updates polling state based on location header for PUT HTTP requests.

Parameters:

  • request (MsRest::HttpOperationRequest)

    The url retrieve data from.

  • polling_state (MsRestAzure::PollingState)

    polling state to update.

  • custom_deserialization_block (Proc)

    custom deserialization method for parsing response.



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/ms_rest_azure/azure_service_client.rb', line 120

def update_state_from_get_resource_operation(request, polling_state, custom_deserialization_block)
  result = get_async_with_custom_deserialization(request, custom_deserialization_block)

  fail AzureOperationError, 'The response from long running operation does not contain a body' if result.response.body.nil? || result.response.body.empty?

  if result.body.respond_to?(:properties) && result.body.properties.respond_to?(:provisioning_state) && !result.body.properties.provisioning_state.nil?
    polling_state.status = result.body.properties.provisioning_state
  else
    polling_state.status = AsyncOperationStatus::SUCCESS_STATUS
  end

  error_data = CloudErrorData.new
  error_data.code = polling_state.status
  error_data.message = "Long running operation failed with status #{polling_state.status}"

  polling_state.error_data = error_data
  polling_state.update_response(result.response)
  polling_state.request = result.request
  polling_state.resource = result.body
end

#update_state_from_location_header(request, polling_state, custom_deserialization_block) ⇒ Object

Updates polling state based on location header for HTTP requests.

Parameters:

  • request (MsRest::HttpOperationRequest)

    The url retrieve data from.

  • polling_state (MsRestAzure::PollingState)

    polling state to update.

  • custom_deserialization_block (Proc)

    custom deserialization method for parsing response.



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/ms_rest_azure/azure_service_client.rb', line 146

def update_state_from_location_header(request, polling_state, custom_deserialization_block)
  result = get_async_with_custom_deserialization(request, custom_deserialization_block)

  polling_state.update_response(result.response)
  polling_state.request = result.request
  status_code = result.response.status
  http_method = request.method

  if status_code === 202
    polling_state.status = AsyncOperationStatus::IN_PROGRESS_STATUS
  elsif status_code === 200 || (status_code === 201 && http_method === :put) ||
      (status_code === 204 && (http_method === :delete || http_method === :post || http_method === :get))
    polling_state.status = AsyncOperationStatus::SUCCESS_STATUS

    error_data = CloudErrorData.new
    error_data.code = polling_state.status
    error_data.message = "Long running operation failed with status #{polling_state.status}"

    polling_state.error_data = error_data
    polling_state.resource = result.body
  else
    fail AzureOperationError, "The response from long running operation does not have a valid status code. Method: #{http_method}, Status Code: #{status_code}"
  end
end