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.
- checksums.yaml +5 -5
- data/.github/FUNDING.yml +2 -0
- data/.github/dependabot.yml +10 -0
- data/.github/workflows/ci.yml +32 -0
- data/.rubocop.yml +16 -12
- data/.rubocop_todo.yml +724 -0
- data/CONTRIBUTING.md +5 -1
- data/Gemfile +1 -1
- data/README.md +2 -1
- data/Rakefile +2 -14
- data/SECURITY.md +6 -0
- data/changelog.md +241 -141
- data/fog-core.gemspec +13 -9
- data/lib/fog/account.rb +0 -16
- data/lib/fog/billing.rb +0 -11
- data/lib/fog/compute/models/server.rb +7 -3
- data/lib/fog/compute.rb +3 -25
- data/lib/fog/core/association.rb +1 -0
- data/lib/fog/core/attributes/default.rb +7 -0
- data/lib/fog/core/attributes.rb +42 -5
- data/lib/fog/core/cache.rb +58 -55
- data/lib/fog/core/collection.rb +9 -3
- data/lib/fog/core/connection.rb +4 -6
- data/lib/fog/core/current_machine.rb +1 -1
- data/lib/fog/core/errors.rb +1 -1
- data/lib/fog/core/logger.rb +5 -2
- data/lib/fog/core/mock.rb +7 -2
- data/lib/fog/core/model.rb +34 -5
- data/lib/fog/core/provider.rb +37 -4
- data/lib/fog/core/scp.rb +16 -11
- data/lib/fog/core/service.rb +5 -5
- data/lib/fog/core/services_mixin.rb +62 -10
- data/lib/fog/core/ssh.rb +49 -25
- data/lib/fog/core/stringify_keys.rb +0 -2
- data/lib/fog/core/time.rb +2 -2
- data/lib/fog/core/uuid.rb +2 -8
- data/lib/fog/core/version.rb +3 -1
- data/lib/fog/core/wait_for.rb +2 -1
- data/lib/fog/core/wait_for_defaults.rb +2 -0
- data/lib/fog/core.rb +57 -59
- data/lib/fog/dns.rb +0 -11
- data/lib/fog/formatador.rb +9 -8
- data/lib/fog/monitoring.rb +0 -11
- data/lib/fog/network.rb +0 -12
- data/lib/fog/schema/data_validator.rb +1 -0
- data/lib/fog/storage.rb +15 -30
- data/lib/fog/support.rb +0 -12
- data/lib/fog/test_helpers/collection_helper.rb +2 -0
- data/lib/fog/test_helpers/formats_helper.rb +2 -2
- data/lib/fog/test_helpers/helper.rb +3 -3
- data/lib/fog/test_helpers/minitest/assertions.rb +1 -1
- data/lib/fog/test_helpers/minitest/expectations.rb +1 -1
- data/lib/fog/test_helpers/mock_helper.rb +84 -84
- data/lib/fog/test_helpers/succeeds_helper.rb +2 -2
- data/lib/fog/test_helpers/types_helper.rb +1 -0
- data/lib/fog/vpn.rb +0 -12
- data/lib/tasks/test_task.rb +4 -5
- metadata +58 -85
- data/.travis.yml +0 -39
- data/spec/compute/models/server_spec.rb +0 -229
- data/spec/compute_spec.rb +0 -95
- data/spec/connection_spec.rb +0 -105
- data/spec/core/cache_spec.rb +0 -191
- data/spec/core/model_spec.rb +0 -36
- data/spec/core/stringify_keys_spec.rb +0 -38
- data/spec/core/whitelist_keys_spec.rb +0 -36
- data/spec/credentials_spec.rb +0 -88
- data/spec/current_machine_spec.rb +0 -36
- data/spec/fake_app/fake_service.rb +0 -18
- data/spec/fake_app/models/collection.rb +0 -5
- data/spec/fake_app/models/model.rb +0 -2
- data/spec/fake_app/requests/request.rb +0 -11
- data/spec/fog_attribute_spec.rb +0 -549
- data/spec/formatador_spec.rb +0 -154
- data/spec/identity_spec.rb +0 -95
- data/spec/mocking_spec.rb +0 -84
- data/spec/service_spec.rb +0 -201
- data/spec/spec_helper.rb +0 -19
- data/spec/storage_spec.rb +0 -114
- data/spec/test_helpers/formats_helper_spec.rb +0 -121
- data/spec/test_helpers/schema_validator_spec.rb +0 -101
- data/spec/timeout_spec.rb +0 -20
- data/spec/utils_spec.rb +0 -29
- data/spec/uuid_spec.rb +0 -11
- 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(:
|
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
|
-
|
93
|
+
return false unless ready? && ssh_ip_address
|
94
|
+
|
95
|
+
Timeout.timeout(sshable_timeout) { ssh("pwd", options) }
|
93
96
|
@sshable_timeout = nil
|
94
|
-
|
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 =
|
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
|
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
|
32
|
+
super
|
55
33
|
end
|
56
34
|
end
|
57
35
|
|
data/lib/fog/core/association.rb
CHANGED
@@ -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
|
data/lib/fog/core/attributes.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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(
|
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
|
-
|
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(
|
209
|
+
missing << arg unless send(arg.to_s) || attributes.key?(arg)
|
173
210
|
end
|
174
211
|
missing
|
175
212
|
end
|
data/lib/fog/core/cache.rb
CHANGED
@@ -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 =
|
117
|
-
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
|
-
|
122
|
-
end.compact
|
124
|
+
next unless valid_for_load?(path)
|
123
125
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
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 =
|
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
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
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
|
-
|
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
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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)
|
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
|
-
|
241
|
-
return metadata
|
242
|
+
yaml_load(File.read(mpath))
|
242
243
|
else
|
243
|
-
|
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
|
-
|
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.
|
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 = {
|
273
|
-
|
274
|
-
|
275
|
-
|
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
|
data/lib/fog/core/collection.rb
CHANGED
@@ -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(:
|
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
|
-
:
|
91
|
-
:
|
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
|
data/lib/fog/core/connection.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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!(:
|
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
|
data/lib/fog/core/errors.rb
CHANGED
@@ -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
|
-
|
123
|
+
YML
|
124
124
|
raise Fog::Errors::LoadError, missing_credentials_message
|
125
125
|
end
|
126
126
|
end
|
data/lib/fog/core/logger.rb
CHANGED
@@ -1,12 +1,15 @@
|
|
1
1
|
module Fog
|
2
2
|
class Logger
|
3
3
|
@channels = {
|
4
|
-
:
|
5
|
-
:
|
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 = { :
|
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
|
data/lib/fog/core/model.rb
CHANGED
@@ -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
|
-
|
81
|
-
|
82
|
-
|
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
|