fog-core 2.1.0 → 2.6.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.
Files changed (85) hide show
  1. checksums.yaml +5 -5
  2. data/.github/FUNDING.yml +2 -0
  3. data/.github/dependabot.yml +10 -0
  4. data/.github/workflows/ci.yml +32 -0
  5. data/.rubocop.yml +16 -12
  6. data/.rubocop_todo.yml +724 -0
  7. data/CONTRIBUTING.md +5 -1
  8. data/Gemfile +1 -1
  9. data/README.md +2 -1
  10. data/Rakefile +2 -14
  11. data/SECURITY.md +6 -0
  12. data/changelog.md +241 -141
  13. data/fog-core.gemspec +13 -9
  14. data/lib/fog/account.rb +0 -16
  15. data/lib/fog/billing.rb +0 -11
  16. data/lib/fog/compute/models/server.rb +7 -3
  17. data/lib/fog/compute.rb +3 -25
  18. data/lib/fog/core/association.rb +1 -0
  19. data/lib/fog/core/attributes/default.rb +7 -0
  20. data/lib/fog/core/attributes.rb +42 -5
  21. data/lib/fog/core/cache.rb +58 -55
  22. data/lib/fog/core/collection.rb +9 -3
  23. data/lib/fog/core/connection.rb +4 -6
  24. data/lib/fog/core/current_machine.rb +1 -1
  25. data/lib/fog/core/errors.rb +1 -1
  26. data/lib/fog/core/logger.rb +5 -2
  27. data/lib/fog/core/mock.rb +7 -2
  28. data/lib/fog/core/model.rb +34 -5
  29. data/lib/fog/core/provider.rb +37 -4
  30. data/lib/fog/core/scp.rb +16 -11
  31. data/lib/fog/core/service.rb +5 -5
  32. data/lib/fog/core/services_mixin.rb +62 -10
  33. data/lib/fog/core/ssh.rb +49 -25
  34. data/lib/fog/core/stringify_keys.rb +0 -2
  35. data/lib/fog/core/time.rb +2 -2
  36. data/lib/fog/core/uuid.rb +2 -8
  37. data/lib/fog/core/version.rb +3 -1
  38. data/lib/fog/core/wait_for.rb +2 -1
  39. data/lib/fog/core/wait_for_defaults.rb +2 -0
  40. data/lib/fog/core.rb +57 -59
  41. data/lib/fog/dns.rb +0 -11
  42. data/lib/fog/formatador.rb +9 -8
  43. data/lib/fog/monitoring.rb +0 -11
  44. data/lib/fog/network.rb +0 -12
  45. data/lib/fog/schema/data_validator.rb +1 -0
  46. data/lib/fog/storage.rb +15 -30
  47. data/lib/fog/support.rb +0 -12
  48. data/lib/fog/test_helpers/collection_helper.rb +2 -0
  49. data/lib/fog/test_helpers/formats_helper.rb +2 -2
  50. data/lib/fog/test_helpers/helper.rb +3 -3
  51. data/lib/fog/test_helpers/minitest/assertions.rb +1 -1
  52. data/lib/fog/test_helpers/minitest/expectations.rb +1 -1
  53. data/lib/fog/test_helpers/mock_helper.rb +84 -84
  54. data/lib/fog/test_helpers/succeeds_helper.rb +2 -2
  55. data/lib/fog/test_helpers/types_helper.rb +1 -0
  56. data/lib/fog/vpn.rb +0 -12
  57. data/lib/tasks/test_task.rb +4 -5
  58. metadata +58 -85
  59. data/.travis.yml +0 -39
  60. data/spec/compute/models/server_spec.rb +0 -229
  61. data/spec/compute_spec.rb +0 -95
  62. data/spec/connection_spec.rb +0 -105
  63. data/spec/core/cache_spec.rb +0 -191
  64. data/spec/core/model_spec.rb +0 -36
  65. data/spec/core/stringify_keys_spec.rb +0 -38
  66. data/spec/core/whitelist_keys_spec.rb +0 -36
  67. data/spec/credentials_spec.rb +0 -88
  68. data/spec/current_machine_spec.rb +0 -36
  69. data/spec/fake_app/fake_service.rb +0 -18
  70. data/spec/fake_app/models/collection.rb +0 -5
  71. data/spec/fake_app/models/model.rb +0 -2
  72. data/spec/fake_app/requests/request.rb +0 -11
  73. data/spec/fog_attribute_spec.rb +0 -549
  74. data/spec/formatador_spec.rb +0 -154
  75. data/spec/identity_spec.rb +0 -95
  76. data/spec/mocking_spec.rb +0 -84
  77. data/spec/service_spec.rb +0 -201
  78. data/spec/spec_helper.rb +0 -19
  79. data/spec/storage_spec.rb +0 -114
  80. data/spec/test_helpers/formats_helper_spec.rb +0 -121
  81. data/spec/test_helpers/schema_validator_spec.rb +0 -101
  82. data/spec/timeout_spec.rb +0 -20
  83. data/spec/utils_spec.rb +0 -29
  84. data/spec/uuid_spec.rb +0 -11
  85. data/spec/wait_for_spec.rb +0 -30
