elzar 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.gitignore +3 -0
  2. data/CHANGELOG.md +6 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +46 -83
  5. data/README.md +19 -17
  6. data/USAGE.md +257 -0
  7. data/bin/elzar +94 -0
  8. data/chef/site-cookbooks/ruby/metadata.rb +3 -1
  9. data/chef/site-cookbooks/ruby/recipes/default.rb +1 -0
  10. data/chef/site-cookbooks/ruby/recipes/path.rb +17 -0
  11. data/elzar.gemspec +4 -0
  12. data/lib/elzar.rb +5 -1
  13. data/lib/elzar/assistant.rb +82 -70
  14. data/lib/elzar/aws_config.rb +46 -0
  15. data/lib/elzar/cli.rb +143 -0
  16. data/lib/elzar/compute.rb +52 -0
  17. data/lib/elzar/core_ext/hash.rb +18 -0
  18. data/lib/elzar/fog.rb +53 -0
  19. data/lib/elzar/ssh_key_locator.rb +37 -0
  20. data/lib/elzar/templates/Gemfile +4 -4
  21. data/lib/elzar/templates/Vagrantfile.erb +1 -1
  22. data/lib/elzar/templates/aws_config.private.yml +13 -0
  23. data/lib/elzar/templates/aws_config.yml +6 -0
  24. data/lib/elzar/templates/data_bags/deploy/authorized_keys.json +4 -5
  25. data/lib/elzar/templates/dna/rails.json +15 -0
  26. data/lib/elzar/templates/gitignore +1 -0
  27. data/lib/elzar/version.rb +1 -1
  28. data/script/ci_nightly +14 -0
  29. data/spec/fixtures/rails_integration_template/add_root_user.rb +9 -0
  30. data/spec/fixtures/rails_integration_template/database.yml +7 -0
  31. data/spec/fixtures/rails_integration_template/deploy.rb +11 -0
  32. data/spec/fixtures/rails_integration_template/template.rb +22 -0
  33. data/spec/integration/rails_spec.rb +190 -0
  34. data/spec/lib/elzar/assistant_spec.rb +30 -0
  35. data/spec/lib/elzar/aws_config_spec.rb +84 -0
  36. data/spec/lib/elzar/ssh_key_locator_spec.rb +51 -0
  37. data/spec/spec_helper.rb +11 -0
  38. data/spec/support/shell_interaction_helpers.rb +33 -0
  39. metadata +107 -7
  40. data/lib/elzar/chef_dna.rb +0 -48
  41. data/lib/elzar/templates/dna.json +0 -25
  42. data/spec/chef_dna_spec.rb +0 -58
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'tempfile'
3
+
4
+ describe Elzar::Assistant do
5
+
6
+ context '.validate_dna!' do
7
+
8
+ def tempfile(content)
9
+ Tempfile.open('dna-tmp') do |f|
10
+ f.write(content)
11
+ f
12
+ end
13
+ end
14
+
15
+ it 'raises an error if the dna contains a TODO item' do
16
+ dna_file = tempfile %Q[{\n"foo": "bar",\n"baz": "TODO - Fill out your baz"\n}]
17
+ expect do
18
+ Elzar::Assistant.validate_dna! dna_file.path
19
+ end.to raise_error(Elzar::Assistant::InvalidDnaError, /dna\.json:3/)
20
+ end
21
+
22
+ it 'does not raise an error if the dna does not contain a TODO item' do
23
+ dna_file = tempfile %Q[{\n"foo": "bar",\n"baz": "filled-out"\n}]
24
+ expect do
25
+ Elzar::Assistant.validate_dna! dna_file.path
26
+ end.to_not raise_error(Elzar::Assistant::InvalidDnaError)
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ describe Elzar::AwsConfig do
5
+ let(:aws_config) do
6
+ <<-YAML
7
+ server:
8
+ creation_config:
9
+ flavor_id: 'm1.large'
10
+ image_id: "ami-fd589594"
11
+ groups: default
12
+ key_name: relevance_aws
13
+ YAML
14
+ end
15
+
16
+ let(:private_aws_config) do
17
+ <<-YAML
18
+ aws_credentials:
19
+ aws_access_key_id: AKIAIQZWXGD2S56W2MMQ
20
+ aws_secret_access_key: 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
21
+
22
+ server:
23
+ private_key: |
24
+ -----BEGIN RSA PRIVATE KEY-----
25
+ SecretsSecretsSecretsSecretsSecretsSecretsSecretsSecretsSecretsSecrets
26
+ SecretsSecretsSecretsSecretsSecretsSecretsSecretsSecretsSecretsSecrets
27
+ SecretsSecretsSecretsSecretsSecretsSecretsSecretsSecretsSecretsSecrets
28
+ -----END RSA PRIVATE KEY-----
29
+ YAML
30
+ end
31
+
32
+ context '.load_configs' do
33
+ def create_configs_at(path)
34
+ FileUtils.mkdir_p path
35
+ File.open(File.join(path, 'aws_config.yml'), 'w') { |f| f << aws_config }
36
+ File.open(File.join(path, 'aws_config.private.yml'), 'w') { |f| f << private_aws_config }
37
+ end
38
+
39
+ def cleanup_configs(path)
40
+ %w(aws_config.yml aws_config.private.yml).each do |base|
41
+ full_path = File.join(path, base)
42
+ FileUtils.rm(full_path) if File.exist?(full_path)
43
+ end
44
+ end
45
+
46
+ after do
47
+ cleanup_configs '/tmp/elzar'
48
+ cleanup_configs '/tmp/elzar-specified'
49
+ end
50
+
51
+ it 'tries to load config files in the DEFAULT_CONFIG_DIR if no config_directory specified' do
52
+ stub_const 'Elzar::AwsConfig::DEFAULT_CONFIG_DIR', '/tmp/elzar'
53
+ create_configs_at '/tmp/elzar'
54
+
55
+ config = Elzar::AwsConfig.load_configs
56
+ config['aws_credentials'].should_not be_nil
57
+ config['aws_credentials']['aws_access_key_id'].should == 'AKIAIQZWXGD2S56W2MMQ'
58
+ end
59
+
60
+ it 'tries to load config files in config_directory if specified' do
61
+ create_configs_at '/tmp/elzar-specified'
62
+
63
+ config = Elzar::AwsConfig.load_configs '/tmp/elzar-specified'
64
+ config['aws_credentials'].should_not be_nil
65
+ config['aws_credentials']['aws_access_key_id'].should == 'AKIAIQZWXGD2S56W2MMQ'
66
+ end
67
+
68
+ it 'does a deep merge of the configuration files' do
69
+ create_configs_at '/tmp/elzar'
70
+ config = Elzar::AwsConfig.load_configs '/tmp/elzar'
71
+
72
+ config['server']['creation_config']['flavor_id'].should == 'm1.large'
73
+ config['server']['private_key'].should match(/Secrets/)
74
+ end
75
+
76
+ it 'raises an error if it was unable to find the configuration files' do
77
+ expect do
78
+ Elzar::AwsConfig.load_configs '/tmp/nothing-to-see-here'
79
+ end.to raise_error(Elzar::AwsConfig::ConfigFileNotFound)
80
+ end
81
+ end
82
+
83
+
84
+ end
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+ require 'tempfile'
3
+ require 'elzar/ssh_key_locator'
4
+
5
+ describe Elzar::SshKeyLocator do
6
+
7
+ describe "#find_local_keys" do
8
+
9
+ def create_key_file(seed, content)
10
+ Tempfile.open(seed) do |f|
11
+ f.write(content)
12
+ f
13
+ end
14
+ end
15
+
16
+ it "returns an array of keys from the first existing key file" do
17
+ key_file_1 = create_key_file 'foo.pub', "foo\nbar"
18
+ key_file_2 = create_key_file 'baz.pub', "baz"
19
+
20
+ keys = Elzar::SshKeyLocator.find_local_keys(["/tmp/bogus.pub", key_file_1.path, key_file_2.path])
21
+ keys.should == ['foo', 'bar']
22
+ end
23
+
24
+ it "returns an empty array when no key files are found" do
25
+ keys = Elzar::SshKeyLocator.find_local_keys(["/tmp/bogus.pub"])
26
+ keys.should == []
27
+ end
28
+
29
+ it "ignores blank lines in key files" do
30
+ key_file = create_key_file 'foo.pub', "\nfoo\n\nbar"
31
+ keys = Elzar::SshKeyLocator.find_local_keys([key_file.path])
32
+ keys.should == ['foo', 'bar']
33
+ end
34
+
35
+ end
36
+
37
+ describe "#find_keys" do
38
+ it "returns the local keys when they exist" do
39
+ Elzar::SshKeyLocator.should_receive(:find_local_keys).and_return ['some-local-key']
40
+ Elzar::SshKeyLocator.find_keys.should == ['some-local-key']
41
+ end
42
+
43
+ it "returns the ssh-agent keys when no local keys exist" do
44
+ Elzar::SshKeyLocator.stub(:find_local_keys).and_return []
45
+ Elzar::SshKeyLocator.should_receive(:find_agent_keys).and_return ['some-agent-key']
46
+ Elzar::SshKeyLocator.find_keys.should == ['some-agent-key']
47
+ end
48
+ end
49
+
50
+ end
51
+
@@ -1,10 +1,21 @@
1
1
  require 'elzar'
