the-maestro 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 (60) hide show
  1. data/.document +5 -0
  2. data/.gitignore +25 -0
  3. data/LICENSE +23 -0
  4. data/README.rdoc +378 -0
  5. data/Rakefile +116 -0
  6. data/VERSION +1 -0
  7. data/lib/maestro.rb +354 -0
  8. data/lib/maestro/cloud.rb +384 -0
  9. data/lib/maestro/cloud/aws.rb +1231 -0
  10. data/lib/maestro/dsl_property.rb +15 -0
  11. data/lib/maestro/log4r/console_formatter.rb +18 -0
  12. data/lib/maestro/log4r/file_formatter.rb +24 -0
  13. data/lib/maestro/node.rb +123 -0
  14. data/lib/maestro/operating_system.rb +53 -0
  15. data/lib/maestro/operating_system/cent_os.rb +23 -0
  16. data/lib/maestro/operating_system/debian.rb +40 -0
  17. data/lib/maestro/operating_system/fedora.rb +23 -0
  18. data/lib/maestro/operating_system/ubuntu.rb +100 -0
  19. data/lib/maestro/role.rb +36 -0
  20. data/lib/maestro/tasks.rb +52 -0
  21. data/lib/maestro/validator.rb +32 -0
  22. data/rails/init.rb +1 -0
  23. data/test/integration/base_aws.rb +156 -0
  24. data/test/integration/fixtures/config/maestro/cookbooks/emacs/metadata.json +41 -0
  25. data/test/integration/fixtures/config/maestro/cookbooks/emacs/metadata.rb +3 -0
  26. data/test/integration/fixtures/config/maestro/cookbooks/emacs/recipes/default.rb +21 -0
  27. data/test/integration/fixtures/config/maestro/roles/default.json +9 -0
  28. data/test/integration/fixtures/config/maestro/roles/web.json +9 -0
  29. data/test/integration/helper.rb +8 -0
  30. data/test/integration/test_aws_cloud.rb +805 -0
  31. data/test/integration/test_cent_os.rb +104 -0
  32. data/test/integration/test_debian.rb +119 -0
  33. data/test/integration/test_fedora.rb +104 -0
  34. data/test/integration/test_ubuntu.rb +149 -0
  35. data/test/unit/fixtures/invalid-clouds-not-a-directory/config/maestro/clouds +1 -0
  36. data/test/unit/fixtures/invalid-cookbooks-not-a-directory/config/maestro/cookbooks +0 -0
  37. data/test/unit/fixtures/invalid-maestro-not-a-directory/config/maestro +0 -0
  38. data/test/unit/fixtures/invalid-missing-cookbooks/config/maestro/clouds/valid.yml +21 -0
  39. data/test/unit/fixtures/invalid-missing-roles/config/maestro/clouds/valid.yml +21 -0
  40. data/test/unit/fixtures/invalid-roles-not-a-directory/config/maestro/roles +1 -0
  41. data/test/unit/fixtures/ssh/id_rsa-maestro-test-keypair +27 -0
  42. data/test/unit/helper.rb +6 -0
  43. data/test/unit/test_aws_cloud.rb +133 -0
  44. data/test/unit/test_aws_ec2_node.rb +76 -0
  45. data/test/unit/test_aws_elb_node.rb +221 -0
  46. data/test/unit/test_aws_rds_node.rb +380 -0
  47. data/test/unit/test_cent_os.rb +28 -0
  48. data/test/unit/test_cloud.rb +142 -0
  49. data/test/unit/test_debian.rb +62 -0
  50. data/test/unit/test_fedora.rb +28 -0
  51. data/test/unit/test_invalid_mode.rb +11 -0
  52. data/test/unit/test_maestro.rb +140 -0
  53. data/test/unit/test_node.rb +50 -0
  54. data/test/unit/test_operating_system.rb +19 -0
  55. data/test/unit/test_rails_mode.rb +77 -0
  56. data/test/unit/test_role.rb +59 -0
  57. data/test/unit/test_standalone_mode.rb +75 -0
  58. data/test/unit/test_ubuntu.rb +95 -0
  59. data/the-maestro.gemspec +150 -0
  60. metadata +228 -0
