dployr 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +53 -25
- data/lib/dployr/cli.rb +16 -16
- data/lib/dployr/compute/aws.rb +239 -0
- data/lib/dployr/scripts/shell.rb +0 -2
- data/lib/dployr/version.rb +1 -1
- metadata +2 -3
- data/lib/dployr/logger.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ccf10af60294e8d7c5e2edbe34f4bc1b2c2c3ea4
|
4
|
+
data.tar.gz: d1d72ea9459501658813c121fb4c3f05450d3d29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89d38a44d6797a60ae5e8593ca958244648dbeff3e33926c2e6e5f689626e05ea2b59f6a0922e26fd83ae1aeb3f73eec6a397b38e0098ab5cf38ed9a8d1c9284
|
7
|
+
data.tar.gz: 6ee5b85aef80f2a1c915ea3195139e9312bdcca676721ae37c843c578a452a8fd6d6b9777e6058bf9a789af6b49ebe4311cb2100d75009b17ccc24ef65cd7560
|
data/README.md
CHANGED
@@ -15,13 +15,17 @@
|
|
15
15
|
|
16
16
|
## About
|
17
17
|
|
18
|
-
**Dployr** is a Ruby utility that simplifies cloud management
|
19
|
-
and deployment across different providers
|
18
|
+
**Dployr** is a Ruby utility that **simplifies cloud management
|
19
|
+
and deployment** across different providers
|
20
20
|
|
21
|
-
You can setup your project cloud infraestructure from a
|
22
|
-
simple configuration file
|
21
|
+
You can setup all your project cloud infraestructure from a
|
22
|
+
simple configuration file and deploy it into multiple clouds easily
|
23
23
|
|
24
|
-
Dployr
|
24
|
+
Through Dployr you can take full control about the multiple stages phases
|
25
|
+
which covers the full deployment infrastructure workflow,
|
26
|
+
such as instances creation, network configuration, provisioning, testing and halting
|
27
|
+
|
28
|
+
It provides a featured [command-line interface](#command-line-interface) and [programmatic API](#programmatic-api)
|
25
29
|
|
26
30
|
## Installation
|
27
31
|
|
@@ -38,25 +42,34 @@ spec.add_dependency 'dployr', '~> 0.0.1'
|
|
38
42
|
gem 'dployr', '>= 0.0.1'
|
39
43
|
```
|
40
44
|
|
41
|
-
|
45
|
+
It requires Ruby `1.9.3+`
|
42
46
|
|
43
47
|
## Features
|
44
48
|
|
45
|
-
- Fully configurable from Ruby or YAML file with rich features like templating
|
46
|
-
-
|
49
|
+
- Fully configurable from Ruby or YAML file with built-in rich features like templating
|
50
|
+
- Simplifies deployment to multiple cloud providers
|
51
|
+
- Allows to create the same infraestructe into multiple cloud providers from one command
|
47
52
|
- Supports default instances and inherited configuration values
|
48
53
|
- Full control of virtual instances (start, restart, stop, test, provision)
|
49
|
-
-
|
54
|
+
- Allows to run local and remote scripts execution per stage with pre and post hooks
|
50
55
|
- Featured command-line and programmatic API
|
51
56
|
|
52
57
|
## Supported providers
|
53
58
|
|
54
|
-
|
59
|
+
Dployr is still a alpha project, so there are only a few providers supported
|
55
60
|
|
56
61
|
- Amazon Web Services (`aws`)
|
57
62
|
- Google Compute Engine (`gce`)
|
58
63
|
- Baremetal
|
59
64
|
|
65
|
+
Upcoming supported providers by priority
|
66
|
+
|
67
|
+
- OpenStack
|
68
|
+
- Verizon
|
69
|
+
- Azure
|
70
|
+
- Rackspace
|
71
|
+
- XenServer
|
72
|
+
|
60
73
|
## Configuration
|
61
74
|
|
62
75
|
Configuration file must be called `Dployrfile`. It can be also a standard Ruby file
|
@@ -69,13 +82,16 @@ Each configuration level supports the followings members:
|
|
69
82
|
- **attributes** `Object` Custom attributes to apply to the current template
|
70
83
|
- **scripts** `Object` Scripts hooks per phase to run (start, stop, test...)
|
71
84
|
- **providers** `Object` Nested configuration provider-specific (aws, gce...)
|
72
|
-
- **extends** `String|Array` Allows to inherits
|
85
|
+
- **extends** `String|Array` Allows to inherits from other template
|
73
86
|
|
74
87
|
#### Templating
|
75
88
|
|
76
|
-
Dployr allows templating features inside configuration values, in order
|
77
|
-
to provide an easy and clean way to dynamically replace values
|
78
|
-
|
89
|
+
Dployr allows templating powerful features inside configuration values, in order
|
90
|
+
to provide an easy, non-redundant and clean way to dynamically replace values for different usage contexts,
|
91
|
+
such as specific context cloud provider, deployment region or environment variables
|
92
|
+
|
93
|
+
Configuration templates can inherits from others templates,
|
94
|
+
so you can reuse environments for multiple projects or environments
|
79
95
|
|
80
96
|
Supported template values notations
|
81
97
|
|
@@ -251,14 +267,15 @@ Dployr API documentation is available from [RubyDoc][rubydoc]
|
|
251
267
|
|
252
268
|
### Configuration
|
253
269
|
|
270
|
+
Example Dployrfile in Ruby which uses the API to configure your project
|
254
271
|
```ruby
|
255
272
|
Dployr::configure do |dployr|
|
256
273
|
|
257
|
-
dployr.config.add_instance({
|
274
|
+
dployr.config.add_instance(:zeus, {
|
258
275
|
attributes: {
|
259
|
-
name: "example",
|
260
276
|
instance_type: "m1.small",
|
261
|
-
version: "${VERSION}"
|
277
|
+
version: "${VERSION}",
|
278
|
+
env: 'dev'
|
262
279
|
},
|
263
280
|
scripts: [
|
264
281
|
{ path: "configure.sh" }
|
@@ -266,18 +283,29 @@ Dployr::configure do |dployr|
|
|
266
283
|
providers: {
|
267
284
|
aws: {
|
268
285
|
attributes: {
|
269
|
-
|
270
|
-
|
271
|
-
|
286
|
+
ami: 'ami-370daf2a', # centos-base-v7
|
287
|
+
keypair: 'vagrant-aws-saopaulo',
|
288
|
+
security_groups: ['sg-3cf3e45e'],
|
289
|
+
subnet_id: 'subnet-1eebe07c'
|
290
|
+
public_ip: 'new'
|
272
291
|
},
|
273
292
|
regions: {
|
274
293
|
"eu-west-1a" => {
|
275
294
|
attributes: {
|
295
|
+
instance_type: "m1.medium",
|
276
296
|
keypair: "vagrant-aws-ireland"
|
277
297
|
},
|
278
|
-
scripts:
|
279
|
-
|
280
|
-
|
298
|
+
scripts: {
|
299
|
+
start: [
|
300
|
+
{ path: "router.sh", args: ["${name}", "${region}", "${provider}"] }
|
301
|
+
]
|
302
|
+
provision: [
|
303
|
+
{ path: "puppet.sh", args: ["${name}", "${region}", "${provider}", '--env %{env}'] }
|
304
|
+
]
|
305
|
+
post-provision: [
|
306
|
+
{ path: "clean.sh" }
|
307
|
+
]
|
308
|
+
}
|
281
309
|
}
|
282
310
|
}
|
283
311
|
}
|
@@ -322,9 +350,9 @@ To build a new version of the gem:
|
|
322
350
|
$ rake build
|
323
351
|
````
|
324
352
|
|
325
|
-
|
353
|
+
Publish the new version to Rubygems:
|
326
354
|
```
|
327
|
-
$
|
355
|
+
$ gem push pkg/dployr-0.1.0.gem
|
328
356
|
```
|
329
357
|
|
330
358
|
## Contributors
|
data/lib/dployr/cli.rb
CHANGED
@@ -5,6 +5,22 @@ require 'dployr/version'
|
|
5
5
|
command = ARGV[0]
|
6
6
|
options = {}
|
7
7
|
|
8
|
+
def run(command, options, arg = nil)
|
9
|
+
begin
|
10
|
+
cmd = Dployr::Commands.const_get command
|
11
|
+
raise "Command not supported: #{command}" unless cmd
|
12
|
+
if arg
|
13
|
+
cmd.new options, arg
|
14
|
+
else
|
15
|
+
cmd.new options
|
16
|
+
end
|
17
|
+
rescue => e
|
18
|
+
puts "Error: #{e}".red
|
19
|
+
puts e.backtrace if e.backtrace and options[:debug]
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
8
24
|
opt_parser = OptionParser.new do |opt|
|
9
25
|
opt.banner = "\n Usage: dployr <command> [options]"
|
10
26
|
opt.separator ""
|
@@ -69,22 +85,6 @@ end
|
|
69
85
|
|
70
86
|
opt_parser.parse!
|
71
87
|
|
72
|
-
def run(command, options, arg = nil)
|
73
|
-
begin
|
74
|
-
cmd = Dployr::Commands.const_get command
|
75
|
-
raise "Command not supported: #{command}" unless cmd
|
76
|
-
if arg
|
77
|
-
cmd.new options, arg
|
78
|
-
else
|
79
|
-
cmd.new options
|
80
|
-
end
|
81
|
-
rescue => e
|
82
|
-
puts "Error: #{e}".red
|
83
|
-
puts e.backtrace if e.backtrace and options[:debug]
|
84
|
-
exit 1
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
88
|
case command
|
89
89
|
when "start"
|
90
90
|
run :Start, options
|
data/lib/dployr/compute/aws.rb
CHANGED
@@ -78,6 +78,29 @@ module Dployr
|
|
78
78
|
wait_ssh @attrs, server, @options[:public_ip]
|
79
79
|
end
|
80
80
|
|
81
|
+
def create_network(network_name, network_range, firewalls, routes)
|
82
|
+
# Routes not used in AWS
|
83
|
+
create_vpc(network_range) # VPC + INTERNET GATEWAY
|
84
|
+
create_subnet(network_range) # SUBNET + ROUTE TABLE
|
85
|
+
configure_security_group(firewalls) # SECURITY GROUP
|
86
|
+
end
|
87
|
+
|
88
|
+
def delete_network(network_name, network_range, firewalls, routes)
|
89
|
+
# Network_name, firewalls and routes not used. We only need "vpc_id"
|
90
|
+
if exist_vpc network_range
|
91
|
+
vpcId = get_vpcId(network_range)
|
92
|
+
|
93
|
+
delete_route_tables(vpcId)
|
94
|
+
delete_subnets(vpcId)
|
95
|
+
delete_network_acls(vpcId)
|
96
|
+
delete_internet_gateways(vpcId)
|
97
|
+
delete_security_groups(vpcId)
|
98
|
+
delete_vpc(vpcId)
|
99
|
+
else
|
100
|
+
puts "\tNetwork #{network_range} not found. Nothing to delete!"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
81
104
|
private
|
82
105
|
|
83
106
|
def get_instance(states)
|
@@ -107,6 +130,222 @@ module Dployr
|
|
107
130
|
end
|
108
131
|
end
|
109
132
|
|
133
|
+
def create_vpc(network_range)
|
134
|
+
if ! exist_vpc(network_range)
|
135
|
+
# Internet Gateway
|
136
|
+
ig = @compute.create_internet_gateway
|
137
|
+
igId = ig.body["internetGatewaySet"][0]["internetGatewayId"]
|
138
|
+
puts "\tInternet Gateway #{igId} created!"
|
139
|
+
|
140
|
+
@attrs["internetGatewayId"] = igId
|
141
|
+
|
142
|
+
# VPC
|
143
|
+
vpc = @compute.create_vpc(network_range)
|
144
|
+
vpcId = vpc.body["vpcSet"][0]["vpcId"]
|
145
|
+
puts "\tVPC #{vpcId} (#{network_range}) created!"
|
146
|
+
|
147
|
+
# Associate both
|
148
|
+
@compute.attach_internet_gateway(igId, vpcId)
|
149
|
+
puts "\t\tBoth associated!"
|
150
|
+
else
|
151
|
+
puts "\tVPC #{network_range} already exists"
|
152
|
+
vpcId = get_vpcId(network_range)
|
153
|
+
end
|
154
|
+
|
155
|
+
@attrs["vpcId"] = vpcId
|
156
|
+
end
|
157
|
+
|
158
|
+
def create_subnet(network_range)
|
159
|
+
if ! exist_subnet(network_range)
|
160
|
+
vpcId = @attrs["vpcId"]
|
161
|
+
|
162
|
+
# SUBNET
|
163
|
+
sn = @compute.create_subnet(vpcId, network_range)
|
164
|
+
snId = sn.body["subnet"]["subnetId"]
|
165
|
+
puts "\tSubnet #{snId} created!"
|
166
|
+
|
167
|
+
@attrs["subnetId"] = snId
|
168
|
+
|
169
|
+
# ROUTE TABLE
|
170
|
+
rt = @compute.create_route_table(vpcId)
|
171
|
+
rtId = rt.body["routeTable"][0]["routeTableId"]
|
172
|
+
puts "\tRoute table #{rtId} created!"
|
173
|
+
|
174
|
+
@attrs["routeTableId"] = rtId
|
175
|
+
|
176
|
+
# Add route for internet gateway
|
177
|
+
igId = @attrs["internetGatewayId"]
|
178
|
+
@compute.create_route(rtId, "0.0.0.0/0", igId, instance_id = nil, network_interface_id = nil)
|
179
|
+
|
180
|
+
# Associate both
|
181
|
+
@compute.associate_route_table(rtId, snId)
|
182
|
+
puts "\t\tBoth associated!"
|
183
|
+
else
|
184
|
+
puts "\tSubnet #{network_range} already exists"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def configure_security_group(firewalls)
|
189
|
+
|
190
|
+
timestamp = Time.now.to_i
|
191
|
+
@attrs["securityGroupName"] = "SG-#{timestamp}"
|
192
|
+
puts "\tConfiguring Security Group: #{@attrs["securityGroupName"]}"
|
193
|
+
|
194
|
+
vpcId = @attrs["vpcId"]
|
195
|
+
|
196
|
+
# Create Security Group
|
197
|
+
sg = @compute.create_security_group( @attrs["securityGroupName"], "dployr", vpcId)
|
198
|
+
@attrs["securityGroupId"] = sg.body["groupId"]
|
199
|
+
puts "\t\tSecurity Group #{@attrs["securityGroupId"]} created!"
|
200
|
+
|
201
|
+
# Create rules
|
202
|
+
if firewalls.respond_to?("each")
|
203
|
+
firewalls.each do |key, value|
|
204
|
+
add_firewall( @attrs["securityGroupId"] , key, value["address"][0], value["protocol"], value["port"])
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
puts "\tSecurity Group #{@attrs["securityGroupId"]} configured!"
|
209
|
+
end
|
210
|
+
|
211
|
+
def add_firewall(sgId, name, cidrIp, protocol, ports)
|
212
|
+
# Split ports into "from" and "to"
|
213
|
+
words = ports.split("-")
|
214
|
+
if words.length > 1
|
215
|
+
from = words[0].to_i
|
216
|
+
to = words[1].to_i
|
217
|
+
else
|
218
|
+
from = to = words[0].to_i
|
219
|
+
end
|
220
|
+
|
221
|
+
group_name = "SG-plumbing"
|
222
|
+
options = {}
|
223
|
+
options["GroupId"] = "#{sgId}"
|
224
|
+
options["CidrIp"] = "#{cidrIp}"
|
225
|
+
options["FromPort"] = from
|
226
|
+
options["IpProtocol"] = "#{protocol}"
|
227
|
+
options["ToPort"] = to
|
228
|
+
|
229
|
+
# Add rule
|
230
|
+
asg = @compute.authorize_security_group_ingress(group_name, options)
|
231
|
+
puts "\t\tRule #{name} added!"
|
232
|
+
end
|
233
|
+
|
234
|
+
def exist_vpc(name)
|
235
|
+
list = @compute.describe_vpcs.data[:body]
|
236
|
+
items = list["vpcSet"]
|
237
|
+
if items.respond_to?("each")
|
238
|
+
items.each do |item|
|
239
|
+
if item["cidrBlock"] == name
|
240
|
+
return true
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
244
|
+
return false
|
245
|
+
end
|
246
|
+
|
247
|
+
def exist_subnet(name)
|
248
|
+
list = @compute.describe_subnets.data[:body]
|
249
|
+
items = list["subnetSet"]
|
250
|
+
if items.respond_to?("each")
|
251
|
+
items.each do |item|
|
252
|
+
if item["cidrBlock"] == name
|
253
|
+
return true
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
return false
|
258
|
+
end
|
259
|
+
|
260
|
+
def get_vpcId(private_net)
|
261
|
+
list = @compute.describe_vpcs.data[:body]
|
262
|
+
items = list["vpcSet"]
|
263
|
+
if items.respond_to?("each")
|
264
|
+
items.each do |item|
|
265
|
+
if item["cidrBlock"] == private_net
|
266
|
+
return item["vpcId"]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
return ""
|
271
|
+
end
|
272
|
+
|
273
|
+
# Route Tables
|
274
|
+
# Delete non-default route tables from VPC. Default tables NOT allowed
|
275
|
+
def delete_route_tables(vpcId)
|
276
|
+
rts = @compute.describe_route_tables('vpc-id' => "#{vpcId}").body["routeTableSet"]
|
277
|
+
if rts.respond_to?("each")
|
278
|
+
rts.each do |rt|
|
279
|
+
if ! rt["associationSet"][0]["main"] # non-default
|
280
|
+
@compute.disassociate_route_table( rt["associationSet"][0]["routeTableAssociationId"] )
|
281
|
+
@compute.delete_route_table( rt["routeTableId"] )
|
282
|
+
puts "\tRoute table #{rt["routeTableId"]} deleted!"
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# Subnets
|
289
|
+
# Delete subnets from VPC.
|
290
|
+
def delete_subnets(vpcId)
|
291
|
+
subnets = @compute.describe_subnets('vpc-id' => "#{vpcId}").body["subnetSet"]
|
292
|
+
if subnets.respond_to?("each")
|
293
|
+
subnets.each do |sn|
|
294
|
+
@compute.delete_subnet( sn["subnetId"] )
|
295
|
+
puts "\tSubnet #{sn["subnetId"]} deleted!"
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# Network ACLs
|
301
|
+
# Delete non-default network ACLs from VPC. Defaul ACLs NOT allowed
|
302
|
+
def delete_network_acls(vpcId)
|
303
|
+
acls = @compute.describe_network_acls('vpc-id' => "#{vpcId}").body["networkAclSet"]
|
304
|
+
if acls.respond_to?("each")
|
305
|
+
acls.each do |acl|
|
306
|
+
if ! acl["default"] # non-default
|
307
|
+
@compute.delete_network_acl( acl["networkAclId"] )
|
308
|
+
puts "\tNetwork ACL #{acl["networkAclId"]} deleted!"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
# Internet Gateway
|
315
|
+
# Delete internet gateways from VPC.
|
316
|
+
def delete_internet_gateways(vpcId)
|
317
|
+
igws = @compute.describe_internet_gateways('attachment.vpc-id' => "#{vpcId}").body["internetGatewaySet"]
|
318
|
+
if igws.respond_to?("each")
|
319
|
+
igws.each do |igw|
|
320
|
+
@compute.detach_internet_gateway( igw["internetGatewayId"], vpcId )
|
321
|
+
@compute.delete_internet_gateway( igw["internetGatewayId"] )
|
322
|
+
puts "\tInternet gateway #{igw["internetGatewayId"]} deleted!"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
# Security Group
|
328
|
+
# Delete non-default security group from VPC. Default SG NOT allowed
|
329
|
+
def delete_security_groups(vpcId)
|
330
|
+
sgs = @compute.describe_security_groups('vpc-id' => "#{vpcId}").body["securityGroupInfo"]
|
331
|
+
if sgs.respond_to?("each")
|
332
|
+
sgs.each do |sg|
|
333
|
+
if sg["groupName"] != "default" # non-default
|
334
|
+
@compute.delete_security_group( nil, sg["groupId"] )
|
335
|
+
puts "\tSecurity Group #{sg["groupId"]} deleted!"
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def delete_vpc(vpcId)
|
342
|
+
if @compute.delete_vpc(vpcId)
|
343
|
+
puts "\tVPC #{vpcId} deleted!"
|
344
|
+
else
|
345
|
+
puts "\tError deleting VPC #{vpcId}!"
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
110
349
|
end
|
111
350
|
end
|
112
351
|
end
|
data/lib/dployr/scripts/shell.rb
CHANGED
@@ -48,13 +48,11 @@ module Dployr
|
|
48
48
|
end
|
49
49
|
channel.on_data do |ch,data|
|
50
50
|
stdout_data+=data
|
51
|
-
#print "[#{@host}] #{data}".green
|
52
51
|
print "#{data}".green
|
53
52
|
end
|
54
53
|
|
55
54
|
channel.on_extended_data do |ch,type,data|
|
56
55
|
stderr_data += data
|
57
|
-
#print "[#{@host}] #{data}".red
|
58
56
|
print "#{data}".red
|
59
57
|
end
|
60
58
|
|
data/lib/dployr/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dployr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomas Aparicio
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-05-
|
12
|
+
date: 2014-05-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog
|
@@ -149,7 +149,6 @@ files:
|
|
149
149
|
- lib/dployr/config/instance.rb
|
150
150
|
- lib/dployr/configuration.rb
|
151
151
|
- lib/dployr/init.rb
|
152
|
-
- lib/dployr/logger.rb
|
153
152
|
- lib/dployr/scripts/default_hooks.rb
|
154
153
|
- lib/dployr/scripts/hook.rb
|
155
154
|
- lib/dployr/scripts/local_shell.rb
|