fog-core 1.21.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +15 -0
  2. data/lib/fog/account.rb +25 -0
  3. data/lib/fog/billing.rb +23 -0
  4. data/lib/fog/cdn.rb +23 -0
  5. data/lib/fog/compute.rb +80 -0
  6. data/lib/fog/compute/models/server.rb +104 -0
  7. data/lib/fog/core.rb +51 -0
  8. data/lib/fog/core/attributes.rb +227 -0
  9. data/lib/fog/core/class_from_string.rb +26 -0
  10. data/lib/fog/core/collection.rb +161 -0
  11. data/lib/fog/core/connection.rb +72 -0
  12. data/lib/fog/core/credentials.rb +70 -0
  13. data/lib/fog/core/current_machine.rb +34 -0
  14. data/lib/fog/core/deprecated_connection_accessors.rb +41 -0
  15. data/lib/fog/core/deprecation.rb +23 -0
  16. data/lib/fog/core/errors.rb +118 -0
  17. data/lib/fog/core/hmac.rb +35 -0
  18. data/lib/fog/core/logger.rb +44 -0
  19. data/lib/fog/core/mock.rb +115 -0
  20. data/lib/fog/core/model.rb +80 -0
  21. data/lib/fog/core/provider.rb +34 -0
  22. data/lib/fog/core/scp.rb +96 -0
  23. data/lib/fog/core/service.rb +223 -0
  24. data/lib/fog/core/ssh.rb +137 -0
  25. data/lib/fog/core/time.rb +32 -0
  26. data/lib/fog/core/uuid.rb +23 -0
  27. data/lib/fog/core/wait_for.rb +15 -0
  28. data/lib/fog/core/wait_for_defaults.rb +21 -0
  29. data/lib/fog/dns.rb +40 -0
  30. data/lib/fog/identity.rb +28 -0
  31. data/lib/fog/image.rb +23 -0
  32. data/lib/fog/metering.rb +25 -0
  33. data/lib/fog/monitoring.rb +24 -0
  34. data/lib/fog/network.rb +28 -0
  35. data/lib/fog/orchestration.rb +25 -0
  36. data/lib/fog/schema/data_validator.rb +154 -0
  37. data/lib/fog/storage.rb +80 -0
  38. data/lib/fog/support.rb +26 -0
  39. data/lib/fog/test_helpers.rb +12 -0
  40. data/lib/fog/test_helpers/collection_helper.rb +102 -0
  41. data/lib/fog/test_helpers/compute/flavors_helper.rb +34 -0
  42. data/lib/fog/test_helpers/compute/server_helper.rb +27 -0
  43. data/lib/fog/test_helpers/compute/servers_helper.rb +12 -0
  44. data/lib/fog/test_helpers/formats_helper.rb +99 -0
  45. data/lib/fog/test_helpers/helper.rb +25 -0
  46. data/lib/fog/test_helpers/mock_helper.rb +107 -0
  47. data/lib/fog/test_helpers/model_helper.rb +35 -0
  48. data/lib/fog/test_helpers/responds_to_helper.rb +13 -0
  49. data/lib/fog/test_helpers/succeeds_helper.rb +11 -0
  50. data/lib/fog/version.rb +3 -0
  51. data/lib/fog/volume.rb +25 -0
  52. data/lib/fog/vpn.rb +25 -0
  53. data/lib/tasks/test_task.rb +46 -0
  54. metadata +267 -0
