dployr 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b382202193f87d485df3e630d80d00fe16757356
4
- data.tar.gz: 84199d78c073963b72f65d641442bbf32e2cdf2c
3
+ metadata.gz: 901f079e84371186e545d8c438b618e84ff8d711
4
+ data.tar.gz: 4abb4a9493c968a60b52337d4a92c0fa83de4128
5
5
  SHA512:
6
- metadata.gz: 7fe63977dac1afc5eaa20966a9500dee3c25af05ddbce63f9056d7376779f9b3a72ab2f72db8d190e5c62b486d0af13ac09e7f78890c8c3fc51cea0bf750ab28
7
- data.tar.gz: 67406e12e53495591bb9e83066519adaf7d9a66c208e6d79c3e2b9a9bc1c324461f382bb664a9e76d90c57378525d6dc0ef145f1376e0222ba3a953b003bd5cb
6
+ metadata.gz: f8f663dcc49d7d2cd944d9001ca96d9f75b80989add9ce2fc0c529723f656f81516cc23da40026afb2b93aeb397438163a79327b84fe45539f4f1df12f4d7f67
7
+ data.tar.gz: 2f946f5046e40ca1acd16410df0731276dc08a5561ccff27b166146cc1c3d3bae5c736ddfe12ecc8a8f4a9157d22072b60848ad6814689539ebc79aa72dadad0
data/.gitignore CHANGED
@@ -4,4 +4,5 @@ Gemfile.lock
4
4
  pkg/*
5
5
  .rvmrc
6
6
  .ruby-version
7
- coverage/*
7
+ coverage/*
8
+ .project
data/README.md CHANGED
@@ -37,78 +37,15 @@ spec.add_dependency 'dployr', '>= 0.0.1'
37
37
  gem 'dployr', '>= 0.0.1'
38
38
  ```
39
39
 
40
- ## Usage
40
+ ## Documentation
41
41
 
42
- ### Command-line interface
43
-
44
- ```
45
- Usage: dployr <command> [options]
46
-
47
- Commands
48
-
49
- up start instances
50
- halt stop instances
51
- status retrieve the instances status
52
- test run remote test in instances
53
- deploy start, provision and test running instances
54
- provision instance provisioning
55
- config generate configuration in YAML format
56
- init create a sample Dployrfile
57
-
58
- Options
59
-
60
- -e, --environment ENV environment to pass to the instances
61
- -n, --name NAME template name identifier to load
62
- -a, --attributes ATTRS aditional attributes to pass to the configuration in matrix query format
63
- -p, --provider provider to use (allow multiple values comma-separated)
64
- -r, --region region to use (allow multiple values comma-separated)
65
- -h, --help help
66
-
67
- ```
68
-
69
- ### Programmatic API
70
-
71
- ```ruby
72
- Dployr::configure do |dployr|
73
-
74
- dployr.config.add_instance({
75
- attributes: {
76
- name: "example",
77
- instance_type: "m1.small",
78
- version: "${VERSION}"
79
- },
80
- scripts: [
81
- { path: "configure.sh" }
82
- ],
83
- providers: {
84
- aws: {
85
- attributes: {
86
- network_id: "be457fca",
87
- instance_type: "m1.small",
88
- "type-%{name}" => "small"
89
- },
90
- regions: {
91
- "eu-west-1a" => {
92
- attributes: {
93
- keypair: "vagrant-aws-ireland"
94
- },
95
- scripts: [
96
- { path: "router.sh", args: ["%{name}", "${region}", "${provider}"] }
97
- ]
98
- }
99
- }
100
- }
101
- }
102
- })
103
-
104
- end
105
- ```
42
+ Dployr documentation and API is available from [RubyDoc][rubydoc]
106
43
 
107
44
  ## Features
108
45
 
109
46
  `To do! but all will be cool :)`
110
47
 
111
- ## Configuration file
48
+ ## Configuration
112
49
 
113
50
  Configuration file must be called `Dployrfile`. It can be also a standard Ruby file
114
51
  or a YAML file (adding the `.yml` or `.yaml` extension)
@@ -238,6 +175,71 @@ custom:
238
175
 
239
176
  ```
240
177
 
178
+ ## Command-line interface
179
+
180
+ ```
181
+ Usage: dployr <command> [options]
182
+
183
+ Commands
184
+
185
+ up start instances
186
+ halt stop instances
187
+ status retrieve the instances status
188
+ test run remote test in instances
189
+ deploy start, provision and test running instances
190
+ provision instance provisioning
191
+ config generate configuration in YAML format
192
+ init create a sample Dployrfile
193
+
194
+ Options
195
+
196
+ -e, --environment ENV environment to pass to the instances
197
+ -n, --name NAME template name identifier to load
198
+ -a, --attributes ATTRS aditional attributes to pass to the configuration in matrix query format
199
+ -p, --provider provider to use (allow multiple values comma-separated)
200
+ -r, --region region to use (allow multiple values comma-separated)
201
+ -h, --help help
202
+
203
+ ```
204
+
205
+ ## Programmatic API
206
+
207
+ ```ruby
208
+ Dployr::configure do |dployr|
209
+
210
+ dployr.config.add_instance({
211
+ attributes: {
212
+ name: "example",
213
+ instance_type: "m1.small",
214
+ version: "${VERSION}"
215
+ },
216
+ scripts: [
217
+ { path: "configure.sh" }
218
+ ],
219
+ providers: {
220
+ aws: {
221
+ attributes: {
222
+ network_id: "be457fca",
223
+ instance_type: "m1.small",
224
+ "type-%{name}" => "small"
225
+ },
226
+ regions: {
227
+ "eu-west-1a" => {
228
+ attributes: {
229
+ keypair: "vagrant-aws-ireland"
230
+ },
231
+ scripts: [
232
+ { path: "router.sh", args: ["%{name}", "${region}", "${provider}"] }
233
+ ]
234
+ }
235
+ }
236
+ }
237
+ }
238
+ })
239
+
240
+ end
241
+ ```
242
+
241
243
  ## Contributing
242
244
 
243
245
  Feel free to report any issue you experiment via Github issues.
@@ -291,4 +293,5 @@ $ rake release
291
293
  [gemnasium]: https://gemnasium.com/innotech/dployr
292
294
  [gem]: http://rubygems.org/gems/dployr
293
295
  [ruby-guide]: https://github.com/bbatsov/ruby-style-guide
294
- [rspec-test]: http://betterspecs.org/
296
+ [rspec-best]: http://betterspecs.org/
297
+ [rubydoc]: http://www.rubydoc.info/gems/dployr/
data/bin/dployr CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  $LOAD_PATH.push File.expand_path("../../lib", __FILE__)
4
- require 'dployr/cli/cli'
4
+ require 'dployr/cli'
@@ -0,0 +1,30 @@
1
+ german-dployr:
2
+ attributes:
3
+ name: "german-dployr"
4
+ prefix: dev
5
+ private_key_path: ~/pems/innotechdev.pem
6
+ username: innotechdev
7
+ scripts:
8
+ pre-provision:
9
+ -
10
+ source: ./hello
11
+ target: /tmp
12
+ provision:
13
+ -
14
+ args: ""
15
+ path: "/tmp/hello/hello.sh"
16
+ -
17
+ args: ""
18
+ path: "ls -l /tmp"
19
+ providers:
20
+ aws:
21
+ attributes:
22
+ instance_type: t1.micro
23
+ regions:
24
+ sa-east-1a:
25
+ attributes:
26
+ ami: ami-370daf2a # centos-base-v7
27
+ keypair: vagrant-aws-saopaulo
28
+ security_groups:
29
+ - sg-3cf3e45e # lib_aws_saopaulo
30
+ subnet_id: subnet-1eebe07c
@@ -0,0 +1,4 @@
1
+ #!/bin/bash
2
+ echo hello
3
+ echo hola >&2
4
+ exit 0
data/dployr.gemspec CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.version = Dployr::VERSION
7
7
  s.summary = "Multicloud management and deployment with asteroids made simple"
8
8
  s.description = "Multicloud management and deployment with asteroids made simple with a rich programmatic API and featured CLI"
9
- s.authors = ["Tomas Aparicio"]
9
+ s.authors = ["Tomas Aparicio", "German Ramos"]
10
10
  s.email = ["nerds@innotechapp.com"]
11
11
  s.homepage = "https://github.com/innotech/dployr"
12
12
  s.license = "MIT"
@@ -21,6 +21,9 @@ Gem::Specification.new do |s|
21
21
 
22
22
  s.add_dependency "fog", "~> 1.21"
23
23
  s.add_dependency "deep_merge", "~> 1.0"
24
+ s.add_dependency "net-ssh", "~> 2.8.0"
25
+ s.add_dependency "net-scp", "~> 1.2.0"
26
+ s.add_dependency "colorize", "~> 0.7.2"
24
27
 
25
28
  s.add_development_dependency "rake", "~> 10"
26
29
  s.add_development_dependency "rspec", "~> 2"
@@ -1,7 +1,6 @@
1
1
  require 'optparse'
2
2
  require 'dployr'
3
3
  require 'dployr/version'
4
- require 'dployr/cli/commands'
5
4
 
6
5
  command = ARGV[0]
7
6
  options = {}
@@ -11,37 +10,38 @@ opt_parser = OptionParser.new do |opt|
11
10
  opt.separator ""
12
11
  opt.separator " Commands"
13
12
  opt.separator ""
14
- opt.separator " up start instances"
13
+ opt.separator " start start instances"
15
14
  opt.separator " halt stop instances"
16
15
  opt.separator " destroy destroy instances"
17
16
  opt.separator " status retrieve the instances status"
18
17
  opt.separator " test run remote test in instances"
19
18
  opt.separator " deploy start, provision and test running instances"
20
19
  opt.separator " provision instance provisioning"
21
- opt.separator " config generate configuration in YAML format"
20
+ opt.separator " config generate configuration in YAML from Dployrfile"
21
+ opt.separator " execute run custom stages"
22
22
  opt.separator " init create a sample Dployrfile"
23
23
  opt.separator ""
24
24
  opt.separator " Options"
25
25
  opt.separator ""
26
26
 
27
- opt.on("-e", "--environment ENV", "environment to pass to the instances") do |v|
28
- options[:environment] = v
29
- end
30
-
31
27
  opt.on("-n", "--name NAME", "template name identifier to load") do |v|
32
28
  options[:name] = v
33
29
  end
34
30
 
31
+ opt.on("-f", "--file PATH", "custom config file path to load") do |v|
32
+ options[:file] = v
33
+ end
34
+
35
35
  opt.on("-a", "--attributes ATTRS", "aditional attributes to pass to the configuration in matrix query format") do |v|
36
36
  options[:attributes] = v
37
37
  end
38
38
 
39
- opt.on("-p", "--provider", "provider to use (allow multiple values comma-separated)") do |v|
39
+ opt.on("-p", "--provider VALUES", "provider to use (allow multiple values comma-separated)") do |v|
40
40
  options[:provider] = v
41
41
  end
42
42
 
43
- opt.on("-r", "--region", "region to use (allow multiple values comma-separated)") do |v|
44
- options[:provider] = v
43
+ opt.on("-r", "--region REGION", "region to use (allow multiple values comma-separated)") do |v|
44
+ options[:region] = v
45
45
  end
46
46
 
47
47
  opt.on("-v", "-V", "--version", "version") do
@@ -50,6 +50,7 @@ opt_parser = OptionParser.new do |opt|
50
50
 
51
51
  opt.on("-h", "--help", "help") do
52
52
  puts opt_parser
53
+ exit 0
53
54
  end
54
55
 
55
56
  opt.separator ""
@@ -57,21 +58,35 @@ end
57
58
 
58
59
  opt_parser.parse!
59
60
 
61
+ dployr = Dployr::Init.new @attributes
62
+ dployr.load_config options[:file]
63
+ config = dployr.config.get_region(options[:name], options[:provider], options[:region])
64
+
60
65
  case command
61
- when "up"
62
- puts "Command currently not available"
66
+ when "start"
67
+ Dployr::Commands::Start.new(config, options)
63
68
  when "halt"
64
- puts "Command currently not available"
69
+ Dployr::Commands::Stop_Destroy.new(config, options, "halt")
70
+ when "destroy"
71
+ Dployr::Commands::Stop_Destroy.new(config, options, "destroy")
65
72
  when "status"
66
73
  puts "Command currently not available"
67
74
  when "provision"
68
- puts "Command currently not available"
75
+ Dployr::Commands::Provision_Test.new(config, options, "provision")
69
76
  when "test"
70
- puts "Command currently not available"
77
+ Dployr::Commands::Provision_Test.new(config, options, "test")
71
78
  when "deploy"
72
- puts "Command currently not available"
79
+ Dployr::Commands::Start.new(config, options)
80
+ Dployr::Commands::Provision_Test.new(config, options, "provision")
81
+ Dployr::Commands::Provision_Test.new(config, options, "test")
82
+ when "execute"
83
+ Dployr::Commands::Execute.new(config, options, ARGV[1..-1])
73
84
  when "config"
74
- Dployr::CLI::Config.new options
85
+ Dployr::Commands::Config.new(config, options)
75
86
  when "init"
76
87
  Dployr::Config::Create.write_file
88
+ when '-h', '--help', 'help'
89
+ # help already showed by option
90
+ else
91
+ puts opt_parser
77
92
  end
@@ -0,0 +1,24 @@
1
+ require 'logger'
2
+ require 'dployr/utils'
3
+ require 'dployr/compute/aws'
4
+ require 'colorize'
5
+
6
+ module Dployr
7
+ module Commands
8
+ class Config
9
+
10
+ include Dployr::Utils
11
+
12
+ def initialize(config, options)
13
+ begin
14
+ puts "Options:", options.to_yaml
15
+ puts "\nConfig:", config.to_yaml
16
+ rescue Exception => e
17
+ @log.error e
18
+ Process.exit! false
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,43 @@
1
+ require 'logger'
2
+ require 'dployr/utils'
3
+ require 'dployr/compute/aws'
4
+ require 'colorize'
5
+
6
+ module Dployr
7
+ module Commands
8
+ class Execute
9
+
10
+ include Dployr::Utils
11
+
12
+ def initialize(config, options, stages)
13
+ begin
14
+ @log = Logger.new STDOUT
15
+ @name = config[:attributes]["name"]
16
+ @provider = options[:provider].upcase
17
+ @region = options[:region]
18
+ @attributes = config[:attributes]
19
+
20
+ puts "Connecting to #{@provider}...".yellow
21
+ @client = Dployr::Compute.const_get(@provider.to_sym).new(@region)
22
+
23
+ puts "Looking for #{@name} in #{@region}...".yellow
24
+ @ip = @client.get_ip(@name)
25
+ if @ip
26
+ puts "#{@name} found with IP #{@ip}".yellow
27
+ else
28
+ raise "#{@name} not found"
29
+ end
30
+
31
+ stages.each do |stage|
32
+ Dployr::Scripts::Hook.new @ip, config, stage
33
+ end
34
+
35
+ rescue Exception => e
36
+ @log.error e
37
+ Process.exit! false
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,45 @@
1
+ require 'logger'
2
+ require 'dployr/utils'
3
+ require 'dployr/compute/aws'
4
+ require 'colorize'
5
+
6
+ module Dployr
7
+ module Commands
8
+ class Provision_Test
9
+
10
+ include Dployr::Utils
11
+
12
+ def initialize(config, options, action)
13
+ begin
14
+ @log = Logger.new STDOUT
15
+ @name = config[:attributes]["name"]
16
+ @provider = options[:provider].upcase
17
+ @region = options[:region]
18
+ @attributes = config[:attributes]
19
+ @action = action
20
+
21
+ puts "Connecting to #{@provider}...".yellow
22
+ @client = Dployr::Compute.const_get(@provider.to_sym).new(@region)
23
+
24
+ puts "Looking for #{@name} in #{@region}...".yellow
25
+ @ip = @client.get_ip(@name)
26
+ if @ip
27
+ puts "#{@name} found with IP #{@ip}".yellow
28
+ else
29
+ raise "#{@name} not found"
30
+ end
31
+
32
+ Dployr::Scripts::Default_Hooks.new @ip, config, @action, self
33
+
34
+ rescue Exception => e
35
+ @log.error e
36
+ Process.exit! false
37
+ end
38
+ end
39
+
40
+ def action
41
+ return @ip
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,46 @@
1
+ require 'logger'
2
+ require 'dployr/utils'
3
+ require 'dployr/compute/aws'
4
+ require 'colorize'
5
+
6
+ module Dployr
7
+ module Commands
8
+ class Start
9
+
10
+ include Dployr::Utils
11
+
12
+ def initialize(config, options)
13
+ begin
14
+ @log = Logger.new STDOUT
15
+ @name = config[:attributes]["name"]
16
+ @provider = options[:provider].upcase
17
+ @region = options[:region]
18
+ @attributes = config[:attributes]
19
+
20
+ puts "Connecting to #{@provider}...".yellow
21
+ @client = Dployr::Compute.const_get(@provider.to_sym).new(@region)
22
+
23
+ puts "Looking for #{@name} in #{@region}...".yellow
24
+ @ip = @client.get_ip(@name)
25
+
26
+ Dployr::Scripts::Default_Hooks.new @ip, config, "start", self
27
+
28
+ rescue Exception => e
29
+ @log.error e
30
+ Process.exit! false
31
+ end
32
+ end
33
+
34
+ def action
35
+ if @ip
36
+ puts "#{@name} found with IP #{@ip}".yellow
37
+ else
38
+ @ip = @client.start(@attributes, @region)
39
+ puts "Startded instance for #{@name} in #{@region} with IP #{@ip} succesfully".yellow
40
+ end
41
+ return @ip
42
+ end
43
+
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,49 @@
1
+ require 'logger'
2
+ require 'dployr/utils'
3
+ require 'dployr/compute/aws'
4
+ require 'colorize'
5
+
6
+ module Dployr
7
+ module Commands
8
+ class Stop_Destroy
9
+
10
+ include Dployr::Utils
11
+
12
+ def initialize(config, options, action)
13
+ begin
14
+ @log = Logger.new STDOUT
15
+ @name = config[:attributes]["name"]
16
+ @provider = options[:provider].upcase
17
+ @region = options[:region]
18
+ @attributes = config[:attributes]
19
+ @action = action
20
+
21
+ puts "Connecting to #{@provider}...".yellow
22
+ @client = Dployr::Compute.const_get(@provider.to_sym).new(@region)
23
+
24
+ puts "Looking for #{@name} in #{@region}...".yellow
25
+ @ip = @client.get_ip(@name)
26
+ if @ip
27
+ puts "#{@name} found with IP #{@ip}".yellow
28
+ else
29
+ puts "#{@name} not found".yellow
30
+ end
31
+
32
+ Dployr::Scripts::Default_Hooks.new @ip, config, @action, self
33
+
34
+ rescue Exception => e
35
+ @log.error e
36
+ Process.exit! false
37
+ end
38
+ end
39
+
40
+ def action
41
+ puts "#{@action.capitalize}ing #{@name} in #{@region}...".yellow
42
+ @client.send(@action.to_sym, @name)
43
+ puts "#{@name} #{@action}ed sucesfully".yellow
44
+ return @ip
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,100 @@
1
+ require 'fog'
2
+ require 'net/ssh'
3
+
4
+ module Dployr
5
+ module Compute
6
+ class AWS
7
+
8
+ def initialize(region)
9
+ @options = {
10
+ region: region[0..-2],
11
+ provider: 'AWS',
12
+ aws_access_key_id: ENV["AWS_ACCESS_KEY"],
13
+ aws_secret_access_key: ENV["AWS_SECRET_KEY"]
14
+ }
15
+ @compute = Fog::Compute.new @options
16
+ end
17
+
18
+ # private
19
+ def get_instance(name, states)
20
+ servers = @compute.servers.all
21
+ servers.each do |instance|
22
+ if instance.tags["Name"] == name and states.include? instance.state
23
+ return instance
24
+ end
25
+ end
26
+ return nil
27
+ end
28
+
29
+ def get_ip(name)
30
+ instance = get_instance(name, ["running"])
31
+ if instance
32
+ return instance.private_ip_address
33
+ end
34
+ end
35
+
36
+ def destroy(name)
37
+ instance = get_instance(name, ["running", "stopped", "stopping"])
38
+ if instance
39
+ return instance.destroy
40
+ end
41
+ raise "Instance #{name} not found"
42
+ end
43
+
44
+ def halt(name)
45
+ instance = get_instance(name, ["running"])
46
+ if instance
47
+ return instance.stop
48
+ end
49
+ raise "Instance #{name} not found"
50
+ end
51
+
52
+ def start(attributes, region)
53
+ server = get_instance(attributes["name"], ["stopped", "stopping"])
54
+ if server
55
+ puts "Starting stopped instance for #{attributes["name"]} in #{region}...".yellow
56
+ server.start
57
+ else
58
+ puts "Creating new instance for #{attributes["name"]} in #{region}...".yellow
59
+ options = {
60
+ availability_zone: region,
61
+ flavor_id: attributes["instance_type"],
62
+ image_id: attributes["ami"],
63
+ key_name: attributes["keypair"],
64
+ subnet_id: attributes["subnet_id"],
65
+ security_group_ids: attributes["security_groups"],
66
+ tags: { Name: attributes["name"] }
67
+ #private_ip_address : private_ip_address,
68
+ #user_data : user_data,
69
+ #elastic_ip : elastic_ip,
70
+ #allocate_elastic_ip : allocate_elastic_ip,
71
+ #block_device_mapping : block_device_mapping,
72
+ #instance_initiated_shutdown_behavior : terminate_on_shutdown == true ? "terminate" : nil,
73
+ #monitoring : monitoring,
74
+ #ebs_optimized : ebs_optimized
75
+ }
76
+ puts options.to_yaml
77
+ server = @compute.servers.create(options)
78
+ end
79
+ print "Wait for instance to get online".yellow
80
+ server.wait_for { print ".".yellow; ready? }
81
+
82
+ print "\nWait for ssh to get ready...".yellow
83
+ while true
84
+ begin
85
+ Net::SSH.start(server.private_ip_address, attributes["username"], :keys => attributes["private_key_path"]) do |ssh|
86
+ print "\n"
87
+ return server.private_ip_address
88
+ end
89
+ rescue Exception => e
90
+ print ".".yellow
91
+ sleep 2
92
+ end
93
+ end
94
+ print "\n"
95
+ return null
96
+ end
97
+
98
+ end
99
+ end
100
+ end
@@ -2,7 +2,10 @@ module Dployr
2
2
  module Config
3
3
  module Constants
4
4
 
5
- FILENAME = "Dployrfile"
5
+ FILENAME = 'Dployrfile'
6
+
7
+ FILENAMES = [FILENAME, 'dployrfile', 'dployr', 'Dployr']
8
+
6
9
  EXTENSIONS = ['rb', 'yml', 'yaml']
7
10
 
8
11
  end
@@ -1,8 +1,10 @@
1
+ require 'dployr/config/constants'
2
+
1
3
  module Dployr
2
4
  module Config
3
5
  module Create
4
6
 
5
- FILENAME = 'Dployrfile'
7
+ include Dployr::Config::Constants
6
8
 
7
9
  RB_CONTENT = <<-EOS
8
10
  Dployr::configure do |dployr|
@@ -20,15 +20,16 @@ module Dployr
20
20
  def discover(dir = Dir.pwd)
21
21
  [nil].concat(EXTENSIONS).each do |ext|
22
22
  (0..5).each do |n|
23
- file_name = FILENAME
24
- file_name += ".#{ext}" if ext
25
- file_path = File.join dir, ('../' * n), file_name
26
- if File.exists? file_path
27
- return File.expand_path file_path, dir
23
+ FILENAMES.each do |file|
24
+ file += ".#{ext}" if ext
25
+ file_path = File.join dir, ('../' * n), file
26
+ if File.file? file_path
27
+ return File.expand_path file_path, dir
28
+ end
28
29
  end
29
30
  end
30
31
  end
31
- nil
32
+ return nil
32
33
  end
33
34
 
34
35
  end
@@ -82,7 +82,7 @@ module Dployr
82
82
  end
83
83
 
84
84
  def set_scripts(scripts)
85
- @scripts = scripts if scripts.is_a? Array
85
+ @scripts = scripts if scripts.is_a? Hash or scripts.is_a? Array
86
86
  end
87
87
 
88
88
  def set_attributes(attrs)
@@ -20,7 +20,7 @@ module Dployr
20
20
  end
21
21
 
22
22
  def set_default(config)
23
- @default = create_instance('default', config) if config.is_a? Hash
23
+ @default = create_instance 'default', config if config.is_a? Hash
24
24
  end
25
25
 
26
26
  def add_instance(name, config)
@@ -44,7 +44,6 @@ module Dployr
44
44
  @instances.each do |i|
45
45
  config << get_config(i.name, attributes)
46
46
  end
47
- puts config
48
47
  config
49
48
  end
50
49
 
@@ -137,7 +136,10 @@ module Dployr
137
136
  keys.each do |type|
138
137
  current = deep_copy get_by_key(parent, type)
139
138
  source = get_by_key child, type
140
- if type == :scripts
139
+ if current and source
140
+ raise Error.new "Cannot merge different types: #{parent}" if current.class != source.class
141
+ end
142
+ if type.to_sym == :scripts and current.is_a? Array
141
143
  current = [] unless current.is_a? Array
142
144
  current.concat source if source.is_a? Array
143
145
  current = current.compact.uniq
@@ -145,7 +147,8 @@ module Dployr
145
147
  current = {} unless current.is_a? Hash
146
148
  current = deep_merge current, source
147
149
  end
148
- child[type] = current if current.length
150
+ child.delete type.to_s unless child[type.to_s].nil?
151
+ child[type.to_sym] = current if current
149
152
  end
150
153
  child
151
154
  end
data/lib/dployr/init.rb CHANGED
@@ -27,7 +27,8 @@ module Dployr
27
27
 
28
28
  include Dployr::Config::FileUtils
29
29
 
30
- attr_reader :file_path, :config
30
+ attr_reader :config
31
+ attr_accessor :file_path
31
32
 
32
33
  @@instance = nil
33
34
 
@@ -35,22 +36,30 @@ module Dployr
35
36
  @@instance = self
36
37
  @attributes = attributes
37
38
  @config = Dployr::Configuration.new
38
- @file_path = discover
39
- load_file @file_path
39
+ @file_path = nil
40
40
  end
41
41
 
42
42
  def self.instance
43
43
  @@instance
44
44
  end
45
45
 
46
+ def load_config(file_path = nil)
47
+ if file_path
48
+ @file_path = file_path
49
+ else
50
+ @file_path = discover
51
+ end
52
+ set_config @file_path
53
+ end
54
+
46
55
  private
47
56
 
48
- def load_file(file_path)
49
- if file_path.is_a? String
50
- if yaml_file? file_path
51
- load_yaml file_path
57
+ def set_config(file_path)
58
+ if @file_path.is_a? String
59
+ if yaml_file? @file_path
60
+ load_yaml @file_path
52
61
  else
53
- load file_path
62
+ load @file_path
54
63
  end
55
64
  end
56
65
  end
@@ -0,0 +1,31 @@
1
+ require 'logger'
2
+ require 'dployr/utils'
3
+ require 'colorize'
4
+
5
+ module Dployr
6
+ module Scripts
7
+ class Default_Hooks
8
+
9
+ include Dployr::Utils
10
+
11
+ def initialize(ip, config, stage, command)
12
+ @log = Logger.new STDOUT
13
+ @config = config
14
+ @ip = ip
15
+ @stage = stage
16
+
17
+ if @config[:scripts]["pre-#{@stage}"]
18
+ Dployr::Scripts::Hook.new @ip, config, "pre-#{@stage}"
19
+ end
20
+ @ip = command.action()
21
+ if @config[:scripts][@stage]
22
+ Dployr::Scripts::Hook.new @ip, config, "#{@stage}"
23
+ end
24
+ if @config[:scripts]["post-#{@stage}"]
25
+ Dployr::Scripts::Hook.new @ip, config, "#{@stage}"
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ require 'logger'
2
+ require 'dployr/utils'
3
+ require 'colorize'
4
+
5
+ module Dployr
6
+ module Scripts
7
+ class Hook
8
+
9
+ include Dployr::Utils
10
+
11
+ def initialize(ip, instance, stage)
12
+ @log = Logger.new STDOUT
13
+ @ip = ip
14
+ @instance = instance
15
+ @stage = stage
16
+ run
17
+ end
18
+
19
+ private
20
+
21
+ def run
22
+ attrs = @instance[:attributes]
23
+ host = attrs["name"]
24
+ username = attrs["username"]
25
+ private_key_path = attrs["private_key_path"]
26
+
27
+ puts "STAGE '#{@stage}':".yellow
28
+ @instance[:scripts][@stage].each do |script|
29
+ if script["target"]
30
+ Dployr::Scripts::Scp.new @ip, host, username, private_key_path, script
31
+ else
32
+ Dployr::Scripts::Shell.new @ip, host, username, private_key_path, script
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,31 @@
1
+ require 'logger'
2
+ require 'net/scp'
3
+ require 'colorize'
4
+ require 'dployr/utils'
5
+
6
+ module Dployr
7
+ module Scripts
8
+ class Scp
9
+
10
+ include Dployr::Utils
11
+
12
+ def initialize(ip, host, username, private_key_path, script)
13
+
14
+ begin
15
+ @log = Logger.new STDOUT
16
+ puts "Connecting to #{host} (SCP)...".yellow
17
+ Net::SCP.start(ip, username, :keys => [private_key_path]) do |scp|
18
+ source = script["source"]
19
+ target = script["target"]
20
+ puts "Coping #{source} -> #{target}".yellow
21
+ scp.upload(source, target, :recursive => true, :preserve => true)
22
+ end
23
+
24
+ rescue Exception => e
25
+ @log.error e
26
+ raise Error.new "Cannot copy to remote: #{e}"
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,86 @@
1
+ require 'logger'
2
+ require 'net/ssh'
3
+ require 'colorize'
4
+ require 'dployr/utils'
5
+
6
+ module Dployr
7
+ module Scripts
8
+ class Shell
9
+
10
+ include Dployr::Utils
11
+
12
+ def initialize(ip, host, username, private_key_path, script)
13
+ @log = Logger.new STDOUT
14
+ @ip = ip
15
+ @host = host
16
+ @username = username
17
+ @private_key_path = private_key_path
18
+ @script = script
19
+
20
+ begin
21
+ start
22
+ rescue Exception => e
23
+ @log.error e
24
+ Process.exit! false
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def start
31
+ puts "Connecting to #{@host} (SSH)...".yellow
32
+ Net::SSH.start(@ip, @username, :keys => [@private_key_path]) do |ssh|
33
+ command = @script["path"]
34
+ arguments = @script["args"]
35
+
36
+ puts "Running remote script '#{command} #{arguments}'".yellow
37
+ result = ssh_exec!(ssh, command)
38
+ if result[:exit_code] > 0
39
+ raise "Exit code #{result[:exit_code]} when running script '#{command} #{arguments}'".yellow
40
+ else
41
+ puts "Remote script '#{command} #{arguments}' finished succesfully".yellow
42
+ end
43
+ end
44
+ end
45
+
46
+ # http://craiccomputing.blogspot.com.es/2010/08/printing-colored-text-in-unix-terminals.html
47
+ def ssh_exec!(ssh, command)
48
+ stdout_data = ""
49
+ stderr_data = ""
50
+ exit_code = nil
51
+ exit_signal = nil
52
+ ssh.open_channel do |channel|
53
+ channel.exec(command) do |ch, success|
54
+ unless success
55
+ abort "FAILED: couldn't execute command (ssh.channel.exec)"
56
+ end
57
+ channel.on_data do |ch,data|
58
+ stdout_data+=data
59
+ print "[#{@host}] #{data}".green
60
+ end
61
+
62
+ channel.on_extended_data do |ch,type,data|
63
+ stderr_data+=data
64
+ print "[#{@host}] #{data}".red
65
+ end
66
+
67
+ channel.on_request("exit-status") do |ch,data|
68
+ exit_code = data.read_long
69
+ end
70
+
71
+ channel.on_request("exit-signal") do |ch, data|
72
+ exit_signal = data.read_long
73
+ end
74
+ end
75
+ end
76
+ ssh.loop
77
+ {
78
+ stdout_data: stdout_data,
79
+ stderr_data: stderr_data,
80
+ exit_code: exit_code,
81
+ exit_signal: exit_signal
82
+ }
83
+ end
84
+ end
85
+ end
86
+ end
data/lib/dployr/utils.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'deep_merge'
2
+
1
3
  module Dployr
2
4
  module Utils
3
5
 
@@ -17,7 +19,7 @@ module Dployr
17
19
  end
18
20
 
19
21
  def get_real_key(hash, key)
20
- if hash.is_a? Hash
22
+ if key and hash.is_a? Hash
21
23
  if hash.key? key
22
24
  key
23
25
  elsif hash.key? key.to_sym
@@ -1,3 +1,3 @@
1
1
  module Dployr
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
data/lib/dployr.rb CHANGED
@@ -1,8 +1,15 @@
1
- require 'yaml'
2
- require 'deep_merge'
3
1
  require 'dployr/version'
4
2
  require 'dployr/init'
5
3
  require 'dployr/configuration'
6
4
  require 'dployr/config/create'
7
5
  require 'dployr/config/file_utils'
8
6
  require 'dployr/config/instance'
7
+ require 'dployr/commands/provision_test'
8
+ require 'dployr/commands/start'
9
+ require 'dployr/commands/stop_destroy'
10
+ require 'dployr/commands/config'
11
+ require 'dployr/commands/execute'
12
+ require 'dployr/scripts/hook'
13
+ require 'dployr/scripts/default_hooks'
14
+ require 'dployr/scripts/shell'
15
+ require 'dployr/scripts/scp'
@@ -359,7 +359,7 @@ describe Dployr::Configuration do
359
359
  zeus[:providers][:aws][:regions]["eu-west-1a"].should be_a Hash
360
360
  end
361
361
 
362
- describe "eu-west-1a" do
362
+ describe "europe-west1-a" do
363
363
  let(:region) {
364
364
  zeus[:providers][:aws][:regions]["eu-west-1a"]
365
365
  }
data/spec/init_spec.rb CHANGED
@@ -7,7 +7,6 @@ describe Dployr::Init do
7
7
 
8
8
  before :all do
9
9
  Dir.chdir fixtures
10
- @dployr = Dployr::Init.new
11
10
  end
12
11
 
13
12
  after :all do
@@ -15,7 +14,13 @@ describe Dployr::Init do
15
14
  end
16
15
 
17
16
  describe "file discovery" do
18
- it "should discover the file" do
17
+
18
+ before :all do
19
+ @dployr = Dployr::Init.new
20
+ @dployr.load_config
21
+ end
22
+
23
+ it "should discover Dployrfile" do
19
24
  @dployr.file_path.should eql "#{fixtures}/Dployrfile"
20
25
  end
21
26
 
@@ -23,5 +28,21 @@ describe Dployr::Init do
23
28
  @dployr.config.should be_instance_of Dployr::Configuration
24
29
  end
25
30
  end
31
+
32
+ describe "custom path" do
33
+
34
+ before :all do
35
+ @dployr = Dployr::Init.new
36
+ @dployr.load_config File.join File.dirname(__FILE__), 'fixtures', 'Dployrfile.yml'
37
+ end
38
+
39
+ it "should load with custom path" do
40
+ @dployr.file_path.should eql "#{fixtures}/Dployrfile.yml"
41
+ end
42
+
43
+ it "should create a new config instance" do
44
+ @dployr.config.should be_instance_of Dployr::Configuration
45
+ end
46
+ end
26
47
  end
27
48
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dployr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomas Aparicio
8
+ - German Ramos
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2014-04-21 00:00:00.000000000 Z
12
+ date: 2014-04-24 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: fog
@@ -38,6 +39,48 @@ dependencies:
38
39
  - - ~>
39
40
  - !ruby/object:Gem::Version
40
41
  version: '1.0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: net-ssh
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: 2.8.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 2.8.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: net-scp
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 1.2.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 1.2.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: colorize
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 0.7.2
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ~>
82
+ - !ruby/object:Gem::Version
83
+ version: 0.7.2
41
84
  - !ruby/object:Gem::Dependency
42
85
  name: rake
43
86
  requirement: !ruby/object:Gem::Requirement
@@ -84,12 +127,17 @@ files:
84
127
  - README.md
85
128
  - Rakefile
86
129
  - bin/dployr
130
+ - config/Dployrfile.yml
131
+ - config/hello/hello.sh
87
132
  - dployr.gemspec
88
133
  - lib/dployr.rb
89
- - lib/dployr/cli/cli.rb
90
- - lib/dployr/cli/commands.rb
91
- - lib/dployr/cli/commands/config.rb
92
- - lib/dployr/compute/client.rb
134
+ - lib/dployr/cli.rb
135
+ - lib/dployr/commands/config.rb
136
+ - lib/dployr/commands/execute.rb
137
+ - lib/dployr/commands/provision_test.rb
138
+ - lib/dployr/commands/start.rb
139
+ - lib/dployr/commands/stop_destroy.rb
140
+ - lib/dployr/compute/aws.rb
93
141
  - lib/dployr/config/constants.rb
94
142
  - lib/dployr/config/create.rb
95
143
  - lib/dployr/config/file_utils.rb
@@ -97,6 +145,10 @@ files:
97
145
  - lib/dployr/configuration.rb
98
146
  - lib/dployr/init.rb
99
147
  - lib/dployr/logger.rb
148
+ - lib/dployr/scripts/default_hooks.rb
149
+ - lib/dployr/scripts/hook.rb
150
+ - lib/dployr/scripts/scp.rb
151
+ - lib/dployr/scripts/shell.rb
100
152
  - lib/dployr/utils.rb
101
153
  - lib/dployr/version.rb
102
154
  - spec/config_file_utils_spec.rb
@@ -1,66 +0,0 @@
1
- require 'logger'
2
- require 'dployr'
3
- require 'dployr/utils'
4
-
5
- module Dployr
6
- module CLI
7
- class Config
8
-
9
- include Dployr::Utils
10
-
11
- def initialize(options)
12
- @options = options
13
- @name = options[:name]
14
- @log = Logger.new STDOUT
15
- @attributes = parse_attributes @options[:attributes]
16
-
17
- begin
18
- create
19
- render_file
20
- rescue Exception => e
21
- @log.error e
22
- Process.exit! false
23
- end
24
- end
25
-
26
- def create
27
- begin
28
- @dployr = Dployr::Init.new @attributes
29
- rescue Exception => e
30
- raise "Cannot load the config: #{e}"
31
- end
32
- end
33
-
34
- def render_file
35
- raise "Dployrfile was not found" if @dployr.file_path.nil?
36
- raise "Configuration is missing" unless @dployr.config.exists?
37
- begin
38
- if @name
39
- config = @dployr.config.get_config @name, @attributes
40
- else
41
- puts @attributes
42
- config = @dployr.config.get_config_all @attributes
43
- end
44
- unless config.nil?
45
- puts config.to_yaml
46
- else
47
- @log.info "Missing configuration data"
48
- end
49
- rescue Exception => e
50
- raise "Cannot generate the config: #{e}"
51
- end
52
- end
53
-
54
- def parse_attributes(attributes)
55
- if attributes.is_a? String
56
- if @options[:attributes][0] == '-'
57
- parse_flags attributes
58
- else
59
- parse_matrix attributes
60
- end
61
- end
62
- end
63
-
64
- end
65
- end
66
- end
@@ -1 +0,0 @@
1
- require 'dployr/cli/commands/config'
@@ -1,28 +0,0 @@
1
- require 'fog'
2
-
3
- module Dployr
4
- module Compute
5
- class Client
6
-
7
- attr_reader :client
8
-
9
- DEFAULT = {
10
- provider: 'AWS'
11
- }
12
-
13
- def initialize(options)
14
- @options = options
15
- @client = Fog::Compute.new DEFAULT.merge options
16
- end
17
-
18
- def servers
19
- @client.servers
20
- end
21
-
22
- def create_server(options)
23
- @client.servers.create options
24
- end
25
-
26
- end
27
- end
28
- end