class MU::Cloud::Azure::SDKClient::ClientCallWrapper

The Azure SDK embeds several “sub-APIs” in each SDK client, and most API calls are made from these second-tier objects. We add an extra wrapper layer for these so that we can gracefully handle errors, retries, etc.

Public Class Methods

new(myobject, myname, parent) click to toggle source
# File modules/mu/providers/azure.rb, line 1086
def initialize(myobject, myname, parent)
  @myobject = myobject
  @myname = myname
  @parent = parent
  @parentname = parent.subclass
end

Public Instance Methods

method_missing(method_sym, *arguments) click to toggle source

For method calls into the Azure API @param method_sym [Symbol] @param arguments [Array]

# File modules/mu/providers/azure.rb, line 1096
          def method_missing(method_sym, *arguments)
            MU.log "Calling #{@parentname}.#{@myname}.#{method_sym.to_s}", MU::DEBUG, details: arguments
            retries = 0
            begin
              if !arguments.nil? and arguments.size == 1
                retval = @myobject.method(method_sym).call(arguments[0])
              elsif !arguments.nil? and arguments.size > 0
                retval = @myobject.method(method_sym).call(*arguments)
              else
                retval = @myobject.method(method_sym).call
              end
            rescue ::Net::ReadTimeout, ::Faraday::TimeoutError, ::Faraday::ConnectionFailed => e
              sleep 5
              if retries < 12
                MU.log e.message+" calling #{@parentname}.#{@myname}.#{method_sym.to_s}(#{arguments.map { |a| a.to_s }.join(", ")})", MU::DEBUG, details: caller
                retries += 1
                retry
              else
                MU.log e.message+" calling #{@parentname}.#{@myname}.#{method_sym.to_s}(#{arguments.map { |a| a.to_s }.join(", ")})", MU::ERR, details: caller
                raise e
              end
            rescue ::MsRestAzure::AzureOperationError, ::MsRest::HttpOperationError => e
              MU.log "Error calling #{@parent.api.class.name}.#{@myname}.#{method_sym.to_s}", MU::DEBUG, details: arguments
              begin
                parsed = JSON.parse(e.message)
                if parsed["response"] and parsed["response"]["body"]
                  response = JSON.parse(parsed["response"]["body"])
                  err = if response["code"] and response["message"]
                    response
                  elsif response["error"] and response["error"]["code"] and
                        response["error"]["message"]
                    response["error"]
                  end
                  if err
                    if method_sym == :get and
                       ["ResourceNotFound", "NotFound"].include?(err["code"])
                      return nil
                    elsif err["code"] == "AnotherOperationInProgress"
                      sleep 10
                      retry
                    end

#                    MU.log "#{@parent.api.class.name}.#{@myname}.#{method_sym.to_s} returned '"+err["code"]+"' - "+err["message"], MU::WARN, details: caller
#                    MU.log e.backtrace[0], MU::WARN, details: parsed
                    raise MU::Cloud::Azure::APIError.new err["code"]+": "+err["message"]+" (call was #{@parent.api.class.name}.#{@myname}.#{method_sym.to_s})", details: parsed, silent: true
                  end
                end
              rescue JSON::ParserError
              end
#              MU.log e.inspect, MU::ERR, details: caller
#              MU.log e.message, MU::ERR, details: @parent.credentials
            end

            retval
          end