2
+ require 'bahia'
3
+
4
+ Dir['spec/support/**/*.rb'].each do |support_file|
5
+ require File.expand_path(support_file)
6
+ end
7
+
8
+ Bahia.project_directory = File.expand_path('../..', __FILE__)
2
9
 
3
10
  RSpec.configure do |config|
4
11
  config.filter_run_excluding :disabled => true
12
+ config.filter_run_excluding :ci => true
5
13
  config.run_all_when_everything_filtered = true
6
14
 
7
15
  config.alias_example_to :fit, :focused => true
8
16
  config.alias_example_to :xit, :disabled => true
9
17
  config.alias_example_to :they
18
+
19
+ config.include Bahia, :ci => true
20
+ config.include ShellInteractionHelpers, :ci => true
10
21
  end
@@ -0,0 +1,33 @@
1
+ module ShellInteractionHelpers
2
+ def capture_stderr(&block)
3
+ original_stderr = $stderr
4
+ $stderr = fake = StringIO.new
5
+ begin
6
+ yield
7
+ ensure
8
+ $stderr = original_stderr
9
+ end
10
+ fake.string
11
+ end
12
+
13
+ def capture_stdout(&block)
14
+ original_stdout = $stdout
15
+ $stdout = fake = StringIO.new
16
+ begin
17
+ yield
18
+ ensure
19
+ $stdout = original_stdout
20
+ end
21
+ fake.string
22
+ end
23
+
24
+ # wrapper around raise_error that captures stderr
25
+ def should_abort_with(msg)
26
+ capture_stderr do
27
+ expect do
28
+ yield
29
+ end.to raise_error SystemExit, msg
30
+ end
31
+ end
32
+ end
33
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elzar
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,8 +10,24 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-07-09 00:00:00.000000000 Z
13
+ date: 2012-10-05 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: gli
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: 2.0.0
15
31
  - !ruby/object:Gem::Dependency
