mystro-common 0.1.11 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. data/.gitignore +3 -0
  2. data/.rspec +2 -0
  3. data/CHANGELOG.md +42 -4
  4. data/Gemfile +7 -1
  5. data/Rakefile +137 -1
  6. data/lib/{mystro/ext/fog → fog/ext}/balancer.rb +0 -0
  7. data/lib/fog/ext/dynect/dns.rb +140 -0
  8. data/lib/fog/ext/dynect/models/dns/record.rb +66 -0
  9. data/lib/fog/ext/dynect/models/dns/records.rb +87 -0
  10. data/lib/fog/ext/dynect/models/dns/zone.rb +60 -0
  11. data/lib/fog/ext/dynect/models/dns/zones.rb +29 -0
  12. data/lib/fog/ext/dynect/requests/dns/delete_record.rb +56 -0
  13. data/lib/fog/ext/dynect/requests/dns/delete_zone.rb +42 -0
  14. data/lib/fog/ext/dynect/requests/dns/get_all_records.rb +56 -0
  15. data/lib/fog/ext/dynect/requests/dns/get_node_list.rb +56 -0
  16. data/lib/fog/ext/dynect/requests/dns/get_record.rb +85 -0
  17. data/lib/fog/ext/dynect/requests/dns/get_zone.rb +58 -0
  18. data/lib/fog/ext/dynect/requests/dns/post_record.rb +72 -0
  19. data/lib/fog/ext/dynect/requests/dns/post_session.rb +44 -0
  20. data/lib/fog/ext/dynect/requests/dns/post_zone.rb +71 -0
  21. data/lib/fog/ext/dynect/requests/dns/put_zone.rb +76 -0
  22. data/lib/fog/ext/dynect.rb +26 -0
  23. data/lib/mystro/cloud/action.rb +22 -0
  24. data/lib/mystro/cloud/connect/aws/balancer.rb +55 -0
  25. data/lib/mystro/cloud/connect/aws/compute.rb +151 -0
  26. data/lib/mystro/cloud/connect/aws/listener.rb +36 -0
  27. data/lib/mystro/cloud/connect/aws/record.rb +58 -0
  28. data/lib/mystro/cloud/connect/aws/zone.rb +35 -0
  29. data/lib/mystro/cloud/connect/aws.rb +14 -0
  30. data/lib/mystro/cloud/connect/dynect/record.rb +72 -0
  31. data/lib/mystro/cloud/connect/dynect/zone.rb +35 -0
  32. data/lib/mystro/cloud/connect/dynect.rb +17 -0
  33. data/lib/mystro/cloud/connect/fog.rb +66 -0
  34. data/lib/mystro/cloud/connect.rb +64 -0
  35. data/lib/mystro/cloud/model/balancer.rb +15 -0
  36. data/lib/mystro/cloud/model/compute.rb +27 -0
  37. data/lib/mystro/cloud/model/listener.rb +30 -0
  38. data/lib/mystro/cloud/model/record.rb +20 -0
  39. data/lib/mystro/cloud/model/volume.rb +12 -0
  40. data/lib/mystro/cloud/model/zone.rb +9 -0
  41. data/lib/mystro/cloud/model.rb +183 -0
  42. data/lib/mystro/cloud.rb +32 -0
  43. data/lib/mystro/common/version.rb +4 -3
  44. data/lib/mystro/dsl/balancer.rb +18 -0
  45. data/lib/mystro/dsl/compute.rb +57 -0
  46. data/lib/mystro/dsl/health.rb +7 -0
  47. data/lib/mystro/dsl/listener.rb +5 -0
  48. data/lib/mystro/dsl/oldtemplate.rb +281 -0
  49. data/lib/mystro/dsl/template.rb +12 -278
  50. data/lib/mystro/dsl/template_file.rb +18 -0
  51. data/lib/mystro/dsl/volume.rb +8 -0
  52. data/lib/mystro/dsl.rb +40 -0
  53. data/lib/mystro/organization.rb +83 -0
  54. data/lib/mystro/plugin.rb +4 -3
  55. data/lib/mystro/provider.rb +40 -0
  56. data/lib/mystro/userdata.rb +1 -1
  57. data/lib/mystro-common.rb +32 -31
  58. data/mystro-common.gemspec +2 -1
  59. data/spec/cloud/aws/balancer_spec.rb +10 -0
  60. data/spec/cloud/aws/compute_spec.rb +10 -0
  61. data/spec/cloud/aws/record_spec.rb +10 -0
  62. data/spec/cloud/dynect/record_spec.rb +10 -0
  63. data/spec/model/compute_spec.rb +36 -0
  64. data/spec/model/model_spec.rb +89 -0
  65. data/spec/model/record_spec.rb +27 -0
  66. data/spec/spec_helper.rb +36 -0
  67. data/spec/support/balancer.rb +49 -0
  68. data/spec/support/compute.rb +65 -0
  69. data/spec/support/record.rb +45 -0
  70. data/test/config.yml +71 -0
  71. metadata +99 -14
  72. data/lib/mystro/account.rb +0 -105
  73. data/lib/mystro/connect/balancer.rb +0 -91
  74. data/lib/mystro/connect/compute.rb +0 -100
  75. data/lib/mystro/connect/dns.rb +0 -51
  76. data/lib/mystro/connect/environment.rb +0 -31
  77. data/lib/mystro/connect.rb +0 -124
  78. data/lib/mystro/job.rb +0 -0
  79. data/lib/mystro/model.rb +0 -71
