mystro-common 0.1.11 → 0.2.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 (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