skewer 0.1.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 (81) hide show
  1. data/.idea/encodings.xml +5 -0
  2. data/.idea/misc.xml +8 -0
  3. data/.idea/modules.xml +9 -0
  4. data/.idea/skewer.iml +61 -0
  5. data/.idea/vcs.xml +7 -0
  6. data/.rvmrc +2 -0
  7. data/Gemfile +3 -0
  8. data/Gemfile.lock +146 -0
  9. data/LICENSE +13 -0
  10. data/README.md +77 -0
  11. data/Rakefile +59 -0
  12. data/Vagrantfile +5 -0
  13. data/assets/Gemfile +5 -0
  14. data/assets/rubygems.sh +39 -0
  15. data/bin/skewer +101 -0
  16. data/features/aws.feature +45 -0
  17. data/features/bootstrapper.feature +14 -0
  18. data/features/configuration.feature +15 -0
  19. data/features/delete.feature +22 -0
  20. data/features/hooks.feature +15 -0
  21. data/features/interface.feature +61 -0
  22. data/features/provision.feature +38 -0
  23. data/features/rackspace.feature +34 -0
  24. data/features/step_definitions/cucumber_steps.rb +43 -0
  25. data/features/step_definitions/delete.rb +32 -0
  26. data/features/support/env.rb +6 -0
  27. data/features/support/puppetcode/manifests/classes/foobar.pp +4 -0
  28. data/features/support/puppetcode/manifests/classes/foobroken.pp +4 -0
  29. data/features/support/puppetcode/manifests/classes/role.pp +3 -0
  30. data/features/support/puppetcode/manifests/site.pp +2 -0
  31. data/features/support/puppetcode/modules/foo/manifests/bar.pp +3 -0
  32. data/features/support/puppetcode/modules/foo/manifests/broken.pp +8 -0
  33. data/features/support/puppetcode/modules/puppet/manifests/munge.pp +5 -0
  34. data/features/update.feature +29 -0
  35. data/lib/aws/node.rb +52 -0
  36. data/lib/aws/security_group.rb +37 -0
  37. data/lib/aws/service.rb +21 -0
  38. data/lib/bootstrapper.rb +112 -0
  39. data/lib/cli.rb +96 -0
  40. data/lib/config.rb +67 -0
  41. data/lib/cuke.rb +26 -0
  42. data/lib/ersatz/ersatz_node.rb +31 -0
  43. data/lib/ersatz/ssh_result.rb +15 -0
  44. data/lib/eucalyptus.rb +15 -0
  45. data/lib/hooks.rb +22 -0
  46. data/lib/node.erb +5 -0
  47. data/lib/node.rb +43 -0
  48. data/lib/parser.rb +92 -0
  49. data/lib/puppet.rb +53 -0
  50. data/lib/puppet_node.rb +26 -0
  51. data/lib/puppet_runtime_error.rb +6 -0
  52. data/lib/rackspace/images.rb +25 -0
  53. data/lib/rackspace/node.rb +60 -0
  54. data/lib/skewer.rb +13 -0
  55. data/lib/skewer/version.rb +3 -0
  56. data/lib/source.rb +54 -0
  57. data/lib/stub_node.rb +25 -0
  58. data/lib/util.rb +17 -0
  59. data/skewer.gemspec +30 -0
  60. data/spec/aws/node_spec.rb +70 -0
  61. data/spec/aws/security_group_spec.rb +20 -0
  62. data/spec/aws/service_spec.rb +31 -0
  63. data/spec/bootstrapper_spec.rb +116 -0
  64. data/spec/cli_spec.rb +71 -0
  65. data/spec/config_spec.rb +68 -0
  66. data/spec/cuke_spec.rb +46 -0
  67. data/spec/ersatz_node_spec.rb +9 -0
  68. data/spec/ersatz_ssh_result_spec.rb +16 -0
  69. data/spec/hooks_spec.rb +19 -0
  70. data/spec/logger_spec.rb +22 -0
  71. data/spec/parser_spec.rb +93 -0
  72. data/spec/puppet.rb +47 -0
  73. data/spec/puppet_node_spec.rb +31 -0
  74. data/spec/rackspace/images_spec.rb +37 -0
  75. data/spec/rackspace/node_spec.rb +30 -0
  76. data/spec/source_spec.rb +45 -0
  77. data/spec/spec_helper.rb +10 -0
  78. data/spec/support/features/example.feature +9 -0
  79. data/spec/support/features/step_definitions/example.rb +8 -0
  80. data/spec/util_spec.rb +27 -0
  81. metadata +288 -0
