buckknife 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +4 -0
  3. data/HISTORY.md +8 -0
  4. data/README.md +65 -0
  5. data/Rakefile +27 -0
  6. data/buckknife.gemspec +31 -0
  7. data/lib/buckknife.rb +44 -0
  8. data/lib/buckknife/command.rb +33 -0
  9. data/lib/buckknife/commands/add_role.rb +13 -0
  10. data/lib/buckknife/commands/base.rb +24 -0
  11. data/lib/buckknife/commands/bootstrap.rb +28 -0
  12. data/lib/buckknife/commands/capistrano.rb +46 -0
  13. data/lib/buckknife/commands/create.rb +42 -0
  14. data/lib/buckknife/commands/euca_create.rb +60 -0
  15. data/lib/buckknife/commands/rackspace_create.rb +58 -0
  16. data/lib/buckknife/commands/run_client.rb +49 -0
  17. data/lib/buckknife/data_accessor.rb +29 -0
  18. data/lib/buckknife/environment.rb +16 -0
  19. data/lib/buckknife/helper.rb +39 -0
  20. data/lib/buckknife/knife_helper.rb +22 -0
  21. data/lib/buckknife/node.rb +30 -0
  22. data/lib/buckknife/project.rb +80 -0
  23. data/lib/buckknife/templates/deploy_environments.rb.erb +85 -0
  24. data/lib/buckknife/templates/project.json.erb +75 -0
  25. data/lib/buckknife/version.rb +3 -0
  26. data/lib/chef/knife/project_add_role.rb +24 -0
  27. data/lib/chef/knife/project_bootstrap.rb +24 -0
  28. data/lib/chef/knife/project_capistrano.rb +19 -0
  29. data/lib/chef/knife/project_create.rb +53 -0
  30. data/lib/chef/knife/project_info.rb +13 -0
  31. data/lib/chef/knife/project_list.rb +17 -0
  32. data/lib/chef/knife/project_new.rb +28 -0
  33. data/lib/chef/knife/project_run_client.rb +30 -0
  34. data/lib/chef/knife/project_show.rb +34 -0
  35. data/spec/buckknife/commands/add_role_spec.rb +14 -0
  36. data/spec/buckknife/commands/bootstrap_spec.rb +22 -0
  37. data/spec/buckknife/commands/capistrano_spec.rb +13 -0
  38. data/spec/buckknife/commands/create_spec.rb +48 -0
  39. data/spec/buckknife/commands/run_client_spec.rb +15 -0
  40. data/spec/buckknife/environment_spec.rb +14 -0
  41. data/spec/buckknife/helper_spec.rb +11 -0
  42. data/spec/buckknife/node_spec.rb +18 -0
  43. data/spec/buckknife/project_spec.rb +49 -0
  44. data/spec/data_bags/projects/myapp.json +139 -0
  45. data/spec/knife.rb +4 -0
  46. data/spec/knife/project_bootstrap_spec.rb +0 -0
  47. data/spec/knife/project_info_spec.rb +17 -0
  48. data/spec/knife/project_list_spec.rb +18 -0
  49. data/spec/spec_helper.rb +27 -0
  50. metadata +251 -0
