pawnee 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +158 -0
- data/Rakefile +11 -0
- data/bin/pawnee +10 -0
- data/docs/FAQ.md +33 -0
- data/docs/GUIDE.md +102 -0
- data/docs/TODO.md +10 -0
- data/lib/pawnee/pawnee/actions/base_model.rb +35 -0
- data/lib/pawnee/pawnee/actions/compile.rb +140 -0
- data/lib/pawnee/pawnee/actions/package.rb +111 -0
- data/lib/pawnee/pawnee/actions/user.rb +116 -0
- data/lib/pawnee/pawnee/actions.rb +29 -0
- data/lib/pawnee/pawnee/base.rb +265 -0
- data/lib/pawnee/pawnee/cli.rb +72 -0
- data/lib/pawnee/pawnee/invocation.rb +13 -0
- data/lib/pawnee/pawnee/parser/options.rb +55 -0
- data/lib/pawnee/pawnee/railtie.rb +23 -0
- data/lib/pawnee/pawnee/roles.rb +79 -0
- data/lib/pawnee/pawnee/setup.rb +23 -0
- data/lib/pawnee/pawnee/templates/newgem/Gemfile.tt +4 -0
- data/lib/pawnee/pawnee/templates/newgem/LICENSE.tt +22 -0
- data/lib/pawnee/pawnee/templates/newgem/README.md.tt +29 -0
- data/lib/pawnee/pawnee/templates/newgem/Rakefile.tt +2 -0
- data/lib/pawnee/pawnee/templates/newgem/bin/newgem.tt +3 -0
- data/lib/pawnee/pawnee/templates/newgem/gitignore.tt +17 -0
- data/lib/pawnee/pawnee/templates/newgem/lib/pawnee/newgem/base.rb.tt +27 -0
- data/lib/pawnee/pawnee/templates/newgem/lib/pawnee/newgem/version.rb.tt +7 -0
- data/lib/pawnee/pawnee/templates/newgem/lib/pawnee/newgem.rb.tt +10 -0
- data/lib/pawnee/pawnee/templates/newgem/newgem.gemspec.tt +18 -0
- data/lib/pawnee/pawnee/version.rb +3 -0
- data/lib/pawnee/pawnee.rb +7 -0
- data/pawnee.gemspec +31 -0
- data/spec/actions/compile_spec.rb +26 -0
- data/spec/actions/package_spec.rb +41 -0
- data/spec/actions/user_spec.rb +54 -0
- data/spec/base_spec.rb +167 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/vagrant/.vagrant +1 -0
- data/spec/vagrant/Vagrantfile +99 -0
- data/spec/vagrant/vagrant.rb +30 -0
- metadata +328 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) <%=Time.now.year%> <%=config[:author]%>
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# <%=config[:constant_name]%>
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem '<%=config[:name]%>'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install <%=config[:name]%>
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "<%= config[:name] %>/version"
|
2
|
+
require 'pawnee/base'
|
3
|
+
|
4
|
+
<%- config[:constant_array].each_with_index do |c,i| -%>
|
5
|
+
<%= ' '*i %>module <%= c %>
|
6
|
+
<%- end -%>
|
7
|
+
<%- j = config[:constant_array].size -%>
|
8
|
+
<%= ' '*j %>class Base < Pawnee::Base
|
9
|
+
<%= ' '*j %> global_options do
|
10
|
+
<%= ' '*j %> method_option :servers, :type => :array, :required => true
|
11
|
+
<%= ' '*j %> end
|
12
|
+
<%= ' '*j %> desc "setup", 'setup on the destination server'
|
13
|
+
<%= ' '*j %> def setup
|
14
|
+
<%= ' '*j %> # Add your setup code here
|
15
|
+
<%= ' '*j %> end
|
16
|
+
<%= ' '*j %>
|
17
|
+
<%= ' '*j %> global_options do
|
18
|
+
<%= ' '*j %> method_option :servers, :type => :array, :required => true
|
19
|
+
<%= ' '*j %> end
|
20
|
+
<%= ' '*j %> desc "teardown", 'teardown on the destination server'
|
21
|
+
<%= ' '*j %> def teardown
|
22
|
+
<%= ' '*j %> # Add your teardown code here
|
23
|
+
<%= ' '*j %> end
|
24
|
+
<%= ' '*j %>end
|
25
|
+
<%- (config[:constant_array].size-1).downto(0) do |i| -%>
|
26
|
+
<%= ' '*i %>end
|
27
|
+
<%- end -%>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'pawnee/setup'
|
2
|
+
Pawnee::Base.setup('pawnee-<%= config[:name] %>')
|
3
|
+
|
4
|
+
<%- config[:constant_array].each_with_index do |c,i| -%>
|
5
|
+
<%= ' '*i %>module <%= c %>
|
6
|
+
<%- end -%>
|
7
|
+
<%= ' '*config[:constant_array].size %># Your code goes here...
|
8
|
+
<%- (config[:constant_array].size-1).downto(0) do |i| -%>
|
9
|
+
<%= ' '*i %>end
|
10
|
+
<%- end -%>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/pawnee/<%=config[:name]%>/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = [<%=config[:author].inspect%>]
|
6
|
+
gem.email = [<%=config[:email].inspect%>]
|
7
|
+
gem.description = %q{TODO: Write a gem description}
|
8
|
+
gem.summary = %q{TODO: Write a gem summary}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "pawnee-<%=config[:name]%>"
|
15
|
+
gem.require_paths = ["lib/pawnee"]
|
16
|
+
gem.add_runtime_dependency 'pawnee'
|
17
|
+
gem.version = <%=config[:constant_name]%>::VERSION
|
18
|
+
end
|
data/pawnee.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/pawnee/pawnee/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Ryan Stout"]
|
6
|
+
gem.email = ["ryanstout@gmail.com"]
|
7
|
+
gem.description = %q{Pawnee attempts to build a better server provisioning system}
|
8
|
+
gem.summary = %q{Better server provisioing}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "pawnee"
|
15
|
+
gem.require_paths = ["lib/pawnee"]
|
16
|
+
gem.add_runtime_dependency 'bundler'
|
17
|
+
gem.add_runtime_dependency 'thor', '>= 0.14.6'
|
18
|
+
gem.add_runtime_dependency 'net-ssh', '= 2.2.2'
|
19
|
+
gem.add_runtime_dependency 'net-sftp', '= 2.0.5'
|
20
|
+
gem.add_runtime_dependency 'thor-ssh'
|
21
|
+
gem.add_runtime_dependency 'activemodel', "~> 3.2.3"
|
22
|
+
gem.add_runtime_dependency 'activesupport', "~> 3.2.3"
|
23
|
+
gem.add_development_dependency "turn"
|
24
|
+
gem.add_development_dependency 'rspec', '~> 2.10'
|
25
|
+
gem.add_development_dependency 'vagrant', '= 1.0.3'
|
26
|
+
gem.add_development_dependency 'sahara', '>= 0.0.11'
|
27
|
+
gem.add_development_dependency 'rake', '~> 0.9'
|
28
|
+
gem.add_development_dependency 'rdoc', '~> 3.9'
|
29
|
+
gem.add_development_dependency 'simplecov', '~> 0.4'
|
30
|
+
gem.version = Pawnee::VERSION
|
31
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pawnee/base'
|
3
|
+
|
4
|
+
|
5
|
+
# NOTE: These are designed to run in order on vagrant
|
6
|
+
describe "compile actions" do
|
7
|
+
before do
|
8
|
+
@base = Pawnee::Base.new
|
9
|
+
@base.destination_connection = VagrantManager.connect
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should install a package' do
|
13
|
+
@base.install_packages('libpcre3', 'libpcre3-dev', 'libpcrecpp0', 'libssl-dev', 'zlib1g-dev')
|
14
|
+
@base.as_root do
|
15
|
+
@base.exec('rm /usr/local/sbin/nginx')
|
16
|
+
end
|
17
|
+
|
18
|
+
@base.exec('which nginx').should == ''
|
19
|
+
|
20
|
+
@base.compile('http://nginx.org/download/nginx-1.2.0.tar.gz', '/home/vagrant/nginx/', {configure: '--sbin-path=/usr/local/sbin', :bin_file => 'nginx'})
|
21
|
+
|
22
|
+
@base.exec('which nginx').should_not == ''
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pawnee/base'
|
3
|
+
|
4
|
+
|
5
|
+
# NOTE: These are designed to run in order on vagrant
|
6
|
+
describe "package actions" do
|
7
|
+
before do
|
8
|
+
@base = Pawnee::Base.new
|
9
|
+
@base.destination_connection = VagrantManager.connect
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should install a package' do
|
13
|
+
@base.install_package('memcached', '1.4.7-0.1ubuntu1')
|
14
|
+
@base.exec('which memcached').strip.should_not == ''
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should not reinstall a package' do
|
18
|
+
# Should be called once for the package version query
|
19
|
+
@base.destination_server.should_receive(:run).once.and_return('ii memcached 1.4.7-0.1ubuntu1')
|
20
|
+
@base.install_package('memcached', '1.4.7-0.1ubuntu1')
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should return the version of a package installed' do
|
24
|
+
@base.installed_package_version('memcached').should == '1.4.7-0.1ubuntu1'
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should remove a package" do
|
28
|
+
@base.remove_package('memcached')
|
29
|
+
@base.exec('which memcached').should == ''
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should not try to re-remove a package" do
|
33
|
+
@base.destination_server.should_receive(:run).once.and_return('')
|
34
|
+
@base.remove_package('memcached')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should not return the package version after the package has been removed" do
|
38
|
+
@base.installed_package_version('memcached').should == nil
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pawnee/base'
|
3
|
+
|
4
|
+
|
5
|
+
# NOTE: These are designed to run in order on vagrant
|
6
|
+
describe "user actions" do
|
7
|
+
before do
|
8
|
+
@base = Pawnee::Base.new
|
9
|
+
@base.destination_connection = VagrantManager.connect
|
10
|
+
end
|
11
|
+
|
12
|
+
def user_exists?(login)
|
13
|
+
_, _, exit_code, _ = @base.exec("id -u #{login}", true)
|
14
|
+
return exit_code == 0
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should create a user" do
|
18
|
+
@base.create_user(
|
19
|
+
name: 'Test Blue',
|
20
|
+
login: 'blue'
|
21
|
+
)
|
22
|
+
|
23
|
+
user_exists?('blue').should == true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should shouldn't recreate a user" do
|
27
|
+
@base.should_receive(:say_status).with(:user_exists, 'blue', :blue)
|
28
|
+
@base.create_user(
|
29
|
+
name: 'Test Blue',
|
30
|
+
login: 'blue'
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should modify a user" do
|
35
|
+
# @base.should_receive(:exec).any_number_of_times.ordered.with('id -u blue', true).and_return(["1002\n", '', 0, nil])
|
36
|
+
# @base.should_receive(:exec).any_number_of_times.ordered.with('id -u blue', true).and_return(["1002\n", '', 0, nil])
|
37
|
+
# @base.should_receive(:exec).any_number_of_times.ordered.with('id -g blue').and_return("1002\n")
|
38
|
+
# @base.should_receive(:exec).any_number_of_times.ordered.with('groups blue').and_return("blue: blue")
|
39
|
+
# @base.should_receive(:exec).once.ordered.with('useradd -c "comment" blue').and_return('')
|
40
|
+
@base.create_user(
|
41
|
+
name: 'Test Blue',
|
42
|
+
login: 'blue',
|
43
|
+
comment: 'comment'
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should delete a user" do
|
48
|
+
user_exists?('blue').should == true
|
49
|
+
|
50
|
+
@base.delete_user('blue')
|
51
|
+
|
52
|
+
user_exists?('blue').should == false
|
53
|
+
end
|
54
|
+
end
|
data/spec/base_spec.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Pawnee::Base do
|
4
|
+
before do
|
5
|
+
@base = Pawnee::Base.new
|
6
|
+
end
|
7
|
+
|
8
|
+
# after(:all) do
|
9
|
+
# puts "Clear after base"
|
10
|
+
# Pawnee::Base.instance_variable_set('@recipes', nil)
|
11
|
+
# Pawnee::Blue.instance_eval { remove_const :Base }
|
12
|
+
# Pawnee.instance_eval { remove_const :Blue }
|
13
|
+
# Pawnee::Red.instance_eval { remove_const :Base }
|
14
|
+
# Pawnee.instance_eval { remove_const :Red }
|
15
|
+
# Pawnee.instance_eval { remove_const :CLI }
|
16
|
+
# require 'pawnee/cli'
|
17
|
+
# end
|
18
|
+
|
19
|
+
it "should respond to setup" do
|
20
|
+
@base.should respond_to(:setup)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should respond to teardown" do
|
24
|
+
@base.should respond_to(:teardown)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should raise an exception when setup is called' do
|
28
|
+
-> { @base.setup() }.should raise_error(RuntimeError)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should raise an exception when teardown is called' do
|
32
|
+
-> { @base.teardown() }.should raise_error(RuntimeError)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
class Dep
|
37
|
+
attr_accessor :name
|
38
|
+
|
39
|
+
def initialize(name)
|
40
|
+
@name = name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should have no recipes before they are defined, but should add them after they are defined" do
|
45
|
+
Pawnee::Base.recipes.should == nil
|
46
|
+
|
47
|
+
# These will persist between tests
|
48
|
+
module Pawnee
|
49
|
+
module Red
|
50
|
+
class Base < Pawnee::Base
|
51
|
+
desc "setup", "setup"
|
52
|
+
def setup
|
53
|
+
puts "SETUP RED"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
module Blue
|
59
|
+
class Base < Pawnee::Base
|
60
|
+
desc "setup", "setup"
|
61
|
+
def setup
|
62
|
+
puts "SETUP BLUE"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
Pawnee::Base.recipes.should == [Pawnee::Red::Base, Pawnee::Blue::Base]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should list the recipes in the order declared in the gem" do
|
72
|
+
deps = [Dep.new('blue'), Dep.new('red')]
|
73
|
+
Bundler.load.stub(:dependencies).and_return(deps)
|
74
|
+
|
75
|
+
Pawnee::Base.ordered_recipes.should == [Pawnee::Blue::Base, Pawnee::Red::Base]
|
76
|
+
|
77
|
+
deps = [Dep.new('red'), Dep.new('blue')]
|
78
|
+
Bundler.load.stub(:dependencies).and_return(deps)
|
79
|
+
Pawnee::Base.instance_variable_set('@ordered_recipes', nil)
|
80
|
+
|
81
|
+
Pawnee::Base.ordered_recipes.should == [Pawnee::Red::Base, Pawnee::Blue::Base]
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
it "should invoke roles based on the roles passed in" do
|
86
|
+
red = Pawnee::Red::Base.new([], {})
|
87
|
+
red.should_receive(:setup)
|
88
|
+
Pawnee::Red::Base.should_receive(:new).and_return(red)
|
89
|
+
|
90
|
+
Pawnee::Blue::Base.should_not_receive(:new)
|
91
|
+
|
92
|
+
Pawnee::Base.invoke_roles(:setup, ['red'])
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should invoke roles limiting to server roles" do
|
96
|
+
# Say we have a config file setup like this
|
97
|
+
config_options = {
|
98
|
+
'servers' => [
|
99
|
+
{'domain' => 'test1.com', 'roles' => ['red']}
|
100
|
+
]
|
101
|
+
}
|
102
|
+
|
103
|
+
# But we want to pass in options with more domains
|
104
|
+
options = {
|
105
|
+
'servers' => [
|
106
|
+
{'domain' => 'test1.com', 'roles' => ['red']},
|
107
|
+
{'domain' => 'test2.com', 'roles' => ['blue', 'red']}
|
108
|
+
]
|
109
|
+
}
|
110
|
+
|
111
|
+
Pawnee::Base.should_receive(:config_options).at_least(:once).and_return(config_options)
|
112
|
+
|
113
|
+
red = Pawnee::Red::Base.new([], options)
|
114
|
+
red.should_receive(:setup).twice
|
115
|
+
Pawnee::Red::Base.should_receive(:new).with([], options).and_return(red)
|
116
|
+
|
117
|
+
blue = Pawnee::Blue::Base.new([], options)
|
118
|
+
blue.should_receive(:setup).once
|
119
|
+
Pawnee::Blue::Base.should_receive(:new).with([], options).and_return(blue)
|
120
|
+
|
121
|
+
Pawnee::Base.invoke_roles(:setup, ['red', 'blue'], options)
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should invoke for each server when doing an individual recipe's setup task" do
|
126
|
+
options = {
|
127
|
+
'servers' => [
|
128
|
+
{'domain' => 'test1.com', 'roles' => ['red']},
|
129
|
+
{'domain' => 'test2.com', 'roles' => ['red']}
|
130
|
+
]
|
131
|
+
}
|
132
|
+
|
133
|
+
Pawnee::Base.should_receive(:config_options).at_least(:once).and_return(options)
|
134
|
+
|
135
|
+
red = Pawnee::Red::Base.new([], options)
|
136
|
+
red.should_receive(:setup).twice
|
137
|
+
Pawnee::Red::Base.should_receive(:new).and_return(red)
|
138
|
+
|
139
|
+
Pawnee::Blue::Base.should_not_receive(:new)
|
140
|
+
|
141
|
+
Pawnee::CLI.start(['red', 'setup'])
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should call all setup methods when called with setup from the command line" do
|
146
|
+
options = {
|
147
|
+
'servers' => [
|
148
|
+
{'domain' => 'test1.com', 'roles' => ['red']},
|
149
|
+
{'domain' => 'test2.com', 'roles' => ['red', 'blue']}
|
150
|
+
]
|
151
|
+
}
|
152
|
+
|
153
|
+
Pawnee::Base.should_receive(:config_options).at_least(:once).and_return(options)
|
154
|
+
|
155
|
+
red = Pawnee::Red::Base.new([], options)
|
156
|
+
red.should_receive(:setup).twice
|
157
|
+
Pawnee::Red::Base.should_receive(:new).and_return(red)
|
158
|
+
|
159
|
+
blue = Pawnee::Blue::Base.new([], options)
|
160
|
+
blue.should_receive(:setup).once
|
161
|
+
Pawnee::Blue::Base.should_receive(:new).with([], options).and_return(blue)
|
162
|
+
|
163
|
+
Pawnee::CLI.start(['setup'])
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
|
3
|
+
libdir = File.expand_path(File.dirname(__FILE__) + "/../lib/pawnee")
|
4
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
5
|
+
|
6
|
+
|
7
|
+
require 'simplecov'
|
8
|
+
SimpleCov.start do
|
9
|
+
add_group 'Libraries', 'lib/pawnee/pawnee'
|
10
|
+
add_group 'Specs', 'spec'
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
require 'pawnee/base'
|
15
|
+
require 'vagrant/vagrant'
|
16
|
+
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
config.after(:suite) do
|
20
|
+
# Rollback the server
|
21
|
+
puts "Roll back test server"
|
22
|
+
`cd spec/vagrant/ ; BUNDLE_GEMFILE=../../Gemfile bundle exec vagrant sandbox rollback`
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
{"active":{"default":"21e9da4d-756c-4cf9-8cae-caf4f70820f7"}}
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
Vagrant::Config.run do |config|
|
5
|
+
# All Vagrant configuration is done here. The most common configuration
|
6
|
+
# options are documented and commented below. For a complete reference,
|
7
|
+
# please see the online documentation at vagrantup.com.
|
8
|
+
|
9
|
+
# Every Vagrant virtual environment requires a box to build off of.
|
10
|
+
config.vm.box = "ubuntu11"
|
11
|
+
|
12
|
+
# The url from where the 'config.vm.box' box will be fetched if it
|
13
|
+
# doesn't already exist on the user's system.
|
14
|
+
# config.vm.box_url = "http://domain.com/path/to/above.box"
|
15
|
+
|
16
|
+
# Boot with a GUI so you can see the screen. (Default is headless)
|
17
|
+
# config.vm.boot_mode = :gui
|
18
|
+
|
19
|
+
# Assign this VM to a host-only network IP, allowing you to access it
|
20
|
+
# via the IP. Host-only networks can talk to the host machine as well as
|
21
|
+
# any other machines on the same network, but cannot be accessed (through this
|
22
|
+
# network interface) by any external networks.
|
23
|
+
# config.vm.network :hostonly, "192.168.33.10"
|
24
|
+
|
25
|
+
# Assign this VM to a bridged network, allowing you to connect directly to a
|
26
|
+
# network using the host's network device. This makes the VM appear as another
|
27
|
+
# physical device on your network.
|
28
|
+
# config.vm.network :bridged
|
29
|
+
|
30
|
+
# Forward a port from the guest to the host, which allows for outside
|
31
|
+
# computers to access the VM, whereas host only networking does not.
|
32
|
+
# config.vm.forward_port 80, 8080
|
33
|
+
|
34
|
+
# Share an additional folder to the guest VM. The first argument is
|
35
|
+
# an identifier, the second is the path on the guest to mount the
|
36
|
+
# folder, and the third is the path on the host to the actual folder.
|
37
|
+
# config.vm.share_folder "v-data", "/vagrant_data", "../data"
|
38
|
+
|
39
|
+
# Enable provisioning with Puppet stand alone. Puppet manifests
|
40
|
+
# are contained in a directory path relative to this Vagrantfile.
|
41
|
+
# You will need to create the manifests directory and a manifest in
|
42
|
+
# the file ubuntu11.pp in the manifests_path directory.
|
43
|
+
#
|
44
|
+
# An example Puppet manifest to provision the message of the day:
|
45
|
+
#
|
46
|
+
# # group { "puppet":
|
47
|
+
# # ensure => "present",
|
48
|
+
# # }
|
49
|
+
# #
|
50
|
+
# # File { owner => 0, group => 0, mode => 0644 }
|
51
|
+
# #
|
52
|
+
# # file { '/etc/motd':
|
53
|
+
# # content => "Welcome to your Vagrant-built virtual machine!
|
54
|
+
# # Managed by Puppet.\n"
|
55
|
+
# # }
|
56
|
+
#
|
57
|
+
# config.vm.provision :puppet do |puppet|
|
58
|
+
# puppet.manifests_path = "manifests"
|
59
|
+
# puppet.manifest_file = "ubuntu11.pp"
|
60
|
+
# end
|
61
|
+
|
62
|
+
# Enable provisioning with chef solo, specifying a cookbooks path, roles
|
63
|
+
# path, and data_bags path (all relative to this Vagrantfile), and adding
|
64
|
+
# some recipes and/or roles.
|
65
|
+
#
|
66
|
+
# config.vm.provision :chef_solo do |chef|
|
67
|
+
# chef.cookbooks_path = "../my-recipes/cookbooks"
|
68
|
+
# chef.roles_path = "../my-recipes/roles"
|
69
|
+
# chef.data_bags_path = "../my-recipes/data_bags"
|
70
|
+
# chef.add_recipe "mysql"
|
71
|
+
# chef.add_role "web"
|
72
|
+
#
|
73
|
+
# # You may also specify custom JSON attributes:
|
74
|
+
# chef.json = { :mysql_password => "foo" }
|
75
|
+
# end
|
76
|
+
|
77
|
+
# Enable provisioning with chef server, specifying the chef server URL,
|
78
|
+
# and the path to the validation key (relative to this Vagrantfile).
|
79
|
+
#
|
80
|
+
# The Opscode Platform uses HTTPS. Substitute your organization for
|
81
|
+
# ORGNAME in the URL and validation key.
|
82
|
+
#
|
83
|
+
# If you have your own Chef Server, use the appropriate URL, which may be
|
84
|
+
# HTTP instead of HTTPS depending on your configuration. Also change the
|
85
|
+
# validation key to validation.pem.
|
86
|
+
#
|
87
|
+
# config.vm.provision :chef_client do |chef|
|
88
|
+
# chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME"
|
89
|
+
# chef.validation_key_path = "ORGNAME-validator.pem"
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# If you're using the Opscode platform, your validator client is
|
93
|
+
# ORGNAME-validator, replacing ORGNAME with your organization name.
|
94
|
+
#
|
95
|
+
# IF you have your own Chef Server, the default validation client name is
|
96
|
+
# chef-validator, unless you changed the configuration.
|
97
|
+
#
|
98
|
+
# chef.validation_client_name = "ORGNAME-validator"
|
99
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'vagrant'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
# Return an ssh connection to the vagrant server
|
5
|
+
class VagrantManager
|
6
|
+
# Returns a connected Net::SSH connection
|
7
|
+
def self.connect
|
8
|
+
@vm = Vagrant::Environment.new(:cwd => File.dirname(__FILE__)).primary_vm
|
9
|
+
|
10
|
+
ssh_info = @vm.ssh.info
|
11
|
+
|
12
|
+
# Build the options we'll use to initiate the connection via Net::SSH
|
13
|
+
opts = {
|
14
|
+
:port => ssh_info[:port],
|
15
|
+
:keys => [ssh_info[:private_key_path]],
|
16
|
+
:keys_only => true,
|
17
|
+
:user_known_hosts_file => [],
|
18
|
+
:paranoid => false,
|
19
|
+
:config => false,
|
20
|
+
:forward_agent => ssh_info[:forward_agent]
|
21
|
+
}
|
22
|
+
|
23
|
+
# Check that the private key permissions are valid
|
24
|
+
@vm.ssh.check_key_permissions(ssh_info[:private_key_path])
|
25
|
+
|
26
|
+
# Connect to SSH, giving it a few tries
|
27
|
+
return Net::SSH.start(ssh_info[:host], ssh_info[:username], opts)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|