azure-core 0.1.0

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.
@@ -0,0 +1,96 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'azure/core/http/http_error'
16
+
17
+ module Azure
18
+ module Core
19
+ module Http
20
+ # A small proxy to clean up the API of Net::HTTPResponse.
21
+ class HttpResponse
22
+
23
+ # Public: Initialize a new response.
24
+ #
25
+ # http_response - A Net::HTTPResponse.
26
+ def initialize(http_response, uri='')
27
+ @http_response = http_response
28
+ @uri = uri
29
+ end
30
+
31
+ attr_accessor :uri
32
+
33
+ # Public: Get the response body.
34
+ #
35
+ # Returns a String.
36
+ def body
37
+ @http_response.body
38
+ end
39
+
40
+ # Public: Get the response status code.
41
+ #
42
+ # Returns a Fixnum.
43
+ def status_code
44
+ @http_response.status
45
+ end
46
+
47
+ # Public: Check if this response was successful. A request is considered
48
+ # successful if the response is in the 200 - 399 range.
49
+ #
50
+ # Returns nil|false.
51
+ def success?
52
+ @http_response.success?
53
+ end
54
+
55
+ # Public: Get all the response headers as a Hash.
56
+ #
57
+ # Returns a Hash.
58
+ def headers
59
+ @http_response.headers
60
+ end
61
+
62
+ # Public: Get an error that wraps this HTTP response, as long as this
63
+ # response was unsuccessful. This method will return nil if the
64
+ # response was successful.
65
+ #
66
+ # Returns an Azure::Core::Http::HTTPError.
67
+ def exception
68
+ HTTPError.new(self) unless success?
69
+ end
70
+
71
+ alias_method :error, :exception
72
+
73
+ # TODO: This needs to be deleted and HttpError needs to be refactored to not rely on HttpResponse.
74
+ # The dependency on knowing the internal structure of HttpResponse breaks good design principles.
75
+ # The only reason this class exists is because the HttpError parses the HttpResponse to produce an error msg.
76
+ class MockResponse
77
+ def initialize(code, body, headers)
78
+ @status = code
79
+ @body = body
80
+ @headers = headers
81
+ @headers.each { |k,v|
82
+ @headers[k] = [v] unless v.respond_to? first
83
+ }
84
+ end
85
+ attr_accessor :status
86
+ attr_accessor :body
87
+ attr_accessor :headers
88
+
89
+ def to_hash
90
+ @headers
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,74 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require "azure/core/http/http_filter"
16
+
17
+ module Azure
18
+ module Core
19
+ module Http
20
+
21
+ # A HttpFilter implementation that handles retrying based on a
22
+ # specific policy when HTTP layer errors occur
23
+ class RetryPolicy < HttpFilter
24
+
25
+ def initialize(&block)
26
+ @block = block
27
+ end
28
+
29
+ attr_accessor :retry_data
30
+
31
+ # Overrides the base class implementation of call to implement
32
+ # a retry loop that uses should_retry? to determine when to
33
+ # break the loop
34
+ #
35
+ # req - HttpRequest. The HTTP request
36
+ # _next - HttpFilter. The next filter in the pipeline
37
+ def call(req, _next)
38
+ retry_data = {}
39
+ response = nil
40
+ begin
41
+ response = _next.call
42
+ rescue
43
+ retry_data[:error] = $!
44
+ end while should_retry?(response, retry_data)
45
+ if retry_data.has_key?(:error)
46
+ raise retry_data[:error]
47
+ else
48
+ response
49
+ end
50
+ end
51
+
52
+ # Determines if the HTTP request should continue retrying
53
+ #
54
+ # response - HttpResponse. The response from the active request
55
+ # retry_data - Hash. Stores stateful retry data
56
+ #
57
+ # The retry_data is a Hash which can be used to store
58
+ # stateful data about the request execution context (such as an
59
+ # incrementing counter, timestamp, etc). The retry_data object
60
+ # will be the same instance throughout the lifetime of the request.
61
+ #
62
+ # If an inline block was passed to the constructor, that block
63
+ # will be used here and should return true to retry the job, or
64
+ # false to stop exit. If an inline block was not passed to the
65
+ # constructor the method returns false.
66
+ #
67
+ # Alternatively, a subclass could override this method.
68
+ def should_retry?(response, retry_data)
69
+ @block ? @block.call(response, retry_data) : false
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,33 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'azure/core/http/http_filter'
16
+
17
+ module Azure
18
+ module Core
19
+ module Http
20
+ # A HttpFilter implementation that creates a authorization signature which is added to the request headers
21
+ class SignerFilter < HttpFilter
22
+ def initialize(signer)
23
+ @signer = signer
24
+ end
25
+
26
+ def call(req, _next)
27
+ @signer.sign_request(req)
28
+ _next.call
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'azure/core/http/http_request'
16
+
17
+ module Azure
18
+ module Core
19
+ # A base class for Service implementations
20
+ class Service
21
+
22
+ # Create a new instance of the Service
23
+ #
24
+ # @param host [String] The hostname. (optional, Default empty)
25
+ # @param options [Hash] options including {:client} (optional, Default {})
26
+ def initialize(host='', options = {})
27
+ @host = host
28
+ @client = options[:client] || Azure
29
+ end
30
+
31
+ attr_accessor :host, :client
32
+
33
+ def call(method, uri, body=nil, headers={})
34
+ request = Core::Http::HttpRequest.new(method, uri, body: body, headers: headers, client: @client)
35
+ yield request if block_given?
36
+ request.call
37
+ end
38
+
39
+ def generate_uri(path='', query={})
40
+ enconded_file_uri_string = URI.encode(File.join(host, path))
41
+ uri = URI.parse(enconded_file_uri_string)
42
+ uri.query = URI.encode_www_form(query) unless query == nil or query.empty?
43
+ uri
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,45 @@
1
+ #-------------------------------------------------------------------------
2
+ # # Copyright (c) Microsoft and contributors. All rights reserved.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+ require 'azure/core/filtered_service'
16
+ require 'azure/core/http/signer_filter'
17
+ require 'azure/core/auth/shared_key'
18
+
19
+ module Azure
20
+ module Core
21
+ # A base class for Service implementations
22
+ class SignedService < FilteredService
23
+
24
+ # Create a new instance of the SignedService
25
+ #
26
+ # @param signer [Azure::Core::Auth::Signer]. An implementation of Signer used for signing requests. (optional, Default=Azure::Core::Auth::SharedKey.new)
27
+ # @param account_name [String] The account name (optional, Default=Azure.config.storage_account_name)
28
+ # @param options [Hash] options
29
+ def initialize(signer=nil, account_name=nil, options={})
30
+ super('', options)
31
+ signer ||= Core::Auth::SharedKey.new(client.storage_account_name, client.storage_access_key)
32
+ @account_name = account_name || client.storage_account_name
33
+ @signer = signer
34
+ filters.unshift Core::Http::SignerFilter.new(signer) if signer
35
+ end
36
+
37
+ attr_accessor :account_name
38
+ attr_accessor :signer
39
+
40
+ def call(method, uri, body=nil, headers=nil)
41
+ super(method, uri, body, headers)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,244 @@
1
+ #-------------------------------------------------------------------------
2
+ # Copyright 2013 Microsoft Open Technologies, Inc.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #--------------------------------------------------------------------------
15
+
16
+ require 'ipaddr'
17
+
18
+ if RUBY_VERSION.to_f < 2.0
19
+ begin
20
+ require 'Win32/Console/ANSI' if RUBY_PLATFORM =~ /win32|mingw32/
21
+ rescue LoadError
22
+ puts 'WARNING: Output will look weird on Windows unless'\
23
+ ' you install the "win32console" gem.'
24
+ end
25
+ end
26
+
27
+ module Azure
28
+ module Error
29
+ # Azure Error
30
+ class Error < Azure::Core::Error
31
+ attr_reader :description
32
+ attr_reader :status_code
33
+ attr_reader :type
34
+
35
+ def initialize(type, status, description)
36
+ @type = type
37
+ @status_code = status
38
+ @description = description
39
+ super("#{type} (#{status_code}): #{description}")
40
+ end
41
+ end
42
+ end
43
+
44
+ module Core
45
+ module Utility
46
+ def random_string(str = 'azure', no_of_char = 5)
47
+ str + (0...no_of_char).map { ('a'..'z').to_a[rand(26)] }.join
48
+ end
49
+
50
+ def xml_content(xml, key, default = '')
51
+ content = default
52
+ node = xml.at_css(key)
53
+ content = node.text if node
54
+ content
55
+ end
56
+
57
+ def locate_file(name)
58
+ if File.exist? name
59
+ name
60
+ elsif File.exist?(File.join(ENV['HOME'], name))
61
+ File.join(ENV['HOME'], name)
62
+ else
63
+ Azure::Loggerx.error_with_exit "Unable to find #{name} file "
64
+ end
65
+ end
66
+
67
+ def export_der(cert, key, pass = nil, name = nil)
68
+ pkcs12 = OpenSSL::PKCS12.create(pass, name, key, cert)
69
+ Base64.encode64(pkcs12.to_der)
70
+ rescue Exception => e
71
+ puts e.message
72
+ abort
73
+ end
74
+
75
+ def export_fingerprint(certificate)
76
+ Digest::SHA1.hexdigest(certificate.to_der)
77
+ end
78
+
79
+ def enable_winrm?(winrm_transport)
80
+ (!winrm_transport.nil? && (winrm_transport.select { |x| x.downcase == 'http' || x.downcase == 'https' }.size > 0))
81
+ end
82
+
83
+ def get_certificate(private_key_file)
84
+ rsa = OpenSSL::PKey.read File.read(private_key_file)
85
+ cert = OpenSSL::X509::Certificate.new
86
+ cert.version = 2
87
+ cert.serial = 0
88
+ name = OpenSSL::X509::Name.new([['CN', 'Azure Management Certificate']])
89
+ cert.subject = cert.issuer = name
90
+ cert.not_before = Time.now
91
+ cert.not_after = cert.not_before + (60*60*24*365)
92
+ cert.public_key = rsa.public_key
93
+ cert.sign(rsa, OpenSSL::Digest::SHA1.new)
94
+ cert
95
+ end
96
+
97
+ def initialize_external_logger(logger)
98
+ Loggerx.initialize_external_logger(logger)
99
+ end
100
+ end
101
+
102
+ # Logger
103
+ module Logger
104
+ class << self
105
+ attr_accessor :logger
106
+
107
+ def info(msg)
108
+ if logger.nil?
109
+ puts msg.bold.white
110
+ else
111
+ logger.info(msg)
112
+ end
113
+ end
114
+
115
+ def error_with_exit(msg)
116
+ if logger.nil?
117
+ puts msg.bold.red
118
+ else
119
+ logger.error(msg)
120
+ end
121
+
122
+ raise msg.bold.red
123
+ end
124
+
125
+ def warn(msg)
126
+ if logger.nil?
127
+ puts msg.yellow
128
+ else
129
+ logger.warn(msg)
130
+ end
131
+
132
+ msg
133
+ end
134
+
135
+ def error(msg)
136
+ if logger.nil?
137
+ puts msg.bold.red
138
+ else
139
+ logger.error(msg)
140
+ end
141
+
142
+ msg
143
+ end
144
+
145
+ def exception_message(msg)
146
+ if logger.nil?
147
+ puts msg.bold.red
148
+ else
149
+ logger.warn(msg)
150
+ end
151
+
152
+ raise msg.bold.red
153
+ end
154
+
155
+ def success(msg)
156
+ msg_with_new_line = msg + "\n"
157
+ if logger.nil?
158
+ print msg_with_new_line.green
159
+ else
160
+ logger.info(msg)
161
+ end
162
+ end
163
+
164
+ def initialize_external_logger(logger)
165
+ @logger = logger
166
+ end
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ class String
173
+ { reset: 0,
174
+ bold: 1,
175
+ dark: 2,
176
+ underline: 4,
177
+ blink: 5,
178
+ orange: 6,
179
+ negative: 7,
180
+ black: 30,
181
+ red: 31,
182
+ green: 32,
183
+ yellow: 33,
184
+ blue: 34,
185
+ magenta: 35,
186
+ cyan: 36,
187
+ white: 37,
188
+ }.each do |key, value|
189
+ define_method key do
190
+ "\e[#{value}m" + self + "\e[0m"
191
+ end
192
+ end
193
+ end
194
+
195
+ # Code validate private/public IP acceptable ranges.
196
+ class IPAddr
197
+ PRIVATE_RANGES = [
198
+ IPAddr.new('10.0.0.0/8'),
199
+ IPAddr.new('172.16.0.0/12'),
200
+ IPAddr.new('192.168.0.0/16')
201
+ ]
202
+
203
+ def private?
204
+ return false unless self.ipv4?
205
+ PRIVATE_RANGES.each do |ipr|
206
+ return true if ipr.include?(self)
207
+ end
208
+ false
209
+ end
210
+
211
+ def public?
212
+ !private?
213
+ end
214
+
215
+ class << self
216
+ def validate_ip_and_prefix(ip, cidr)
217
+ if cidr.to_s.empty?
218
+ raise "Cidr is missing for IP '#{ip}'."
219
+ elsif valid?(ip)
220
+ raise "Ip address '#{ip}' is invalid."
221
+ elsif !IPAddr.new(ip).private?
222
+ raise "Ip Address #{ip} must be private."
223
+ end
224
+ end
225
+
226
+ def validate_address_space(ip)
227
+ if ip.split('/').size != 2
228
+ raise "Cidr is invalid for IP #{ip}."
229
+ elsif valid?(ip)
230
+ raise "Address space '#{ip}' is invalid."
231
+ end
232
+ end
233
+
234
+ def address_prefix(ip, cidr)
235
+ ip + '/' + cidr.to_s
236
+ end
237
+
238
+ def valid?(ip)
239
+ (IPAddr.new(ip) rescue nil).nil?
240
+ end
241
+ end
242
+ end
243
+
244
+ Azure::Loggerx = Azure::Core::Logger