data/lib/fog/billing.rb CHANGED
@@ -1,16 +1,5 @@
1
1
  module Fog
2
2
  module Billing
3
3
  extend Fog::ServicesMixin
4
-
5
- def self.new(orig_attributes)
6
- attributes = orig_attributes.dup
7
- provider = attributes.delete(:provider).to_s.downcase.to_sym
8
- if provider == :stormondemand
9
- require "fog/billing/storm_on_demand"
10
- Fog::Billing::StormOnDemand.new(attributes)
11
- else
12
- super(orig_attributes)
13
- end
14
- end
15
4
  end
16
5
  end
@@ -53,12 +53,13 @@ module Fog
53
53
  def ssh_ip_address
54
54
  return public_ip_address unless @ssh_ip_address
55
55
  return @ssh_ip_address.call(self) if @ssh_ip_address.is_a?(Proc)
56
+
56
57
  @ssh_ip_address
57
58
  end
58
59
 
59
60
  def ssh_options
60
61
  @ssh_options ||= {}
61
- ssh_options = @ssh_options.merge(:port => ssh_port)
62
+ ssh_options = @ssh_options.merge(port: ssh_port)
62
63
  if private_key
63
64
  ssh_options[:key_data] = [private_key]
64
65
  ssh_options[:auth_methods] = %w(publickey)
@@ -89,9 +90,12 @@ module Fog
89
90
  end
90
91
 
91
92
  def sshable?(options = {})
92
- result = ready? && !ssh_ip_address.nil? && !!Timeout.timeout(sshable_timeout) { ssh("pwd", options) }
93
+ return false unless ready? && ssh_ip_address
94
+
95
+ Timeout.timeout(sshable_timeout) { ssh("pwd", options) }
93
96
  @sshable_timeout = nil
94
- result
97
+
98
+ true
95
99
  rescue SystemCallError
96
100
  false
97
101
  rescue Net::SSH::AuthenticationFailed, Net::SSH::Disconnect
data/lib/fog/compute.rb CHANGED
@@ -7,16 +7,6 @@ module Fog
7
7
  provider = attributes.delete(:provider).to_s.downcase.to_sym
8
8
 
9
9
  case provider
10
- when :gogrid
11
- require "fog/go_grid/compute"
12
- Fog::Compute::GoGrid.new(attributes)
13
- when :new_servers
14
- require "fog/bare_metal_cloud/compute"
15
- Fog::Logger.deprecation "`new_servers` is deprecated. Please use `bare_metal_cloud` instead."
16
- Fog::Compute::BareMetalCloud.new(attributes)
17
- when :baremetalcloud
18
- require "fog/bare_metal_cloud/compute"
19
- Fog::Compute::BareMetalCloud.new(attributes)
20
10
  when :rackspace
21
11
  version = attributes.delete(:version)
22
12
  version = version.to_s.downcase.to_sym unless version.nil?
@@ -32,26 +22,14 @@ module Fog
32
22
  version = attributes.delete(:version)
33
23
  version = version.to_s.downcase.to_sym unless version.nil?
34
24
  if version == :v1
