elzar 0.1.2 → 0.2.0

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.
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