16
32
  name: multi_json
17
33
  requirement: !ruby/object:Gem::Requirement
@@ -28,6 +44,38 @@ dependencies:
28
44
  - - ~>
29
45
  - !ruby/object:Gem::Version
30
46
  version: 1.3.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: fog
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.5.0
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 1.5.0
63
+ - !ruby/object:Gem::Dependency
64
+ name: slushy
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: 0.1.3
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 0.1.3
31
79
  - !ruby/object:Gem::Dependency
32
80
  name: rake
33
81
  requirement: !ruby/object:Gem::Requirement
@@ -60,6 +108,22 @@ dependencies:
60
108
  - - ! '>='
61
109
  - !ruby/object:Gem::Version
62
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: bahia
113
+ requirement: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
63
127
  - !ruby/object:Gem::Dependency
64
128
  name: bundler
65
129
  requirement: !ruby/object:Gem::Requirement
@@ -80,16 +144,20 @@ description: Provides Chef cookbooks for a production Rails environment. Also su
80
144
  Chef-erizing a Rails app.
81
145
  email:
82
146
  - alex.redington@thinkrelevance.com
83
- executables: []
147
+ executables:
148
+ - elzar
84
149
  extensions: []
85
150
  extra_rdoc_files: []
86
151
  files:
87
152
  - .gitignore