35
- error_message = 'DigitalOcean V1 is deprecated.Please use `:version => :v2` attribute to use Next Gen Cloud Servers.'
25
+ error_message = "DigitalOcean V1 is deprecated.Please use `:version => :v2` attribute to use Next Gen Cloud Servers."
36
26
  raise error_message
37
27
  else
38
- require 'fog/digitalocean/compute'
28
+ require "fog/digitalocean/compute"
39
29
  Fog::Compute::DigitalOcean.new(attributes)
40
30
  end
41
- when :stormondemand
42
- require "fog/compute/storm_on_demand"
43
- Fog::Compute::StormOnDemand.new(attributes)
44
- when :vcloud
45
- require "fog/vcloud/compute"
46
- Fog::Vcloud::Compute.new(attributes)
47
- when :vclouddirector
48
- require "fog/vcloud_director/compute"
49
- Fog::Compute::VcloudDirector.new(attributes)
50
- when :cloudatcost
51
- require "fog/cloudatcost/compute"
52
- Fog::Compute::CloudAtCost.new(attributes)
53
31
  else
54
- super(orig_attributes)
32
+ super
55
33
  end
56
34
  end
57
35
 
@@ -7,6 +7,7 @@ module Fog
7
7
 
8
8
  def load(associations)
9
9
  return unless associations.kind_of?(Array)
10
+
10
11
  associations.each do |association|
11
12
  self << association
12
13
  end
@@ -7,6 +7,13 @@ module Fog
7
7
  class Default
8
8
  attr_reader :model, :name, :squash, :aliases, :default, :as
9
9
 
10
+ # @param [Klass] model model class
11
+ # @param [Symbol] name name of the attribute
12
+ # @param [Hash] options attribute options
13
+ # @option options [Symbol] :squash
14
+ # @option options [::Array] :aliases
15
+ # @option options [Object] :default
16
+ # @option options [Object] :as
10
17
  def initialize(model, name, options)
11
18
  @model = model
12
19
  @model.attributes << name
@@ -25,6 +25,14 @@ module Fog
25
25
  @masks ||= {}
26
26
  end
27
27
 
28
+ # Defines a new attribute
29
+ # @param [Symbol] name attribute name
30
+ # @param [Hash] options (see {Default#initialize})
31
+ # @option options [Symbol, ::String] :type attribute type (see {Attributes})
32
+ # @option options [Symbol] :squash
33
+ # @option options [::Array] :aliases
34
+ # @option options [Object] :default
35
+ # @option options [Object] :as
28
36
  def attribute(name, options = {})
29
37
  type = options.fetch(:type, "default").to_s.capitalize
30
38
  Fog::Attributes.const_get(type).new(self, name, options)
@@ -79,14 +87,26 @@ module Fog
79
87
 
80
88
  def all_attributes
81
89
  self.class.attributes.reduce({}) do |hash, attribute|
82
- hash[masks[attribute]] = send(attribute)
90
+ if masks[attribute].nil?
91
+ Fog::Logger.deprecation("Please define #{attribute} using the Fog DSL")
92
+ hash[attribute] = send(attribute)
93
+ else
94
+ hash[masks[attribute]] = send(attribute)
95
+ end
96
+
83
97
  hash
84
98
  end
85
99
  end
86
100
 
87
101
  def all_associations
88
102
  self.class.associations.keys.reduce({}) do |hash, association|
89
- hash[masks[association]] = associations[association] || send(association)
103
+ if masks[association].nil?
104
+ Fog::Logger.deprecation("Please define #{association} using the Fog DSL")
105
+ hash[association] = associations[association] || send(association)
106
+ else
107
+ hash[masks[association]] = associations[association] || send(association)
108
+ end
109
+
90
110
  hash
91
111
  end
92
112
  end
@@ -113,9 +133,13 @@ module Fog
113
133
  send("#{identity_name}=", new_identity)
114
134
  end
115
135
 
136
+ # Merges attributes into self
137
+ # @note Ignored attributes are not merged (see {ClassMethods.ignored_attributes})
138
+ # @return [self]
116
139
  def merge_attributes(new_attributes = {})
117
140
  new_attributes.each_pair do |key, value|