@@ -0,0 +1,183 @@
1
+ require 'mystro/log'
2
+
3
+ module Mystro
4
+ module Cloud
5
+ class Model
6
+ attr_reader :data
7
+
8
+ def initialize(hash={})
9
+ @data = {}
10
+ load(hash)
11
+ end
12
+
13
+ def load(hash)
14
+ #puts "LOAD: #{hash.inspect}"
15
+ if hash.is_a?(Hash)
16
+ hash.each do |k, v|
17
+ k = normal_key(k)
18
+ k = alias_for(k) || k
19
+ attr = attribute_for(k)
20
+ #puts "attr: #{k}: #{attr.inspect}"
21
+ raise "#{self.class.name}: attr not found for #{k.inspect}" unless attr
22
+ if attr[:child]
23
+ if attr[:type] == Array
24
+ next unless v# && v.count
25
+ v = [v] unless v.is_a?(Array)
26
+ @data[k] ||= []
27
+ v.each do |e|
28
+ if e.is_a?(Mystro::Cloud::Model)
29
+ @data[k] << e
30
+ else
31
+ c = class_for(attr[:of])
32
+ @data[k] << c.new(e)
33
+ end
34
+ end
35
+ else
36
+ c = class_for(attr[:type])
37
+ if v.class == c
38
+ @data[k] = v
39
+ else
40
+ @data[k] = c.new(v)
41
+ end
42
+ end
43
+ elsif attr[:type] == :boolean
44
+ @data[k] = v && (v == true || v == "true")
45
+ else
46
+ @data[k] = v
47
+ end
48
+ end
49
+ else
50
+ hash
51
+ end
52
+ end
53
+
54
+ def validate!
55
+ self.class.validate!(@data)
56
+ end
57
+
58
+ def attribute_for(name)
59
+ self.class.attribute_for(name)
60
+ end
61
+
62
+ def alias_for(name)
63
+ self.class.alias_for(name)
64
+ end
65
+
66
+ def normal_key(k)
67
+ self.class.normal_key(k)
68
+ end
69
+
70
+ def class_for(name)
71
+ self.class.class_for(name)
72
+ end
73
+
74
+ def [](key)
75
+ send(key.to_sym)
76
+ end
77
+ def []=(key, value)
78
+ send("#{key}=", value)
79
+ end
80
+
81
+ def to_hash
82
+ out = {}
83
+ #puts "#{self.class.name}: to_hash:"
84
+ @data.each do |k, v|
85
+ #puts " #{k} => #{v}"
86
+ if v.respond_to?(:to_hash)
87
+ out[k] = v.to_hash
88
+ elsif v.is_a?(Array)
89
+ out[k] = v.map {|e| e.respond_to?(:to_hash) ? e.to_hash : e}
90
+ else
91
+ out[k] = v
92
+ end
93
+ end
94
+ out
95
+ end
96
+
97
+ class << self
98
+
99
+ def validate!(data)
100
+ @attributes.each do |k, v|
101
+ type = v[:type]
102
+ type = type.is_a?(String) ? class_for(type) : type
103
+ value = data[k]
104
+ value = value.to_s if value.is_a?(Symbol)
105
+ #puts "checking: #{k}#{'*' if v[:required]} (#{type})"
106
+ raise "#{k} required but is nil or false" if v[:required] && !value
107
+ raise "#{k} required but empty" if v[:required] && type == Array && value.empty?
108
+ raise "incorrect type: #{k}: '#{value.inspect}' is not a '#{type}'" if value && !value.is_a?(type)
109
+ end
110
+ rescue => e
111
+ raise "#{e.message}: #{data.inspect}"
112
+ end
113
+
114
+ def attribute_for(name)
115
+ @attributes[name] || @attributes[name] || @aliases[name] && @attributes[@aliases[name]]
116
+ end
117
+
118
+ def alias_for(name)
119
+ @aliases[name]
120
+ end
121
+
122
+ def class_for(name)
123
+ n = name.to_s.capitalize
124
+ begin
125
+ return "Mystro::Cloud::#{n}".constantize
126
+ rescue => e
127
+ begin
128
+ return n.constantize
129
+ rescue => e
130
+ raise "couldn't find class: #{n}: #{e.message}"
131
+ end
132
+ end
133
+ end
134
+
135
+ def normal_key(k)
136
+ k.to_s.downcase.to_sym
137
+ end
138
+
139
+ protected
140
+
141
+ def identity(name, options={})
142
+ attribute(name, options.merge(identity: true))
143
+ end
144
+
145
+ def attribute(name, options={})
146
+ @attributes ||= {}
147
+ @aliases ||= {}
148
+ name = normal_key(name)
149
+ o = {name: name, type: String, required: true, aliases: []}.merge(options)
150
+ @attributes[name.to_sym] = o
151
+ list = [name] + o[:aliases]
152
+ list += [:identity] if o[:identity]
153
+ list.each do |m|
154
+ define_method(m) do
155
+ @data[name.to_sym]
156
+ end
157
+ define_method("#{m}=") do |value|
158
+ h = {}
159
+ h[name.to_sym] = value
160
+ load(h)
161
+ end
162
+ end
163
+ o[:aliases].each do |a|
164
+ @aliases[normal_key(a)] = name
165
+ end
166
+ end
167
+
168
+ def has_one(name, options={})
169
+ attribute(name, {type: options.delete(:type), child: true}.merge(options))
170
+ end
171
+
172
+ def has_many(name, options={})
173
+ attribute(name, {type: Array, of: options.delete(:type), child: true}.merge(options))
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+
180
+ Dir["#{File.dirname(__FILE__)}/model/*.rb"].each do |file|
181
+ #puts "require: #{file}"
182
+ require "#{file.gsub(/\.rb/, '')}"
183
+ end
@@ -0,0 +1,32 @@
1
+ module Mystro
2
+ module Cloud
3
+ class << self
4
+ def new(provider, type, options={})
5
+ Mystro::Log.debug "Mystro::Cloud.new #{provider.inspect} #{type.inspect} #{options.inspect}"
6
+ d = {
7
+ options: {},
8
+ config: {},
9
+ }.merge(options)
10
+ type = type.to_sym
11
+ d[:options] ||= {}
12
+ d[:config] ||= {}
13
+ o = d[:options].merge(Mystro::Provider.get(provider).to_hash)
14
+ c = d[:config]
15
+ klass = class_for(provider, type)
16
+ klass.new(o, c)
17
+ end
18
+
19
+ def class_for(provider, type)
20
+ n = provider.to_s.capitalize
21
+ t = type.to_s.capitalize
22
+ c = "Mystro::Cloud::#{n}::#{t}"
23
+ c.constantize
24
+ end
25
+ end
26
+ class NotFound < StandardError; end
27
+ end
28
+ end
29
+
30
+ require 'mystro/cloud/model'
31
+ require 'mystro/cloud/connect'
32
+ require 'mystro/cloud/action'
@@ -2,10 +2,11 @@ module Mystro
2
2
  module Common