data/bin/skewer ADDED
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env ruby
2
+ $: << File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ require 'optparse'
6
+ require 'parser'
7
+
8
+ options = {:kind => :ersatz}
9
+
10
+ type = ARGV.shift
11
+
12
+ optparse = OptionParser.new do |opts|
13
+ #
14
+ # Provision
15
+ #
16
+ opts.on('-c', '--cloud KIND', "Cloud kind ('ec2', 'linode', 'rackspace')") do |c|
17
+ options[:kind] = c.to_sym
18
+ end
19
+
20
+ opts.on('-r', '--role NAME', "puppet role class to call") do |r|
21
+ options[:role] = r
22
+ end
23
+
24
+ opts.on('-pc', '--puppetcode') do |pc|
25
+ options[:puppet_repo] = pc
26
+ puts "puppetcode is: " + pc
27
+ end
28
+
29
+ opts.on('-m', '--mock') do
30
+ options[:mock] = true
31
+ end
32
+
33
+ opts.on('--keep') do
34
+ options[:keep] = true
35
+ end
36
+
37
+ opts.on('-hk', '--hook') do |hook|
38
+ options[:hook] = hook
39
+ end
40
+
41
+ # AWS options
42
+ opts.on('-i', '--image NAME') do |img|
43
+ options[:image] = img
44
+ end
45
+ opts.on('--volume SIZE') do |vol|
46
+ # EBS group
47
+ options[:volume] = vol
48
+ end
49
+ opts.on('--region NAME') do |region|
50
+ # AWS region
51
+ options[:region] = region
52
+ end
53
+ opts.on('--key', '--key_name NAME') do |k|
54
+ # AWS SSH key
55
+ options[:key_name] = k
56
+ end
57
+ opts.on('--group NAME') do |group|
58
+ # EC2 Security Group
59
+ options[:group] = group
60
+ end
61
+ opts.on('--flavor FLAVOR') do |flavor|
62
+ # AWS instance size
63
+ options[:flavor_id] = flavor
64
+ end
65
+
66
+ #
67
+ # Updating.
68
+ #
69
+ # TODO: This shouldn't be -h for hostname.
70
+ opts.on('-h', '--host KIND', "Hostname to update") do |c|
71
+ options[:host] = c
72
+ end
73
+ opts.on('-u', '--user KIND', "User to connect with") do |u|
74
+ options[:user] = u
75
+ end
76
+ opts.on('-r', '--role NAME', "puppet role class to call") do |r|
77
+ options[:role] = r
78
+ end
79
+ opts.on('-n', '--noop', "do a dry run first") do
80
+ options[:noop] = true
81
+ end
82
+ opts.on('-pc', '--puppetcode') do |pc|
83
+ options[:puppet_repo] = pc
84
+ puts "puppetcode is: " + pc
85
+ end
86
+
87
+ opts.on('--features DIRECTORY') do |dir|
88
+ options[:cuke_dir] = dir
89
+ end
90
+
91
+ # TODO: Fix this, and update the above for --host/-h
92
+ opts.on('-q', '--help') do
93
+ options[:help] = true
94
+ end
95
+ end
96
+
97
+ optparse.parse!
98
+
99
+ Fog.mock! if options[:mock]
100
+
101
+ Skewer::CLI::Parser.new(type, options)
@@ -0,0 +1,45 @@
1
+ Feature: provisioning a node on AWS
2
+ In order to run my puppet code on a new AWS machine
3
+ As someone who wants to deploy something to the machine
4
+ I want to run the provision command
5
+
6
+ @announce-stdout
7
+ @announce-stderr
8
+
9
+ Scenario: Roll out AWS node and configure it
10
+ Given I have puppet code in "/tmp/skewer_test_code"
11
+ And a file named ".skewer.json" with:
12
+ """
13
+ {"puppet_repo": "/tmp/skewer_test_code" }
14
+ """
15
+ When I run `./bin/skewer provision --cloud ec2 --role foobar --image ami-5c9b4935 --key testytesty`
16
+ Then the exit status should be 0
17
+ And the stdout should contain "Puppet run succeeded"
18
+
19
+
20
+
21
+ Scenario: Roll out AWS node and configure it without a JSON file
22
+ Given I have puppet code in "/tmp/skewer_test_code"
23
+ When I run `./bin/skewer provision --cloud ec2 --role foobar --image ami-5c9b4935 --key testytesty --puppetcode /tmp/skewer_test_code`
24
+ Then the exit status should be 0
25
+ And the stdout should contain "Puppet run succeeded"
26
+
27
+
28
+ @announce-stdout
29
+ @announce-stderr
30
+ @wip
31
+ Scenario: Roll out AWS node with a specific region
32
+ Given I have puppet code in "/tmp/skewer_test_code"
33
+ When I run `./bin/skewer provision --cloud ec2 --role foobar --image ami-f6340182 --region eu-west-1 --key testytesty --puppetcode /tmp/skewer_test_code`
34
+ Then the exit status should be 0
35
+ And the stdout should contain "Puppet run succeeded"
36
+
37
+
38
+ Scenario: Roll out AWS node with a specific size
39
+ Given I have puppet code in "/tmp/skewer_test_code"
40
+ And a file named ".skewer.json" with:
41
+ """
42
+ {"puppet_repo": "/tmp/skewer_test_code" }
43
+ """
44
+ When I run `./bin/skewer provision --cloud ec2 --role foobar --image ami-5c9b4935 --flavor m1.small --key testytesty`
45
+ Then the stdout should contain "Puppet run succeeded"
@@ -0,0 +1,14 @@
1
+ Feature: valid bash bootstrap code
2
+ In order to run the tool
3
+ As a user
4
+ I want the bootstrap code to work
5
+
6
+ Scenario: valid bash file
7
+ When I run `bash -nx assets/rubygems.sh`
8
+ Then the exit status should be 0
9
+
10
+ Scenario: only indents should be tabs
11
+ When a file named "assets/rubygems.sh" should exist
12
+ Then the file "assets/rubygems.sh" shouldnt match "^ +"
13
+ And the file "assets/rubygems.sh" should match "^\t"
14
+
@@ -0,0 +1,15 @@
1
+ Feature: Configuration
2
+ In order to tell Skewer what I am doing
3
+ As a user
4
+ I want it to accept a config file
5
+
6
+ Scenario: read config from project directory
7
+ Given a file named ".skewer.json" with:
8
+ """
9
+ {"puppet_repo":"/foo/bar/baz"}
10
+ """
11
+ When I run `./bin/skewer provision --cloud stub --image foo --role bar`
12
+ Then the stdout should contain "Using Puppet Code from /foo/bar/baz"
13
+
14
+ Scenario: read config from home directory
15
+
@@ -0,0 +1,22 @@
1
+ Feature: updating a node
2
+ In order to delete a node
3
+ As a someone who knows the cloud and host address
4
+ I want to run the delete command
5
+
6
+ @announce-stdout @announce-stderr
7
+ Scenario: run the command with bad input
8
+ When I run `./bin/skewer delete --cloud ec2 --host bleh --key ~/.ssh/testytest.pem`
9
+ Then the stderr should contain "bleh not found"
10
+ And the exit status should not be 0
11
+
12
+ @announce-stdout @announce-stderr
13
+ Scenario: run the command with bad input
14
+ When I run `./bin/skewer delete --cloud ec2 --host bleh --key ~/.ssh/testytest.pem`
15
+ Then the stderr should contain "bleh not found"
16
+ And the exit status should not be 0
17
+
18
+ @wip @announce-stdout @announce-stderr
19
+ Scenario: create a new Rackspace server and delete it
20
+ Given I create a new Rackspace server
21
+ When I delete the new Rackspace server I created
22
+ Then the output should say that the Rackspace server was deleted
@@ -0,0 +1,15 @@
1
+ Feature: Hooks
2
+ In order to integrate Skewer with other processes
3
+ As a user
4
+ I want it to execute a command when it's finihsed
5
+
6
+ Scenario: accept hook on CLI
7
+ Given a file named "/tmp/skewer_hook" with:
8
+ """
9
+ #!/bin/bash
10
+ echo $1 > /tmp/skewer_hook_result
11
+ """
12
+ And I run `chmod +x /tmp/skewer_hook`
13
+ When I run `./bin/skewer provision --cloud stub --image foo --role bar --hook /tmp/skewer_hook`
14
+ Then the file "/tmp/skewer_hook_result" should exist
15
+
@@ -0,0 +1,61 @@
1
+ Feature: help output for the skewer command-line tool
2
+ In order to get sufficient feedback
3
+ As someone who wants to use skewer
4
+ When I do something wrong or provide the help option
5
+ I want the help messages to appear
6
+
7
+ Scenario: run the command without arguments
8
+ When I run `./bin/skewer`
9
+ Then the output should contain:
10
+ """
11
+ Usage: skewer COMMAND [options]
12
+
13
+ The available skewer commands are:
14
+ provision spawn a new VM via a cloud system and provision it with puppet code
15
+ update update the puppet code on a machine that you've already provisioned
16
+ """
17
+ And the exit status should not be 0
18
+
19
+ Scenario: run the command with help option
20
+ When I run `./bin/skewer --help`
21
+ Then the output should contain:
22
+ """
23
+ Usage: skewer COMMAND [options]
24
+
25
+ The available skewer commands are:
26
+ provision spawn a new VM via a cloud system and provision it with puppet code
27
+ update update the puppet code on a machine that you've already provisioned
28
+ """
29
+ And the exit status should not be 0
30
+
31
+ Scenario: run the provision command without arguments
32
+ When I run `./bin/skewer provision`
33
+ Then the output should contain:
34
+ """
35
+ Usage: skewer provision --cloud <which cloud> --image <AWS image> --role <puppet role class>
36
+ """
37
+ And the exit status should not be 0
38
+
39
+ Scenario: run the provision command with help arguments
40
+ When I run `./bin/skewer provision --help`
41
+ Then the output should contain:
42
+ """
43
+ Usage: skewer provision --cloud <which cloud> --image <AWS image> --role <puppet role class>
44
+ """
45
+ And the exit status should not be 0
46
+
47
+ Scenario: run the update command without arguments
48
+ When I run `./bin/skewer update`
49
+ Then the output should contain:
50
+ """
51
+ Usage: skewer update --host <host> --user <user with sudo rights> --role <puppet role class>
52
+ """
53
+ And the exit status should not be 0
54
+
55
+ Scenario: run the update command with help arguments
56
+ When I run `./bin/skewer update --help`
57
+ Then the output should contain:
58
+ """
59
+ Usage: skewer update --host <host> --user <user with sudo rights> --role <puppet role class>
60
+ """
61
+ And the exit status should not be 0
@@ -0,0 +1,38 @@
1
+ Feature: provisioning a node
2
+ In order to run my puppet code for the first time
3
+ As a someone who wants to deploy something to the machine
4
+ I want to run the provision command
5
+
6
+ @puts
7
+ Scenario: run the command without args
8
+ When I run `./bin/skewer provision`
9
+ Then the exit status should not be 0
10
+
11
+ @announce-stdout
12
+ @announce-stderr
13
+ Scenario: pass in a cloud image and role
14
+ When I run `./bin/skewer provision --cloud stub --image foo --role foo`
15
+ Then the exit status should be 0
16
+
17
+ @announce-stdout
18
+ @announce-stderr
19
+ Scenario: config in local file
20
+ Given I have puppet code in "/tmp/skewer_test_code"
21
+ And a file named ".skewer.json" with:
22
+ """
23
+ {"puppet_repo":"/tmp/skewer_test_code"}
24
+ """
25
+ When I run `./bin/skewer provision --cloud stub --role foobar --image ami-deadbeef`
26
+ Then the stdout should contain "Using Puppet Code from /tmp/skewer_test_code"
27
+ And the exit status should be 0
28
+
29
+ @announce-stdout
30
+ @announce-stderr
31
+ Scenario: generated node file
32
+ Given I have puppet code in "/tmp/more_skewer_test_code"
33
+ And a file named ".skewer.json" with:
34
+ """
35
+ {"puppet_repo":"/tmp/skewer_test_code"}
36
+ """
37
+ When I run `./bin/skewer provision --cloud stub --role foobar --image ami-deadbeef`
38
+ Then the file "/tmp/more_skewer_test_code/manifests/nodes.pp" should exist
@@ -0,0 +1,34 @@
1
+ Feature: provisioning a node on Rackspace
2
+ In order to run my puppet code on a new Rackspace machine
3
+ As someone who wants to deploy something to the machine
4
+ I want to run the provision command
5
+
6
+ @announce-stdout
7
+ @announce-stderr
8
+ Scenario: config in local file
9
+ Given I have puppet code in "/tmp/skewer_test_code"
10
+ And a file named ".skewer.json" with:
11
+ """
12
+ {
13
+ "puppet_repo":"/tmp/skewer_test_code",
14
+ "flavor_id":"1",
15
+ "image_id":"112"
16
+ }
17
+ """
18
+ When I run `./bin/skewer provision --cloud rackspace --role foobar --image 112`
19
+ Then the stdout should contain "Evaluating cloud rackspace"
20
+ And the stdout should contain "Launching a Rackspace node"
21
+
22
+ @announce-stdout
23
+ @announce-stderr
24
+ Scenario: Build a machine with a specific flavor (RAM size)
25
+ Given I run `./bin/skewer provision --cloud rackspace --role foobar --image 112 --flavor 3`
26
+ Then the stdout should contain "Evaluating cloud rackspace"
27
+ And the stdout should contain "Launching a Rackspace node"
28
+
29
+ @announce-stdout
30
+ @announce-stderr
31
+ Scenario: Build a machine with a symbolic image ID
32
+ Given I run `./bin/skewer provision --cloud rackspace --role foobar --image ubuntu1104 --flavor 2`
33
+ Then the stdout should contain "Evaluating cloud rackspace"
34
+ And the stdout should contain "Launching a Rackspace node"
@@ -0,0 +1,43 @@
1
+ Before do
2
+ config_file = File.join(File.dirname(__FILE__), '../..', '.skewer.json')
3
+ puts "Checking for #{config_file}"
4
+ if File.exists?(config_file)
5
+ puts "Removing #{config_file}"
6
+ FileUtils.rm_f(config_file)
7
+ end
8
+ end
9
+
10
+ Given /^I have puppet code in "([^"]*)"$/ do |dir|
11
+
12
+ puppet_code_source = File.join(File.dirname(__FILE__), '../support/puppetcode')
13
+ puts "Copying #{puppet_code_source} to #{dir}"
14
+ FileUtils.cp_r(puppet_code_source, dir) unless File.exists?(dir)
15
+ @puppet_repo = dir
16
+ end
17
+
18
+
19
+ require 'resolv-replace'
20
+ require 'ping'
21
+
22
+ def internet_connection?
23
+ Ping.pingecho "google.com", 1, 80
24
+ end
25
+
26
+
27
+ Given /^I have access to the internet$/ do
28
+ internet_connection?.should == true
29
+ end
30
+
31
+ Then /^the file "([^"]*)" should exist$/ do |file|
32
+ File.exists?(file).should == true
33
+ end
34
+
35
+ Then /^the file "([^"]*)" (.*) match "([^"]*)"$/ do |file, condition, expr|
36
+ file_contents = File.read(file)
37
+ if condition == 'should'
38
+ file_contents.should match expr
39
+ else
40
+ file_contents.should_not match expr
41
+ end
42
+ end
43
+
@@ -0,0 +1,32 @@
1
+ require 'fog'
2
+
3
+ Given /^I create a new Rackspace server$/ do
4
+ build = lambda {
5
+ service = Fog::Compute.new(
6
+ :provider => 'Rackspace',
7
+ :rackspace_auth_url => "lon.auth.api.rackspacecloud.com")
8
+ path = File.expand_path '~/.ssh/id_rsa.pub'
9
+ path = File.expand_path '~/.ssh/id_dsa.pub' if not File.exist? path
10
+ key = File.open(path, 'rb').read
11
+ return service.servers.bootstrap({
12
+ :flavor_id => 1,
13
+ :image_id => 112,
14
+ :name => "i-shouldnt-exist",
15
+ :public_key => key})
16
+ }
17
+ @node = build.call
18
+ @ip_address = node.public_ip_address
19
+ end
20
+
21
+ When /^I delete the new Rackspace server I created$/ do
22
+ ip = @ip_address
23
+ # The 2>&1 tells shell to redirect stderr to stdout.
24
+ @out = `./bin/skewer delete --cloud rackspace --host #{ip} 2>&1`
25
+ end
26
+
27
+ Then /^the output should say that the Rackspace server was deleted$/ do
28
+ ip = @ip_address
29
+ match = @out.match("#{ip} deleted")
30
+ match.should_not == nil
31
+ match.class.should == MatchData
32
+ end
@@ -0,0 +1,6 @@
1
+ require 'aruba/cucumber'
2
+
3
+ Before do
4
+ @dirs = [Dir.pwd]
5
+ @aruba_timeout_seconds = 600
6
+ end