118
141
  next if self.class.ignored_attributes.include?(key)
142
+
119
143
  if self.class.aliases[key]
120
144
  send("#{self.class.aliases[key]}=", value)
121
145
  elsif self.respond_to?("#{key}=", true)
@@ -127,6 +151,18 @@ module Fog
127
151
  self
128
152
  end
129
153
 
154
+ # Filters attributes by selected attribute names
155
+ # @note In some cases we want to easily get subset of model attributes
156
+ # @note Hash#slice requires Ruby >= 2.5.0
157
+ # @param [Symbol] selected attribute names
158
+ # @return [Hash] new hash with selected attributes
159
+ def filter_attributes(*selected)
160
+ filtered = attributes.select { |a, _| selected.include?(a) }
161
+
162
+ # we should use getters instead of direct accessing attributes hash
163
+ filtered.each_key { |k| filtered[k] = send(k) }
164
+ end
165
+
130
166
  # Returns true if a remote resource has been assigned an
131
167
  # identity and we can assume it has been persisted.
132
168
  #
@@ -154,14 +190,15 @@ module Fog
154
190
  if missing.length == 1
155
191
  raise(ArgumentError, "#{missing.first} is required for this operation")
156
192
  elsif missing.any?
157
- raise(ArgumentError, "#{missing[0...-1].join(", ")} and #{missing[-1]} are required for this operation")
193
+ raise(ArgumentError, "#{missing[0...-1].join(', ')} and #{missing[-1]} are required for this operation")
158
194
  end
159
195
  end
160
196
 
161
197
  def requires_one(*args)
162
198
  missing = missing_attributes(args)
163
199
  return unless missing.length == args.length
164
- raise(ArgumentError, "#{missing[0...-1].join(", ")} or #{missing[-1]} are required for this operation")
200
+
201
+ raise(ArgumentError, "#{missing[0...-1].join(', ')} or #{missing[-1]} are required for this operation")
165
202
  end
166
203
 
167
204
  protected
@@ -169,7 +206,7 @@ module Fog
169
206
  def missing_attributes(args)
170
207
  missing = []
171
208
  ([:service] | args).each do |arg|
172
- missing << arg unless send("#{arg}") || attributes.key?(arg)
209
+ missing << arg unless send(arg.to_s) || attributes.key?(arg)
173
210
  end
174
211
  missing
175
212
  end
@@ -93,6 +93,9 @@ module Fog
93
93
  # see the +namespace_prefix=+ method.
94
94
  SANDBOX = ENV["HOME"] ? File.expand_path("~/.fog-cache") : File.expand_path(".fog-cache")
95
95
 
96
+ # required attributes to load model from cache
97
+ REQUIRED_ATTRIBUTES = [:identity, :collection_klass, :collection_attrs, :model_klass, :model_attrs].freeze
98
+
96
99
  # when a resource is used such as `server.cache.dump` the model klass is passed in
97
100
  # so that it can be identified from a different session.
98
101
  attr_reader :model
@@ -112,26 +115,34 @@ module Fog
112
115
  # collection_klass and model_klass should be the same across all instances
113
116
  # choose a valid cache record from the dump to use as a sample to deterine
114
117
  # which collection/model to instantiate.
115
- sample_path = cache_files.detect{ |path| valid_for_load?(path) }
116
- model_klass = const_get_compat(load_cache(sample_path)[:model_klass])
117
- collection_klass = const_get_compat(load_cache(sample_path)[:collection_klass]) if load_cache(sample_path)[:collection_klass]
118
+ sample_path = cache_files.detect { |path| valid_for_load?(path) }
119
+ model_klass = Object.const_get(load_cache(sample_path)[:model_klass])
120
+ collection_klass = Object.const_get(load_cache(sample_path)[:collection_klass]) if load_cache(sample_path)[:collection_klass]
118
121
 
119
122
  # Load the cache data into actual ruby instances
120
123
  loaded = cache_files.map do |path|
121
- model_klass.new(load_cache(path)[:attrs]) if valid_for_load?(path)
122
- end.compact
124
+ next unless valid_for_load?(path)
123
125
 