@@ -0,0 +1,35 @@
1
+ module Fog
2
+ class HMAC
3
+
4
+ def initialize(type, key)
5
+ @key = key
6
+ case type
7
+ when 'sha1'
8
+ setup_sha1
9
+ when 'sha256'
10
+ setup_sha256
11
+ end
12
+ end
13
+
14
+ def sign(data)
15
+ @signer.call(data)
16
+ end
17
+
18
+ private
19
+
20
+ def setup_sha1
21
+ @digest = OpenSSL::Digest.new('sha1')
22
+ @signer = lambda do |data|
23
+ OpenSSL::HMAC.digest(@digest, @key, data)
24
+ end
25
+ end
26
+
27
+ def setup_sha256
28
+ @digest = OpenSSL::Digest.new('sha256')
29
+ @signer = lambda do |data|
30
+ OpenSSL::HMAC.digest(@digest, @key, data)
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,44 @@
1
+ module Fog
2
+ class Logger
3
+
4
+ @channels = {
5
+ :deprecation => ::STDERR,
6
+ :warning => ::STDERR
7
+ }
8
+
9
+ @channels[:debug] = ::STDERR if ENV['DEBUG']
10
+
11
+ def self.[](channel)
12
+ @channels[channel]
13
+ end
14
+
15
+ def self.[]=(channel, value)
16
+ @channels[channel] = value
17
+ end
18
+
19
+ def self.debug(message)
20
+ self.write(:debug, "[light_black][fog][DEBUG] #{message}[/]\n")
21
+ end
22
+
23
+ def self.deprecation(message)
24
+ self.write(:deprecation, "[yellow][fog][DEPRECATION] #{message}[/]\n")
25
+ end
26
+
27
+ def self.warning(message)
28
+ self.write(:warning, "[yellow][fog][WARNING] #{message}[/]\n")
29
+ end
30
+
31
+ def self.write(key, value)
32
+ if channel = @channels[key]
33
+ message = if channel.tty?
34
+ value.gsub(Formatador::PARSE_REGEX) { "\e[#{Formatador::STYLES[$1.to_sym]}m" }.gsub(Formatador::INDENT_REGEX, '')
35
+ else
36
+ value.gsub(Formatador::PARSE_REGEX, '').gsub(Formatador::INDENT_REGEX, '')
37
+ end
38
+ channel.write(message)
39
+ end
40
+ nil
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,115 @@
1
+ module Fog
2
+
3
+ @mocking = false
4
+
5
+ def self.mock!
6
+ @mocking = true
7
+ end
8
+
9
+ def self.unmock!
10
+ @mocking = false
11
+ end
12
+
13
+ def self.mock?
14
+ @mocking
15
+ end
16
+
17
+ def self.mocking?
18
+ @mocking
19
+ end
20
+
21
+ module Mock
22
+
23
+ @delay = 1
24
+ def self.delay
25
+ @delay
26
+ end
27
+
28
+ def self.delay=(new_delay)
29
+ raise ArgumentError, "delay must be non-negative" unless new_delay >= 0
30
+ @delay = new_delay
31
+ end
32
+
33
+ def self.not_implemented(message = 'Contributions welcome!')
34
+ raise Fog::Errors::MockNotImplemented.new(message)
35
+ end
36
+
37
+ def self.random_ip(opts = {:version => :v4})
38
+ version = opts[:version]
39
+ if version == :v6
40
+ bit_length = 128
41
+ family = Socket::AF_INET6
42
+ elsif version == :v4
43
+ bit_length = 32
44
+ family = Socket::AF_INET
45
+ else
46
+ raise ArgumentError, "Unknown IP version: #{version}"
47
+ end
48
+
49
+ seed = 1 + rand((2**bit_length)-1)
50
+ IPAddr.new(seed, family).to_s
51
+ end
52
+
53
+ def self.random_base64(length)
54
+ random_selection(
55
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
56
+ length
57
+ )
58
+ end
59
+
60
+ def self.random_hex(length)
61
+ max = ('f' * length).to_i(16)
62
+ rand(max).to_s(16).rjust(length, '0')
63
+ end
64
+
65
+ def self.random_letters(length)
66
+ random_selection(
67
+ 'abcdefghijklmnopqrstuvwxyz',
68
+ length
69
+ )
70
+ end
71
+
72
+ def self.random_numbers(length)
73
+ max = ('9' * length).to_i
74
+ rand(max).to_s
75
+ end
76
+
77
+ def self.random_letters_and_numbers(length)
78
+ random_selection(
79
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
80
+ length
81
+ )
82
+ end
83
+
84
+ def self.random_selection(characters, length)
85
+ selection = ''
86
+ length.times do
87
+ position = rand(characters.length)
88
+ selection << characters[position..position]
89
+ end
90
+ selection
91
+ end
92
+
93
+ def self.reset
94
+ mocked_services = []
95
+ Fog.constants.map do |x|
96
+ x_const = Fog.const_get(x)
97
+ x_const.respond_to?(:constants) && x_const.constants.map do |y|
98
+ y_const = x_const.const_get(y)
99
+ y_const.respond_to?(:constants) && y_const.constants.map do |z|
100
+ if z.to_sym == :Mock
101
+ mocked_services << y_const.const_get(z)
102
+ end
103
+ end
104
+ end
105
+ end
106
+
107
+ for mocked_service in mocked_services
108
+ next unless mocked_service.respond_to?(:reset)
109
+ mocked_service.reset
110
+ end
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,80 @@
1
+ require "fog/core/deprecated_connection_accessors"
2
+
3
+ module Fog
4
+ class Model
5
+
6
+ extend Fog::Attributes::ClassMethods
7
+ include Fog::Attributes::InstanceMethods
8
+ include Fog::Core::DeprecatedConnectionAccessors
9
+
10
+ attr_accessor :collection
11
+ attr_reader :service
12
+
13
+ def initialize(new_attributes = {})
14
+ # TODO Remove compatibility with old connection option
15
+ @service = new_attributes.delete(:service)
16
+ if @service.nil? && new_attributes[:connection]
17
+ Fog::Logger.deprecation("Passing :connection option is deprecated, use :service instead [light_black](#{caller.first})[/]")
18
+ @service = new_attributes[:connection]
19
+ end
20
+ merge_attributes(new_attributes)
21
+ end
22
+
23
+ def inspect
24
+ Thread.current[:formatador] ||= Formatador.new
25
+ data = "#{Thread.current[:formatador].indentation}<#{self.class.name}"
26
+ Thread.current[:formatador].indent do
27
+ unless self.class.attributes.empty?
28
+ data << "\n#{Thread.current[:formatador].indentation}"
29
+ data << self.class.attributes.map {|attribute| "#{attribute}=#{send(attribute).inspect}"}.join(",\n#{Thread.current[:formatador].indentation}")
30
+ end
31
+ end
32
+ data << "\n#{Thread.current[:formatador].indentation}>"
33
+ data
34
+ end
35
+
36
+ def reload
37
+ requires :identity
38
+
39
+ return unless data = begin
40
+ collection.get(identity)
41
+ rescue Excon::Errors::SocketError
42
+ nil
43
+ end
44
+
45
+ new_attributes = data.attributes
46
+ merge_attributes(new_attributes)
47
+ self
48
+ end
49
+
50
+ def to_json(options = {})
51
+ Fog::JSON.encode(attributes)
52
+ end
53
+
54
+ def symbolize_keys(hash)
55
+ return nil if hash.nil?
56
+ hash.inject({}) do |options, (key, value)|
57
+ options[(key.to_sym rescue key) || key] = value
58
+ options
59
+ end
60
+ end
61
+
62
+ def wait_for(timeout=Fog.timeout, interval=1, &block)
63
+ reload_has_succeeded = false
64
+ duration = Fog.wait_for(timeout, interval) do # Note that duration = false if it times out
65
+ if reload
66
+ reload_has_succeeded = true
67
+ instance_eval(&block)
68
+ else
69
+ false
70
+ end
71
+ end
72
+ if reload_has_succeeded
73
+ return duration # false if timeout; otherwise {:duration => elapsed time }
74
+ else
75
+ raise Fog::Errors::Error.new("Reload failed, #{self.class} #{self.identity} not present.")
76
+ end
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,34 @@
1
+ module Fog
2
+
3
+ def self.providers
4
+ @providers ||= {}
5
+ end
6
+
7
+ def self.providers=(new_providers)
8
+ @providers = new_providers
9
+ end
10
+
11
+ module Provider
12
+
13
+ def self.extended(base)
14
+ provider = base.to_s.split('::').last
15
+ Fog.providers[provider.downcase.to_sym] = provider
16
+ end
17
+
18
+ def [](service_key)
19
+ eval(@services_registry[service_key]).new
20
+ end
21
+
22
+ def service(new_service, constant_string)
23
+ Fog.services[new_service] ||= []
24
+ Fog.services[new_service] |= [self.to_s.split('::').last.downcase.to_sym]
25
+ @services_registry ||= {}
26
+ @services_registry[new_service] = [self.to_s, constant_string].join('::')
27
+ end
28
+
29
+ def services
30
+ @services_registry.keys
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,96 @@
1
+ module Fog
2
+ module SCP
3
+
4
+ def self.new(address, username, options = {})
5
+ if Fog.mocking?
6
+ Fog::SCP::Mock.new(address, username, options)
7
+ else
8
+ Fog::SCP::Real.new(address, username, options)
9
+ end
10
+ end
11
+
12
+ class Mock
13
+
14
+ def self.data
15
+ @data ||= Hash.new do |hash, key|
16
+ hash[key] = []
17
+ end
18
+ end
19
+
20
+ def initialize(address, username, options)
21
+ @address = address
22
+ @username = username
23
+ @options = options
24
+ end
25
+
26
+ def upload(local_path, remote_path, upload_options = {})
27
+ self.class.data[@address] << { :username => @username,
28
+ :options => @options,
29
+ :local_path => local_path,
30
+ :remote_path => remote_path,
31
+ :upload_options => upload_options }
32
+ end
33
+
34
+ def download(remote_path, local_path, download_options = {})
35
+ self.class.data[@address] << { :username => @username,
36
+ :options => @options,
37
+ :remote_path => remote_path,
38
+ :local_path => local_path,
39
+ :download_options => download_options }
40
+ end
41
+
42
+ end
43
+
44
+ class Real
45
+
46
+ def initialize(address, username, options)
47
+ require 'net/scp'
48
+
49
+ key_manager = Net::SSH::Authentication::KeyManager.new(nil, options)
50
+
51
+ unless options[:key_data] || options[:keys] || options[:password] || key_manager.agent
52
+ raise ArgumentError.new(':key_data, :keys, :password or a loaded ssh-agent is required to initialize SSH')
53
+ end
54
+
55
+ options[:timeout] = 30
56
+ if options[:key_data] || options[:keys]
57
+ options[:keys_only] = true
58
+ #Explicitly set these so net-ssh doesn't add the default keys
59
+ #as seen at https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/authentication/session.rb#L131-146
60
+ options[:keys] = [] unless options[:keys]
61
+ options[:key_data] = [] unless options[:key_data]
62
+ end
63
+
64
+ @address = address
65
+ @username = username
66
+ @options = { :paranoid => false }.merge(options)
67
+ end
68
+
69
+ def upload(local_path, remote_path, upload_options = {}, &block)
70
+ begin
71
+ Net::SCP.start(@address, @username, @options) do |scp|
72
+ scp.upload!(local_path, remote_path, upload_options) do |ch, name, sent, total|
73
+ block.call(ch, name, sent, total) if block
74
+ end
75
+ end
76
+ rescue Exception => error
77
+ raise error
78
+ end
79
+ end
80
+
81
+ def download(remote_path, local_path, download_options = {}, &block)
82
+ begin
83
+ Net::SCP.start(@address, @username, @options) do |scp|
84
+ scp.download!(remote_path, local_path, download_options) do |ch, name, sent, total|
85
+ block.call(ch, name, sent, total) if block
86
+ end
87
+ end
88
+ rescue Exception => error
89
+ raise error
90
+ end
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,223 @@
1
+ module Fog
2
+
3
+ def self.services
4
+ @services ||= {}
5
+ end
6
+
7
+ class Service
8
+
9
+ class Error < Fog::Errors::Error; end
10
+ class NotFound < Fog::Errors::NotFound; end
11
+
12
+ module NoLeakInspector
13
+ def inspect
14
+ "#<#{self.class}:#{self.object_id} #{(self.instance_variables - service.secrets).map {|iv| [iv, self.instance_variable_get(iv).inspect].join('=')}.join(' ')}>"
15
+ end
16
+ end
17
+
18
+ module Collections
19
+
20
+ def collections
21
+ service.collections
22
+ end
23
+
24
+ def mocked_requests
25
+ service.mocked_requests
26
+ end
27
+
28
+ def requests
29
+ service.requests
30
+ end
31
+
32
+ end
33
+
34
+ class << self
35
+
36
+ def inherited(child)
37
+ child.class_eval <<-EOS, __FILE__, __LINE__
38
+ class Error < Fog::Service::Error; end
39
+ class NotFound < Fog::Service::NotFound; end
40
+
41
+ module Collections
42
+ include Fog::Service::Collections
43
+
44
+ def service
45
+ #{child}
46
+ end
47
+ end
48
+
49
+ def self.service
50
+ #{child}
51
+ end
52
+ EOS
53
+ end
54
+
55
+ def new(options={})
56
+ options = Fog.symbolize_credentials(options)
57
+ options = fetch_credentials(options).merge(options)
58
+ validate_options(options)
59
+ coerce_options(options)
60
+ setup_requirements
61
+
62
+ if Fog.mocking?
63
+ service::Mock.send(:include, service::Collections)
64
+ service::Mock.new(options)
65
+ else
66
+ service::Real.send(:include, service::Collections)
67
+ service::Real.send(:include, service::NoLeakInspector)
68
+ service::Real.new(options)
69
+ end
70
+ end
71
+
72
+ def fetch_credentials(options)
73
+ # attempt to load credentials from config file
74
+ begin
75
+ Fog.credentials.reject {|key, value| !(recognized | requirements).include?(key)}
76
+ rescue LoadError
77
+ # if there are no configured credentials, do nothing
78
+ {}
79
+ end
80
+ end
81
+
82
+ def setup_requirements
83
+ if superclass.respond_to?(:setup_requirements)
84
+ superclass.setup_requirements
85
+ end
86
+
87
+ @required ||= false
88
+ unless @required
89
+ for collection in collections
90
+ require [@model_path, collection].join('/')
91
+ constant = collection.to_s.split('_').map {|characters| characters[0...1].upcase << characters[1..-1]}.join('')
92
+ service::Collections.module_eval <<-EOS, __FILE__, __LINE__
93
+ def #{collection}(attributes = {})
94
+ #{service}::#{constant}.new({:service => self}.merge(attributes))
95
+ end
96
+ EOS
97
+ end
98
+ for model in models
99
+ require [@model_path, model].join('/')
100
+ end
101
+ for request in requests
102
+ require [@request_path, request].join('/')
103
+ if service::Mock.method_defined?(request)
104
+ mocked_requests << request
105
+ else
106
+ service::Mock.module_eval <<-EOS, __FILE__, __LINE__
107
+ def #{request}(*args)
108
+ Fog::Mock.not_implemented
109
+ end
110
+ EOS
111
+ end
112
+ end
113
+ @required = true
114
+ end
115
+ end
116
+
117
+ def model_path(new_path)
118
+ @model_path = new_path
119
+ end
120
+
121
+ def collection(new_collection)
122
+ collections << new_collection
123
+ end
124
+
125
+ def collections
126
+ @collections ||= []
127
+ end
128
+
129
+ def coerce_options(options)
130
+ options.each do |key, value|
131
+ value_string = value.to_s.downcase
132
+ if value.nil?
133
+ options.delete(key)
134
+ elsif value == value_string.to_i.to_s
135
+ options[key] = value.to_i
136
+ else
137
+ options[key] = case value_string
138
+ when 'false'
139
+ false
140
+ when 'true'
141
+ true
142
+ else
143
+ value
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ def mocked_requests
150
+ @mocked_requests ||= []
151
+ end
152
+
153
+ def model(new_model)
154
+ models << new_model
155
+ end
156
+
157
+ def models
158
+ @models ||= []
159
+ end
160
+
161
+ def request_path(new_path)
162
+ @request_path = new_path
163
+ end
164
+
165
+ def request(new_request)
166
+ requests << new_request
167
+ end
168
+
169
+ def requests
170
+ @requests ||= []
171
+ end
172
+
173
+ def secrets(*args)
174
+ if args.empty?
175
+ @secrets ||= []
176
+ else
177
+ args.inject(secrets) do |secrets, secret|
178
+ secrets << "@#{secret}".to_sym
179
+ end
180
+ end
181
+ end
182
+
183
+ def requires(*args)
184
+ requirements.concat(args)
185
+ end
186
+
187
+ def requirements
188
+ @requirements ||= []
189
+ end
190
+
191
+ def recognizes(*args)
192
+ recognized.concat(args)
193
+ end
194
+
195
+ def recognized
196
+ @recognized ||= [:connection_options]
197
+ end
198
+
199
+ def validate_options(options)
200
+ keys = []
201
+ for key, value in options
202
+ unless value.nil?
203
+ keys << key
204
+ end
205
+ end
206
+ missing = requirements - keys
207
+ unless missing.empty?
208
+ raise ArgumentError, "Missing required arguments: #{missing.join(', ')}"
209
+ end
210
+
211
+ unless recognizes.empty?
212
+ unrecognized = options.keys - requirements - recognized
213
+ unless unrecognized.empty?
214
+ Fog::Logger.warning("Unrecognized arguments: #{unrecognized.join(', ')}")
215
+ end
216
+ end
217
+ end
218
+
219
+ end
220
+
221
+ end
222
+ end
223
+