88
153
  - .rvmrc
89
154
  - CHANGELOG.md
155
+ - Gemfile
90
156
  - Gemfile.lock
91
157
  - README.md
92
158
  - Rakefile
159
+ - USAGE.md
160
+ - bin/elzar
93
161
  - chef/cookbooks/.gitkeep
94
162
  - chef/cookbooks/apt/README.md
95
163
  - chef/cookbooks/apt/files/default/apt-cacher
@@ -221,25 +289,43 @@ files:
221
289
  - chef/site-cookbooks/ruby/attributes/default.rb
222
290
  - chef/site-cookbooks/ruby/metadata.rb
223
291
  - chef/site-cookbooks/ruby/recipes/default.rb
292
+ - chef/site-cookbooks/ruby/recipes/path.rb
224
293
  - elzar.gemspec
225
294
  - lib/elzar.rb
226
295
  - lib/elzar/assistant.rb
227
- - lib/elzar/chef_dna.rb
296
+ - lib/elzar/aws_config.rb
297
+ - lib/elzar/cli.rb
298
+ - lib/elzar/compute.rb
299
+ - lib/elzar/core_ext/hash.rb
300
+ - lib/elzar/fog.rb
301
+ - lib/elzar/ssh_key_locator.rb
228
302
  - lib/elzar/template.rb
229
303
  - lib/elzar/templates/.chef/knife.rb
230
304
  - lib/elzar/templates/.rvmrc
231
305
  - lib/elzar/templates/Gemfile
232
306
  - lib/elzar/templates/README.md
233
307
  - lib/elzar/templates/Vagrantfile.erb
308
+ - lib/elzar/templates/aws_config.private.yml
309
+ - lib/elzar/templates/aws_config.yml
234
310
  - lib/elzar/templates/data_bags/deploy/authorized_keys.json
235
- - lib/elzar/templates/dna.json
311
+ - lib/elzar/templates/dna/rails.json
312
+ - lib/elzar/templates/gitignore
236
313
  - lib/elzar/templates/script/install_cookbook
237
314
  - lib/elzar/templates/script/new_cookbook
238
315
  - lib/elzar/templates/solo.rb.erb
239
316
  - lib/elzar/templates/upgrade-chef.sh
240
317
  - lib/elzar/version.rb
241
- - spec/chef_dna_spec.rb
318
+ - script/ci_nightly
319
+ - spec/fixtures/rails_integration_template/add_root_user.rb
320
+ - spec/fixtures/rails_integration_template/database.yml
321
+ - spec/fixtures/rails_integration_template/deploy.rb
322
+ - spec/fixtures/rails_integration_template/template.rb
323
+ - spec/integration/rails_spec.rb
324
+ - spec/lib/elzar/assistant_spec.rb
325
+ - spec/lib/elzar/aws_config_spec.rb
326
+ - spec/lib/elzar/ssh_key_locator_spec.rb
242
327
  - spec/spec_helper.rb
