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,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