124
- # Set the collection and service so they can be reloaded/connection is set properly.
125
- # See https://github.com/fog/fog-aws/issues/354#issuecomment-286789702
126
- loaded.each do |i|
127
- i.collection = collection_klass.new(:service => service) if collection_klass
128
- i.instance_variable_set(:@service, service)
129
- end
126
+ cache = load_cache(path)
127
+
128
+ # make sure attributes are not nil
129
+ cache[:collection_attrs] ||= {}
130
+ cache[:model_attrs] ||= {}
131
+
132
+ m = model_klass.new(cache[:model_attrs])
133
+
134
+ # Set the collection and service so they can be reloaded/connection is set properly.
135
+ # See https://github.com/fog/fog-aws/issues/354#issuecomment-286789702
136
+ m.instance_variable_set(:@service, service)
137
+ m.collection = collection_klass.new(cache[:collection_attrs].merge(service: service)) if collection_klass
138
+
139
+ m
140
+ end.compact
130
141
 
131
142
  # uniqe-ify based on the total of attributes. duplicate cache can exist due to
132
143
  # `model#identity` not being unique. but if all attributes match, they are unique
133
144
  # and shouldn't be loaded again.
134
- uniq_loaded = uniq_w_block(loaded) { |i| i.attributes }
145
+ uniq_loaded = loaded.uniq { |i| i.attributes }
135
146
  if uniq_loaded.size != loaded.size
136
147
  Fog::Logger.warning("Found duplicate items in the cache. Expire all & refresh cache soon.")
137
148
  end
@@ -142,38 +153,18 @@ module Fog
142
153
  uniq_loaded
143
154
  end
144
155
 
145
- # :nodoc: compatability for 1.8.7 1.9.3
146
- def self.const_get_compat(strklass)
147
- # https://stackoverflow.com/questions/3163641/get-a-class-by-name-in-ruby
148
- strklass.split('::').inject(Object) do |mod, class_name|
149
- mod.const_get(class_name)
150
- end
151
- end
152
-
153
- # :nodoc: compatability for 1.8.7 1.9.3
154
- def self.uniq_w_block(arr)
155
- ret, keys = [], []
156
- arr.each do |x|
157
- key = block_given? ? yield(x) : x
158
- unless keys.include? key
159
- ret << x
160
- keys << key
161
- end
162
- end
163
- ret
164
- end
165
-
166
156
  # method to determine if a path can be loaded and is valid fog cache format.
167
157
  def self.valid_for_load?(path)
168
158
  data = load_cache(path)
169
159
  if data && data.is_a?(Hash)
170
- if [:identity, :model_klass, :collection_klass, :attrs].all? { |k| data.keys.include?(k) }
171
- return true
172
- else
173
- Fog::Logger.warning("Found corrupt items in the cache: #{path}. Expire all & refresh cache soon.\n\nData:#{File.read(path)}")
174
- return false
175
- end
160
+ missing_attrs = REQUIRED_ATTRIBUTES.reject { |k| data.keys.include?(k) }
161
+ return true if missing_attrs.empty?
162
+
163
+ Fog::Logger.warning("Found corrupt items in the cache: #{path}. Expire all & refresh cache soon.\n\nMissing: #{missing_attrs}.\nData:\n#{File.read(path)}")
164
+ return false
176
165
  end
166
+
167
+ false
177
168
  end
178
169
 
179
170
  # creates on-disk cache of this specific +model_klass+ and +@service+
@@ -193,12 +184,23 @@ module Fog
193
184
  FileUtils.rm_rf(SANDBOX)
194
185
  end
195
186
 
187
+ # Load YAML file with aliases
188
+ # @note Starting from Ruby 3.1 we must explicitly tell Psych to allow aliases
189
+ def self.yaml_load(path)
190
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.1.0")
191
+ YAML.load(path, aliases: true)
192
+ else
193
+ YAML.load(path)
194
+ end
195
+ end
196
+
196
197
  # loads yml cache from path on disk, used
197
198
  # to initialize Fog models.
198
199
  def self.load_cache(path)
199
200
  @memoized ||= {}
200
201
  return @memoized[path] if @memoized[path]
201
- @memoized[path] = YAML.load(File.read(path))
202
+
203
+ @memoized[path] = yaml_load(File.read(path))
202
204
  end
