Removing core, to move it as a separate gem (#366)
This commit is contained in:
Родитель
fe56690bea
Коммит
6068568091
|
@ -32,6 +32,7 @@ Gem::Specification.new do |s|
|
|||
s.required_ruby_version = '>= 1.9.3'
|
||||
|
||||
s.add_runtime_dependency('addressable', '~> 2.3')
|
||||
s.add_runtime_dependency('azure-core', '~> 0.1')
|
||||
s.add_runtime_dependency('faraday', '~> 0.9')
|
||||
s.add_runtime_dependency('faraday_middleware', '~> 0.10')
|
||||
s.add_runtime_dependency('json', '~> 1.8')
|
||||
|
|
|
@ -30,7 +30,6 @@ module Azure
|
|||
autoload :Default, 'azure/default'
|
||||
autoload :HttpClient, 'azure/http_client'
|
||||
autoload :Version, 'azure/version'
|
||||
autoload :HttpResponseHelper, 'azure/http_response_helper'
|
||||
|
||||
# helpers because the naming is far too verbose
|
||||
autoload :BaseManagementService, 'azure/base_management/base_management_service'
|
||||
|
@ -63,15 +62,6 @@ module Azure
|
|||
autoload :CloudService, 'azure/cloud_service_management/cloud_service'
|
||||
end
|
||||
|
||||
module Core
|
||||
autoload :Utility, 'azure/core/utility'
|
||||
autoload :Logger, 'azure/core/utility'
|
||||
autoload :Error, 'azure/core/error'
|
||||
autoload :Service, 'azure/core/service'
|
||||
autoload :FilteredService, 'azure/core/filtered_service'
|
||||
autoload :SignedService, 'azure/core/signed_service'
|
||||
end
|
||||
|
||||
module Queue
|
||||
autoload :QueueService, 'azure/queue/queue_service'
|
||||
autoload :Message, 'azure/queue/message'
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'azure/core'
|
||||
|
||||
module Azure
|
||||
module BaseManagement
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require "azure/core/configuration"
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Auth
|
||||
class Authorizer
|
||||
# Public: Signs an HTTP request before it's made, by adding the
|
||||
# Authorization header
|
||||
#
|
||||
# request - An Azure::Core::HttpRequest that hasn't been signed
|
||||
# signer - A signing strategy, such as Azure::Table::Auth::SharedKey
|
||||
#
|
||||
# Returns the modified request
|
||||
def sign(request, signer)
|
||||
signature = signer.sign(request.method, request.uri, request.headers)
|
||||
request.headers['Authorization'] = "#{signer.name} #{signature}"
|
||||
request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,118 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'cgi'
|
||||
require 'azure/core/auth/signer'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Auth
|
||||
class SharedKey < Signer
|
||||
# The Azure account's name.
|
||||
attr :account_name
|
||||
|
||||
# Initialize the Signer.
|
||||
#
|
||||
# @param account_name [String] The account name. Defaults to the one in the
|
||||
# global configuration.
|
||||
# @param access_key [String] The access_key encoded in Base64. Defaults to the
|
||||
# one in the global configuration.
|
||||
def initialize(account_name=Azure.storage_account_name, access_key=Azure.storage_access_key)
|
||||
@account_name = account_name
|
||||
super(access_key)
|
||||
end
|
||||
|
||||
# The name of the strategy.
|
||||
#
|
||||
# @return [String]
|
||||
def name
|
||||
'SharedKey'
|
||||
end
|
||||
|
||||
# Create the signature for the request parameters
|
||||
#
|
||||
# @param method [Symbol] HTTP request method.
|
||||
# @param uri [URI] URI of the request we're signing.
|
||||
# @param headers [Hash] HTTP request headers.
|
||||
#
|
||||
# @return [String] base64 encoded signature
|
||||
def sign(method, uri, headers)
|
||||
"#{account_name}:#{super(signable_string(method, uri, headers))}"
|
||||
end
|
||||
|
||||
# Sign the request
|
||||
#
|
||||
# @param req [Azure::Core::Http::HttpRequest] HTTP request to sign
|
||||
#
|
||||
# @return [Azure::Core::Http::HttpRequest]
|
||||
def sign_request(req)
|
||||
req.headers['Authorization'] = "#{name} #{sign(req.method, req.uri, req.headers)}"
|
||||
req
|
||||
end
|
||||
|
||||
# Generate the string to sign.
|
||||
#
|
||||
# @param method [Symbol] HTTP request method.
|
||||
# @param uri [URI] URI of the request we're signing.
|
||||
# @param headers [Hash] HTTP request headers.
|
||||
#
|
||||
# @return [String]
|
||||
def signable_string(method, uri, headers)
|
||||
[
|
||||
method.to_s.upcase,
|
||||
headers.fetch('Content-Encoding', ''),
|
||||
headers.fetch('Content-Language', ''),
|
||||
headers.fetch('Content-Length', ''),
|
||||
headers.fetch('Content-MD5', ''),
|
||||
headers.fetch('Content-Type', ''),
|
||||
headers.fetch('Date', ''),
|
||||
headers.fetch('If-Modified-Since', ''),
|
||||
headers.fetch('If-Match', ''),
|
||||
headers.fetch('If-None-Match', ''),
|
||||
headers.fetch('If-Unmodified-Since', ''),
|
||||
headers.fetch('Range', ''),
|
||||
canonicalized_headers(headers),
|
||||
canonicalized_resource(uri)
|
||||
].join("\n")
|
||||
end
|
||||
|
||||
# Calculate the Canonicalized Headers string for a request.
|
||||
#
|
||||
# @param headers [Hash] HTTP request headers.
|
||||
#
|
||||
# @return [String] a string with the canonicalized headers.
|
||||
def canonicalized_headers(headers)
|
||||
headers = headers.map { |k,v| [k.to_s.downcase, v] }
|
||||
headers.select! { |k,v| k =~ /^x-ms-/ }
|
||||
headers.sort_by! { |(k,v)| k }
|
||||
headers.map! { |k,v| '%s:%s' % [k, v] }
|
||||
headers.map! { |h| h.gsub(/\s+/, ' ') }.join("\n")
|
||||
end
|
||||
|
||||
# Calculate the Canonicalized Resource string for a request.
|
||||
#
|
||||
# @param uri [URI] URI of the request we're signing.
|
||||
#
|
||||
# @return [String] a string with the canonicalized resource.
|
||||
def canonicalized_resource(uri)
|
||||
resource = '/' + account_name + (uri.path.empty? ? '/' : uri.path)
|
||||
params = CGI.parse(uri.query.to_s).map { |k,v| [k.downcase, v] }
|
||||
params.sort_by! { |k,v| k }
|
||||
params.map! { |k,v| '%s:%s' % [k, v.map(&:strip).sort.join(',')] }
|
||||
[resource, *params].join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,48 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require "azure/core/auth/shared_key"
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Auth
|
||||
class SharedKeyLite < SharedKey
|
||||
# The name of the strategy.
|
||||
#
|
||||
# @return [String]
|
||||
def name
|
||||
'SharedKeyLite'
|
||||
end
|
||||
|
||||
# Generate the string to sign.
|
||||
#
|
||||
# @param method [Symbol] The HTTP request method.
|
||||
# @param uri [URI] The URI of the request we're signing.
|
||||
# @param headers [Hash] A Hash of HTTP request headers.
|
||||
#
|
||||
# Returns a plain text string.
|
||||
def signable_string(method, uri, headers)
|
||||
[
|
||||
method.to_s.upcase,
|
||||
headers.fetch('Content-MD5', ''),
|
||||
headers.fetch('Content-Type', ''),
|
||||
headers.fetch('Date') { raise IndexError, 'Headers must include Date' },
|
||||
canonicalized_headers(headers),
|
||||
canonicalized_resource(uri)
|
||||
].join("\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,51 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'openssl'
|
||||
require 'base64'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Auth
|
||||
# Utility class to sign strings with HMAC-256 and then encode the
|
||||
# signed string using Base64.
|
||||
class Signer
|
||||
# The access key for the account
|
||||
attr :access_key
|
||||
|
||||
# Initialize the Signer.
|
||||
#
|
||||
# @param access_key [String] The access_key encoded in Base64.
|
||||
def initialize(access_key)
|
||||
if access_key.nil?
|
||||
raise ArgumentError, 'Signing key must be provided'
|
||||
end
|
||||
|
||||
@access_key = Base64.strict_decode64(access_key)
|
||||
end
|
||||
|
||||
# Generate an HMAC signature.
|
||||
#
|
||||
# @param body [String] The string to sign.
|
||||
#
|
||||
# @return [String] a Base64 String signed with HMAC.
|
||||
def sign(body)
|
||||
signed = OpenSSL::HMAC.digest('sha256', access_key, body)
|
||||
Base64.strict_encode64(signed)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,21 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
module Azure
|
||||
module Core
|
||||
# Superclass for errors generated from this library, so people can
|
||||
# just rescue this for generic error handling
|
||||
class Error < StandardError;end
|
||||
end
|
||||
end
|
|
@ -1,45 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'azure/core/service'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
# A base class for Service implementations
|
||||
class FilteredService < Service
|
||||
|
||||
# Create a new instance of the FilteredService
|
||||
#
|
||||
# @param host [String] The hostname. (optional, Default empty)
|
||||
# @param options [Hash] options including {:client} (optional, Default {})
|
||||
def initialize(host='', options={})
|
||||
super
|
||||
@filters = []
|
||||
end
|
||||
|
||||
attr_accessor :filters
|
||||
|
||||
def call(method, uri, body=nil, headers=nil)
|
||||
super(method, uri, body, headers) do |request|
|
||||
filters.each { |filter| request.with_filter filter } if filters
|
||||
end
|
||||
end
|
||||
|
||||
def with_filter(filter=nil, &block)
|
||||
filter = filter || block
|
||||
filters.push filter if filter
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,36 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require "azure/core/http/http_filter"
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Http
|
||||
# A HttpFilter implementation that displays information about the request and response for debugging
|
||||
class DebugFilter < HttpFilter
|
||||
def call(req, _next)
|
||||
puts "--REQUEST-BEGIN---------------------------"
|
||||
puts "method:", req.method, "uri:", req.uri, "headers:", req.headers, "body:", req.body
|
||||
puts "--REQUEST-END---------------------------"
|
||||
|
||||
r = _next.call
|
||||
puts "--RESPONSE-BEGIN---------------------------"
|
||||
puts "status_code:", r.status_code, "headers:", r.headers, "body:", r.body
|
||||
puts "--RESPONSE-END---------------------------"
|
||||
r
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,86 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'azure/core/error'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Http
|
||||
# Public: Class for handling all HTTP response errors
|
||||
class HTTPError < Azure::Core::Error
|
||||
|
||||
attr :uri
|
||||
|
||||
# Public: The HTTP status code of this error
|
||||
#
|
||||
# Returns a Fixnum
|
||||
attr :status_code
|
||||
|
||||
# Public: The type of error
|
||||
#
|
||||
# http://msdn.microsoft.com/en-us/library/azure/dd179357
|
||||
#
|
||||
# Returns a String
|
||||
attr :type
|
||||
|
||||
# Public: Description of the error
|
||||
#
|
||||
# Returns a String
|
||||
attr :description
|
||||
|
||||
# Public: Detail of the error
|
||||
#
|
||||
# Returns a String
|
||||
attr :detail
|
||||
|
||||
# Public: Initialize an error
|
||||
#
|
||||
# http_response - An Azure::Core::HttpResponse
|
||||
def initialize(http_response)
|
||||
@http_response = http_response
|
||||
@uri = http_response.uri
|
||||
@status_code = http_response.status_code
|
||||
parse_response
|
||||
super("#{type} (#{status_code}): #{description}")
|
||||
end
|
||||
|
||||
# Extract the relevant information from the response's body. If the response
|
||||
# body is not an XML, we return an 'Unknown' error with the entire body as
|
||||
# the description
|
||||
#
|
||||
# Returns nothing
|
||||
def parse_response
|
||||
if @http_response.body && @http_response.body.include?('<')
|
||||
|
||||
document = Nokogiri.Slop(@http_response.body)
|
||||
|
||||
@type = document.css('code').first.text if document.css('code').any?
|
||||
@type = document.css('Code').first.text if document.css('Code').any?
|
||||
@description = document.css('message').first.text if document.css('message').any?
|
||||
@description = document.css('Message').first.text if document.css('Message').any?
|
||||
|
||||
# service bus uses detail instead of message
|
||||
@detail = document.css('detail').first.text if document.css('detail').any?
|
||||
@detail = document.css('Detail').first.text if document.css('Detail').any?
|
||||
else
|
||||
@type = 'Unknown'
|
||||
if @http_response.body
|
||||
@description = "#{@http_response.body.strip}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,53 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
module Azure
|
||||
module Core
|
||||
module Http
|
||||
# A filter which can modify the HTTP pipeline both before and
|
||||
# after requests/responses. Multiple filters can be nested in a
|
||||
# "Russian Doll" model to create a compound HTTP pipeline
|
||||
class HttpFilter
|
||||
|
||||
# Initialize a HttpFilter
|
||||
#
|
||||
# &block - An inline block which implements the filter.
|
||||
#
|
||||
# The inline block should take parameters |request, _next| where
|
||||
# request is a HttpRequest and _next is an object that implements
|
||||
# a method .call which returns an HttpResponse. The block passed
|
||||
# to the constructor should also return HttpResponse, either as
|
||||
# the result of calling _next.call or by customized logic.
|
||||
#
|
||||
def initialize(&block)
|
||||
@block = block
|
||||
end
|
||||
|
||||
# Executes the filter
|
||||
#
|
||||
# request - HttpRequest. The request
|
||||
# _next - An object that implements .call (no params)
|
||||
#
|
||||
# NOTE: _next is a either a subsequent HttpFilter wrapped in a
|
||||
# closure, or the HttpRequest object's call method. Either way,
|
||||
# it must have it's .call method executed within each filter to
|
||||
# complete the pipeline. _next.call should return an HttpResponse
|
||||
# and so should this Filter.
|
||||
def call(request, _next)
|
||||
@block ? @block.call(request, _next) : _next.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,162 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'digest/md5'
|
||||
require 'base64'
|
||||
require 'net/http'
|
||||
require 'time'
|
||||
|
||||
require 'azure/version'
|
||||
require 'azure/core/http/http_response'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Http
|
||||
# Represents a HTTP request can perform synchronous queries to a
|
||||
# HTTP server, returning a HttpResponse
|
||||
class HttpRequest
|
||||
include Azure::HttpResponseHelper
|
||||
alias_method :_method, :method
|
||||
|
||||
# The HTTP method to use (:get, :post, :put, :delete, etc...)
|
||||
attr_accessor :method
|
||||
|
||||
# The URI of the HTTP endpoint to query
|
||||
attr_accessor :uri
|
||||
|
||||
# The header values as a Hash
|
||||
attr_accessor :headers
|
||||
|
||||
# The body of the request (IO or String)
|
||||
attr_accessor :body
|
||||
|
||||
# Azure client which contains configuration context and http agents
|
||||
# @return [Azure::Client]
|
||||
attr_accessor :client
|
||||
|
||||
# Public: Create the HttpRequest
|
||||
#
|
||||
# @param method [Symbol] The HTTP method to use (:get, :post, :put, :del, etc...)
|
||||
# @param uri [URI] The URI of the HTTP endpoint to query
|
||||
# @param options_or_body [Hash|IO|String] The request options including {:client, :body} or raw body only
|
||||
def initialize(method, uri, options_or_body = {})
|
||||
options ||= unless options_or_body.is_a?(Hash)
|
||||
{body: options_or_body}
|
||||
end || options_or_body || {}
|
||||
|
||||
@method = method
|
||||
@uri = if uri.is_a?(String)
|
||||
URI.parse(uri)
|
||||
else
|
||||
uri
|
||||
end
|
||||
|
||||
@client = options[:client] || Azure
|
||||
|
||||
self.headers = default_headers(options[:current_time] || Time.now.httpdate).merge(options[:headers] || {})
|
||||
self.body = options[:body]
|
||||
end
|
||||
|
||||
# Public: Applies a HttpFilter to the HTTP Pipeline
|
||||
#
|
||||
# filter - Any object that responds to .call(req, _next) and
|
||||
# returns a HttpResponse eg. HttpFilter, Proc,
|
||||
# lambda, etc. (optional)
|
||||
#
|
||||
# &block - An inline block may be used instead of a filter
|
||||
#
|
||||
# example:
|
||||
#
|
||||
# request.with_filter do |req, _next|
|
||||
# _next.call
|
||||
# end
|
||||
#
|
||||
# NOTE:
|
||||
#
|
||||
# The code block provided must call _next or the filter pipeline
|
||||
# will not complete and the HTTP request will never execute
|
||||
#
|
||||
def with_filter(filter=nil, &block)
|
||||
filter = filter || block
|
||||
if filter
|
||||
old_impl = self._method(:call)
|
||||
|
||||
# support 1.8.7 (define_singleton_method doesn't exist until 1.9.1)
|
||||
new_impl = Proc.new do
|
||||
filter.call(self, old_impl)
|
||||
end
|
||||
k = class << self;
|
||||
self;
|
||||
end
|
||||
if k.method_defined? :define_singleton_method
|
||||
self.define_singleton_method(:call, new_impl)
|
||||
else
|
||||
k.send(:define_method, :call, new_impl)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Build a default headers Hash
|
||||
def default_headers(current_time)
|
||||
{}.tap do |def_headers|
|
||||
def_headers['User-Agent'] = Azure::Default::USER_AGENT
|
||||
def_headers['x-ms-date'] = current_time
|
||||
def_headers['x-ms-version'] = '2014-02-14'
|
||||
def_headers['DataServiceVersion'] = '1.0;NetFx'
|
||||
def_headers['MaxDataServiceVersion'] = '2.0;NetFx'
|
||||
def_headers['Content-Type'] = 'application/atom+xml; charset=utf-8'
|
||||
end
|
||||
end
|
||||
|
||||
def http_setup
|
||||
@client.agents(uri)
|
||||
end
|
||||
|
||||
def body=(body)
|
||||
@body = body
|
||||
apply_body_headers
|
||||
end
|
||||
|
||||
# Sends request to HTTP server and returns a HttpResponse
|
||||
#
|
||||
# @return [HttpResponse]
|
||||
def call
|
||||
conn = http_setup
|
||||
res = set_up_response(method.to_sym, uri, conn, headers ,body)
|
||||
response = HttpResponse.new(res)
|
||||
response.uri = uri
|
||||
raise response.error unless response.success?
|
||||
response
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def apply_body_headers
|
||||
if body
|
||||
if IO === body
|
||||
headers['Content-Length'] = body.size.to_s
|
||||
headers['Content-MD5'] = Digest::MD5.file(body.path).base64digest
|
||||
else
|
||||
headers['Content-Length'] = body.bytesize.to_s
|
||||
headers['Content-MD5'] = Base64.strict_encode64(Digest::MD5.digest(body))
|
||||
end
|
||||
else
|
||||
headers['Content-Length'] = '0'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,96 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'azure/core/http/http_error'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Http
|
||||
# A small proxy to clean up the API of Net::HTTPResponse.
|
||||
class HttpResponse
|
||||
|
||||
# Public: Initialize a new response.
|
||||
#
|
||||
# http_response - A Net::HTTPResponse.
|
||||
def initialize(http_response, uri='')
|
||||
@http_response = http_response
|
||||
@uri = uri
|
||||
end
|
||||
|
||||
attr_accessor :uri
|
||||
|
||||
# Public: Get the response body.
|
||||
#
|
||||
# Returns a String.
|
||||
def body
|
||||
@http_response.body
|
||||
end
|
||||
|
||||
# Public: Get the response status code.
|
||||
#
|
||||
# Returns a Fixnum.
|
||||
def status_code
|
||||
@http_response.status
|
||||
end
|
||||
|
||||
# Public: Check if this response was successful. A request is considered
|
||||
# successful if the response is in the 200 - 399 range.
|
||||
#
|
||||
# Returns nil|false.
|
||||
def success?
|
||||
@http_response.success?
|
||||
end
|
||||
|
||||
# Public: Get all the response headers as a Hash.
|
||||
#
|
||||
# Returns a Hash.
|
||||
def headers
|
||||
@http_response.headers
|
||||
end
|
||||
|
||||
# Public: Get an error that wraps this HTTP response, as long as this
|
||||
# response was unsuccessful. This method will return nil if the
|
||||
# response was successful.
|
||||
#
|
||||
# Returns an Azure::Core::Http::HTTPError.
|
||||
def exception
|
||||
HTTPError.new(self) unless success?
|
||||
end
|
||||
|
||||
alias_method :error, :exception
|
||||
|
||||
# TODO: This needs to be deleted and HttpError needs to be refactored to not rely on HttpResponse.
|
||||
# The dependency on knowing the internal structure of HttpResponse breaks good design principles.
|
||||
# The only reason this class exists is because the HttpError parses the HttpResponse to produce an error msg.
|
||||
class MockResponse
|
||||
def initialize(code, body, headers)
|
||||
@status = code
|
||||
@body = body
|
||||
@headers = headers
|
||||
@headers.each { |k,v|
|
||||
@headers[k] = [v] unless v.respond_to? first
|
||||
}
|
||||
end
|
||||
attr_accessor :status
|
||||
attr_accessor :body
|
||||
attr_accessor :headers
|
||||
|
||||
def to_hash
|
||||
@headers
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,74 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require "azure/core/http/http_filter"
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Http
|
||||
|
||||
# A HttpFilter implementation that handles retrying based on a
|
||||
# specific policy when HTTP layer errors occur
|
||||
class RetryPolicy < HttpFilter
|
||||
|
||||
def initialize(&block)
|
||||
@block = block
|
||||
end
|
||||
|
||||
attr_accessor :retry_data
|
||||
|
||||
# Overrides the base class implementation of call to implement
|
||||
# a retry loop that uses should_retry? to determine when to
|
||||
# break the loop
|
||||
#
|
||||
# req - HttpRequest. The HTTP request
|
||||
# _next - HttpFilter. The next filter in the pipeline
|
||||
def call(req, _next)
|
||||
retry_data = {}
|
||||
response = nil
|
||||
begin
|
||||
response = _next.call
|
||||
rescue
|
||||
retry_data[:error] = $!
|
||||
end while should_retry?(response, retry_data)
|
||||
if retry_data.has_key?(:error)
|
||||
raise retry_data[:error]
|
||||
else
|
||||
response
|
||||
end
|
||||
end
|
||||
|
||||
# Determines if the HTTP request should continue retrying
|
||||
#
|
||||
# response - HttpResponse. The response from the active request
|
||||
# retry_data - Hash. Stores stateful retry data
|
||||
#
|
||||
# The retry_data is a Hash which can be used to store
|
||||
# stateful data about the request execution context (such as an
|
||||
# incrementing counter, timestamp, etc). The retry_data object
|
||||
# will be the same instance throughout the lifetime of the request.
|
||||
#
|
||||
# If an inline block was passed to the constructor, that block
|
||||
# will be used here and should return true to retry the job, or
|
||||
# false to stop exit. If an inline block was not passed to the
|
||||
# constructor the method returns false.
|
||||
#
|
||||
# Alternatively, a subclass could override this method.
|
||||
def should_retry?(response, retry_data)
|
||||
@block ? @block.call(response, retry_data) : false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,33 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'azure/core/http/http_filter'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
module Http
|
||||
# A HttpFilter implementation that creates a authorization signature which is added to the request headers
|
||||
class SignerFilter < HttpFilter
|
||||
def initialize(signer)
|
||||
@signer = signer
|
||||
end
|
||||
|
||||
def call(req, _next)
|
||||
@signer.sign_request(req)
|
||||
_next.call
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,47 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'azure/core/http/http_request'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
# A base class for Service implementations
|
||||
class Service
|
||||
|
||||
# Create a new instance of the Service
|
||||
#
|
||||
# @param host [String] The hostname. (optional, Default empty)
|
||||
# @param options [Hash] options including {:client} (optional, Default {})
|
||||
def initialize(host='', options = {})
|
||||
@host = host
|
||||
@client = options[:client] || Azure
|
||||
end
|
||||
|
||||
attr_accessor :host, :client
|
||||
|
||||
def call(method, uri, body=nil, headers={})
|
||||
request = Core::Http::HttpRequest.new(method, uri, body: body, headers: headers, client: @client)
|
||||
yield request if block_given?
|
||||
request.call
|
||||
end
|
||||
|
||||
def generate_uri(path='', query={})
|
||||
enconded_file_uri_string = URI.encode(File.join(host, path))
|
||||
uri = URI.parse(enconded_file_uri_string)
|
||||
uri.query = URI.encode_www_form(query) unless query == nil or query.empty?
|
||||
uri
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,45 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# # Copyright (c) Microsoft and contributors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'azure/core/filtered_service'
|
||||
require 'azure/core/http/signer_filter'
|
||||
require 'azure/core/auth/shared_key'
|
||||
|
||||
module Azure
|
||||
module Core
|
||||
# A base class for Service implementations
|
||||
class SignedService < FilteredService
|
||||
|
||||
# Create a new instance of the SignedService
|
||||
#
|
||||
# @param signer [Azure::Core::Auth::Signer]. An implementation of Signer used for signing requests. (optional, Default=Azure::Core::Auth::SharedKey.new)
|
||||
# @param account_name [String] The account name (optional, Default=Azure.config.storage_account_name)
|
||||
# @param options [Hash] options
|
||||
def initialize(signer=nil, account_name=nil, options={})
|
||||
super('', options)
|
||||
signer ||= Core::Auth::SharedKey.new(client.storage_account_name, client.storage_access_key)
|
||||
@account_name = account_name || client.storage_account_name
|
||||
@signer = signer
|
||||
filters.unshift Core::Http::SignerFilter.new(signer) if signer
|
||||
end
|
||||
|
||||
attr_accessor :account_name
|
||||
attr_accessor :signer
|
||||
|
||||
def call(method, uri, body=nil, headers=nil)
|
||||
super(method, uri, body, headers)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,244 +0,0 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright 2013 Microsoft Open Technologies, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
require 'ipaddr'
|
||||
|
||||
if RUBY_VERSION.to_f < 2.0
|
||||
begin
|
||||
require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32|mingw32/
|
||||
rescue LoadError
|
||||
puts 'WARNING: Output will look weird on Windows unless'\
|
||||
' you install the "win32console" gem.'
|
||||
end
|
||||
end
|
||||
|
||||
module Azure
|
||||
module Error
|
||||
# Azure Error
|
||||
class Error < Azure::Core::Error
|
||||
attr_reader :description
|
||||
attr_reader :status_code
|
||||
attr_reader :type
|
||||
|
||||
def initialize(type, status, description)
|
||||
@type = type
|
||||
@status_code = status
|
||||
@description = description
|
||||
super("#{type} (#{status_code}): #{description}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Core
|
||||
module Utility
|
||||
def random_string(str = 'azure', no_of_char = 5)
|
||||
str + (0...no_of_char).map { ('a'..'z').to_a[rand(26)] }.join
|
||||
end
|
||||
|
||||
def xml_content(xml, key, default = '')
|
||||
content = default
|
||||
node = xml.at_css(key)
|
||||
content = node.text if node
|
||||
content
|
||||
end
|
||||
|
||||
def locate_file(name)
|
||||
if File.exist? name
|
||||
name
|
||||
elsif File.exist?(File.join(ENV['HOME'], name))
|
||||
File.join(ENV['HOME'], name)
|
||||
else
|
||||
Azure::Loggerx.error_with_exit "Unable to find #{name} file "
|
||||
end
|
||||
end
|
||||
|
||||
def export_der(cert, key, pass = nil, name = nil)
|
||||
pkcs12 = OpenSSL::PKCS12.create(pass, name, key, cert)
|
||||
Base64.encode64(pkcs12.to_der)
|
||||
rescue Exception => e
|
||||
puts e.message
|
||||
abort
|
||||
end
|
||||
|
||||
def export_fingerprint(certificate)
|
||||
Digest::SHA1.hexdigest(certificate.to_der)
|
||||
end
|
||||
|
||||
def enable_winrm?(winrm_transport)
|
||||
(!winrm_transport.nil? && (winrm_transport.select { |x| x.downcase == 'http' || x.downcase == 'https' }.size > 0))
|
||||
end
|
||||
|
||||
def get_certificate(private_key_file)
|
||||
rsa = OpenSSL::PKey.read File.read(private_key_file)
|
||||
cert = OpenSSL::X509::Certificate.new
|
||||
cert.version = 2
|
||||
cert.serial = 0
|
||||
name = OpenSSL::X509::Name.new([['CN', 'Azure Management Certificate']])
|
||||
cert.subject = cert.issuer = name
|
||||
cert.not_before = Time.now
|
||||
cert.not_after = cert.not_before + (60*60*24*365)
|
||||
cert.public_key = rsa.public_key
|
||||
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
||||
cert
|
||||
end
|
||||
|
||||
def initialize_external_logger(logger)
|
||||
Loggerx.initialize_external_logger(logger)
|
||||
end
|
||||
end
|
||||
|
||||
# Logger
|
||||
module Logger
|
||||
class << self
|
||||
attr_accessor :logger
|
||||
|
||||
def info(msg)
|
||||
if logger.nil?
|
||||
puts msg.bold.white
|
||||
else
|
||||
logger.info(msg)
|
||||
end
|
||||
end
|
||||
|
||||
def error_with_exit(msg)
|
||||
if logger.nil?
|
||||
puts msg.bold.red
|
||||
else
|
||||
logger.error(msg)
|
||||
end
|
||||
|
||||
raise msg.bold.red
|
||||
end
|
||||
|
||||
def warn(msg)
|
||||
if logger.nil?
|
||||
puts msg.yellow
|
||||
else
|
||||
logger.warn(msg)
|
||||
end
|
||||
|
||||
msg
|
||||
end
|
||||
|
||||
def error(msg)
|
||||
if logger.nil?
|
||||
puts msg.bold.red
|
||||
else
|
||||
logger.error(msg)
|
||||
end
|
||||
|
||||
msg
|
||||
end
|
||||
|
||||
def exception_message(msg)
|
||||
if logger.nil?
|
||||
puts msg.bold.red
|
||||
else
|
||||
logger.warn(msg)
|
||||
end
|
||||
|
||||
raise msg.bold.red
|
||||
end
|
||||
|
||||
def success(msg)
|
||||
msg_with_new_line = msg + "\n"
|
||||
if logger.nil?
|
||||
print msg_with_new_line.green
|
||||
else
|
||||
logger.info(msg)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize_external_logger(logger)
|
||||
@logger = logger
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class String
|
||||
{ reset: 0,
|
||||
bold: 1,
|
||||
dark: 2,
|
||||
underline: 4,
|
||||
blink: 5,
|
||||
orange: 6,
|
||||
negative: 7,
|
||||
black: 30,
|
||||
red: 31,
|
||||
green: 32,
|
||||
yellow: 33,
|
||||
blue: 34,
|
||||
magenta: 35,
|
||||
cyan: 36,
|
||||
white: 37,
|
||||
}.each do |key, value|
|
||||
define_method key do
|
||||
"\e[#{value}m" + self + "\e[0m"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Code validate private/public IP acceptable ranges.
|
||||
class IPAddr
|
||||
PRIVATE_RANGES = [
|
||||
IPAddr.new('10.0.0.0/8'),
|
||||
IPAddr.new('172.16.0.0/12'),
|
||||
IPAddr.new('192.168.0.0/16')
|
||||
]
|
||||
|
||||
def private?
|
||||
return false unless self.ipv4?
|
||||
PRIVATE_RANGES.each do |ipr|
|
||||
return true if ipr.include?(self)
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
def public?
|
||||
!private?
|
||||
end
|
||||
|
||||
class << self
|
||||
def validate_ip_and_prefix(ip, cidr)
|
||||
if cidr.to_s.empty?
|
||||
raise "Cidr is missing for IP '#{ip}'."
|
||||
elsif valid?(ip)
|
||||
raise "Ip address '#{ip}' is invalid."
|
||||
elsif !IPAddr.new(ip).private?
|
||||
raise "Ip Address #{ip} must be private."
|
||||
end
|
||||
end
|
||||
|
||||
def validate_address_space(ip)
|
||||
if ip.split('/').size != 2
|
||||
raise "Cidr is invalid for IP #{ip}."
|
||||
elsif valid?(ip)
|
||||
raise "Address space '#{ip}' is invalid."
|
||||
end
|
||||
end
|
||||
|
||||
def address_prefix(ip, cidr)
|
||||
ip + '/' + cidr.to_s
|
||||
end
|
||||
|
||||
def valid?(ip)
|
||||
(IPAddr.new(ip) rescue nil).nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Azure::Loggerx = Azure::Core::Logger
|
|
@ -14,6 +14,7 @@
|
|||
#--------------------------------------------------------------------------
|
||||
require 'test_helper'
|
||||
require 'azure'
|
||||
require 'azure/core'
|
||||
require 'vcr'
|
||||
|
||||
if ENV['INTEG_RECORDED'].nil? || ENV['INTEG_RECORDED'] == false
|
||||
|
|
Загрузка…
Ссылка в новой задаче