@@ -0,0 +1,15 @@
1
+ class Module
2
+ def dsl_property(*symbols)
3
+ symbols.each do |sym|
4
+ class_eval %{
5
+ def #{sym}(*val)
6
+ if val.empty?
7
+ @#{sym}
8
+ else
9
+ @#{sym} = val.size == 1 ? val[0] : val
10
+ end
11
+ end
12
+ }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ require "log4r"
2
+
3
+ # Custom Log4r formatter for the console
4
+ class ConsoleFormatter < Log4r::BasicFormatter
5
+
6
+ def initialize(hash={})
7
+ super(hash)
8
+ end
9
+
10
+ def format(logevent)
11
+ if Log4r::LNAMES[logevent.level].eql? "PROGRESS"
12
+ # Formats the data as is with no newline, to allow progress bars to be logged.
13
+ sprintf("%s", logevent.data.to_s)
14
+ else
15
+ format_object(logevent.data) + "\n"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ require "log4r"
2
+
3
+ # Custom Log4r formatter for files
4
+ class FileFormatter < Log4r::BasicFormatter
5
+
6
+ def initialize(hash={})
7
+ super(hash)
8
+ end
9
+
10
+ def format(logevent)
11
+ if Log4r::LNAMES[logevent.level].eql? "PROGRESS"
12
+ # Formats the data as is with no newline, to allow progress bars to be logged.
13
+ sprintf("%s", logevent.data.to_s)
14
+ else
15
+ if logevent.data.kind_of? String
16
+ # remove ^M characters
17
+ logevent.data.gsub!(/\r/, "")
18
+ # Prevent two newlines in the log file
19
+ logevent.data.chop! if logevent.data =~ /\n$/
20
+ end
21
+ sprintf("[%s %s] %s\n", Log4r::LNAMES[logevent.level], Time.now.strftime("%m/%d/%Y %I:%M:%S %p"), format_object(logevent.data))
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,123 @@
1
+ require "maestro/validator"
2
+ require "log4r"
3
+ require "maestro/log4r/console_formatter"
4
+ require "maestro/log4r/file_formatter"
5
+
6
+
7
+ module Maestro
8
+ module Node
9
+ # A node (i.e. a server, a machine, a vm, a device, etc...) in a cloud.
10
+ class Base
11
+ include Validator
12
+
13
+ # the name of this Node
14
+ attr_reader :name
15
+ # the Cloud this Node is associated with
16
+ attr_reader :cloud
17
+ # the host name of this Node
18
+ attr_accessor :hostname
19
+ # the IP address of this Node
20
+ attr_accessor :ip_address
21
+ # the logger of this Node
22
+ attr_accessor :logger
23
+
24
+ # Creates a new Node
25
+ def initialize(name, cloud, &block)
26
+ super()
27
+ raise StandardError, "Node name cannot contain spaces: #{name}" if name.is_a?(String) && !name.index(/\s/).nil?
28
+ @name = name
29
+ @cloud = cloud
30
+ @logger = Log4r::Logger.new(Regexp::quote(@name.to_s))
31
+ outputter = Log4r::StdoutOutputter.new("#{@name.to_s}-stdout")
32
+ outputter.formatter = ConsoleFormatter.new
33
+ @logger.add(outputter)
34
+ init_logs
35
+ instance_eval(&block) if block_given?
36
+ end
37
+
38
+ def method_missing(name, *params) #:nodoc:
39
+ invalidate "Unexpected attribute: #{name}"
40
+ end
41
+
42
+ # disables the stdout Outputter and only logs to this Node's log file
43
+ def disable_stdout
44
+ stdoutoutputter = Log4r::Outputter["#{@name.to_s}-stdout"]
45
+ stdoutoutputter.level = Log4r::OFF
46
+ end
47
+
48
+ # enables the stdout Outputter
49
+ def enable_stdout
50
+ stdoutoutputter = Log4r::Outputter["#{@name.to_s}-stdout"]
51
+ stdoutoutputter.level = Log4r::ALL
52
+ end
53
+
54
+
55
+ protected
56
+
57
+ # validates this Node
58
+ def validate_internal
59
+ end
60
+
61
+ # creates log files for this cloud and all of its nodes. If the log files exist, no action is taken.
62
+ def init_logs
63
+ begin
64
+ if !@cloud.log_directory.nil?
65
+ node_log_file = @cloud.log_directory + "/#{@name.to_s}.log"
66
+ if !File.exists?(node_log_file)
67
+ File.new(node_log_file, "a+")
68
+ @logger.info "Created #{node_log_file}"
69
+ end
70
+ outputter = Log4r::FileOutputter.new("#{@name.to_s}-file", :formatter => FileFormatter.new, :filename => node_log_file, :truncate => false)
71
+ @logger.add(outputter)
72
+ end
73
+ rescue RuntimeError => rerr
74
+ if !rerr.message.eql?("Maestro not configured correctly. Either RAILS_ROOT or ENV['MAESTRO_DIR'] must be defined")
75
+ @logger.error "Unexpected Error"
76
+ @logger.error rerr
77
+ end
78
+ rescue SystemCallError => syserr
79
+ @logger.error "Error creating Node log file"
80
+ @logger.error syserr
81
+ rescue StandardError => serr
82
+ @logger.error "Unexpected Error"
83
+ @logger.error serr
84
+ end
85
+ end
86
+ end
87
+
88
+
89
+ # A node which is able to be SSH'd into to be configured by Maestro with Chef
90
+ class Configurable < Base
91
+
92
+ DEFAULT_SSH_USER = "root"
93
+
94
+ dsl_property :roles, :ssh_user
95
+ # the file name of this Configurable Node's Chef Node JSON file
96
+ attr_accessor :json_filename
97
+ # the contents of this Configurable Node's Chef Node JSON file
98
+ attr_accessor :json
99
+
100
+ # Creates a new Configurable Node
101
+ def initialize(name, cloud, &block)
102
+ super(name, cloud, &block)
103
+ @json_filename = cloud.name.to_s + "-" + name.to_s + ".json"
104
+ @json = "{ \"run_list\": ["
105
+ if !@roles.nil? && !@roles.empty?
106
+ @roles.each {|role_name| @json = @json + "\"role[#{role_name.to_s}]\", "}
107
+ @json.chop! if @json =~ /\s$/
108
+ @json.chop! if @json =~ /,$/
109
+ end
110
+ @json = @json + "]}"
111
+ end
112
+
113
+ protected
114
+
115
+ # validates this Configurable
116
+ def validate_internal
117
+ super
118
+ invalidate "'#{@name}' Node missing roles map" if roles.nil?
119
+ end
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,53 @@
1
+ module Maestro
2
+ module OperatingSystem
3
+ # Reads the given string containing the contents of <code>/etc/issue</code> and returns
4
+ # an OperatingSystem object matching the Linux version. Raises an exception
5
+ # if the operating system cannot be determined or is unsupported by Maestro.
6
+ def self.create_from_etc_issue(etc_issue_str)
7
+ raise StandardError, "Invalid etc_issue_str" if (etc_issue_str.nil? || etc_issue_str.empty?)
8
+ if etc_issue_str.include?("Ubuntu 9.10")
9
+ Ubuntu910.new(etc_issue_str)
10
+ elsif etc_issue_str.include?("Ubuntu 9.04")
11
+ Ubuntu904.new(etc_issue_str)
12
+ elsif etc_issue_str.include?("Ubuntu 8.10")
13
+ Ubuntu810.new(etc_issue_str)
14
+ elsif etc_issue_str.include?("Ubuntu 8.04")
15
+ Ubuntu804.new(etc_issue_str)
16
+ elsif etc_issue_str.include?("Ubuntu")
17
+ Ubuntu.new(etc_issue_str)
18
+ elsif etc_issue_str.include?("Debian GNU/Linux 6.0")
19
+ Debian6.new(etc_issue_str)
20
+ elsif etc_issue_str.include?("Debian GNU/Linux 5.0")
21
+ Debian5.new(etc_issue_str)
22
+ elsif etc_issue_str.include?("Debian")
23
+ Debian.new(etc_issue_str)
24
+ elsif etc_issue_str.include?("Fedora")
25
+ Fedora.new(etc_issue_str)
26
+ elsif etc_issue_str.include?("CentOS")
27
+ CentOs.new(etc_issue_str)
28
+ else
29
+ raise StandardError, "ERROR: Unsupported Linux Distro: #{etc_issue_str}"
30
+ end
31
+ end
32
+
33
+
34
+ # An operating system
35
+ class Base
36
+ @name
37
+ @version
38
+ @etc_issue_string
39
+ @chef_install_script
40
+
41
+ attr_reader :name, :version, :etc_issue_string, :chef_install_script
42
+
43
+ def initialize(etc_issue_string)
44
+ @etc_issue_string = etc_issue_string
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ require "maestro/operating_system/cent_os"
51
+ require "maestro/operating_system/debian"
52
+ require "maestro/operating_system/fedora"
53
+ require "maestro/operating_system/ubuntu"
@@ -0,0 +1,23 @@
1
+ module Maestro
2
+ module OperatingSystem
3
+ # The CentOS Linux distro
4
+ class CentOs < Base
5
+ def initialize(etc_issue_str)
6
+ super(etc_issue_str)
7
+ @chef_install_script =
8
+ ["sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm",
9
+ "sudo rpm -Uvh http://download.elff.bravenet.com/5/i386/elff-release-5-3.noarch.rpm",
10
+ "sudo yum install -y ruby ruby-shadow ruby-ri ruby-rdoc gcc gcc-c++ ruby-devel",
11
+ "sudo mkdir -p /usr/local/src",
12
+ "sudo wget -P /usr/local/src http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz",
13
+ "sudo tar zxf /usr/local/src/rubygems-1.3.6.tgz -C /usr/local/src",
14
+ "sudo ruby /usr/local/src/rubygems-1.3.6/setup.rb",
15
+ "sudo rm /usr/local/src/rubygems-1.3.6.tgz",
16
+ "sudo gem sources -a http://gems.opscode.com",
17
+ "sudo gem install rake --no-rdoc --no-ri",
18
+ "sudo gem install chef --no-rdoc --no-ri --version '= 0.8.14'",
19
+ "sudo ln -sfv $(gem environment gemdir)/gems/chef-0.8.14/bin/chef-solo /usr/bin/chef-solo"]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ module Maestro
2
+ module OperatingSystem
3
+ # The Debian Linux distro
4
+ class Debian < Base
5
+ def initialize(etc_issue_str)
6
+ super(etc_issue_str)
7
+ # TODO: Fix Perl locale warnings. They don't appear to effect anything, but are very noisy
8
+ @chef_install_script =
9
+ ["sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get update -y'",
10
+ "sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get upgrade -y'",
11
+ "sh -c 'export DEBIAN_FRONTEND=noninteractive; apt-get install -y sudo'", # http://wiki.debian.org/sudo
12
+ "sh -c 'export DEBIAN_FRONTEND=noninteractive; sudo apt-get install -y ruby irb ri rdoc libyaml-ruby and libzlib-ruby build-essential libopenssl-ruby ruby1.8-dev wget'",
13
+ "sudo mkdir -p /usr/local/src",
14
+ "sudo wget -P /usr/local/src http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz",
15
+ "sudo tar zxf /usr/local/src/rubygems-1.3.6.tgz -C /usr/local/src",
16
+ "sudo ruby /usr/local/src/rubygems-1.3.6/setup.rb",
17
+ "sudo rm /usr/local/src/rubygems-1.3.6.tgz",
18
+ "sudo ln -sfv /usr/bin/gem1.8 /usr/bin/gem",
19
+ "sudo gem sources -a http://gems.opscode.com",
20
+ "sudo gem install rake --no-rdoc --no-ri",
21
+ "sudo gem install chef --no-rdoc --no-ri --version '= 0.8.14'",
22
+ "sudo ln -sfv $(gem environment gemdir)/gems/chef-0.8.14/bin/chef-solo /usr/bin/chef-solo"]
23
+ end
24
+ end
25
+
26
+ # The Debian 6.0 Linux distro
27
+ class Debian6 < Debian
28
+ def initialize(etc_issue_str)
29
+ super(etc_issue_str)
30
+ end
31
+ end
32
+
33
+ # The Debian 5.0 Linux distro
34
+ class Debian5 < Debian
35
+ def initialize(etc_issue_str)
36
+ super(etc_issue_str)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ module Maestro
2
+ module OperatingSystem
3
+ # The Fedora Linux distro
4
+ class Fedora < Base
5
+ def initialize(etc_issue_str)
6
+ super(etc_issue_str)
7
+ @chef_install_script =
8
+ ["sudo rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm",
9
+ "sudo rpm -Uvh http://download.elff.bravenet.com/5/i386/elff-release-5-3.noarch.rpm",
10
+ "sudo yum install -y ruby ruby-shadow ruby-ri ruby-rdoc gcc gcc-c++ ruby-devel",
11
+ "sudo mkdir -p /usr/local/src",
12
+ "sudo wget -P /usr/local/src http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz",
13
+ "sudo tar zxf /usr/local/src/rubygems-1.3.6.tgz -C /usr/local/src",
14
+ "sudo ruby /usr/local/src/rubygems-1.3.6/setup.rb",
15
+ "sudo rm /usr/local/src/rubygems-1.3.6.tgz",
16
+ "sudo gem sources -a http://gems.opscode.com",
17
+ "sudo gem install rake --no-rdoc --no-ri",
18
+ "sudo gem install chef --no-rdoc --no-ri --version '= 0.8.14'",
19
+ "sudo ln -sfv $(gem environment gemdir)/gems/chef-0.8.14/bin/chef-solo /usr/bin/chef-solo"]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,100 @@
1
+ module Maestro
2
+ module OperatingSystem
3
+ # Base Ubuntu Linux Distro Class
4
+ class Ubuntu < Base
5
+ def initialize(etc_issue_str)
6
+ super(etc_issue_str)
7
+ @chef_install_script =
8
+ ["sh -c 'export DEBIAN_FRONTEND=noninteractive; sudo apt-get update -y'",
9
+ "sh -c 'export DEBIAN_FRONTEND=noninteractive; sudo apt-get upgrade -y'",
10
+ "sh -c 'export DEBIAN_FRONTEND=noninteractive; sudo apt-get install -y ruby irb ri rdoc libyaml-ruby and libzlib-ruby build-essential libopenssl-ruby ruby1.8-dev wget'",
11
+ "sudo mkdir -p /usr/local/src",
12
+ "sudo wget -P /usr/local/src http://rubyforge.org/frs/download.php/69365/rubygems-1.3.6.tgz",
13
+ "sudo tar zxf /usr/local/src/rubygems-1.3.6.tgz -C /usr/local/src",
14
+ "sudo ruby /usr/local/src/rubygems-1.3.6/setup.rb",
15
+ "sudo rm /usr/local/src/rubygems-1.3.6.tgz",
16
+ "sudo ln -sfv /usr/bin/gem1.8 /usr/bin/gem",
17
+ "sudo gem sources -a http://gems.opscode.com",
18
+ "sudo gem install rake --no-rdoc --no-ri",
19
+ "sudo gem install chef --no-rdoc --no-ri --version '= 0.8.14'",
20
+ "sudo ln -sfv $(gem environment gemdir)/gems/chef-0.8.14/bin/chef-solo /usr/bin/chef-solo"]
21
+ end
22
+ end
23
+
24
+
25
+ # The Ubuntu 9.10 Linux distro
26
+ class Ubuntu910 < Ubuntu
27
+ def initialize(etc_issue_str)
28
+ super(etc_issue_str)
29
+ # Package install (0.7!)
30
+ # The native package installs install Chef 0.7, not the newest 0.8. Must use rubygem install for now
31
+ # @chef_install_script =
32
+ # ["sudo apt-get -y dist-upgrade",
33
+ # "sudo sh -c \"echo deb http://apt.opscode.com/ karmic universe > /etc/apt/sources.list.d/opscode.list\"",
34
+ # "curl http://apt.opscode.com/packages@opscode.com.gpg.key | sudo apt-key add -",
35
+ # "sudo apt-get -y update",
36
+ # "sudo aptitude -y install ruby ri rdoc libyaml-ruby libzlib-ruby build-essential libopenssl-ruby ruby1.8-dev rubygems ohai chef",
37
+ # "sudo gem install rake --no-rdoc --no-ri",
38
+ # "sudo /etc/init.d/chef-client stop",
39
+ # "sudo chef-solo"]
40
+ end
41
+ end
42
+
43
+
44
+ # The Ubuntu 9.04 Linux distro
45
+ class Ubuntu904 < Ubuntu
46
+ def initialize(etc_issue_str)
47
+ super(etc_issue_str)
48
+ # Package install (0.7!)
49
+ # The native package installs install Chef 0.7, not the newest 0.8. Must use rubygem install for now
50
+ # @chef_install_script =
51
+ # ["sudo apt-get -y dist-upgrade",
52
+ # "sudo sh -c \"echo deb http://apt.opscode.com/ jaunty universe > /etc/apt/sources.list.d/opscode.list\"",
53
+ # "curl http://apt.opscode.com/packages@opscode.com.gpg.key | sudo apt-key add -",
54
+ # "sudo apt-get -y update",
55
+ # "sudo aptitude -y install ruby ri rdoc libyaml-ruby libzlib-ruby build-essential libopenssl-ruby ruby1.8-dev rubygems ohai chef",
56
+ # "sudo gem install rake --no-rdoc --no-ri",
57
+ # "sudo /etc/init.d/chef-client stop",
58
+ # "sudo chef-solo"]
59
+ end
60
+ end
61
+
62
+
63
+ # The Ubuntu 8.10 Linux distro
64
+ class Ubuntu810 < Ubuntu
65
+ def initialize(etc_issue_str)
66
+ super(etc_issue_str)
67
+ # Package install (0.7!)
68
+ # The native package installs install Chef 0.7, not the newest 0.8. Must use rubygem install for now
69
+ # @chef_install_script =
70
+ # ["sudo apt-get -y dist-upgrade",
71
+ # "sudo sh -c \"echo deb http://apt.opscode.com/ intrepid universe > /etc/apt/sources.list.d/opscode.list\"",
72
+ # "curl http://apt.opscode.com/packages@opscode.com.gpg.key | sudo apt-key add -",
73
+ # "sudo apt-get -y update",
74
+ # "sudo aptitude -y install ruby ri rdoc libyaml-ruby libzlib-ruby build-essential libopenssl-ruby ruby1.8-dev rubygems ohai chef",
75
+ # "sudo gem install rake --no-rdoc --no-ri",
76
+ # "sudo /etc/init.d/chef-client stop",
77
+ # "sudo chef-solo"]
78
+ end
79
+ end
80
+
81
+
82
+ # The Ubuntu 8.04 Linux distro
83
+ class Ubuntu804 < Ubuntu
84
+ def initialize(etc_issue_str)
85
+ super(etc_issue_str)
86
+ # Package install (0.7!)
87
+ # The native package installs install Chef 0.7, not the newest 0.8. Must use rubygem install for now
88
+ # @chef_install_script =
89
+ # ["sudo apt-get -y dist-upgrade",
90
+ # "sudo sh -c \"echo deb http://apt.opscode.com/ hardy universe > /etc/apt/sources.list.d/opscode.list\"",
91
+ # "curl http://apt.opscode.com/packages@opscode.com.gpg.key | sudo apt-key add -",
92
+ # "sudo apt-get -y update",
93
+ # "sudo aptitude -y install ruby ri rdoc libyaml-ruby libzlib-ruby build-essential libopenssl-ruby ruby1.8-dev rubygems ohai chef",
94
+ # "sudo gem install rake --no-rdoc --no-ri",
95
+ # "sudo /etc/init.d/chef-client stop",
96
+ # "sudo chef-solo"]
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,36 @@
1
+ require 'maestro/validator'
2
+
3
+ module Maestro
4
+ # A role that a Node in a Cloud can play
5
+ class Role
6
+ include Validator
7
+
8
+ # the name of this Role
9
+ attr_reader :name
10
+ # the Cloud this Role belongs to
11
+ attr_reader :cloud
12
+ dsl_property :public_ports
13
+
14
+ def initialize(name, cloud, &block)
15
+ super()
16
+ raise StandardError, "Role name cannot contain spaces: #{name}" if name.is_a?(String) && !name.index(/\s/).nil?
17
+ @name = name
18
+ @cloud = cloud
19
+ instance_eval(&block) if block_given?
20
+ end
21
+
22
+ private
23
+
24
+ # validates this Role
25
+ def validate_internal
26
+ if !public_ports.nil?
27
+ if !public_ports.instance_of? Array
28
+ invalidate "'#{@name}' Role's public_ports attribute must be an Array (found #{public_ports.class})"
29
+ else
30
+ valid_ports = public_ports.all? {|port| port.instance_of? Fixnum}
31
+ invalidate "'#{@name}' Role's public_ports attribute must be an Array of numbers" if !valid_ports
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end