mystro-common 0.1.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +51 -0
- data/lib/mystro/account.rb +97 -0
- data/lib/mystro/capistrano.rb +50 -0
- data/lib/mystro/common/version.rb +11 -0
- data/lib/mystro/config.rb +29 -0
- data/lib/mystro/connect/balancer.rb +91 -0
- data/lib/mystro/connect/compute.rb +100 -0
- data/lib/mystro/connect/dns.rb +38 -0
- data/lib/mystro/connect/environment.rb +31 -0
- data/lib/mystro/connect.rb +123 -0
- data/lib/mystro/dsl/template.rb +281 -0
- data/lib/mystro/ext/fog/balancer.rb +15 -0
- data/lib/mystro/job.rb +0 -0
- data/lib/mystro/log.rb +58 -0
- data/lib/mystro/model.rb +71 -0
- data/lib/mystro/plugin.rb +73 -0
- data/lib/mystro/userdata.rb +42 -0
- data/lib/mystro-common.rb +66 -0
- data/mystro-common.gemspec +26 -0
- metadata +164 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
module Mystro
|
2
|
+
module Connect
|
3
|
+
class Base
|
4
|
+
class << self
|
5
|
+
attr_accessor :model
|
6
|
+
attr_accessor :collection
|
7
|
+
|
8
|
+
def cname
|
9
|
+
self.name.split("::").last.downcase
|
10
|
+
end
|
11
|
+
|
12
|
+
def fog
|
13
|
+
Mystro.send(cname).fog || nil rescue nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def after(event, &block)
|
17
|
+
@hooks ||= {}
|
18
|
+
@hooks[event] ||= []
|
19
|
+
@hooks[event] << block
|
20
|
+
end
|
21
|
+
|
22
|
+
def hooks(event, *args)
|
23
|
+
Mystro::Log.debug "#{cname}:hooks:#{event} #{@hooks[event].count}"
|
24
|
+
@hooks[event].each do |e|
|
25
|
+
Mystro::Log.debug "#{cname}:hooks:#{event} #{e}"
|
26
|
+
e.call(*args) if e
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :cfg
|
32
|
+
attr_reader :opt
|
33
|
+
attr_reader :fog
|
34
|
+
|
35
|
+
def initialize(account)
|
36
|
+
a = account.data
|
37
|
+
c = cname
|
38
|
+
|
39
|
+
# opt is used to initialize fog in connect classes
|
40
|
+
defaults = a.connect!.fog? ? a.connect.fog : {}
|
41
|
+
overrides = a[c] && a[c].fog? ? a[c].fog : {}
|
42
|
+
raw = defaults.deep_merge(overrides)
|
43
|
+
@opt = Hashie::Mash.new(raw)
|
44
|
+
|
45
|
+
# cfg is the additional configuration parms (aside from the fog block)
|
46
|
+
raw = {}
|
47
|
+
if a[c]
|
48
|
+
raw = a[c].to_hash
|
49
|
+
raw.delete(:fog) if raw[:fog]
|
50
|
+
end
|
51
|
+
@cfg = Hashie::Mash.new(raw)
|
52
|
+
|
53
|
+
self.class.after :create do |e, model|
|
54
|
+
Mystro::Plugin.run "#{cname}:create", e, model
|
55
|
+
end
|
56
|
+
|
57
|
+
self.class.after :destroy do |e, tags|
|
58
|
+
Mystro::Plugin.run "#{cname}:destroy", e, tags
|
59
|
+
end
|
60
|
+
|
61
|
+
connect
|
62
|
+
end
|
63
|
+
|
64
|
+
def connect
|
65
|
+
@fog ||= model.new(opt) if opt
|
66
|
+
rescue => e
|
67
|
+
Mystro::Log.error "#{cname} connect failed: #{e.message} at #{e.backtrace.first}"
|
68
|
+
end
|
69
|
+
|
70
|
+
def connected?
|
71
|
+
fog.nil? ? false : true
|
72
|
+
end
|
73
|
+
|
74
|
+
def find(id)
|
75
|
+
fog.send(collection).get(id)
|
76
|
+
end
|
77
|
+
|
78
|
+
def all
|
79
|
+
fog.send(collection).all
|
80
|
+
end
|
81
|
+
|
82
|
+
def create(model)
|
83
|
+
Mystro::Log.debug "#{cname}#create #{model.inspect}"
|
84
|
+
Mystro::Log.debug "#{cname}#create #{fog.inspect}"
|
85
|
+
e = fog.send(collection).create(model.fog_options)
|
86
|
+
e
|
87
|
+
end
|
88
|
+
|
89
|
+
def destroy(models)
|
90
|
+
list = [*models].flatten
|
91
|
+
list.each do |m|
|
92
|
+
Mystro::Log.debug "#{cname}#destroy #{m.rid}"
|
93
|
+
e = find(m.rid)
|
94
|
+
e.destroy if e
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def model
|
99
|
+
raise "model not set for '#{cname}'" unless self.class.model
|
100
|
+
@model ||= self.class.model.constantize
|
101
|
+
end
|
102
|
+
|
103
|
+
def collection
|
104
|
+
raise "collection not set for '#{cname}'" unless self.class.collection
|
105
|
+
@collection ||= self.class.collection
|
106
|
+
end
|
107
|
+
|
108
|
+
def cname
|
109
|
+
self.class.cname
|
110
|
+
end
|
111
|
+
|
112
|
+
def after(*args)
|
113
|
+
self.class.after(*args)
|
114
|
+
end
|
115
|
+
|
116
|
+
def hooks(*args)
|
117
|
+
self.class.hooks(*args)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
Dir["#{File.dirname(__FILE__)}/connect/*.rb"].each {|file| require "#{file.gsub(/\.rb/,'')}" }
|
@@ -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
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# make load balancers act more like other models in Fog
|
2
|
+
# ultimately a hack, but makes things work for now.
|
3
|
+
module Fog
|
4
|
+
class Balancer
|
5
|
+
def self.new(attributes)
|
6
|
+
attributes = attributes.dup
|
7
|
+
case provider = attributes.delete(:provider).to_s.downcase.to_sym
|
8
|
+
when :aws
|
9
|
+
Fog::AWS::ELB.new(attributes)
|
10
|
+
else
|
11
|
+
raise ArgumentError.new("#{provider} is not a recognized balancer provider")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/mystro/job.rb
ADDED
File without changes
|
data/lib/mystro/log.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "yell"
|
2
|
+
|
3
|
+
module Mystro
|
4
|
+
class Log
|
5
|
+
class << self
|
6
|
+
attr_reader :loggers
|
7
|
+
|
8
|
+
def init
|
9
|
+
@loggers = { }
|
10
|
+
@loggers["STDOUT"] = Yell.new(STDOUT, :level => [:info, :warn], :format => Yell::NoFormat)
|
11
|
+
@loggers["STDERR"] = Yell.new(STDERR, :level => [:error, :fatal], :format => Yell::NoFormat)
|
12
|
+
#@loggers["/tmp/mystro.log"] = Yell.new(:datefile, "/tmp/mystro.log", :level => :debug, :format => Yell::DefaultFormat, :keep => 7, :symlink => true)
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(level, dest, format=Yell::DefaultFormat)
|
16
|
+
if [STDOUT, STDERR].include?(dest)
|
17
|
+
console_disable
|
18
|
+
@loggers["STDOUT"] = Yell.new(dest, :level => level, :format => format)
|
19
|
+
else
|
20
|
+
@loggers.delete(dest) if @loggers[dest]
|
21
|
+
FileUtils.mkdir_p(File.dirname(dest))
|
22
|
+
@loggers[dest] = Yell.new(:datefile, dest,
|
23
|
+
:level => level, :format => format,
|
24
|
+
:keep => 7, :symlink => true)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def console_disable
|
29
|
+
%w{STDOUT STDERR}.each { |s| @loggers.delete(s) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def console_debug
|
33
|
+
console_disable
|
34
|
+
@loggers["STDOUT"] = Yell.new(STDOUT, :level => [:debug, :info, :warn], :format => Yell::NoFormat)
|
35
|
+
@loggers["STDERR"] = Yell.new(STDERR, :level => [:error, :fatal], :format => Yell::NoFormat)
|
36
|
+
end
|
37
|
+
|
38
|
+
def console_quiet
|
39
|
+
console_disable
|
40
|
+
@loggers["STDOUT"] = Yell.new(STDOUT, :level => [:warn], :format => Yell::NoFormat)
|
41
|
+
@loggers["STDERR"] = Yell.new(STDERR, :level => [:error, :fatal], :format => Yell::NoFormat)
|
42
|
+
end
|
43
|
+
|
44
|
+
%w{debug info warn error fatal}.each do |method_name|
|
45
|
+
class_eval(<<-METHOD_DEFN, __FILE__, __LINE__)
|
46
|
+
def #{method_name}(msg=nil, &block)
|
47
|
+
@loggers.each {|k, l| l.#{method_name}(msg, &block) }
|
48
|
+
end
|
49
|
+
METHOD_DEFN
|
50
|
+
end
|
51
|
+
|
52
|
+
def reset
|
53
|
+
@loggers = {}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
Mystro::Log.init
|
data/lib/mystro/model.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'mystro-common'
|
2
|
+
|
3
|
+
module Mystro
|
4
|
+
module Model
|
5
|
+
class Base
|
6
|
+
attr_reader :attributes
|
7
|
+
|
8
|
+
def initialize(attributes={ })
|
9
|
+
# all the stringify keys calls are to make sure that we normalize EVERYTHING before merges
|
10
|
+
d = defaults.stringify_keys!
|
11
|
+
c = load_from_config.stringify_keys!
|
12
|
+
a = attributes.stringify_keys!
|
13
|
+
# attributes should ALWAYS be stringified keys
|
14
|
+
@attributes = d.deep_merge(c).deep_merge(a).stringify_keys!
|
15
|
+
end
|
16
|
+
|
17
|
+
def defaults
|
18
|
+
self.class.defaults || {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def fog_tags(hash=self.class.tagnames.each {|t| hash[t] = send(t) })
|
22
|
+
hash.inject({ }) do |h, e|
|
23
|
+
(k, v) = e
|
24
|
+
h["#{k.to_s.capitalize}"] = v
|
25
|
+
h
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def load_from_config
|
32
|
+
cname = self.class.name.split("::").last.downcase
|
33
|
+
config = { }
|
34
|
+
if Mystro.account && Mystro.account[cname]
|
35
|
+
config = Mystro.account[cname].to_hash
|
36
|
+
end
|
37
|
+
config["account"] = Mystro.selected
|
38
|
+
config
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
attr_reader :tagnames
|
43
|
+
attr_reader :attrnames
|
44
|
+
attr_reader :defaults
|
45
|
+
|
46
|
+
def attr(*list)
|
47
|
+
@attrnames = list
|
48
|
+
list.each do |a|
|
49
|
+
define_method(a) do
|
50
|
+
@attributes[a.to_s]
|
51
|
+
end
|
52
|
+
define_method("#{a}=") do |val|
|
53
|
+
@attributes[a.to_s] = val
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def tag(*list)
|
59
|
+
@tagnames = list
|
60
|
+
attr(*list)
|
61
|
+
end
|
62
|
+
|
63
|
+
def default(hash)
|
64
|
+
@defaults = hash
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
Dir["#{File.dirname(__FILE__)}/model/*.rb"].each { |file| require file.gsub(/\.rb/, '') }
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Mystro
|
2
|
+
module Plugin
|
3
|
+
class << self
|
4
|
+
def run(event, *args)
|
5
|
+
return if Mystro.config.mock
|
6
|
+
|
7
|
+
@hooks ||= []
|
8
|
+
@hooks.select { |e| e[:event] == event }.each do |plugin|
|
9
|
+
klass = plugin[:class]
|
10
|
+
block = plugin[:block]
|
11
|
+
begin
|
12
|
+
Mystro::Log.debug "calling #{klass} :: #{event}"
|
13
|
+
block.call(args.dup)
|
14
|
+
rescue => e
|
15
|
+
Mystro::Log.error "failed to run event #{event} for #{klass}: #{e.message}"
|
16
|
+
Mystro::Log.debug e
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def on(klass, event, &block)
|
22
|
+
@hooks ||= []
|
23
|
+
@hooks << { :event => event, :class => klass, :block => block }
|
24
|
+
end
|
25
|
+
|
26
|
+
def load(plugins={ })
|
27
|
+
plugins.each do |plugin, data|
|
28
|
+
begin
|
29
|
+
f = "#{Mystro.directory}/plugins/#{plugin}"
|
30
|
+
Mystro::Log.debug "loading plugin: #{plugin} #{f}"
|
31
|
+
require f
|
32
|
+
rescue LoadError, StandardError => e
|
33
|
+
Mystro::Log.error "error while loading plugin: #{plugin}: #{e.message} at #{e.backtrace.first}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def register(plugin, type, klass)
|
39
|
+
@plugins ||= {}
|
40
|
+
@plugins[type] ||= {}
|
41
|
+
@plugins[type][plugin] = klass
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
module Base
|
46
|
+
def self.included(base)
|
47
|
+
base.extend self
|
48
|
+
end
|
49
|
+
|
50
|
+
def config_for(klass)
|
51
|
+
name = klass.name.split('::').last.downcase.to_sym
|
52
|
+
return Mystro.account.plugins[name] if Mystro.account.plugins && Mystro.account.plugins[name]
|
53
|
+
{ }
|
54
|
+
end
|
55
|
+
|
56
|
+
def on(event, &block)
|
57
|
+
Mystro::Plugin.on(self, event, &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def command(name, desc, klass=nil, &block)
|
61
|
+
on "commands:loaded" do |args|
|
62
|
+
Mystro::Log.debug "loading commands for #{name}"
|
63
|
+
command = args.shift
|
64
|
+
if klass
|
65
|
+
command.subcommand name, "#{desc} (#{self})", klass
|
66
|
+
else
|
67
|
+
command.subcommand name, "#{desc} (#{self})", &block
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
3
|
+
module Mystro
|
4
|
+
class Userdata
|
5
|
+
class << self
|
6
|
+
def create(name, roles, environment, opts={ })
|
7
|
+
package = opts.delete(:package)
|
8
|
+
dependencies = opts.delete(:dependencies)
|
9
|
+
gems = opts.delete(:gems)
|
10
|
+
files = opts.delete(:files)
|
11
|
+
directory = "#{Mystro.directory}/userdata/#{package}"
|
12
|
+
file = "#{directory}/userdata.yml"
|
13
|
+
raise "userdata error: package not specified" unless package
|
14
|
+
raise "userdata error: pacakge #{package} directory does not exist (#{directory})" unless File.directory?(directory)
|
15
|
+
raise "userdata error: configuration file does not exist (#{file})" unless File.exists?(file)
|
16
|
+
config = YAML.load_file(file)
|
17
|
+
|
18
|
+
data = {
|
19
|
+
:name => name,
|
20
|
+
:roles => roles,
|
21
|
+
:environment => environment,
|
22
|
+
:nickname => name,
|
23
|
+
:account => "unknown",
|
24
|
+
:zone => "unknown.local",
|
25
|
+
:dependencies => [],
|
26
|
+
:gems => [],
|
27
|
+
:files => [],
|
28
|
+
:directory => directory,
|
29
|
+
:template => "userdata.sh.erb",
|
30
|
+
}.deep_merge(config.symbolize_keys!).deep_merge(opts.symbolize_keys!)
|
31
|
+
|
32
|
+
data[:gems] += gems if gems
|
33
|
+
data[:dependencies] += dependencies if dependencies
|
34
|
+
data[:files] += files if files
|
35
|
+
|
36
|
+
template = File.open("#{directory}/#{data[:template]}").read
|
37
|
+
erb = Erubis::Eruby.new(template)
|
38
|
+
out = erb.evaluate(data)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|