203
205
 
204
206
  def self.namespace_prefix=(name)
@@ -222,13 +224,13 @@ module Fog
222
224
 
223
225
  mpath = File.join(SANDBOX, namespace_prefix, "metadata.yml")
224
226
  to_write = if File.exist?(mpath)
225
- YAML.dump(YAML.load(File.read(mpath)).merge!(h))
226
- else
227
- YAML.dump(h)
228
- end
227
+ YAML.dump(yaml_load(File.read(mpath)).merge!(h))
228
+ else
229
+ YAML.dump(h)
230
+ end
229
231
 
230
232
  mdir = File.join(SANDBOX, namespace_prefix)
231
- FileUtils.mkdir_p(mdir) if !File.exist?(mdir)
233
+ FileUtils.mkdir_p(mdir)
232
234
 
233
235
  File.open(mpath, "w") { |f| f.write(to_write) }
234
236
  end
@@ -237,10 +239,9 @@ module Fog
237
239
  def self.metadata
238
240
  mpath = File.join(SANDBOX, namespace_prefix, "metadata.yml")
239
241
  if File.exist?(mpath)
240
- metadata = YAML.load(File.read(mpath))
241
- return metadata
242
+ yaml_load(File.read(mpath))
242
243
  else
243
- return {}
244
+ {}
244
245
  end
245
246
  end
246
247
 
@@ -249,11 +250,10 @@ module Fog
249
250
 
250
251
  raise CacheDir.new("Must set an explicit identifier/name for this cache. Example: 'serviceX-regionY'") unless namespace_prefix
251
252
 
252
- ns = File.join(SANDBOX, namespace_prefix, service.class.to_s, model_klass.to_s)
253
- ns = safe_path(ns)
253
+ File.join(SANDBOX, namespace_prefix, safe_class_path(service.class), safe_class_path(model_klass))
254
254
  end
255
255
 
256
- def self.safe_path(klass)
256
+ def self.safe_class_path(klass)
257
257
  klass.to_s.gsub("::", "_").downcase
258
258
  end
259
259
 
@@ -269,10 +269,13 @@ module Fog
269
269
  self.class.create_namespace(model.class, model.service)
270
270
  end
271
271
 
272
- data = { :identity => model.identity,
273
- :model_klass => model.class.to_s,
274
- :collection_klass => model.collection && model.collection.class.to_s,
275
- :attrs => model.attributes }
272
+ data = {
273
+ identity: model.identity,
274
+ model_klass: model.class.to_s,
275
+ collection_klass: model.collection && model.collection.class.to_s,
276
+ collection_attrs: model.collection && model.collection.attributes,
277
+ model_attrs: model.attributes
278
+ }
276
279
 
277
280
  File.open(dump_to, "w") { |f| f.write(YAML.dump(data)) }
278
281
  end
@@ -11,6 +11,7 @@ module Fog
11
11
 
12
12
  Array.public_instance_methods(false).each do |method|
13
13
  next if [:reject, :select, :slice, :clear, :inspect].include?(method.to_sym)
14
+
14
15
  class_eval <<-EOS, __FILE__, __LINE__
15
16
  def #{method}(*args)
16
17
  unless @loaded
@@ -18,6 +19,7 @@ module Fog
18
19
  end
19
20
  super
20
21
  end
22
+ ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
21
23
  EOS
22
24
  end
23
25
 
@@ -30,6 +32,7 @@ module Fog
30
32
  data = super
31
33
  self.clone.clear.concat(data)
32
34
  end
35
+ ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
33
36
  EOS
34
37
  end
35
38
 
@@ -52,7 +55,7 @@ module Fog
52
55
  end
53
56
 
54
57
  def destroy(identity)
55
- new(:identity => identity).destroy
58
+ new(identity: identity).destroy
56
59
  end
57
60
 
58
61
  # Creates a new Fog::Collection based around the passed service
@@ -85,10 +88,11 @@ module Fog
85
88
  unless attributes.is_a?(::Hash)
86
89
  raise ArgumentError, "Initialization parameters must be an attributes hash, got #{attributes.class} #{attributes.inspect}"
