dployr 0.0.8 → 0.0.9
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.
- 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
|