hubcap 0.0.1
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/Capfile.example +37 -0
- data/README.md +168 -0
- data/Rakefile +10 -0
- data/bin/hubcap +98 -0
- data/hubcap.gemspec +17 -0
- data/lib/hubcap/application.rb +24 -0
- data/lib/hubcap/group.rb +223 -0
- data/lib/hubcap/hub.rb +125 -0
- data/lib/hubcap/recipes/puppet.rb +176 -0
- data/lib/hubcap/recipes/servers.rb +21 -0
- data/lib/hubcap/server.rb +46 -0
- data/lib/hubcap/version.rb +5 -0
- data/lib/hubcap.rb +29 -0
- data/test/data/example.rb +68 -0
- data/test/data/parts/foo_param.rb +1 -0
- data/test/data/readme.rb +47 -0
- data/test/data/simple.rb +4 -0
- data/test/test_helper.rb +2 -0
- data/test/unit/test_application.rb +20 -0
- data/test/unit/test_group.rb +176 -0
- data/test/unit/test_hub.rb +104 -0
- data/test/unit/test_hubcap.rb +39 -0
- data/test/unit/test_server.rb +69 -0
- metadata +94 -0
@@ -0,0 +1,176 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
namespace(:puppet) do
|
4
|
+
|
5
|
+
unless exists?(:puppet_repository)
|
6
|
+
set(:puppet_repository) { raise "Required variable: puppet_repository" }
|
7
|
+
end
|
8
|
+
set(:puppet_branch, 'master')
|
9
|
+
set(:puppet_path, '/var/www/provision/puppet')
|
10
|
+
set(:puppet_git_password) { Capistrano::CLI.password_prompt }
|
11
|
+
set(:puppet_manifest_path) { "#{puppet_path}/puppet/host.pp" }
|
12
|
+
set(:puppet_modules_path) { "#{puppet_path}/puppet/modules" }
|
13
|
+
set(:puppet_yaml_path) { "#{puppet_path}/puppet/host.yaml" }
|
14
|
+
set(:puppet_enc_path) { "#{puppet_path}/puppet/enc" }
|
15
|
+
set(:puppet_enc) { "#!/bin/sh\ncat '#{puppet_yaml_path}'" }
|
16
|
+
set(:puppet_parameters, '--no-report')
|
17
|
+
|
18
|
+
|
19
|
+
desc <<-DESC
|
20
|
+
Calls 'check' and 'update' and 'properties', which means it performs a
|
21
|
+
check for the necessary puppet dependencies, deploys the puppet scripts
|
22
|
+
via git, then pushes up a special yaml file describing the properties of
|
23
|
+
this particular server.
|
24
|
+
DESC
|
25
|
+
task(:freshen) do
|
26
|
+
check
|
27
|
+
update
|
28
|
+
properties
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
desc <<-DESC
|
33
|
+
Looks for Ruby 1.9 on the server. Installs it (and git-core) if not found.
|
34
|
+
Also looks for Puppet 3.0 gem on the server, and installs it if not found.
|
35
|
+
DESC
|
36
|
+
task(:check) do
|
37
|
+
unless exists?(:hubcap_agnostic)
|
38
|
+
raise "Hubcap has not configured this Capistrano instance."
|
39
|
+
end
|
40
|
+
unless hubcap_agnostic
|
41
|
+
raise "Puppet tasks are not available in Hubcap application mode"
|
42
|
+
end
|
43
|
+
|
44
|
+
apt_cmd = [
|
45
|
+
"env",
|
46
|
+
"DEBCONF_TERSE='yes'",
|
47
|
+
"DEBIAN_PRIORITY='critical'",
|
48
|
+
"DEBIAN_FRONTEND=noninteractive",
|
49
|
+
"apt-get --force-yes -qyu"
|
50
|
+
].join(" ")
|
51
|
+
|
52
|
+
# Because Ubuntu is weird, the 1.9.1 package installs Ruby 1.9.3-p0.
|
53
|
+
sudo_bash([
|
54
|
+
'if [[ `which ruby` && (`ruby -v` =~ "ruby 1.9") ]]; then',
|
55
|
+
'echo "Ruby 1.9 verified";',
|
56
|
+
'else',
|
57
|
+
"#{apt_cmd} update;",
|
58
|
+
"#{apt_cmd} install ruby1.9.1 git-core;",
|
59
|
+
'fi'
|
60
|
+
].join(' '))
|
61
|
+
|
62
|
+
# 3.0.0-rc5 is the last version that a) runs on Ruby 1.9 and b) works.
|
63
|
+
ppt_ver = '3.0.0.rc5'
|
64
|
+
sudo_bash([
|
65
|
+
"if [[ `gem q -i -n \"^puppet$\" -v #{ppt_ver}` =~ \"true\" ]]; then",
|
66
|
+
'echo "Puppet verified";',
|
67
|
+
'else',
|
68
|
+
"gem install puppet -v #{ppt_ver} --pre --no-rdoc --no-ri;",
|
69
|
+
'fi'
|
70
|
+
].join(' '))
|
71
|
+
|
72
|
+
# Workaround for: http://projects.puppetlabs.com/issues/9862
|
73
|
+
sudo_bash([
|
74
|
+
'if [[ `egrep -i "^puppet" /etc/group` =~ "puppet" ]]; then',
|
75
|
+
'echo "Puppet group exists";',
|
76
|
+
'else',
|
77
|
+
'groupadd puppet;',
|
78
|
+
'fi'
|
79
|
+
].join(' '))
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
desc <<-DESC
|
84
|
+
Basically, this pulls down your puppet scripts so you can run them.
|
85
|
+
It does this by cloning the Hubcap repository to each server (if necessary),
|
86
|
+
then fetching the latest code and resetting to the HEAD of the
|
87
|
+
specified branch.
|
88
|
+
DESC
|
89
|
+
task(:update) do
|
90
|
+
handle_data = lambda { |channel, stream, text|
|
91
|
+
host = channel[:host]
|
92
|
+
logger.info "[#{host} :: #{stream}] #{text}"
|
93
|
+
out = case text
|
94
|
+
when /\bpassword.*:/i, /passphrase/i # Git password or SSH passphrase.
|
95
|
+
"#{puppet_git_password}\n"
|
96
|
+
when %r{\(yes/no\)} # Should git connect?
|
97
|
+
"yes\n"
|
98
|
+
when /accept \(t\)emporarily/ # Should git accept certificate?
|
99
|
+
"t\n"
|
100
|
+
end
|
101
|
+
channel.send_data(out) if out
|
102
|
+
}
|
103
|
+
sudo("mkdir -p #{File.dirname(puppet_path)}")
|
104
|
+
sudo("chown #{user} #{File.dirname(puppet_path)}")
|
105
|
+
run(
|
106
|
+
"[ -d #{puppet_path} ] || git clone #{puppet_repository} #{puppet_path}",
|
107
|
+
:shell => nil,
|
108
|
+
&handle_data
|
109
|
+
)
|
110
|
+
run(
|
111
|
+
[
|
112
|
+
"cd #{puppet_path}",
|
113
|
+
"git fetch origin",
|
114
|
+
"git reset --hard origin/#{puppet_branch}"
|
115
|
+
].join(' && '),
|
116
|
+
:shell => nil,
|
117
|
+
&handle_data
|
118
|
+
)
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
desc <<-DESC
|
123
|
+
Pushes a YAML file containing all the classes and parameters that Puppet
|
124
|
+
needs to know about in order to provision this server. Each file is
|
125
|
+
server-specific.
|
126
|
+
DESC
|
127
|
+
task(:properties) do
|
128
|
+
hubcap.servers.each { |s|
|
129
|
+
put(s.yaml, puppet_yaml_path, :hosts => s.address)
|
130
|
+
}
|
131
|
+
put(puppet_enc, puppet_enc_path)
|
132
|
+
run("chmod +x #{puppet_enc_path}")
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
desc <<-DESC
|
137
|
+
Tells you what would happen if you ran puppet:apply. This is a safe way
|
138
|
+
to test your changes.
|
139
|
+
DESC
|
140
|
+
task(:noop) do
|
141
|
+
run_puppet('--noop')
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
desc <<-DESC
|
146
|
+
Runs the puppet scripts on each server. Be careful!
|
147
|
+
DESC
|
148
|
+
task(:apply) do
|
149
|
+
run_puppet
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def sudo_bash(cmd, options = {}, &blk)
|
154
|
+
sudo("/bin/bash -c \'#{cmd}\'", options, &blk)
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
def run_puppet(params = nil)
|
159
|
+
sudo([
|
160
|
+
"puppet apply",
|
161
|
+
"--node_terminus exec",
|
162
|
+
"--external_nodes '#{puppet_enc_path}'",
|
163
|
+
"--modulepath '#{puppet_modules_path}'",
|
164
|
+
puppet_parameters,
|
165
|
+
params,
|
166
|
+
"'#{puppet_manifest_path}'"
|
167
|
+
].compact.join(' '))
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
before('puppet:noop', 'puppet:freshen')
|
172
|
+
before('puppet:apply', 'puppet:freshen')
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
namespace(:servers) do
|
4
|
+
|
5
|
+
desc <<-DESC
|
6
|
+
Lists all the servers that match the filter used when Hubcap was loaded.
|
7
|
+
DESC
|
8
|
+
task(:list) do
|
9
|
+
puts(hubcap.servers.collect(&:tree))
|
10
|
+
end
|
11
|
+
|
12
|
+
desc <<-DESC
|
13
|
+
Show the entire Hubcap configuration tree for the given filter.
|
14
|
+
DESC
|
15
|
+
task(:tree) do
|
16
|
+
puts(hubcap.tree)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
class Hubcap::Server < Hubcap::Group
|
2
|
+
|
3
|
+
attr_reader(:address)
|
4
|
+
|
5
|
+
|
6
|
+
def initialize(parent, name, options = {}, &blk)
|
7
|
+
@address = options[:address] || name
|
8
|
+
super(parent, name, &blk)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def application(*args)
|
13
|
+
raise(Hubcap::ServerSubgroupDisallowed, 'application')
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def server(*args)
|
18
|
+
raise(Hubcap::ServerSubgroupDisallowed, 'server')
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def group(*args)
|
23
|
+
raise(Hubcap::ServerSubgroupDisallowed, 'group')
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def application_parent
|
28
|
+
p = self
|
29
|
+
while p && p != hub
|
30
|
+
return p if p.kind_of?(Hubcap::Application)
|
31
|
+
p = p.instance_variable_get(:@parent)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def yaml
|
37
|
+
{
|
38
|
+
'classes' => @puppet_roles.collect(&:to_s),
|
39
|
+
'parameters' => @params
|
40
|
+
}.to_yaml
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
class Hubcap::ServerSubgroupDisallowed < StandardError; end
|
45
|
+
|
46
|
+
end
|
data/lib/hubcap.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module Hubcap
|
4
|
+
|
5
|
+
def self.hub(filter_string = '', &blk)
|
6
|
+
Hubcap::Hub.new(filter_string).tap { |scope| scope.instance_eval(&blk) }
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
def self.load(filter_string, *paths)
|
11
|
+
Hubcap::Hub.new(filter_string).tap { |scope|
|
12
|
+
while paths.any?
|
13
|
+
path = paths.shift
|
14
|
+
if File.directory?(path)
|
15
|
+
paths += Dir.glob(File.join(path, '*.rb'))
|
16
|
+
else
|
17
|
+
scope.absorb(path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
require 'hubcap/group'
|
27
|
+
require 'hubcap/application'
|
28
|
+
require 'hubcap/server'
|
29
|
+
require 'hubcap/hub'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
application('example', :recipes => 'deploy') {
|
2
|
+
|
3
|
+
# These cap settings will apply to all the servers within this application
|
4
|
+
# group or any subgroups. (The same applies for roles, attributes, etc.)
|
5
|
+
cap_set(:repository, 'git@github.com:example/example.git')
|
6
|
+
cap_set(:branch, 'master')
|
7
|
+
|
8
|
+
# Load some ssh keys into param() from a separate (more secure?) file.
|
9
|
+
# These will be handed to your puppet scripts.
|
10
|
+
#absorb('nodes/private/admin_ssh_keys')
|
11
|
+
|
12
|
+
# Just a normal Ruby hash var we can reuse throughout the config.
|
13
|
+
common_env = {
|
14
|
+
'PGUSER' => 'example',
|
15
|
+
'RABBIT_URI' => 'amqp://example:password@localhost:54322'
|
16
|
+
}
|
17
|
+
|
18
|
+
# A local dev simulation.
|
19
|
+
group('vagrant') {
|
20
|
+
param('env' => common_env.merge('PGPASSWORD' => 'password'))
|
21
|
+
server('127.0.0.1:2222') {
|
22
|
+
role(:app, :db, :queue)
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
# Your staging environment.
|
27
|
+
group('staging') {
|
28
|
+
param('env' => common_env.merge(
|
29
|
+
'PGPASSWORD' => 'pa55w3rd',
|
30
|
+
'PGHOST' => '10.10.10.20',
|
31
|
+
'RABBIT_URI' => 'amqp://example:pa55w3rd@10.10.10.20'
|
32
|
+
))
|
33
|
+
server('app', :address => '10.10.10.10') {
|
34
|
+
role(:app)
|
35
|
+
}
|
36
|
+
server('db', :address => '10.10.10.15') {
|
37
|
+
role(:db)
|
38
|
+
}
|
39
|
+
server('queue', :address => '10.10.10.20') {
|
40
|
+
role(:queue)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
# Your production environment.
|
45
|
+
group('production') {
|
46
|
+
prod_env = common_env.merge(
|
47
|
+
'PGPASSWORD' => '1391f3a24daef0c78f75cbef9d62eb848c2d454c71a5fd2a',
|
48
|
+
'PGHOST' => '20.20.20.20',
|
49
|
+
'RABBIT_URI' => 'amqp://example:e18edfa58fa6c5d3a9a@20.20.20.30'
|
50
|
+
)
|
51
|
+
param('env' => prod_env)
|
52
|
+
group('app') {
|
53
|
+
role(:app)
|
54
|
+
param('env' => prod_env.merge('FORCE_SSL' => '1'))
|
55
|
+
server('app-1.example.com')
|
56
|
+
server('app-2.example.com')
|
57
|
+
server('app-3.example.com')
|
58
|
+
}
|
59
|
+
group('db') {
|
60
|
+
role(:db)
|
61
|
+
server('db-1.example.com')
|
62
|
+
server('db-2.example.com')
|
63
|
+
}
|
64
|
+
server('queue-1.example.com') {
|
65
|
+
role(:queue)
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
param(:foo => 'foo')
|
data/test/data/readme.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# An application called 'readme' that uses Cap's default deployment recipe.
|
2
|
+
application('readme', :recipes => 'deploy') {
|
3
|
+
# Set a capistrano variable.
|
4
|
+
cap_set('repository', 'git@github.com:joseph/readme.git')
|
5
|
+
|
6
|
+
# Declare that all servers will have the 'baseline' puppet class.
|
7
|
+
role(:puppet => 'baseline')
|
8
|
+
|
9
|
+
group('staging') {
|
10
|
+
# Puppet will have a $::exception_subject_prefix variable on these servers.
|
11
|
+
param('exception_subject_prefix' => '[STAGING] ')
|
12
|
+
# For simple staging, just one server that does everything.
|
13
|
+
server('readme.stage') {
|
14
|
+
role(:cap => [:web, :app, :db], :puppet => ['proxy', 'app', 'db'])
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
group('production') {
|
19
|
+
# Puppet will have these top-scope variables on all these servers.
|
20
|
+
param(
|
21
|
+
'exception_subject_prefix' => '[PRODUCTION] ',
|
22
|
+
'env' => {
|
23
|
+
"FORCE_SSL" => true,
|
24
|
+
"S3_KEY" => "AKIAKJRK23943202JK",
|
25
|
+
"S3_SECRET" => "KDJkaddsalkjfkawjri32jkjaklvjgakljkj"
|
26
|
+
}
|
27
|
+
)
|
28
|
+
|
29
|
+
group('proxy') {
|
30
|
+
# Servers will have the :web role and the 'proxy' puppet class.
|
31
|
+
role(:cap => :web, :puppet => 'proxy')
|
32
|
+
server('proxy-1', :address => '10.10.10.5')
|
33
|
+
}
|
34
|
+
|
35
|
+
group('app') {
|
36
|
+
# Servers will have the :app role and the 'app' puppet class.
|
37
|
+
role(:app)
|
38
|
+
server('app-1', :address => '10.10.10.10')
|
39
|
+
server('app-2', :address => '10.10.10.11')
|
40
|
+
}
|
41
|
+
|
42
|
+
group('db') {
|
43
|
+
role(:db)
|
44
|
+
server('db-1', :address => '10.10.10.50')
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
data/test/data/simple.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Hubcap::TestApplication < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_recipe_paths
|
6
|
+
hub = Hubcap.hub { application('test', :recipes => 'foo') }
|
7
|
+
assert_equal(['foo'], hub.applications.first.recipe_paths)
|
8
|
+
|
9
|
+
hub = Hubcap.hub { application('test', :recipes => ['foo', 'bar']) }
|
10
|
+
assert_equal(['foo', 'bar'], hub.applications.first.recipe_paths)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
def test_nested_application_disallowed
|
15
|
+
assert_raises(Hubcap::NestedApplicationDisallowed) {
|
16
|
+
Hubcap.hub { application('test') { application('child') } }
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class Hubcap::TestGroup < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_name
|
6
|
+
hub = Hubcap.hub { group('test') }
|
7
|
+
assert_equal('test', hub.groups.first.name)
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def test_hub
|
12
|
+
hub = Hubcap.hub { group('test') }
|
13
|
+
assert_equal(hub, hub.groups.first.hub)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
def test_must_have_parent_unless_hub
|
18
|
+
assert_raises(Hubcap::GroupWithoutParent) { Hubcap::Group.new(nil, 'foo') }
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def test_history
|
23
|
+
hub = Hubcap.hub { group('test') { group('child') } }
|
24
|
+
assert_equal(['test'], hub.children.first.history)
|
25
|
+
assert_equal(['test', 'child'], hub.children.first.children.first.history)
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def test_absorb
|
30
|
+
hub = Hubcap.hub {
|
31
|
+
group('test') { absorb('test/data/parts/foo_param') }
|
32
|
+
}
|
33
|
+
assert_equal('foo', hub.groups.first.params[:foo])
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def test_processable_and_collectable
|
38
|
+
x = {}
|
39
|
+
hub = Hubcap.hub('g1.a1') {
|
40
|
+
x[:g1] = group('g1') {
|
41
|
+
x[:a1] = application('a1') {
|
42
|
+
x[:s1] = server('s1')
|
43
|
+
}
|
44
|
+
x[:a2] = application('a2') {
|
45
|
+
x[:s2] = server('s2')
|
46
|
+
}
|
47
|
+
}
|
48
|
+
x[:g2] = group('g2') {
|
49
|
+
x[:a3] = application('a3') {
|
50
|
+
x[:s3] = server('s3')
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
assert_equal(true, x[:g1].processable?)
|
55
|
+
assert_equal(false, x[:g1].collectable?)
|
56
|
+
assert_equal(true, x[:a1].processable?)
|
57
|
+
assert_equal(true, x[:a1].collectable?)
|
58
|
+
assert_equal(true, x[:s1].processable?)
|
59
|
+
assert_equal(true, x[:s1].collectable?)
|
60
|
+
assert_equal(false, x[:g2].processable?)
|
61
|
+
assert_equal(false, x[:g2].collectable?)
|
62
|
+
assert_nil(x[:a3])
|
63
|
+
assert_nil(x[:s3])
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def test_cap_set
|
68
|
+
# Single value, as key, val arguments
|
69
|
+
hub = Hubcap.hub { group('test') { cap_set(:foo, 'bar') } }
|
70
|
+
assert_equal('bar', hub.cap_sets[:foo])
|
71
|
+
|
72
|
+
# Single value, as one hash argument
|
73
|
+
hub = Hubcap.hub { group('test') { cap_set('baz' => 'yyy') } }
|
74
|
+
assert_equal('yyy', hub.cap_sets['baz'])
|
75
|
+
|
76
|
+
# Multiple values
|
77
|
+
hub = Hubcap.hub { group('test') { cap_set(:a => 1, :z => 0) } }
|
78
|
+
assert_equal(1, hub.cap_sets[:a])
|
79
|
+
assert_equal(0, hub.cap_sets[:z])
|
80
|
+
|
81
|
+
# Lazily-evaluated block
|
82
|
+
hub = Hubcap.hub { group('test') { cap_set(:blk) { 'garply' } } }
|
83
|
+
assert_equal('garply', hub.cap_sets[:blk].call)
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
def test_cap_attribute
|
88
|
+
# Single value as key, val arguments
|
89
|
+
hub = Hubcap.hub { server('test') { cap_attribute(:foo, 'bar') } }
|
90
|
+
assert_equal({ :foo => 'bar' }, hub.servers.first.cap_attributes)
|
91
|
+
|
92
|
+
# Single value as hash
|
93
|
+
hub = Hubcap.hub { server('test') { cap_attribute(:foo => 'bar') } }
|
94
|
+
assert_equal({ :foo => 'bar' }, hub.servers.first.cap_attributes)
|
95
|
+
|
96
|
+
# Multiple values
|
97
|
+
hub = Hubcap.hub { server('test') { cap_attribute(:a => 1, :z => 0) } }
|
98
|
+
assert_equal({ :a => 1, :z => 0 }, hub.servers.first.cap_attributes)
|
99
|
+
|
100
|
+
# Cap attributes are additive down the tree
|
101
|
+
hub = Hubcap.hub {
|
102
|
+
group('g') {
|
103
|
+
cap_attribute(:excellent => true)
|
104
|
+
server('s') { cap_attribute(:modest => false) }
|
105
|
+
}
|
106
|
+
}
|
107
|
+
assert_equal({ :excellent => true }, hub.groups.first.cap_attributes)
|
108
|
+
assert_equal(
|
109
|
+
{ :excellent => true, :modest => false },
|
110
|
+
hub.servers.first.cap_attributes
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
def test_role
|
116
|
+
# Single role
|
117
|
+
hub = Hubcap.hub {
|
118
|
+
role(:baseline)
|
119
|
+
server('test')
|
120
|
+
}
|
121
|
+
assert_equal([:baseline], hub.servers.first.cap_roles)
|
122
|
+
assert_equal([:baseline], hub.servers.first.puppet_roles)
|
123
|
+
|
124
|
+
# Multiple roles in a single declaration
|
125
|
+
hub = Hubcap.hub {
|
126
|
+
role(:baseline, :app)
|
127
|
+
server('test')
|
128
|
+
}
|
129
|
+
assert_equal([:baseline, :app], hub.servers.first.cap_roles)
|
130
|
+
assert_equal([:baseline, :app], hub.servers.first.puppet_roles)
|
131
|
+
|
132
|
+
# Multiple declarations are additive
|
133
|
+
hub = Hubcap.hub {
|
134
|
+
role(:baseline)
|
135
|
+
server('test') { role(:db) }
|
136
|
+
}
|
137
|
+
assert_equal([:baseline, :db], hub.servers.first.cap_roles)
|
138
|
+
assert_equal([:baseline, :db], hub.servers.first.puppet_roles)
|
139
|
+
|
140
|
+
# Separate cap and puppet roles
|
141
|
+
hub = Hubcap.hub {
|
142
|
+
role(:cap => :app, :puppet => 'testapp')
|
143
|
+
server('test')
|
144
|
+
}
|
145
|
+
assert_equal([:app], hub.servers.first.cap_roles)
|
146
|
+
assert_equal(['testapp'], hub.servers.first.puppet_roles)
|
147
|
+
|
148
|
+
# Separate cap/puppet roles can be defined with an array
|
149
|
+
# Also shows that multiple role declarations are additive
|
150
|
+
hub = Hubcap.hub {
|
151
|
+
role(:cap => [:app, :db])
|
152
|
+
server('test') { role(:baseline) }
|
153
|
+
}
|
154
|
+
assert_equal([:app, :db], hub.cap_roles)
|
155
|
+
assert_equal([], hub.puppet_roles)
|
156
|
+
assert_equal([:app, :db, :baseline], hub.servers.first.cap_roles)
|
157
|
+
assert_equal([:baseline], hub.servers.first.puppet_roles)
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
def test_param
|
162
|
+
# Single key/val.
|
163
|
+
hub = Hubcap.hub {
|
164
|
+
server('test') { param('foo' => 1) }
|
165
|
+
}
|
166
|
+
assert_equal(1, hub.servers.first.params['foo'])
|
167
|
+
|
168
|
+
# Multiple key/vals.
|
169
|
+
hub = Hubcap.hub {
|
170
|
+
server('test') { param('foo' => 1, 'baz' => 2) }
|
171
|
+
}
|
172
|
+
assert_equal(1, hub.servers.first.params['foo'])
|
173
|
+
assert_equal(2, hub.servers.first.params['baz'])
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|