87
90
  end
91
+
88
92
  model.new(
89
93
  {
90
- :collection => self,
91
- :service => service
94
+ collection: self,
95
+ service: service
92
96
  }.merge(attributes)
93
97
  )
94
98
  end
@@ -112,6 +116,7 @@ module Fog
112
116
  all
113
117
  end
114
118
  end
119
+
115
120
  # Base class for collection classes whose 'all' method returns only a single
116
121
  # page of results and passes the 'Marker' option along as
117
122
  # self.filters[:marker]
@@ -120,6 +125,7 @@ module Fog
120
125
  if block_given?
121
126
  Kernel.loop do
122
127
  break unless filters[:marker]
128
+
123
129
  page = all(collection_filters)
124
130
  # We need to explicitly use the base 'each' method here on the page,
125
131
  # otherwise we get infinite recursion
@@ -44,17 +44,15 @@ module Fog
44
44
  # @option params [Class] :instrumentor Responds to #instrument as in ActiveSupport::Notifications
45
45
  # @option params [String] :instrumentor_name Name prefix for #instrument events. Defaults to 'excon'
46
46
  def initialize(url, persistent = false, params = {})
47
- if params[:path_prefix]
48
- if params[:path]
49
- raise ArgumentError, "optional arg 'path' is invalid when 'path_prefix' is provided"
50
- end
47
+ @path_prefix = params.delete(:path_prefix)
51
48
 
52
- @path_prefix = params.delete(:path_prefix)
49
+ if @path_prefix && params[:path]
50
+ raise ArgumentError, "optional arg 'path' is invalid when 'path_prefix' is provided"
53
51
  end
54
52
 
55
53
  params[:debug_response] = true unless params.key?(:debug_response)
56
54
  params[:headers] ||= {}
57
- params.merge!(:persistent => params.fetch(:persistent, persistent))
55
+ params.merge!(persistent: params.fetch(:persistent, persistent))
58
56
  params[:headers]["User-Agent"] ||= user_agent
59
57
  @excon = Excon.new(url, params)
60
58
  end
@@ -4,7 +4,7 @@ module Fog
4
4
  class CurrentMachine
5
5
  @lock = Mutex.new
6
6
 
7
- AMAZON_AWS_CHECK_IP = "http://checkip.amazonaws.com"
7
+ AMAZON_AWS_CHECK_IP = "http://checkip.amazonaws.com".freeze
8
8
 
9
9
  def self.ip_address=(ip_address)
10
10
  @lock.synchronize do
@@ -120,7 +120,7 @@ An alternate file may be used by placing its path in the FOG_RC environment vari
120
120
  # End of Fog Credentials File
121
121
  #######################################################
122
122
 
123
- YML
123
+ YML
124
124
  raise Fog::Errors::LoadError, missing_credentials_message
125
125
  end
126
126
  end
@@ -1,12 +1,15 @@
1
1
  module Fog
2
2
  class Logger
3
3
  @channels = {
4
- :deprecation => ::STDERR,
5
- :warning => ::STDERR
4
+ deprecation: ::STDERR,
5
+ warning: ::STDERR
6
6
  }
7
7
 
8
8
  @channels[:debug] = ::STDERR if ENV["DEBUG"]
9
9
 
10
+ # provide an env var with narrower scope in case of namespace conflicts
11
+ @channels[:debug] = ::STDERR if ENV["FOG_DEBUG"]
12
+
10
13
  def self.[](channel)
11
14
  @channels[channel]
12
15
  end
data/lib/fog/core/mock.rb CHANGED
@@ -25,6 +25,7 @@ module Fog
25
25
 
26
26
  def self.delay=(new_delay)
27
27
  raise ArgumentError, "delay must be non-negative" unless new_delay >= 0
28
+
28
29
  @delay = new_delay
29
30
  end
30
31
 
@@ -32,7 +33,7 @@ module Fog
32
33
  raise Fog::Errors::MockNotImplemented, message
33
34
  end
34
35
 
35
- def self.random_ip(opts = { :version => :v4 })
36
+ def self.random_ip(opts = { version: :v4 })
36
37
  version = opts[:version]
37
38
  if version == :v6