@@ -0,0 +1,3 @@
1
+ module BuckKnife
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,24 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectAddRole < Chef::Knife
5
+ banner "knife project add role PROJECT [NODE]"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ include BuckKnife::KnifeHelper
10
+ end
11
+
12
+ def run
13
+ project = project_from_arg_or_ask
14
+ node_name = @name_args[1]
15
+ nodes = Array(project.node(node_name) || project.nodes)
16
+
17
+ nodes.each do |node|
18
+ ui.output "# Run these command to add roles one at a time to #{node.name}:"
19
+ ui.output BuckKnife::Commands::AddRole.new( node )
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectBootstrap < Chef::Knife
5
+ banner "knife project bootstrap PROJECT [NODE]"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ include BuckKnife::KnifeHelper
10
+ end
11
+
12
+ def run
13
+ project = project_from_arg_or_ask
14
+ node_name = @name_args[1]
15
+ nodes = Array(project.node(node_name) || project.nodes)
16
+
17
+ nodes.each do |node|
18
+ ui.output "# Run this command to bootstrap #{node.name}:"
19
+ ui.output BuckKnife::Commands::Bootstrap.new( project, node )
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectCapistrano < Chef::Knife
5
+ banner "knife project capistrano PROJECT"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ include BuckKnife::KnifeHelper
10
+ end
11
+
12
+ def run
13
+ project = project_from_arg_or_ask
14
+ ui.output "# Copy and commit this file to the project's repository:"
15
+ ui.output BuckKnife::Commands::Capistrano.new(project).call
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,53 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectCreate < Chef::Knife
5
+ banner "knife project create PROJECT [NODE]"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ include BuckKnife::KnifeHelper
10
+ end
11
+
12
+ option :identity_file,
13
+ :short => "-i IDENTITY_FILE",
14
+ :long => "--identity-file",
15
+ :description => "The SSH identity file used for authentication"
16
+
17
+ option :provider,
18
+ :short => "-p PROVIDER",
19
+ :long => "--provider",
20
+ :description => "The cloud provider to use (euca, rackspace, ...)"
21
+
22
+ option :ssh_username,
23
+ :short => "-x USERNAME",
24
+ :long => "--ssh-user",
25
+ :description => "The ssh username"
26
+
27
+ def run
28
+ project = project_from_arg_or_ask
29
+ node_name = @name_args[1]
30
+ nodes = Array(project.node(node_name) || project.nodes)
31
+
32
+ project.identity_file = Chef::Config[:knife][:euca_identity_file] if Chef::Config[:knife][:euca_identity_file]
33
+ project.provider = config[:provider] if config[:provider]
34
+ project.ssh_username = config[:ssh_username] if config[:ssh_username]
35
+
36
+ # TODO: Move this into project, ActiveModel validation?
37
+ unless project.valid?
38
+ ui.fatal("The #{project.name}.json file has some errors that need to be fixed:")
39
+ project.errors.each do |att, err|
40
+ ui.fatal("'#{att}' #{err}")
41
+ end
42
+
43
+ exit 1
44
+ end
45
+
46
+ nodes.each do |node|
47
+ ui.output "# Run this command to create #{node.name}:"
48
+ ui.output BuckKnife::Commands::Create[project.provider].new(project, node)
49
+ end
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,13 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectInfo < Chef::Knife
5
+ banner "knife project info"
6
+
7
+ def run
8
+ ui.output "Config file: %s" % Chef::Config[:config_file] || config[:config_file]
9
+ ui.output "Chef Server: %s" % Chef::Config[:chef_server_url]
10
+ ui.output "Project Dir: %s" % Chef::Config[:knife][:project_dir]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectList < Chef::Knife
5
+ banner "knife project list"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ end
10
+
11
+ def run
12
+ BuckKnife::Project.all.each do |project|
13
+ ui.output " #{project.name}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectNew < Chef::Knife
5
+ banner "knife project new PROJECT"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ end
10
+
11
+ def run
12
+ project_name = @name_args[0]
13
+
14
+ if project_name.nil?
15
+ show_usage
16
+ ui.fatal("You must specify a project name")
17
+ exit 1
18
+ end
19
+
20
+ template = BuckKnife.template_root.join("project.json.erb").read
21
+ compiled = ERB.new(template, nil, '%>').result(binding)
22
+ project_path = Project.root.join("#{project_name}.json")
23
+ project_path.open("w") { |f| f.write compiled }
24
+
25
+ ui.output ui.color("#{project_name}.json written to #{project_path}", :green)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectRunClient < Chef::Knife
5
+ banner "knife project run client PROJECT [NODE] [options]"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ include BuckKnife::KnifeHelper
10
+ end
11
+
12
+ option :env,
13
+ :short => "-e ENVIRONMENT",
14
+ :long => "--env ENVIRONMENT",
15
+ :description => "Project environment to scope to (dev,staging,production)"
16
+
17
+ def run
18
+ project = project_from_arg_or_ask
19
+ node_name = @name_args[1]
20
+
21
+ ui.output "# Run this command to run client:"
22
+ ui.output BuckKnife::Commands::RunClient.new(
23
+ :project => project.name,
24
+ :node => node_name,
25
+ :environment => config[:env]
26
+ )
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ require 'chef/knife'
2
+
3
+ module BuckKnife
4
+ class ProjectShow < Chef::Knife
5
+ banner "knife project show PROJECT"
6
+
7
+ deps do
8
+ require 'buckknife'
9
+ include BuckKnife::KnifeHelper
10
+ end
11
+
12
+ def run
13
+ ui.use_presenter BuckKnife::ProjectPresenter
14
+ project = project_from_arg_or_ask
15
+ output(project)
16
+ end
17
+ end
18
+
19
+ class ProjectPresenter < Chef::Knife::Core::GenericPresenter
20
+
21
+ def summarize(project)
22
+ summarized = <<-SUMMARY
23
+ #{ui.color('Project Name:', :bold)} #{ui.color(project.name, :bold)}
24
+ #{key('Environments:')} #{project.environment_names.join(', ')}
25
+ #{key('Nodes:')} #{project.node_names.join("\n" + ' ' * 14)}
26
+ SUMMARY
27
+ end
28
+
29
+ def key(key_text)
30
+ ui.color(key_text, :cyan)
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe BuckKnife::Commands::AddRole do
4
+ it "should output a knife command to add roles" do
5
+ project = BuckKnife::Project.find('myapp')
6
+ node = project.node('myapp-monitor1')
7
+ cmd = BuckKnife::Commands::AddRole.new(node)
8
+
9
+ cmd.to_s.should == [
10
+ "knife node run_list add myapp-monitor1 'role[monitor_client]'",
11
+ "knife node run_list add myapp-monitor1 'role[rails_app]'"
12
+ ].join("\n")
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ # cli = BuckKnife::CLI.new(args, options, config)
2
+ # cli.invoke(:task, [first_arg, second_arg, third_arg], {options hash})
3
+ require 'spec_helper'
4
+
5
+ describe BuckKnife::Commands::Bootstrap do
6
+ it "should output a knife command to bootstrap the server on rackspace" do
7
+ project = BuckKnife::Project.find('myapp')
8
+ node = project.node('myapp-monitor1')
9
+ cmd = BuckKnife::Commands::Bootstrap.new(project, node)
10
+
11
+ cmd.to_s.should == [
12
+ "knife bootstrap 127.0.0.1",
13
+ "-N myapp-monitor1",
14
+ "-x username",
15
+ "-P password",
16
+ "-r 'role[base],recipe[base_projects::myapp],role[base_server]'",
17
+ "-d ubuntu10.04.deb",
18
+ "--sudo"
19
+ ].join(' ')
20
+
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ # cli = BuckKnife::CLI.new(args, options, config)
2
+ # cli.invoke(:task, [first_arg, second_arg, third_arg], {options hash})
3
+ require 'spec_helper'
4
+
5
+ describe BuckKnife::Commands::Capistrano do
6
+ it "should output a capistrano deploy script for a project" do
7
+ BuckKnife::Commands::Capistrano.any_instance.stub(:fetch_ip) { "127.0.0.1" }
8
+ project = BuckKnife::Project.find('myapp')
9
+ cmd = BuckKnife::Commands::Capistrano.new(project)
10
+
11
+ cmd.call.should =~ /DO NOT MODIFY THIS FILE/
12
+ end
13
+ end
@@ -0,0 +1,48 @@
1
+ # cli = BuckKnife::CLI.new(args, options, config)
2
+ # cli.invoke(:task, [first_arg, second_arg, third_arg], {options hash})
3
+ require 'spec_helper'
4
+
5
+ describe BuckKnife::Commands::Create do
6
+ it "should output a knife command to create the server on rackspace" do
7
+ project = BuckKnife::Project.find('myapp')
8
+ node = project.node('myapp-monitor1')
9
+ cmd = BuckKnife::Commands::Create[project.provider].new(project, node)
10
+
11
+ cmd.to_s.should == [
12
+ "knife rackspace server create",
13
+ "-r 'role[base],recipe[base_projects::myapp],role[base_server]'",
14
+ "-f 4",
15
+ "-I 49",
16
+ "-d ubuntu10.04.deb",
17
+ "-s http://localhost:4000",
18
+ "-N myapp-monitor1",
19
+ "-S myapp-monitor1",
20
+ "-K ''",
21
+ "-A ''"
22
+ ].join(' ')
23
+
24
+ end
25
+
26
+ it "should output a knife command to create the server on eucalyptus" do
27
+ project = BuckKnife::Project.find('myapp')
28
+ project.should_receive(:provider) { "euca" }.twice
29
+ node = project.node('myapp-monitor1')
30
+
31
+ node.flavor.should be_nil
32
+
33
+ cmd = BuckKnife::Commands::Create[project.provider].new(project, node)
34
+ cmd.should_receive(:availability_zone) { "us-west-1" }.twice
35
+
36
+ cmd.to_s.should == [
37
+ "knife euca server create",
38
+ "-r 'role[base],recipe[base_projects::myapp],role[base_server]'",
39
+ "-f m1.large",
40
+ "-I emi-DFB9107F",
41
+ "-d ubuntu10.04.deb",
42
+ "-s http://localhost:4000",
43
+ "-N myapp-monitor1",
44
+ "-Z us-west-1"
45
+ ].join(' ')
46
+
47
+ end
48
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe BuckKnife::Commands::RunClient do
4
+ it "should output a knife command to add roles" do
5
+ cmd = BuckKnife::Commands::RunClient.new(:project => 'myapp', :node => 'myapp-monitor1')
6
+
7
+ cmd.to_s.should == [
8
+ "knife ssh 'project:myapp AND name:myapp-monitor1'",
9
+ "'sudo chef-client'",
10
+ "--attribute ipaddress",
11
+ "-x username",
12
+ "-P password"
13
+ ].join(' ')
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe BuckKnife::Environment do
4
+ context "initialized with a name and hash of data" do
5
+ subject { BuckKnife::Environment.new("dev", {"domain_name" => "dev.myapp.com"}, []) }
6
+ it "should have a name" do
7
+ subject.name.should == "dev"
8
+ end
9
+
10
+ it "should have a domain name" do
11
+ subject.domain_name.should == "dev.myapp.com"
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe BuckKnife::Helper do
4
+ it "should create a run list from roles and recipes" do
5
+ roles = ['base', 'base_server']
6
+ recipes = ["base_projects::projectname"]
7
+ sep = ','
8
+ result = BuckKnife::Helper.combine_roles_and_recipes(roles, recipes, sep)
9
+ result.should == "role[base],role[base_server],recipe[base_projects::projectname]"
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe BuckKnife::Node do
4
+ context "initialized with a hash of data" do
5
+ subject { BuckKnife::Project.find("myapp").node("myapp-monitor1") }
6
+ it "should have a name" do
7
+ subject.name.should == "myapp-monitor1"
8
+ end
9
+
10
+ it "should have a size" do
11
+ subject.size.should == "2G"
12
+ end
13
+
14
+ it "should have a run list" do
15
+ subject.run_list.should == "role[monitor_client] role[rails_app]"
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe BuckKnife::Project do
4
+ context "initialized with a hash of data" do
5
+ subject { BuckKnife::Project.find("myapp") }
6
+ it "should have a name" do
7
+ subject.name.should == "myapp"
8
+ end
9
+
10
+ it "should have node names" do
11
+ subject.node_names.should == %w[
12
+ myapp-dev-app1
13
+ myapp-dev-app2
14
+ myapp-dev-job1
15
+ myapp-monitor1
16
+ myapp-prod-app1
17
+ myapp-prod-app2
18
+ myapp-prod-job1
19
+ myapp-staging-app1
20
+ myapp-staging-app2
21
+ myapp-staging-job1
22
+ ]
23
+ end
24
+
25
+ it "should have nodes" do
26
+ subject.nodes.first.should be_instance_of BuckKnife::Node
27
+ end
28
+
29
+ it "can look up a node based on name" do
30
+ subject.node("myapp-monitor1").should be_instance_of BuckKnife::Node
31
+ end
32
+
33
+ it "should have a repository" do
34
+ subject.repository.should == "http://svn.domain.com/myapp/trunk"
35
+ end
36
+
37
+ it "should have environment names" do
38
+ subject.environment_names.should == ["dev", "production", "staging"]
39
+ end
40
+
41
+ it "should have environments" do
42
+ subject.environments.first.should be_instance_of BuckKnife::Environment
43
+ end
44
+
45
+ it "should have a provider" do
46
+ subject.provider.should == "rackspace"
47
+ end
48
+ end
49
+ end