3
3
  module Version
4
4
  MAJOR = 0
5
- MINOR = 1
6
- TINY = 11
5
+ MINOR = 2
6
+ TINY = 0
7
7
  TAG = nil
8
- STRING = [MAJOR, MINOR, TINY, TAG].compact.join(".")
8
+ LIST = [MAJOR, MINOR, TINY, TAG]
9
+ STRING = LIST.compact.join(".")
9
10
  end
10
11
  end
11
12
  end
@@ -0,0 +1,18 @@
1
+ class Mystro::Dsl::Balancer < Mystro::Dsl::Base
2
+ attribute :name
3
+ attribute :primary, type: :boolean, value: false
4
+ has_one :health
5
+ has_many :listeners
6
+
7
+ def actions
8
+ hash = to_hash
9
+ action = Mystro::Cloud::Action.new('Mystro::Cloud::Balancer', :create)
10
+ action.data = {
11
+ name: hash[:name],
12
+ primary: hash[:primary],
13
+ health: hash[:health],
14
+ listeners: hash[:listener],
15
+ }
16
+ [action]
17
+ end
18
+ end
@@ -0,0 +1,57 @@
1
+ class Mystro::Dsl::Compute < Mystro::Dsl::Base
2
+ attribute :num, value: 0 do |value|
3
+ value == value.to_i
4
+ end
5
+ attribute :name
6
+ attribute :image
7
+ attribute :flavor
8
+ attribute :keypair
9
+ attribute :userdata
10
+ attribute :group, type: Array
11
+ attribute :role, type: Array
12
+ has_many :volumes
13
+ has_many :records
14
+ references :balancer
15
+
16
+ def actions
17
+ c = to_hash
18
+ n = c[:num].to_i
19
+ out = []
20
+ if n > 0
21
+ 1.upto(n) do |i|
22
+ out << create_action(i, c)
23
+ end
24
+ else
25
+ out << create_action(nil, c)
26
+ end
27
+ out
28
+ end
29
+
30
+ private
31
+
32
+ def create_action(i, c)
33
+ num = i ? "%02d" % i : ''
34
+ name = "#{c[:name]}#{num}"
35
+ roles = (c[:role]||[]).join(',')
36
+ action = Mystro::Cloud::Action.new('Mystro::Cloud::Compute', :create)
37
+ action.options = {
38
+ balancer: c[:balancer],
39
+ records: c[:record],
40
+ }
41
+ data = {
42
+ image: c[:image],
43
+ flavor: c[:flavor],
44
+ keypair: c[:keypair],
45
+ userdata: c[:userdata],
46
+ groups: c[:group],
47
+ tags: {'Roles' => roles, 'Name' => name},
48
+ }.delete_if {|k, v| v.nil?}
49
+ if c[:volume]
50
+ data[:volumes] = c[:volume].map do |vol|
51
+ Mystro::Cloud::Volume.new(vol)
52
+ end
53
+ end
54
+ action.data = data
55
+ action
56
+ end
57
+ end
@@ -0,0 +1,7 @@
1
+ class Mystro::Dsl::Health < Mystro::Dsl::Base
2
+ attribute :healthy, value: 10
3
+ attribute :unhealthy, value: 2
4
+ attribute :interval, value: 5
5
+ attribute :target, value: 'HTTP:80/'
6
+ attribute :time, value: 30 #TODO: timeout doesn't work, doesn't override Timeout#timeout
7
+ end
@@ -0,0 +1,5 @@
1
+ class Mystro::Dsl::Listener < Mystro::Dsl::Base
2
+ attribute :from, value: 'HTTP:80'
3
+ attribute :to, value: 'HTTP:80'
4
+ attribute :cert
5
+ end
@@ -0,0 +1,281 @@
1
+ #module Mystro
2
+ # module DSL
3
+ # module Template
4
+ # class << self
5
+ # def load(name_or_file)
6
+ # @templates ||= {}
7
+ # template_name = nil
8
+ # template_file = nil
9
+ # if File.exists?(name_or_file)
10
+ # template_name = File.basename(name_or_file).gsub(/\.rb$/, "").to_sym
11
+ # template_file = name_or_file
12
+ # elsif File.exists?("#{dir}/#{name_or_file}.rb")
13
+ # template_name = name.to_sym
14
+ # template_file = "#{dir}/#{name}.rb"
15
+ # end
16
+ # raise "could not load template #{template_name} (#{template_file})" unless template_file && File.file?(template_file)
17
+ # #raise "template already loaded #{template_name}" if @templates[template_name]
18
+ # @templates[template_name] ||= begin
19
+ # t = Mystro::DSL::Template::DSL.new(template_name)
20
+ # t.instance_eval(File.read(template_file), "Template(#{template_file})")
21
+ # @templates[template_name] = t
22
+ # end
23
+ # end
24
+ #
25
+ # def load_yaml_file(path)
26
+ # file = File.expand_path(path)
27
+ # raise "Configuration not found: #{path} (#{file})" unless File.exists?(file)
28
+ # yaml = YAML.load_file(file)
29
+ # yaml = yaml[yaml.keys.first] if yaml.keys.count == 1
30
+ #
31
+ # yaml
32
+ # end
33
+ #
34
+ # def list
35
+ # Dir["#{dir}/*"].inject({}) do |h, e|
36
+ # f = e.gsub("#{dir}/", "")
37
+ # f = File.basename(f, ".yml")
38
+ # h[f.to_sym] = e
39
+ # h
40
+ # end
41
+ # end
42
+ #
43
+ # private
44
+ # def dir
45
+ # "#{Mystro.directory}/templates"
46
+ # end
47
+ # end
48
+ #
49
+ # class DSL
50
+ # attr_reader :balancers, :servers
51
+ #
52
+ # def initialize(name)
53
+ # @name = name.to_sym
54
+ # @balancers = []
55
+ # @servers = []
56
+ # end
57
+ #
58
+ # def template(&block)
59
+ # instance_eval &block
60
+ # end
61
+ #
62
+ # def balancer(name, &block)
63
+ # balancer = Balancer.new(name)
64
+ # balancer.instance_eval &block
65
+ # @balancers << balancer
66
+ # end
67
+ #
68
+ # def server(name, &block)
69
+ # server = Server.new(name)
70
+ # server.instance_eval &block
71
+ # @servers << server
72
+ # end
73
+ # end
74
+ #
75
+ # class Base
76
+ # def attr(name, value=nil)
77
+ # @attrs[name] = value unless value.nil?
78
+ # @attrs[name]
79
+ # end
80
+ #
81
+ # def list_attr(name, value=nil)
82
+ # @attrs[name] ||= []
83
+ # unless value.nil?
84
+ # if value.kind_of?(Array)
85
+ # @attrs[name] += value
86
+ # else
87
+ # @attrs[name] << value
88
+ # end
89
+ # end
90
+ # @attrs[name]
91
+ # end
92
+ # end
93
+ #
94
+ # class Server < Base
95
+ # def initialize(name)
96
+ # @attrs = {
97
+ # :name => name.to_sym,
98
+ # :roles => [],
99
+ # :groups => [],
100
+ # :count => 1,
101
+ # :image => nil,
102
+ # :flavor => nil,
103
+ # :keypair => nil,
104
+ # :userdata => "default",
105
+ # :dnsnames => [],
106
+ # }
107
+ # end
108
+ #
109
+ # def name
110
+ # @attrs[:name]
111
+ # end
112
+ #
113
+ # def roles
114
+ # @attrs[:roles]
115
+ # end
116
+ #
117
+ # def groups
118
+ # @attrs[:groups]
119
+ # end
120
+ #
121
+ # def dnsnames
122
+ # @attrs[:dnsnames]
123
+ # end
124
+ #
125
+ # def role(r)
126
+ # list_attr(:roles, r)
127
+ # end
128
+ #
129
+ # def count(c=nil)
130
+ # attr(:count, c)
131
+ # end
132
+ #
133
+ # def image(i=nil)
134
+ # attr(:image, i)
135
+ # end
136
+ #
137
+ # def flavor(f=nil)
138
+ # attr(:flavor, f)
139
+ # end
140
+ #
141
+ # def group(g)
142
+ # list_attr(:groups, g)
143
+ # end
144
+ #
145
+ # def keypair(k=nil)
146
+ # attr(:keypair, k)
147
+ # end
148
+ #
149
+ # def userdata(u=nil)
150
+ # attr(:userdata, u)
151
+ # end
152
+ #
153
+ # def balancer(b=nil, &block)
154
+ # if block_given?
155
+ # raise "balancer block must specify name" unless b
156
+ # Mystro::DSL::Template::DSL.balancer(b, &block)
157
+ # end
158
+ # attr(:balancer, b)
159
+ # end
160
+ #
161
+ # def dns(name)
162
+ # n = name.gsub(Mystro.get_config(:dns_zone), "")
163
+ # list_attr(:dnsnames, n)
164
+ # end
165
+ # end
166
+ #
167
+ # class Balancer
168
+ # attr_reader :name, :sticky, :primary, :sticky_type, :sticky_arg
169
+ #
170
+ # def initialize(name)
171
+ # @listeners = []
172
+ # @name = name.to_sym
173
+ # @primary = false
174
+ # @sticky = false
175
+ # end
176
+ #
177
+ # def primary(enable = nil)
178
+ # enable.nil? ? @primary : @primary = enable
179
+ # end
180
+ #
181
+ # def listener(&block)
182
+ # listener = Listener.new
183
+ # listener.instance_eval &block
184
+ # @listeners << listener
185
+ # end
186
+ #
187
+ # def health(&block)
188
+ # healthcheck = HealthCheck.new
189
+ # healthcheck.instance_eval &block
190
+ # @healthcheck = healthcheck
191
+ # end
192
+ #
193
+ # def listeners
194
+ # @listeners.map { |e| e.spec }
195
+ # end
196
+ #
197
+ # def sticky(type=nil, expires_or_cookie=nil)
198
+ # if type && expires_or_cookie
199
+ # @sticky = true
200
+ # @sticky_type = type
201
+ # @sticky_arg = expires_or_cookie
202
+ # end
203
+ # @sticky
204
+ # end
205
+ # end
206
+ #
207
+ # class Listener
208
+ # def initialize
209
+ # @from_proto = nil
210
+ # @from_port = nil
211
+ # @to_proto = nil
212
+ # @to_port = nil
213
+ # @cert = nil
214
+ # end
215
+ #
216
+ # def from(proto, port)
217
+ # @from_proto = proto
218
+ # @from_port = port
219
+ # end
220
+ #
221
+ # def to(proto, port)
222
+ # @to_proto = proto
223
+ # @to_port = port
224
+ # end
225
+ #
226
+ # def cert(cert)
227
+ # @cert = cert
228
+ # end
229
+ #
230
+ # def spec
231
+ # {
232
+ # :from => "#@from_proto:#@from_port",
233
+ # :to => "#@to_proto:#@to_port",
234
+ # :cert => @cert,
235
+ # }
236
+ # end
237
+ # end
238
+ #
239
+ # class HealthCheck
240
+ # def initialize
241
+ # @healthy = 10
242
+ # @unhealthy = 2
243
+ # @interval = 30
244
+ # @target = nil
245
+ # @timeout = 5
246
+ # end
247
+ #
248
+ # def healthy(v)
249
+ # @healthy = v
250
+ # end
251
+ #
252
+ # def unhealthy(v)
253
+ # @unhealthy = v
254
+ # end
255
+ #
256
+ # def interval(v)
257
+ # @interval = v
258
+ # end
259
+ #
260
+ # def target(v)
261
+ # @target = v
262
+ # end
263
+ #
264
+ # def timeout(v)
265
+ # @timeout = v
266
+ # end
267
+ #
268
+ # def spec
269
+ # raise "target not specified for health check" unless @target
270
+ # {
271
+ # healthy: @healthy,
272
+ # unhealthy: @unhealthy,
273
+ # interval: @interval,
274
+ # target: @target,
275
+ # timeout: @timeout,
276
+ # }
277
+ # end
278
+ # end
279
+ # end
280
+ # end
281
+ #end