38
39
  bit_length = 128
@@ -80,7 +81,7 @@ module Fog
80
81
  end
81
82
 
82
83
  def self.random_selection(characters, length)
83
- selection = ""
84
+ selection = +""
84
85
  length.times do
85
86
  position = rand(characters.length)
86
87
  selection << characters[position..position]
@@ -92,12 +93,15 @@ module Fog
92
93
  mocked_services = []
93
94
  Fog.constants.map do |x|
94
95
  next if Fog.autoload?(x)
96
+
95
97
  x_const = Fog.const_get(x)
96
98
  x_const.respond_to?(:constants) && x_const.constants.map do |y|
97
99
  next if x_const.autoload?(y)
100
+
98
101
  y_const = x_const.const_get(y)
99
102
  y_const.respond_to?(:constants) && y_const.constants.map do |z|
100
103
  next if y_const.autoload?(z)
104
+
101
105
  mocked_services << y_const.const_get(z) if z.to_sym == :Mock
102
106
  end
103
107
  end
@@ -105,6 +109,7 @@ module Fog
105
109
 
106
110
  mocked_services.each do |mocked_service|
107
111
  next unless mocked_service.respond_to?(:reset)
112
+
108
113
  mocked_service.reset
109
114
  end
110
115
  end
@@ -21,6 +21,33 @@ module Fog
21
21
  merge_attributes(attribs)
22
22
  end
23
23
 
24
+ # Creates new or updates existing model
25
+ # @return [self]
26
+ def save
27
+ persisted? ? update : create
28
+ end
29
+
30
+ # Creates new entity from model
31
+ # @raise [Fog::Errors::NotImplemented] you must implement #create method in child class and return self
32
+ # @return [self]
33
+ def create
34
+ raise Fog::Errors::NotImplemented, "Implement method #create for #{self.class}. Method must return self"
35
+ end
36
+
37
+ # Updates new entity with model
38
+ # @raise [Fog::Errors::NotImplemented] you must implement #update method in child class and return self
39
+ # @return [self]
40
+ def update
41
+ raise Fog::Errors::NotImplemented, "Implement method #update for #{self.class}. Method must return self"
42
+ end
43
+
44
+ # Destroys entity by model identity
45
+ # @raise [Fog::Errors::NotImplemented] you must implement #destroy method in child class and return self
46
+ # @return [self]
47
+ def destroy
48
+ raise Fog::Errors::NotImplemented, "Implement method #destroy for #{self.class}. Method must return self"
49
+ end
50
+
24
51
  def cache
25
52
  Fog::Cache.new(self)
26
53
  end
@@ -41,6 +68,8 @@ module Fog
41
68
  end
42
69
  end
43
70
 
71
+ # @return [self] if model successfully reloaded
72
+ # @return [nil] if something went wrong or model was not found
44
73
  def reload
45
74
  requires :identity
46
75
 
@@ -61,6 +90,7 @@ module Fog
61
90
 
62
91
  def symbolize_keys(hash)
63
92
  return nil if hash.nil?
93
+
64
94
  hash.reduce({}) do |options, (key, value)|
65
95
  options[(key.to_sym rescue key) || key] = value
66
96
  options
@@ -69,6 +99,7 @@ module Fog
69
99
 
70
100
  def wait_for(timeout = Fog.timeout, interval = Fog.interval, &block)
71
101
  reload_has_succeeded = false
102
+
72
103
  duration = Fog.wait_for(timeout, interval) do # Note that duration = false if it times out
73
104
  if reload
74
105
  reload_has_succeeded = true
@@ -77,11 +108,9 @@ module Fog
77
108
  false
78
109
  end
79
110
  end
80
- if reload_has_succeeded
81
- return duration # false if timeout; otherwise {:duration => elapsed time }
82
- else
83
- raise Fog::Errors::Error, "Reload failed, #{self.class} #{identity} not present."
84
- end
111
+ raise Fog::Errors::Error, "Reload failed, #{self.class} #{identity} not present." unless reload_has_succeeded
112
+
113
+ duration # false if timeout; otherwise {:duration => elapsed time }
85
114
  end
86
115
  end
87
116
  end