buckknife 0.0.4

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 (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,58 @@
1
+ module BuckKnife
2
+ module Commands
3
+ class RackspaceCreate < Create
4
+ include Base
5
+
6
+ # --bootstrap-version VERSION The version of Chef to install
7
+ # -N, --node-name NAME The Chef node name for your new node
8
+ # -s, --server-url URL Chef Server URL
9
+ # -k, --key KEY API Client Key
10
+ # --color Use colored output
11
+ # -c, --config CONFIG The configuration file to use
12
+ # --defaults Accept default values for all questions
13
+ # -d, --distro DISTRO Bootstrap a distro using a template; default is 'ubuntu10.04-gems'
14
+ # -e, --editor EDITOR Set the editor to use for interactive commands
15
+ # -E, --environment ENVIRONMENT Set the Chef environment
16
+ # -f, --flavor FLAVOR The flavor of server; default is 2 (512 MB)
17
+ # -F, --format FORMAT Which format to use for output
18
+ # -I, --image IMAGE The image of the server
19
+ # --no-color Don't use colors in the output
20
+ # -n, --no-editor Do not open EDITOR, just accept the data as is
21
+ # -u, --user USER API Client Username
22
+ # --prerelease Install the pre-release chef gems
23
+ # --print-after Show the data after a destructive operation
24
+ # --rackspace-api-auth-url URL Your rackspace API auth url; default is 'auth.api.rackspacecloud.com'
25
+ # -K, --rackspace-api-key KEY Your rackspace API key
26
+ # -A USERNAME Your rackspace API username
27
+ # --rackspace-api-username
28
+ # -r, --run-list RUN_LIST Comma separated list of roles/recipes to apply
29
+ # -S, --server-name NAME The server name
30
+ # -P, --ssh-password PASSWORD The ssh password
31
+ # -x, --ssh-user USERNAME The ssh username; default is 'root'
32
+ # --template-file TEMPLATE Full path to location of template to use
33
+ # --sudo Execute the bootstrap via sudo
34
+ # -V, --verbose More verbose output. Use twice for max verbosity
35
+ # -v, --version Show chef version
36
+ # -y, --yes Say yes to all prompts for confirmation
37
+ # -h, --help Show this message
38
+
39
+ def command
40
+ super.tap do |c|
41
+ c.opt '-S', node.name
42
+ c.opt '-K', project.rs_api_key
43
+ c.opt '-A', project.rs_api_username
44
+ end
45
+ end
46
+
47
+ protected
48
+
49
+ def image_id
50
+ node.image_id || '49'
51
+ end
52
+
53
+ def flavor
54
+ BuckKnife::Helper.rackspace_flavors[ node.size ].to_s
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ module BuckKnife
2
+ module Commands
3
+ # options is a hash with one or more of the following keys specified:
4
+ # :project => Project Name eg. myapp
5
+ # :environment => Environment Name eg. staging
6
+ # :node => Node Name eg. myapp-staging-app1
7
+ # :ssh_user => (optional) ssh user to connect with
8
+ # :ssh_password => (optional) ssh user's password
9
+ class RunClient
10
+ include Base
11
+
12
+ def initialize(options)
13
+ @project = BuckKnife::Project.find( options[:project] )
14
+ @options = options
15
+ end
16
+
17
+ def command
18
+ super.tap do |c|
19
+ c.arg 'ssh', query, 'sudo chef-client'
20
+ c.opt '--attribute', 'ipaddress'
21
+ c.opt '-x', ssh_username
22
+ c.opt '-P', ssh_password
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ def query
29
+ result = []
30
+ result << "project:#{@options[:project]}" if @options[:project]
31
+ result << "environment:#{@options[:environment]}" if @options[:environment]
32
+ result << "name:#{@options[:node]}" if @options[:node]
33
+ result.join(' AND ')
34
+ end
35
+
36
+ def node
37
+ @project.node(@options[:node]) || @project.nodes.first
38
+ end
39
+
40
+ def ssh_username
41
+ node.ssh_username
42
+ end
43
+
44
+ def ssh_password
45
+ node.ssh_password
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,29 @@
1
+ module BuckKnife
2
+ module DataAccessor
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+
6
+ def _read_data(key)
7
+ @data[key.to_s]
8
+ end
9
+
10
+ def _write_data(key, val)
11
+ @data[key.to_s] = val
12
+ end
13
+ end
14
+
15
+ module ClassMethods
16
+ def data_accessor(*names)
17
+ names.each do |name|
18
+ define_method(name) do
19
+ _read_data(name)
20
+ end
21
+
22
+ define_method("#{name}=") do |val|
23
+ _write_data(name, val)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,16 @@
1
+ module BuckKnife
2
+ class Environment
3
+ attr_reader :name, :nodes
4
+
5
+ def initialize(name, data, nodes)
6
+ @data = data
7
+ @name = name
8
+ @nodes = nodes
9
+ end
10
+
11
+ def domain_name
12
+ @data['domain_name']
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ module BuckKnife::Helper
2
+ extend self
3
+
4
+ def parse_node_ip(node, interface)
5
+ network = node['network']
6
+ interfaces = network['interfaces']
7
+ iface = interfaces[interface]
8
+ addresses = iface['addresses']
9
+
10
+ return addresses.keys.select {|key| addresses[key]['family'] == 'inet'}.first
11
+ end
12
+
13
+ def read_project_data_bag(project)
14
+ project_data_bag_file = File.expand_path File.join( BuckKnife.project_root, "#{project}.json" )
15
+ project_data = JSON.parse File.read(project_data_bag_file)
16
+ end
17
+
18
+ def combine_roles_and_recipes(roles=[], recipes=[], separator=' ')
19
+ role_array = roles.map { |role| "role[#{role}]" }
20
+ recipe_array = recipes.map { |recipe| "recipe[#{recipe}]" }
21
+ roles_and_recipes = role_array.concat(recipe_array).join(separator)
22
+
23
+ roles_and_recipes
24
+ end
25
+
26
+ def rackspace_flavors
27
+ {
28
+ '256M' => 1,
29
+ '512M' => 2,
30
+ '1G' => 3,
31
+ '2G' => 4,
32
+ '4G' => 5,
33
+ '8G' => 6,
34
+ '16G' => 7
35
+ }
36
+ end
37
+
38
+ end
39
+
@@ -0,0 +1,22 @@
1
+ module BuckKnife
2
+ module KnifeHelper
3
+ def project_from_arg_or_ask
4
+ project_name = @name_args[0]
5
+
6
+ if project_name.nil?
7
+ show_usage
8
+ ui.fatal("You must specify a project name")
9
+ exit 1
10
+ end
11
+
12
+ begin
13
+ project = Project.find(project_name)
14
+ rescue BuckKnife::UnknownProjectError
15
+ ui.fatal("A project data file '#{project_name}.json' was not found in #{Project.root}")
16
+ exit 1
17
+ end
18
+
19
+ return project
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ module BuckKnife
2
+ class Node
3
+ include DataAccessor
4
+ attr_accessor :name
5
+
6
+ def initialize(name, data)
7
+ @name = name
8
+ @data = data
9
+ end
10
+
11
+ data_accessor :image_id, :size, :flavor, :environment, :address, :group
12
+ data_accessor :ssh_username, :ssh_password
13
+
14
+ def roles
15
+ @data["roles"].split(' ')
16
+ end
17
+
18
+ def recipes
19
+ @data["recipes"].split(' ')
20
+ end
21
+
22
+ def run_list
23
+ BuckKnife::Helper.combine_roles_and_recipes(roles, recipes)
24
+ end
25
+
26
+ def run_list_items
27
+ run_list.split(' ')
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,80 @@
1
+ require 'pathname'
2
+ require 'active_model'
3
+
4
+ module BuckKnife
5
+ class Project
6
+ include DataAccessor
7
+ include ActiveModel::Validations
8
+
9
+ data_accessor :repository, :distro, :base_run_list, :provider
10
+ data_accessor :ssh_username, :identity_file
11
+ data_accessor :rs_api_key, :rs_api_username
12
+
13
+ validates_presence_of :provider, :distro, :base_run_list
14
+
15
+ class << self
16
+ def all_names
17
+ Dir["#{root}/*.json"].map { |f| File.basename(f).split(".").first }
18
+ end
19
+
20
+ def all
21
+ Dir["#{root}/*.json"].map { |f| from_file(f) }
22
+ end
23
+
24
+ def find(name)
25
+ from_file root.join("#{name}.json")
26
+ end
27
+
28
+ def from_file(path)
29
+ raise UnknownProjectError unless File.exist?(path)
30
+ new( JSON.parse( File.read(path) ) )
31
+ end
32
+
33
+ def root
34
+ @root ||= begin
35
+ unless path = Chef::Config[:knife][:project_dir]
36
+ raise UnknownProjectRootError, "You must define knife[:project_dir] in your knife.rb"
37
+ end
38
+
39
+ Pathname.new path
40
+ end
41
+ end
42
+
43
+ def root=(path)
44
+ @root = Pathname.new(path)
45
+ end
46
+ end
47
+
48
+ def initialize(data)
49
+ @data = data
50
+ end
51
+
52
+ def name
53
+ @data["id"]
54
+ end
55
+
56
+ def node_names
57
+ @data["nodes"].keys.sort
58
+ end
59
+
60
+ def nodes
61
+ @data["nodes"].map { |name, data| Node.new(name, data) }
62
+ end
63
+
64
+ def node(name)
65
+ nodes.find { |n| n.name == name }
66
+ end
67
+
68
+ def environment_names
69
+ @data["environments"].keys.sort
70
+ end
71
+
72
+ def environments
73
+ @data["environments"].map do |name, data|
74
+ Environment.new( name, data, nodes.select { |n| n.environment == name } )
75
+ end
76
+ end
77
+
78
+ end
79
+ end
80
+
@@ -0,0 +1,85 @@
1
+ # This file is automatically generated by BuckKnife.
2
+ #
3
+ # DO NOT MODIFY THIS FILE
4
+ #
5
+ # Place your custom variables, tasks and overrides in the deploy.rb
6
+ # file. To add this file to your Rails application copy it the the
7
+ # config directory as config/deploy_environments.rb
8
+ #
9
+ # Then load it at the top of your deploy.rb file with the following
10
+ # statement:
11
+ #
12
+ # load 'config/deploy_environments'
13
+
14
+
15
+ require "bundler/capistrano"
16
+ require 'highline/import'
17
+
18
+
19
+ default_run_options[:pty] = true
20
+
21
+ set :repository, "<%= project.repository %>"
22
+ set :scm, :git
23
+ set :app_user, "deploy"
24
+ set :user, "<%= project.nodes.first.ssh_username %>"
25
+ set :password, "<%= project.nodes.first.ssh_password %>"
26
+ set :use_sudo, true
27
+
28
+ set :checkout, "export"
29
+ set :deploy_via, "copy"
30
+ set :copy_strategy, :export
31
+ set :copy_exclude, ".git/*"
32
+ set :copy_compression, :zip
33
+
34
+
35
+
36
+ <% environments.each do |environment| %>
37
+
38
+ desc "Deploy to <%= environment[:name] %> (usage: cap <%= environment[:name] %> deploy)"
39
+ task :<%= environment[:name] %> do
40
+ set :domain, "<%= environment[:domain_name] %>"
41
+ set :application, "<%= project.name %>"
42
+ set :rails_env, "<%= environment[:name] %>"
43
+ set :deploy_to, "/var/www/<%= environment[:domain_name] %>"
44
+
45
+ <% environment[:app_servers].each do |app_server| %>
46
+
47
+ role :app, "<%= app_server.address %>" # <%= app_server.name %>
48
+ <% end %>
49
+ <% environment[:job_servers].each do |job_server| %>
50
+
51
+ role :job, "<%= job_server.address %>" # <%= job_server.name %>
52
+ <% end %>
53
+
54
+ role :db, "<%= environment[:primary_db].address %>", :primary => true # <%= environment[:primary_db].name %>
55
+
56
+ end
57
+
58
+ <% end %>
59
+
60
+ namespace :deploy do
61
+ task :start do ; end
62
+ task :stop do ; end
63
+
64
+ task :restart, :roles => :app, :except => { :no_release => true } do
65
+ run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
66
+ end
67
+
68
+ task :chown_project, :roles => [:app, :job] do
69
+ sudo "chmod 777 #{deploy_to}/releases"
70
+ sudo "chown -R #{app_user}:sysadmin #{deploy_to}"
71
+ end
72
+
73
+ task :symlink_database_config, :roles => [:app, :job] do
74
+ run "rm #{release_path}/config/database.yml"
75
+ run "ln -s #{deploy_to}/shared/database.yml #{release_path}/config/database.yml"
76
+ end
77
+
78
+ end
79
+
80
+
81
+ after 'deploy:setup', 'deploy:chown_project'
82
+ after 'deploy', 'deploy:chown_project'
83
+ after 'deploy:finalize_update', 'deploy:symlink_database_config'
84
+
85
+
@@ -0,0 +1,75 @@
1
+ {
2
+ "id": "<%= project_name %>",
3
+ "domain": "<%= project_name %>.com",
4
+ "repository": "FIXME",
5
+ "provider": "rackspace",
6
+ "public_interface": "eth0",
7
+ "internal_interface": "eth1",
8
+ "distro": "FIXME",
9
+ "base_run_list": "monitor_client",
10
+
11
+ "environments": {
12
+ "production": {
13
+ "domain_name": "origin.<%= project_name %>.com",
14
+ "www_virtual_ip": "FIXME",
15
+ "database_user": "FIXME",
16
+ "database_password": "FIXME"
17
+ },
18
+ "staging": {
19
+ "domain_name": "staging.<%= project_name %>.com",
20
+ "www_virtual_ip": "127.0.0.1",
21
+ "database_user": "FIXME",
22
+ "database_password": "FIXME"
23
+ },
24
+ "dev": {
25
+ "domain_name": "dev.<%= project_name %>.com",
26
+ "www_virtual_ip": "127.0.0.1",
27
+ "database_user": "FIXME",
28
+ "database_password": "FIXME"
29
+ }
30
+ },
31
+
32
+ "nodes": {
33
+ "myapp-monitor1": {
34
+ "group": "monitor",
35
+ "size": "2G",
36
+ "environment": "production",
37
+ "roles": "",
38
+ "recipes": "",
39
+ "address": "127.0.0.1",
40
+ "ssh_username": "FIXME",
41
+ "ssh_password": "FIXME"
42
+ },
43
+
44
+ "myapp-dev-app1": {
45
+ "group": "app",
46
+ "size": "2G",
47
+ "environment": "dev",
48
+ "roles": "app_heartbeat_pair rails_app rails_nginx_app",
49
+ "recipes": "",
50
+ "address": "127.0.0.1",
51
+ "ssh_username": "FIXME",
52
+ "ssh_password": "FIXME"
53
+ },
54
+ "myapp-dev-app2": {
55
+ "group": "app",
56
+ "size": "2G",
57
+ "environment": "dev",
58
+ "roles": "app_heartbeat_pair rails_app rails_nginx_app",
59
+ "recipes": "",
60
+ "address": "127.0.0.1",
61
+ "ssh_username": "username",
62
+ "ssh_password": "password"
63
+ },
64
+ "myapp-dev-job1": {
65
+ "group": "job",
66
+ "size": "2G",
67
+ "environment": "dev",
68
+ "roles": "rails_app rails_job",
69
+ "recipes": "",
70
+ "address": "127.0.0.1",
71
+ "ssh_username": "username",
72
+ "ssh_password": "password"
73
+ }
74
+ }
75
+ }