fog-core 1.21.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 (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,137 @@
1
+ require 'delegate'
2
+
3
+ module Fog
4
+ module SSH
5
+
6
+ def self.new(address, username, options = {})
7
+ if Fog.mocking?
8
+ Fog::SSH::Mock.new(address, username, options)
9
+ else
10
+ Fog::SSH::Real.new(address, username, options)
11
+ end
12
+ end
13
+
14
+ class Mock
15
+
16
+ def self.data
17
+ @data ||= Hash.new do |hash, key|
18
+ hash[key] = []
19
+ end
20
+ end
21
+
22
+ def self.reset
23
+ @data= nil
24
+ end
25
+
26
+ def initialize(address, username, options)
27
+ @address = address
28
+ @username = username
29
+ @options = options
30
+ end
31
+
32
+ def run(commands, &blk)
33
+ self.class.data[@address] << {:commands => commands, :username => @username, :options => @options}
34
+ end
35
+
36
+ end
37
+
38
+ class Real
39
+
40
+ def initialize(address, username, options)
41
+ require 'net/ssh'
42
+
43
+ key_manager = Net::SSH::Authentication::KeyManager.new(nil, options)
44
+
45
+ unless options[:key_data] || options[:keys] || options[:password] || key_manager.agent
46
+ raise ArgumentError.new(':key_data, :keys, :password or a loaded ssh-agent is required to initialize SSH')
47
+ end
48
+
49
+ options[:timeout] ||= 30
50
+ if options[:key_data] || options[:keys]
51
+ options[:keys_only] = true
52
+ #Explicitly set these so net-ssh doesn't add the default keys
53
+ #as seen at https://github.com/net-ssh/net-ssh/blob/master/lib/net/ssh/authentication/session.rb#L131-146
54
+ options[:keys] = [] unless options[:keys]
55
+ options[:key_data] = [] unless options[:key_data]
56
+ end
57
+
58
+ @address = address
59
+ @username = username
60
+ @options = { :paranoid => false }.merge(options)
61
+ end
62
+
63
+ def run(commands, &blk)
64
+ commands = [*commands]
65
+ results = []
66
+ begin
67
+ Net::SSH.start(@address, @username, @options) do |ssh|
68
+ commands.each do |command|
69
+ result = Result.new(command)
70
+ ssh.open_channel do |ssh_channel|
71
+ ssh_channel.request_pty
72
+ ssh_channel.exec(command) do |channel, success|
73
+ unless success
74
+ raise "Could not execute command: #{command.inspect}"
75
+ end
76
+
77
+ channel.on_data do |ch, data|
78
+ result.stdout << data
79
+ yield [data, ''] if blk
80
+ end
81
+
82
+ channel.on_extended_data do |ch, type, data|
83
+ next unless type == 1
84
+ result.stderr << data
85
+ yield ['', data] if blk
86
+ end
87
+
88
+ channel.on_request('exit-status') do |ch, data|
89
+ result.status = data.read_long
90
+ end
91
+
92
+ channel.on_request('exit-signal') do |ch, data|
93
+ result.status = 255
94
+ end
95
+ end
96
+ end
97
+ ssh.loop
98
+ results << result
99
+ end
100
+ end
101
+ rescue Net::SSH::HostKeyMismatch => exception
102
+ exception.remember_host!
103
+ sleep 0.2
104
+ retry
105
+ end
106
+ results
107
+ end
108
+
109
+ end
110
+
111
+ class Result
112
+
113
+ attr_accessor :command, :stderr, :stdout, :status
114
+
115
+ def display_stdout
116
+ data = stdout.split("\r\n")
117
+ if data.is_a?(String)
118
+ Formatador.display_line(data)
119
+ elsif data.is_a?(Array)
120
+ Formatador.display_lines(data)
121
+ end
122
+ end
123
+
124
+ def display_stderr
125
+ Formatador.display_line(stderr.split("\r\n"))
126
+ end
127
+
128
+ def initialize(command)
129
+ @command = command
130
+ @stderr = ''
131
+ @stdout = ''
132
+ end
133
+
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,32 @@
1
+ require 'time'
2
+
3
+ module Fog
4
+ class Time < ::Time
5
+
6
+ DAYS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
7
+ MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
8
+
9
+ def self.now
10
+ at((::Time.now - offset).to_i)
11
+ end
12
+
13
+ def self.now=(new_now)
14
+ old_now = ::Time.now
15
+ @offset = old_now - new_now
16
+ new_now
17
+ end
18
+
19
+ def self.offset
20
+ @offset ||= 0
21
+ end
22
+
23
+ def to_date_header
24
+ self.utc.strftime("#{DAYS[self.utc.wday]}, %d #{MONTHS[self.utc.month - 1]} %Y %H:%M:%S +0000")
25
+ end
26
+
27
+ def to_iso8601_basic
28
+ self.utc.strftime('%Y%m%dT%H%M%SZ')
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,23 @@
1
+ require 'securerandom'
2
+
3
+ module Fog
4
+ class UUID
5
+ class << self
6
+
7
+ def uuid
8
+ if supported?
9
+ SecureRandom.uuid
10
+ else
11
+ ary = SecureRandom.random_bytes(16).unpack("NnnnnN")
12
+ ary[2] = (ary[2] & 0x0fff) | 0x4000
13
+ ary[3] = (ary[3] & 0x3fff) | 0x8000
14
+ "%08x-%04x-%04x-%04x-%04x%08x" % ary
15
+ end
16
+ end
17
+
18
+ def supported?
19
+ SecureRandom.respond_to?(:uuid)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module Fog
2
+ def self.wait_for(timeout=Fog.timeout, interval=Fog.interval, &block)
3
+ duration = 0
4
+ start = Time.now
5
+ until yield || duration > timeout
6
+ sleep(interval.to_f)
7
+ duration = Time.now - start
8
+ end
9
+ if duration > timeout
10
+ raise Errors::TimeoutError.new("The specified wait_for timeout (#{timeout} seconds) was exceeded")
11
+ else
12
+ { :duration => duration }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ module Fog
2
+ @interval = 1
3
+ def self.interval
4
+ @interval
5
+ end
6
+
7
+ def self.interval=(interval)
8
+ raise ArgumentError, "interval must be non-negative" unless interval >= 0
9
+ @interval = interval
10
+ end
11
+
12
+ @timeout = 600
13
+ def self.timeout
14
+ @timeout
15
+ end
16
+
17
+ def self.timeout=(timeout)
18
+ raise ArgumentError, "timeout must be non-negative" unless timeout >= 0
19
+ @timeout = timeout
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ module Fog
2
+ module DNS
3
+
4
+ def self.[](provider)
5
+ self.new(:provider => provider)
6
+ end
7
+
8
+ def self.new(attributes)
9
+ attributes = attributes.dup # prevent delete from having side effects
10
+ case provider = attributes.delete(:provider).to_s.downcase.to_sym
11
+ when :stormondemand
12
+ require 'fog/storm_on_demand/dns'
13
+ Fog::DNS::StormOnDemand.new(attributes)
14
+ else
15
+ if self.providers.include?(provider)
16
+ require "fog/#{provider}/dns"
17
+ return Fog::DNS.const_get(Fog.providers[provider]).new(attributes)
18
+ end
19
+
20
+ raise ArgumentError.new("#{provider} is not a recognized dns provider")
21
+ end
22
+ end
23
+
24
+ def self.providers
25
+ Fog.services[:dns]
26
+ end
27
+
28
+ def self.zones
29
+ zones = []
30
+ for provider in self.providers
31
+ begin
32
+ zones.concat(self[provider].zones)
33
+ rescue # ignore any missing credentials/etc
34
+ end
35
+ end
36
+ zones
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,28 @@
1
+ module Fog
2
+ module Identity
3
+
4
+ def self.[](provider)
5
+ self.new(:provider => provider)
6
+ end
7
+
8
+ def self.new(attributes)
9
+ attributes = attributes.dup # Prevent delete from having side effects
10
+ case provider = attributes.delete(:provider).to_s.downcase.to_sym
11
+ when :rackspace
12
+ require 'fog/rackspace/identity'
13
+ Fog::Rackspace::Identity.new(attributes)
14
+ else
15
+ if self.providers.include?(provider)
16
+ require "fog/#{provider}/identity"
17
+ return Fog::Identity.const_get(Fog.providers[provider]).new(attributes)
18
+ end
19
+ raise ArgumentError.new("#{provider} has no identity service")
20
+ end
21
+ end
22
+
23
+ def self.providers
24
+ Fog.services[:identity]
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,23 @@
1
+ module Fog
2
+ module Image
3
+
4
+ def self.[](provider)
5
+ self.new(:provider => provider)
6
+ end
7
+
8
+ def self.new(attributes)
9
+ attributes = attributes.dup # Prevent delete from having side effects
10
+ provider = attributes.delete(:provider).to_s.downcase.to_sym
11
+ if self.providers.include?(provider)
12
+ require "fog/#{provider}/image"
13
+ return Fog::Image.const_get(Fog.providers[provider]).new(attributes)
14
+ end
15
+ raise ArgumentError.new("#{provider} has no identity service")
16
+ end
17
+
18
+ def self.providers
19
+ Fog.services[:image]
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ module Fog
2
+ module Metering
3
+
4
+ def self.[](provider)
5
+ self.new(:provider => provider)
6
+ end
7
+
8
+ def self.new(attributes)
9
+ attributes = attributes.dup # Prevent delete from having side effects
10
+ provider = attributes.delete(:provider).to_s.downcase.to_sym
11
+ if self.providers.include?(provider)
12
+ require "fog/#{provider}/metering"
13
+ return Fog::Metering.const_get(Fog.providers[provider]).new(attributes)
14
+ end
15
+
16
+ raise ArgumentError.new("#{provider} has no identity service")
17
+ end
18
+
19
+ def self.providers
20
+ Fog.services[:metering]
21
+ end
22
+
23
+ end
24
+ end
25
+
@@ -0,0 +1,24 @@
1
+ module Fog
2
+ module Monitoring
3
+
4
+ def self.[](provider)
5
+ self.new(:provider => provider)
6
+ end
7
+
8
+ def self.new(attributes)
9
+ attributes = attributes.dup
10
+ provider = attributes.delete(:provider).to_s.downcase.to_sym
11
+ if provider == :stormondemand
12
+ require 'fog/storm_on_demand/billing'
13
+ Fog::Monitoring::StormOnDemand.new(attributes)
14
+ else
15
+ raise ArgumentError.new("#{provider} has no monitoring service")
16
+ end
17
+ end
18
+
19
+ def self.providers
20
+ Fog.services[:monitoring]
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,28 @@
1
+ module Fog
2
+ module Network
3
+
4
+ def self.[](provider)
5
+ self.new(:provider => provider)
6
+ end
7
+
8
+ def self.new(attributes)
9
+ attributes = attributes.dup # Prevent delete from having side effects
10
+ provider = attributes.delete(:provider).to_s.downcase.to_sym
11
+
12
+ if provider == :stormondemand
13
+ require "fog/storm_on_demand/network"
14
+ return Fog::Network::StormOnDemand.new(attributes)
15
+ elsif self.providers.include?(provider)
16
+ require "fog/#{provider}/network"
17
+ return Fog::Network.const_get(Fog.providers[provider]).new(attributes)
18
+ end
19
+
20
+ raise ArgumentError.new("#{provider} has no network service")
21
+ end
22
+
23
+ def self.providers
24
+ Fog.services[:network]
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module Fog
2
+ module Orchestration
3
+
4
+ def self.[](provider)
5
+ self.new(:provider => provider)
6
+ end
7
+
8
+ def self.new(attributes)
9
+ attributes = attributes.dup # Prevent delete from having side effects
10
+ provider = attributes.delete(:provider).to_s.downcase.to_sym
11
+
12
+ if self.providers.include?(provider)
13
+ require "fog/#{provider}/network"
14
+ return Fog::Orchestration.const_get(Fog.providers[provider]).new(attributes)
15
+ end
16
+
17
+ raise ArgumentError.new("#{provider} has no orchestration service")
18
+ end
19
+
20
+ def self.providers
21
+ Fog.services[:orchestration]
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,154 @@
1
+ module Fog
2
+ module Schema
3
+ # This validates a data object against a Ruby based schema to see
4
+ # if they match.
5
+ #
6
+ # * An object matches the schema if +==+ or +===+ returns +true+
7
+ # * Hashes match if all the key's values match the classes given
8
+ # in the schema as well. This can be configured in the options
9
+ # * Arrays match when every element in the data matches the case
10
+ # given in the schema.
11
+ #
12
+ # The schema and validation are very simple and probably not
13
+ # suitable for some cases.
14
+ #
15
+ # The following classes can be used to check for special behaviour
16
+ #
17
+ # * Fog::Boolean - value may be +true+ or +false+
18
+ # * Fog::Nullable::Boolean - value may be +true+, +false+ or +nil+
19
+ # * Fog::Nullable::Integer - value may be an Integer or +nil+
20
+ # * Fog::Nullable::String
21
+ # * Fog::Nullable::Time
22
+ # * Fog::Nullable::Float
23
+ # * Fog::Nullable::Hash
24
+ # * Fog::Nullable::Array
25
+ #
26
+ # All the "nullable" objects will pass if the value is of the class
27
+ # or if it is +nil+. This allows you to match APIs that may include
28
+ # keys when the value is not available in some cases but will
29
+ # always be a String. Such as an password that is only displayed
30
+ # on the reset action.
31
+ #
32
+ # The keys for "nullable" resources should always be present but
33
+ # original matcher had a bug that allowed these to also appear to
34
+ # work as optional keys/values.
35
+ #
36
+ # If you need the original behaviour, data with a missing key is
37
+ # still valid, then you may pass the +:allow_optional_rules+
38
+ # option to the #validate method.
39
+ #
40
+ # That is not recommended because you are describing a schema
41
+ # with optional keys in a format that does not support it.
42
+ #
43
+ # Setting +:allow_extra_keys+ as +true+ allows the data to
44
+ # contain keys not declared by the schema and still pass. This
45
+ # is useful if new attributes appear in the API in a backwards
46
+ # compatible manner and can be ignored.
47
+ #
48
+ # This is the behaviour you would have seen with +strict+ being
49
+ # +false+ in the original test helper.
50
+ #
51
+ # @example Schema example
52
+ # {
53
+ # "id" => String,
54
+ # "ram" => Integer,
55
+ # "disks" => [
56
+ # "size" => Float
57
+ # ],
58
+ # "dns_name" => Fog::Nullable::String,
59
+ # "active" => Fog::Boolean,
60
+ # "created" => DateTime
61
+ # }
62
+ #
63
+ class DataValidator
64
+
65
+ def initialize
66
+ @message = nil
67
+ end
68
+
69
+ # Checks if the data structure matches the schema passed in and
70
+ # returns +true+ if it fits.
71
+ #
72
+ # @param [Object] data Hash or Array to check
73
+ # @param [Object] schema Schema pattern to check against
74
+ # @param [Boolean] options
75
+ # @option options [Boolean] :allow_extra_keys
76
+ # If +true+ does not fail if extra keys are in the data
77
+ # that are not in the schema.
78
+ # @option options [Boolean] :allow_optional_rules
79
+ # If +true+ does not fail if extra keys are in the schema
80
+ # that do not match the data. Not recommended!
81
+ #
82
+ # @return [Boolean] Did the data fit the schema?
83
+ def validate(data, schema, options = {})
84
+ valid = validate_value(schema, data, options)
85
+
86
+ unless valid
87
+ @message = "#{data.inspect} does not match #{schema.inspect}"
88
+ end
89
+ valid
90
+ end
91
+
92
+ # This returns the last message set by the validator
93
+ #
94
+ # @return [String]
95
+ def message
96
+ @message
97
+ end
98
+
99
+ private
100
+
101
+ # This contains a slightly modified version of the Hashidator gem
102
+ # but unfortunately the gem does not cope with Array schemas.
103
+ #
104
+ # @see https://github.com/vangberg/hashidator/blob/master/lib/hashidator.rb
105
+ #
106
+ def validate_value(validator, value, options)
107
+ Fog::Logger.write :debug, "[yellow][DEBUG] #{value.inspect} against #{validator.inspect}[/]\n"
108
+
109
+ case validator
110
+ when Array
111
+ return false if value.is_a?(Hash)
112
+ value.respond_to?(:all?) && value.all? {|x| validate_value(validator[0], x, options)}
113
+ when Symbol
114
+ value.respond_to? validator
115
+ when Hash
116
+ return false if value.is_a?(Array)
117
+
118
+ # When being strict values not specified in the schema are fails
119
+ unless options[:allow_extra_keys]
120
+ if value.respond_to?(:empty?)
121
+ # Validator is empty but values are not
122
+ return false if !value.empty? && validator.empty?
123
+ end
124
+ end
125
+
126
+ unless options[:allow_optional_rules]
127
+ if value.respond_to?(:empty?)
128
+ # Validator has rules left but no more values
129
+ return false if value.empty? && !validator.empty?
130
+ end
131
+ end
132
+
133
+ validator.all? do |key, sub_validator|
134
+ Fog::Logger.write :debug, "[blue][DEBUG] #{key.inspect} against #{sub_validator.inspect}[/]\n"
135
+ validate_value(sub_validator, value[key], options)
136
+ end
137
+ else
138
+ result = validator == value
139
+ result = validator === value unless result
140
+ # Repeat unless we have a Boolean already
141
+ unless (result.is_a?(TrueClass) || result.is_a?(FalseClass))
142
+ result = validate_value(result, value, options)
143
+ end
144
+ if result
145
+ Fog::Logger.write :debug, "[green][DEBUG] Validation passed: #{value.inspect} against #{validator.inspect}[/]\n"
146
+ else
147
+ Fog::Logger.write :debug, "[red][DEBUG] Validation failed: #{value.inspect} against #{validator.inspect}[/]\n"
148
+ end
149
+ result
150
+ end
151
+ end
152
+ end
153
+ end
154
+ end