328
+ - spec/support/shell_interaction_helpers.rb
243
329
  homepage: http://github.com/relevance/elzar
244
330
  licenses: []
245
331
  post_install_message:
@@ -252,12 +338,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
252
338
  - - ! '>='
253
339
  - !ruby/object:Gem::Version
254
340
  version: '0'
341
+ segments:
342
+ - 0
343
+ hash: -228900275979059414
255
344
  required_rubygems_version: !ruby/object:Gem::Requirement
256
345
  none: false
257
346
  requirements:
258
347
  - - ! '>='
259
348
  - !ruby/object:Gem::Version
260
349
  version: '0'
350
+ segments:
351
+ - 0
352
+ hash: -228900275979059414
261
353
  requirements: []
262
354
  rubyforge_project:
263
355
  rubygems_version: 1.8.24
@@ -265,5 +357,13 @@ signing_key:
265
357
  specification_version: 3
266
358
  summary: Chef cookbooks for Rails
267
359
  test_files:
268
- - spec/chef_dna_spec.rb
360
+ - spec/fixtures/rails_integration_template/add_root_user.rb
361
+ - spec/fixtures/rails_integration_template/database.yml
362
+ - spec/fixtures/rails_integration_template/deploy.rb
363
+ - spec/fixtures/rails_integration_template/template.rb
364
+ - spec/integration/rails_spec.rb
365
+ - spec/lib/elzar/assistant_spec.rb
366
+ - spec/lib/elzar/aws_config_spec.rb
367
+ - spec/lib/elzar/ssh_key_locator_spec.rb
269
368
  - spec/spec_helper.rb
369
+ - spec/support/shell_interaction_helpers.rb
@@ -1,48 +0,0 @@
1
- module Elzar
2
- module ChefDNA
3
- def self.gene_splice(content, database, ruby_version)
4
- set_ruby(content, ruby_version)
5
- set_database(content, database)
6
- end
7
-
8
- private
9
-
10
- def self.set_database(content, database)
11
- if database == 'postgresql'
12
- db_index = content['run_list'].find_index { |e| (e == 'mysql::server') || (e == 'role[postgres_database]')}
13
- content['run_list'][db_index] = 'role[postgres_database]'
14
- elsif database.nil? || (database == 'mysql')
15
- db_index = content['run_list'].find_index { |e| (e == 'mysql::server') || (e == 'role[postgres_database]')}
16
- content['run_list'][db_index] = 'mysql::server'
17
- end
18
- end
19
-
20
- def self.set_ruby(content, ruby_version)
21
- if ruby_version =~ /^ree-(.*)/i
22
- content['ruby_enterprise']['version'] = $1
23
- content['ruby_enterprise']['url'] = "http://rubyenterpriseedition.googlecode.com/files/ruby-enterprise-#{$1}"
24
- content['ruby_enterprise']['gems_version'] = rubygems_version
25
- update_run_list! content['run_list'], 'role[enterprise_appstack]'
26
- elsif ruby_version =~ /^ruby-(.*)/i
27
- full_version = $1
28
- content['ruby']['version'] = full_version
29
- major_version = full_version[/(\d\.\d).*/, 1]
30
- content['ruby']['url'] = "http://ftp.ruby-lang.org/pub/ruby/#{major_version}/ruby-#{full_version}.tar.gz"
31
- content['ruby']['gems_version'] = rubygems_version
32
- update_run_list! content['run_list'], 'role[ruby_appstack]'
33
- else
34
- raise "Your ruby is NOT SUPPORTED. Please use ree or ruby."
35
- end
36
- end
37
-
38
- def self.update_run_list!(run_list, val)
39
- appstack_index = run_list.find_index {|e| e[/^role\[.*_appstack\]$/] }
40
- run_list[appstack_index] = val
41
- end
42
-
43
- def self.rubygems_version
44
- require 'rubygems' unless defined?(Gem)
45
- Gem::VERSION
46
- end
47
- end
48
- end