hubcap 0.0.3 → 0.0.4
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 +1 -0
- data/README.md +79 -72
- data/lib/hubcap/group.rb +24 -2
- data/lib/hubcap/recipes/puppet.rb +1 -1
- data/lib/hubcap/recipes/servers.rb +7 -0
- data/lib/hubcap/server.rb +7 -1
- data/lib/hubcap/version.rb +1 -1
- data/test/unit/test_server.rb +100 -0
- metadata +2 -2
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -17,23 +17,25 @@ derive from decentralization and pushing changes on-demand.)
|
|
17
17
|
|
18
18
|
Here's a really simple infrastructure configuration file:
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
20
|
+
```ruby
|
21
|
+
group('us') {
|
22
|
+
server('app.example.com') {
|
23
|
+
role(:app)
|
24
|
+
cap_attribute(:primary => true)
|
25
|
+
}
|
26
|
+
server('db.example.com') {
|
27
|
+
role(:db)
|
28
|
+
cap_attribute(:no_release => true)
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
group('au') {
|
33
|
+
server('example.com.au') {
|
34
|
+
role(:app, :db)
|
35
|
+
cap_attribute(:primary => true)
|
36
|
+
}
|
37
|
+
}
|
38
|
+
```
|
37
39
|
|
38
40
|
Using this config, you could tell Capistrano to deploy to all servers, servers
|
39
41
|
in one group, or just a single server.
|
@@ -42,54 +44,55 @@ Here's a more advanced example - an application that can be deployed to a set
|
|
42
44
|
of *staging* servers or a larger set of *production* servers. It has special
|
43
45
|
parameters that Puppet will use.
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
47
|
+
```ruby
|
48
|
+
# An application called 'readme' that uses Cap's default deployment recipe.
|
49
|
+
application('readme', :recipes => 'deploy') {
|
50
|
+
# Set a capistrano variable.
|
51
|
+
cap_set('repository', 'git@github.com:joseph/readme.git')
|
52
|
+
|
53
|
+
# Declare that all servers will have the 'baseline' puppet class.
|
54
|
+
role(:puppet => 'baseline')
|
55
|
+
|
56
|
+
group('staging') {
|
57
|
+
# Puppet gets a $::exception_subject_prefix variable on these servers.
|
58
|
+
param('exception_subject_prefix' => '[STAGING] ')
|
59
|
+
# For simple staging, just one server that does everything.
|
60
|
+
server('readme.stage') {
|
61
|
+
role(:cap => [:web, :app, :db], :puppet => ['proxy', 'app', 'db'])
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
group('production') {
|
66
|
+
# Puppet gets these top-scope variables on servers in this group.
|
67
|
+
param(
|
68
|
+
'exception_subject_prefix' => '[PRODUCTION] ',
|
69
|
+
'env' => {
|
70
|
+
'FORCE_SSL' => true,
|
71
|
+
'S3_KEY' => 'AKIAKJRK23943202JK',
|
72
|
+
'S3_SECRET' => 'KDJkaddsalkjfkawjri32jkjaklvjgakljkj'
|
60
73
|
}
|
74
|
+
)
|
61
75
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
'env' => {
|
67
|
-
'FORCE_SSL' => true,
|
68
|
-
'S3_KEY' => 'AKIAKJRK23943202JK',
|
69
|
-
'S3_SECRET' => 'KDJkaddsalkjfkawjri32jkjaklvjgakljkj'
|
70
|
-
}
|
71
|
-
)
|
72
|
-
|
73
|
-
group('proxy') {
|
74
|
-
# Servers will have the :web role and the 'proxy' puppet class.
|
75
|
-
role(:cap => :web, :puppet => 'proxy')
|
76
|
-
server('proxy-1', :address => '10.10.10.5')
|
77
|
-
}
|
78
|
-
|
79
|
-
group('app') {
|
80
|
-
# Servers will have the :app role and the 'app' puppet class.
|
81
|
-
role(:app)
|
82
|
-
server('app-1', :address => '10.10.10.10')
|
83
|
-
server('app-2', :address => '10.10.10.11')
|
84
|
-
}
|
85
|
-
|
86
|
-
group('db') {
|
87
|
-
role(:db)
|
88
|
-
server('db-1', :address => '10.10.10.50')
|
89
|
-
}
|
90
|
-
}
|
76
|
+
group('proxy') {
|
77
|
+
# Servers will have the :web role and the 'proxy' puppet class.
|
78
|
+
role(:cap => :web, :puppet => 'proxy')
|
79
|
+
server('proxy-1', :address => '10.10.10.5')
|
91
80
|
}
|
92
81
|
|
82
|
+
group('app') {
|
83
|
+
# Servers will have the :app role and the 'app' puppet class.
|
84
|
+
role(:app)
|
85
|
+
server('app-1', :address => '10.10.10.10')
|
86
|
+
server('app-2', :address => '10.10.10.11')
|
87
|
+
}
|
88
|
+
|
89
|
+
group('db') {
|
90
|
+
role(:db)
|
91
|
+
server('db-1', :address => '10.10.10.50')
|
92
|
+
}
|
93
|
+
}
|
94
|
+
}
|
95
|
+
```
|
93
96
|
|
94
97
|
Save this as `example.rb` in a `hub` subdirectory of the location of your
|
95
98
|
`Capfile`.
|
@@ -167,8 +170,10 @@ http://docs.puppetlabs.com/guides/external_nodes.html
|
|
167
170
|
If you'd rather run `cap` than `hubcap`, you can load your hub configuration
|
168
171
|
directly in your `Capfile`. Add this to the end of the file:
|
169
172
|
|
170
|
-
|
171
|
-
|
173
|
+
```ruby
|
174
|
+
require('hubcap')
|
175
|
+
Hubcap.load('', 'hub').configure_capistrano(self)
|
176
|
+
```
|
172
177
|
|
173
178
|
The two arguments to `Hubcap.load` are the filter (where `''` means no filter),
|
174
179
|
and the path to the hub configuration. This will load `*.rb` in the `hub`
|
@@ -178,15 +183,17 @@ arguments -- whole directories or specific files.
|
|
178
183
|
If you want to simulate the behaviour of the `hubcap` script, you could do it
|
179
184
|
with something like this in your `Capfile`.
|
180
185
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
186
|
+
```ruby
|
187
|
+
# Load servers and sets from node config. Any recipes loaded after this
|
188
|
+
# point will be available only in application mode.
|
189
|
+
if (target = ENV['TO']) && !ENV['TO'].empty?
|
190
|
+
target = '' if target == 'ALL'
|
191
|
+
require('hubcap')
|
192
|
+
Hubcap.load(target, 'hub').configure_capistrano(self)
|
193
|
+
else
|
194
|
+
warn('NB: No servers specified. Target a Hubcap group with TO.')
|
195
|
+
end
|
196
|
+
```
|
190
197
|
|
191
198
|
In this set-up, you'd run `cap` like this:
|
192
199
|
|
data/lib/hubcap/group.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
class Hubcap::Group
|
2
2
|
|
3
|
+
IP_PATTERN = /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/
|
4
|
+
|
3
5
|
attr_reader(:name, :parent, :children)
|
4
6
|
|
5
7
|
# Supply the parent group, the name of this new group and a block of code to
|
@@ -198,7 +200,7 @@ class Hubcap::Group
|
|
198
200
|
# the IP of a hostname just for a child-group, you can (but: caveat emptor).
|
199
201
|
#
|
200
202
|
def host(hash)
|
201
|
-
@hosts
|
203
|
+
@hosts.update(hash)
|
202
204
|
end
|
203
205
|
|
204
206
|
|
@@ -232,13 +234,32 @@ class Hubcap::Group
|
|
232
234
|
#
|
233
235
|
def resolv(*hnames)
|
234
236
|
if hnames.size == 1
|
235
|
-
|
237
|
+
result = lookup(hnames.first)
|
238
|
+
result.match(IP_PATTERN) ? result : Resolv.getaddress(result)
|
236
239
|
else
|
237
240
|
hnames.collect { |hname| resolv(hname) }
|
238
241
|
end
|
239
242
|
end
|
240
243
|
|
241
244
|
|
245
|
+
# Dereferences the host name using the @hosts table. Follows references.
|
246
|
+
# Returns the first value that looks like an IP address OR that it can't
|
247
|
+
# find in the table. (So, if there's no match, you just get the name back.
|
248
|
+
#
|
249
|
+
def lookup(hname, history = [])
|
250
|
+
return hname if hname.match(IP_PATTERN)
|
251
|
+
result = hosts[hname]
|
252
|
+
if !result
|
253
|
+
return hname
|
254
|
+
elsif history.include?(result)
|
255
|
+
raise(Hubcap::HostCircularReference, history.to_s)
|
256
|
+
else
|
257
|
+
history << hname
|
258
|
+
lookup(result, history)
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
|
242
263
|
# Instantiate an application as a child of this group.
|
243
264
|
#
|
244
265
|
def application(name, options = {}, &blk)
|
@@ -301,5 +322,6 @@ class Hubcap::Group
|
|
301
322
|
|
302
323
|
class Hubcap::GroupWithoutParent < StandardError; end
|
303
324
|
class Hubcap::InvalidParamKeyType < StandardError; end
|
325
|
+
class Hubcap::HostCircularReference < StandardError; end
|
304
326
|
|
305
327
|
end
|
@@ -55,7 +55,7 @@ Capistrano::Configuration.instance(:must_exist).load do
|
|
55
55
|
'echo "Ruby 1.9 verified";',
|
56
56
|
'else',
|
57
57
|
"#{apt_cmd} update;",
|
58
|
-
"#{apt_cmd} install ruby1.9.1 ruby1.9.1-dev git-core;",
|
58
|
+
"#{apt_cmd} install ruby1.9.1 ruby1.9.1-dev git-core build-essential;",
|
59
59
|
'fi'
|
60
60
|
].join(' '))
|
61
61
|
|
data/lib/hubcap/server.rb
CHANGED
@@ -4,8 +4,14 @@ class Hubcap::Server < Hubcap::Group
|
|
4
4
|
|
5
5
|
|
6
6
|
def initialize(parent, name, options = {}, &blk)
|
7
|
-
@address = options[:address] || name
|
8
7
|
super(parent, name, &blk)
|
8
|
+
# If name is an IP, or is not in hosts hash, use name as address
|
9
|
+
# Otherwise, dereference it from the hash and assign it
|
10
|
+
unless @address = options[:address]
|
11
|
+
hist = history.join('.')
|
12
|
+
@address = lookup(hist)
|
13
|
+
@address = lookup(name) if @address == hist
|
14
|
+
end
|
9
15
|
end
|
10
16
|
|
11
17
|
|
data/lib/hubcap/version.rb
CHANGED
data/test/unit/test_server.rb
CHANGED
@@ -66,4 +66,104 @@ class Hubcap::TestServer < Test::Unit::TestCase
|
|
66
66
|
assert_equal([1, 2], hash['parameters'].values.sort)
|
67
67
|
end
|
68
68
|
|
69
|
+
|
70
|
+
def test_host_lookup_single_level
|
71
|
+
hub = Hubcap.hub {
|
72
|
+
host('test' => '0.0.0.0')
|
73
|
+
server('test')
|
74
|
+
}
|
75
|
+
assert_equal('0.0.0.0', hub.servers.first.address)
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def test_host_lookup_multiple_levels
|
80
|
+
hub = Hubcap.hub {
|
81
|
+
host('g1.t1' => '1.1.1.1')
|
82
|
+
host('g1.a1.t2' => '2.2.2.2')
|
83
|
+
group('g1') {
|
84
|
+
server('t1')
|
85
|
+
application('a1') {
|
86
|
+
server('t2')
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
assert_equal('1.1.1.1', hub.servers[0].address)
|
91
|
+
assert_equal('2.2.2.2', hub.servers[1].address)
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def test_host_lookup_where_name_is_ip
|
96
|
+
hub = Hubcap.hub {
|
97
|
+
host(
|
98
|
+
'foo' => '255.255.255.255',
|
99
|
+
'1.1.1.1' => '255.255.255.254'
|
100
|
+
)
|
101
|
+
server('1.1.1.1')
|
102
|
+
}
|
103
|
+
assert_equal('1.1.1.1', hub.servers.first.address)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def test_host_lookup_where_name_is_not_in_hosts
|
108
|
+
hub = Hubcap.hub {
|
109
|
+
host(
|
110
|
+
'foo.bar.com' => '255.255.255.255',
|
111
|
+
'baz.bar.com' => '255.255.255.254'
|
112
|
+
)
|
113
|
+
server('garply.bar.com')
|
114
|
+
}
|
115
|
+
assert_equal('garply.bar.com', hub.servers.first.address)
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
def test_host_lookup_dereferencing
|
120
|
+
hub = Hubcap.hub {
|
121
|
+
host('some.other.thing' => '1.1.1.1')
|
122
|
+
group('g1') {
|
123
|
+
host('g1.t1' => 'some.other.thing')
|
124
|
+
server('t1')
|
125
|
+
}
|
126
|
+
}
|
127
|
+
assert_equal('1.1.1.1', hub.servers.first.address)
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
def test_host_lookup_handle_circular_reference
|
132
|
+
assert_raises(Hubcap::HostCircularReference) {
|
133
|
+
hub = Hubcap.hub {
|
134
|
+
host('some.other.thing' => 'g1.t1')
|
135
|
+
group('g1') {
|
136
|
+
host('g1.t1' => 'some.other.thing')
|
137
|
+
server('t1')
|
138
|
+
}
|
139
|
+
}
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
def test_host_lookup_where_hosts_is_overridden_in_subgroup
|
145
|
+
hub = Hubcap.hub {
|
146
|
+
host('g1.t1' => '2.2.2.2')
|
147
|
+
group('g1') {
|
148
|
+
host('g1.t1' => '1.1.1.1')
|
149
|
+
server('t1')
|
150
|
+
}
|
151
|
+
}
|
152
|
+
assert_equal('1.1.1.1', hub.servers[0].address)
|
153
|
+
end
|
154
|
+
|
155
|
+
|
156
|
+
def test_resolv
|
157
|
+
hub = Hubcap.hub {
|
158
|
+
host('g1.t1' => '2.2.2.2')
|
159
|
+
group('g1') {
|
160
|
+
host('g1.t1' => '1.1.1.1')
|
161
|
+
server('t1')
|
162
|
+
}
|
163
|
+
server('t2', :address => resolv('g1.t1'))
|
164
|
+
}
|
165
|
+
assert_equal('1.1.1.1', hub.servers[0].address)
|
166
|
+
assert_equal('2.2.2.2', hub.servers[1].address)
|
167
|
+
end
|
168
|
+
|
69
169
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hubcap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-29 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Create a hub for your server configuration. Use it with Capistrano, Puppet
|
15
15
|
and others.
|