the-maestro 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.rdoc +30 -9
- data/VERSION +1 -1
- data/lib/maestro/cloud.rb +4 -1
- data/lib/maestro/node.rb +19 -4
- data/test/unit/test_cloud.rb +19 -0
- data/test/unit/test_configurable_node.rb +51 -0
- data/test/unit/test_node.rb +24 -30
- data/the-maestro.gemspec +4 -2
- metadata +4 -2
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -22,7 +22,7 @@ Add the following gem dependency to your Rails project's <code>config/environmen
|
|
22
22
|
|
23
23
|
Rails::Initializer.run do |config|
|
24
24
|
|
25
|
-
config.gem "the-maestro", :lib => "maestro", :version => "0.3.
|
25
|
+
config.gem "the-maestro", :lib => "maestro", :version => "0.3.2", :source => "http://gemcutter.org"
|
26
26
|
|
27
27
|
end
|
28
28
|
|
@@ -132,7 +132,7 @@ A cloud name may only contain alphanumerics and dashes.
|
|
132
132
|
|
133
133
|
==== aws_cloud attributes
|
134
134
|
|
135
|
-
The following attributes must be present
|
135
|
+
The following attributes must be present within your aws_cloud declaration:
|
136
136
|
|
137
137
|
- <b>keypair_name</b>: A keypair associated with your Amazon Web Services account
|
138
138
|
- <b>keypair_file</b>: Fully qualified path to the keypair file on your computer matching the above keypair_name
|
@@ -175,7 +175,7 @@ Creates an Elastic Cloud Compute (EC2) node. An EC2 node name may only contain a
|
|
175
175
|
|
176
176
|
The following attributes must be present:
|
177
177
|
|
178
|
-
- <b>roles</b>: An array of Chef roles to apply to this node. The role names in the array must match the Chef roles that are defined in config/maestro/roles
|
178
|
+
- <b>roles</b>: An array of Chef roles to apply to this node. The role names in the array must match the Chef roles that are defined in <code>config/maestro/roles</code>.
|
179
179
|
- <b>ami</b>: The AMI identifier to use.
|
180
180
|
- <b>ssh_user</b>: The name of the user to use to ssh to the instance.
|
181
181
|
- <b>instance_type</b>: The instance type to use for this EC2 node.
|
@@ -183,6 +183,8 @@ The following attributes must be present:
|
|
183
183
|
|
184
184
|
The following attributes are optional:
|
185
185
|
|
186
|
+
- <b>cookbook_attributes</b>: Chef cookbook attribute overrides, in JSON format (see {the Chef documentation}[http://wiki.opscode.com/display/chef/Attributes#Attributes-AttributesinJSON] for more information).
|
187
|
+
Since the attribute JSON format necessitates lots of " characters, the use of heredocs is recomended to avoid manual escaping of " characters and improve readability. See the example below.
|
186
188
|
- <b>elastic_ip</b>: The Elastic IP address to associate with this node.
|
187
189
|
- <b>ebs_volume_id</b>: The id of the EBS Volume to attach to this node.
|
188
190
|
- <b>ebs_device</b>: The device to attach the EBS Volume to.
|
@@ -195,6 +197,20 @@ An example ec2_node:
|
|
195
197
|
ssh_user "ubuntu"
|
196
198
|
instance_type "m1.small"
|
197
199
|
availability_zone "us-east-1b"
|
200
|
+
cookbook_attributes <<-COOKBOOK_ATTRIBUTES
|
201
|
+
"apache": {
|
202
|
+
"listen_ports": ["81", "8181"],
|
203
|
+
"worker" : {
|
204
|
+
"startservers" : "5"
|
205
|
+
}
|
206
|
+
},
|
207
|
+
"mysql": {
|
208
|
+
"server_root_password": "XXXXXXXX",
|
209
|
+
"tunable": {
|
210
|
+
"max_connections": "500"
|
211
|
+
}
|
212
|
+
}
|
213
|
+
COOKBOOK_ATTRIBUTES
|
198
214
|
elastic_ip "123.45.678.90"
|
199
215
|
ebs_volume_id "vol-xxxxxxxx"
|
200
216
|
ebs_device "/dev/sdh"
|
@@ -284,9 +300,9 @@ At any time, you may run the following Rake task to validate your Maestro config
|
|
284
300
|
|
285
301
|
rake maestro:validate_configs
|
286
302
|
|
287
|
-
This will validate all of the files in your Maestro config directory
|
303
|
+
This will validate all of the files in your Maestro config directory, and report any errors.
|
288
304
|
|
289
|
-
=== Conduct
|
305
|
+
=== Conduct!
|
290
306
|
|
291
307
|
Maestro creates Rake tasks for all of your valid clouds. These tasks allow you to provision, configure, and deploy to your cloud.
|
292
308
|
A very simplistic workflow:
|
@@ -322,9 +338,9 @@ For a more in depth explanation of Chef, please consult {the Chef documentation}
|
|
322
338
|
Maestro will log cloud-wide workflow messages to STDOUT. In addition, log files will be created for your cloud, as well as each of the nodes in your cloud. These
|
323
339
|
can be found at the following location:
|
324
340
|
|
325
|
-
YOUR_RAILS_APP/log/maestro/clouds
|
326
|
-
YOUR_RAILS_APP/log/maestro/clouds
|
327
|
-
YOUR_RAILS_APP/log/maestro/clouds
|
341
|
+
YOUR_RAILS_APP/log/maestro/clouds/cloud-name/
|
342
|
+
YOUR_RAILS_APP/log/maestro/clouds/cloud-name/cloud-name.log
|
343
|
+
YOUR_RAILS_APP/log/maestro/clouds/cloud-name/node-name.log
|
328
344
|
|
329
345
|
Node-specific messages are not logged to STDOUT, but only to the node's log file. For troubleshooting problems configuring your nodes, please
|
330
346
|
consult the individual node log files for information.
|
@@ -337,6 +353,11 @@ consult the individual node log files for information.
|
|
337
353
|
TODO...
|
338
354
|
|
339
355
|
|
356
|
+
== Where To Get Help
|
357
|
+
|
358
|
+
The {Maestro Users Google Group}[http://groups.google.com/group/maestro-users] is the recommended place to get help.
|
359
|
+
|
360
|
+
|
340
361
|
== Contributing
|
341
362
|
Please use the {Issues}[http://github.com/bploetz/maestro/issues] page on the Maestro GitHub site to report bugs or feature requests.
|
342
363
|
|
@@ -383,7 +404,7 @@ To generate RDoc locally:
|
|
383
404
|
|
384
405
|
(The MIT License)
|
385
406
|
|
386
|
-
Copyright (c) 2010 Brian Ploetz <bploetz
|
407
|
+
Copyright (c) 2010 Brian Ploetz <bploetz (at) gmail.com>
|
387
408
|
|
388
409
|
Permission is hereby granted, free of charge, to any person
|
389
410
|
obtaining a copy of this software and associated documentation
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.2
|
data/lib/maestro/cloud.rb
CHANGED
@@ -22,6 +22,8 @@ module Maestro
|
|
22
22
|
attr_reader :configurable_nodes
|
23
23
|
# String containing the full path to this Cloud's log directory
|
24
24
|
attr_reader :log_directory
|
25
|
+
# String containing the full path to this Cloud's log file
|
26
|
+
attr_reader :log_file
|
25
27
|
dsl_property :keypair_name, :keypair_file
|
26
28
|
|
27
29
|
# Creates a new Cloud object.
|
@@ -123,7 +125,7 @@ module Maestro
|
|
123
125
|
else
|
124
126
|
@logger.info "chef-solo already installed on Nodes #{@configurable_nodes.keys.inspect}"
|
125
127
|
end
|
126
|
-
@logger.info "Running chef-solo on Nodes #{@configurable_nodes.keys.inspect}..."
|
128
|
+
@logger.info "Running chef-solo on Nodes #{@configurable_nodes.keys.inspect}. This may take a few minutes..."
|
127
129
|
session = open_ssh_session
|
128
130
|
run_chef_solo(session)
|
129
131
|
session.close
|
@@ -315,6 +317,7 @@ module Maestro
|
|
315
317
|
File.new(cloud_log_file, "a+")
|
316
318
|
@logger.info "Created #{cloud_log_file}"
|
317
319
|
end
|
320
|
+
@log_file = cloud_log_file
|
318
321
|
outputter = Log4r::FileOutputter.new("#{@name}-file", :formatter => FileFormatter.new, :filename => cloud_log_file, :truncate => false)
|
319
322
|
@logger.add(outputter)
|
320
323
|
rescue RuntimeError => rerr
|
data/lib/maestro/node.rb
CHANGED
@@ -19,7 +19,9 @@ module Maestro
|
|
19
19
|
# the IP address of this Node
|
20
20
|
attr_accessor :ip_address
|
21
21
|
# the logger of this Node
|
22
|
-
|
22
|
+
attr_reader :logger
|
23
|
+
# String containing the fully qualified path to the log file of this Node
|
24
|
+
attr_reader :log_file
|
23
25
|
|
24
26
|
# Creates a new Node
|
25
27
|
def initialize(name, cloud, &block)
|
@@ -65,6 +67,7 @@ module Maestro
|
|
65
67
|
node_log_file = @cloud.log_directory + "/#{@name.to_s}.log"
|
66
68
|
if !File.exists?(node_log_file)
|
67
69
|
File.new(node_log_file, "a+")
|
70
|
+
@log_file = node_log_file
|
68
71
|
@logger.info "Created #{node_log_file}"
|
69
72
|
end
|
70
73
|
outputter = Log4r::FileOutputter.new("#{@name.to_s}-file", :formatter => FileFormatter.new, :filename => node_log_file, :truncate => false)
|
@@ -91,7 +94,7 @@ module Maestro
|
|
91
94
|
|
92
95
|
DEFAULT_SSH_USER = "root"
|
93
96
|
|
94
|
-
dsl_property :roles, :ssh_user
|
97
|
+
dsl_property :roles, :ssh_user, :cookbook_attributes
|
95
98
|
# the file name of this Configurable Node's Chef Node JSON file
|
96
99
|
attr_accessor :json_filename
|
97
100
|
# the contents of this Configurable Node's Chef Node JSON file
|
@@ -107,7 +110,17 @@ module Maestro
|
|
107
110
|
@json.chop! if @json =~ /\s$/
|
108
111
|
@json.chop! if @json =~ /,$/
|
109
112
|
end
|
110
|
-
@json = @json + "]
|
113
|
+
@json = @json + "]"
|
114
|
+
if !@cookbook_attributes.nil?
|
115
|
+
@cookbook_attributes.gsub!(/(\n|\n\r)\s{0,}/, ' ')
|
116
|
+
@cookbook_attributes.strip!
|
117
|
+
@cookbook_attributes.chop! if @cookbook_attributes =~ /,$/
|
118
|
+
@cookbook_attributes.slice!(0) if @cookbook_attributes =~ /^\{/
|
119
|
+
@json = @json + ", "
|
120
|
+
@json = @json + @cookbook_attributes
|
121
|
+
@json.chop! if @json =~ /\s$/
|
122
|
+
end
|
123
|
+
@json = @json + " }"
|
111
124
|
end
|
112
125
|
|
113
126
|
protected
|
@@ -116,8 +129,10 @@ module Maestro
|
|
116
129
|
def validate_internal
|
117
130
|
super
|
118
131
|
invalidate "'#{@name}' Node missing roles map" if roles.nil?
|
132
|
+
if !cookbook_attributes.nil?
|
133
|
+
invalidate "'#{@name}' Node's cookbook_attributes must be a String" if !cookbook_attributes.is_a?(String)
|
134
|
+
end
|
119
135
|
end
|
120
136
|
end
|
121
|
-
|
122
137
|
end
|
123
138
|
end
|
data/test/unit/test_cloud.rb
CHANGED
@@ -14,6 +14,7 @@ class TestCloud < Test::Unit::TestCase
|
|
14
14
|
|
15
15
|
context "A Cloud instance" do
|
16
16
|
setup do
|
17
|
+
ENV[Maestro::MAESTRO_DIR_ENV_VAR] = File.join(File.dirname(File.expand_path(__FILE__)), 'fixtures', 'standalone')
|
17
18
|
@cloud = aws_cloud :test do
|
18
19
|
keypair_name "XXXXXXX-keypair"
|
19
20
|
keypair_file "/path/to/id_rsa-XXXXXXX-keypair"
|
@@ -32,6 +33,11 @@ class TestCloud < Test::Unit::TestCase
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
teardown do
|
37
|
+
FileUtils.rm_rf([Maestro.maestro_log_directory], :secure => true) if File.exists?(Maestro.maestro_log_directory)
|
38
|
+
ENV.delete Maestro::MAESTRO_DIR_ENV_VAR
|
39
|
+
end
|
40
|
+
|
35
41
|
|
36
42
|
should "raise exception on space in name" do
|
37
43
|
assert_raise StandardError do
|
@@ -138,5 +144,18 @@ class TestCloud < Test::Unit::TestCase
|
|
138
144
|
assert !@cloud.valid?
|
139
145
|
assert @cloud.validation_errors.any? {|message| !message.index("Missing nodes").nil? }
|
140
146
|
end
|
147
|
+
|
148
|
+
should "create logs" do
|
149
|
+
assert_nothing_raised do
|
150
|
+
base_dir = ENV[Maestro::MAESTRO_DIR_ENV_VAR]
|
151
|
+
assert !File.exists?("#{base_dir}/log/maestro/clouds/foo")
|
152
|
+
assert !File.exists?("#{base_dir}/log/maestro/clouds/foo/foo.log")
|
153
|
+
cloud = aws_cloud :foo do end
|
154
|
+
assert cloud.log_file.eql? "#{base_dir}/log/maestro/clouds/foo/foo.log"
|
155
|
+
assert cloud.log_directory.eql? "#{base_dir}/log/maestro/clouds/foo"
|
156
|
+
assert File.exists?("#{base_dir}/log/maestro/clouds/foo/foo.log")
|
157
|
+
assert File.exists?("#{base_dir}/log/maestro/clouds/foo")
|
158
|
+
end
|
159
|
+
end
|
141
160
|
end
|
142
161
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
# Unit tests for Maestro::Node::Configurable
|
4
|
+
class TestConfigurableNode < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context "Maestro::Node::Configurable" do
|
7
|
+
setup do
|
8
|
+
@cloud = aws_cloud :test do
|
9
|
+
nodes do
|
10
|
+
ec2_node "web-1" do
|
11
|
+
roles ["web", "mail"]
|
12
|
+
cookbook_attributes <<-COOKBOOK_ATTRIBUTES
|
13
|
+
"apache": {
|
14
|
+
"listen_ports": ["81", "8181"],
|
15
|
+
"worker" : {
|
16
|
+
"startservers" : "5"
|
17
|
+
}
|
18
|
+
},
|
19
|
+
"mysql": {
|
20
|
+
"server_root_password": "XXXXXXXX",
|
21
|
+
"tunable": {
|
22
|
+
"max_connections": "500"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
COOKBOOK_ATTRIBUTES
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@node = @cloud.nodes["web-1"]
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
should "be invalid due to missing role map" do
|
34
|
+
@node.roles nil
|
35
|
+
@node.validate
|
36
|
+
assert !@node.valid?
|
37
|
+
assert @node.validation_errors.any? {|message| !message.index("missing roles map").nil? }
|
38
|
+
end
|
39
|
+
|
40
|
+
should "be invalid due to cookbook_attributes not a string" do
|
41
|
+
@node.cookbook_attributes Hash.new
|
42
|
+
@node.validate
|
43
|
+
assert !@node.valid?
|
44
|
+
assert @node.validation_errors.any? {|message| !message.index("cookbook_attributes must be a String").nil? }
|
45
|
+
end
|
46
|
+
|
47
|
+
should "have valid JSON" do
|
48
|
+
assert @node.json.eql? "{ \"run_list\": [\"role[web]\", \"role[mail]\"], \"apache\": { \"listen_ports\": [\"81\", \"8181\"], \"worker\" : { \"startservers\" : \"5\" } }, \"mysql\": { \"server_root_password\": \"XXXXXXXX\", \"tunable\": { \"max_connections\": \"500\" } } }"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/test/unit/test_node.rb
CHANGED
@@ -1,36 +1,21 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
|
-
# Unit tests for Maestro::Node
|
3
|
+
# Unit tests for Maestro::Node::Base
|
4
4
|
class TestNode < Test::Unit::TestCase
|
5
5
|
|
6
|
-
context "Maestro::Node" do
|
6
|
+
context "Maestro::Node::Base" do
|
7
7
|
setup do
|
8
|
-
|
9
|
-
keypair_name "XXXXXXX-keypair"
|
10
|
-
keypair_file "/path/to/id_rsa-XXXXXXX-keypair"
|
11
|
-
|
12
|
-
roles do
|
13
|
-
role "web" do
|
14
|
-
public_ports [80, 443]
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
nodes do
|
19
|
-
ec2_node "web-1" do
|
20
|
-
roles ["web"]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
@node = @cloud.nodes["web-1"]
|
8
|
+
ENV[Maestro::MAESTRO_DIR_ENV_VAR] = File.join(File.dirname(File.expand_path(__FILE__)), 'fixtures', 'standalone')
|
25
9
|
end
|
26
|
-
|
27
|
-
|
10
|
+
|
11
|
+
teardown do
|
12
|
+
FileUtils.rm_rf([Maestro.maestro_log_directory], :secure => true) if File.exists?(Maestro.maestro_log_directory)
|
13
|
+
ENV.delete Maestro::MAESTRO_DIR_ENV_VAR
|
14
|
+
end
|
15
|
+
|
28
16
|
should "raise exception on space in name" do
|
29
17
|
assert_raise StandardError do
|
30
|
-
|
31
|
-
keypair_name "XXXXXXX-keypair"
|
32
|
-
keypair_file "/path/to/id_rsa-XXXXXXX-keypair"
|
33
|
-
roles {}
|
18
|
+
cloud = aws_cloud :test do
|
34
19
|
nodes do
|
35
20
|
ec2_node "foo bar" do
|
36
21
|
roles ["web"]
|
@@ -40,11 +25,20 @@ class TestNode < Test::Unit::TestCase
|
|
40
25
|
end
|
41
26
|
end
|
42
27
|
|
43
|
-
should "
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
28
|
+
should "create log file" do
|
29
|
+
assert_nothing_raised do
|
30
|
+
base_dir = ENV[Maestro::MAESTRO_DIR_ENV_VAR]
|
31
|
+
assert !File.exists?("#{base_dir}/log/maestro/clouds/test/foo.log")
|
32
|
+
cloud = aws_cloud :test do
|
33
|
+
nodes do
|
34
|
+
ec2_node "foo" do
|
35
|
+
roles ["web"]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
assert cloud.nodes["foo"].log_file.eql? "#{base_dir}/log/maestro/clouds/test/foo.log"
|
40
|
+
assert File.exists?("#{base_dir}/log/maestro/clouds/test/foo.log")
|
41
|
+
end
|
48
42
|
end
|
49
43
|
end
|
50
44
|
end
|
data/the-maestro.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{the-maestro}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Brian Ploetz"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-23}
|
13
13
|
s.description = %q{Maestro is a cloud provisioning, configuration, and deployment utility for your Ruby and Ruby On Rails applications.}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
@@ -64,6 +64,7 @@ Gem::Specification.new do |s|
|
|
64
64
|
"test/unit/test_aws_rds_node.rb",
|
65
65
|
"test/unit/test_cent_os.rb",
|
66
66
|
"test/unit/test_cloud.rb",
|
67
|
+
"test/unit/test_configurable_node.rb",
|
67
68
|
"test/unit/test_debian.rb",
|
68
69
|
"test/unit/test_fedora.rb",
|
69
70
|
"test/unit/test_invalid_mode.rb",
|
@@ -98,6 +99,7 @@ Gem::Specification.new do |s|
|
|
98
99
|
"test/unit/test_aws_rds_node.rb",
|
99
100
|
"test/unit/test_cent_os.rb",
|
100
101
|
"test/unit/test_cloud.rb",
|
102
|
+
"test/unit/test_configurable_node.rb",
|
101
103
|
"test/unit/test_debian.rb",
|
102
104
|
"test/unit/test_fedora.rb",
|
103
105
|
"test/unit/test_invalid_mode.rb",
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: the-maestro
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Ploetz
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-05-
|
12
|
+
date: 2010-05-23 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -160,6 +160,7 @@ files:
|
|
160
160
|
- test/unit/test_aws_rds_node.rb
|
161
161
|
- test/unit/test_cent_os.rb
|
162
162
|
- test/unit/test_cloud.rb
|
163
|
+
- test/unit/test_configurable_node.rb
|
163
164
|
- test/unit/test_debian.rb
|
164
165
|
- test/unit/test_fedora.rb
|
165
166
|
- test/unit/test_invalid_mode.rb
|
@@ -216,6 +217,7 @@ test_files:
|
|
216
217
|
- test/unit/test_aws_rds_node.rb
|
217
218
|
- test/unit/test_cent_os.rb
|
218
219
|
- test/unit/test_cloud.rb
|
220
|
+
- test/unit/test_configurable_node.rb
|
219
221
|
- test/unit/test_debian.rb
|
220
222
|
- test/unit/test_fedora.rb
|
221
223
|
- test/unit/test_invalid_mode.rb
|