knife-stackbuilder 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8de9741b23271b0bafcd08a39d7fe5f5e7a53030
4
+ data.tar.gz: 8d134e95054c1bb253f477fa4d10eed38e34ca74
5
+ SHA512:
6
+ metadata.gz: 16f91cc0f5846a7710a50cde9ba66cf2fad80c91a82a3d35246c4109ec6a3d9abfece254b6ff5dd0d68ab533c499c6bdccac8f5e170984c4f24900802b8b5c89
7
+ data.tar.gz: 12fcdbf1f952293f844e4ef8379e565e36148393a16a7ac8a26517639328bc29642ccc51d3dc794c57ffaaceadf34d23deed1cf4ae673684743305e7e219c3bc
data/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # Knife StackBuilder plugin
2
+
3
+ ## Usage
4
+
5
+ ```
6
+ knife stack initialize repo
7
+
8
+ Initializes or validates an existing stack repo. The stack repo should contain the
9
+ following folders along with a Berksfile.
10
+
11
+ * cookbooks
12
+ * environments
13
+ * secrets
14
+ * databags
15
+ * roles
16
+ * stacks
17
+
18
+ --path
19
+
20
+ Path to create and initialize the stack chef repository. If the repository already
21
+ exists then any it will be validated. If the provided path begins with git:, http:
22
+ or https:, it will be assumed to be a git repo. A branch/label may be specified
23
+ by preceding it with a : after the path.
24
+
25
+ i.e. http://github.com/mevansam/mystack:tag1
26
+
27
+ --cert_path | --certs
28
+
29
+ If "--cert_path" is specified then it should point to a directory with a folder for
30
+ each server domain name containing that server's certificate files.
31
+
32
+ If instead "--certs" are specified then it should provide a comma separated list of
33
+ server domain names for which self-signed certificates will be generated.
34
+
35
+ --envs
36
+
37
+ Comma separated list of environments to generate.
38
+
39
+ --cookbooks
40
+
41
+ A comma separated list of cookbooks and their versions to be added to the Berksfile.
42
+
43
+ i.e. "mysql:=5.6.1, wordpress:~> 2.3.0"
44
+ ```
45
+
46
+ ```
47
+ knife stack upload cookbook[s]
48
+ ```
49
+
50
+ ```
51
+ knife stack upload environment[s]
52
+ ```
53
+
54
+ ```
55
+ knife stack upload role[s]
56
+ ```
57
+
58
+ ```
59
+ knife stack upload data bag[s]
60
+ ```
61
+
62
+ ```
63
+ knife stack upload repo
64
+ ```
65
+
66
+ ```
67
+ knife stack build
68
+ ```
69
+
70
+ ## Design
71
+
72
+ ### Berkshelf Cookbook Repository Management
73
+
74
+ ### Externalizing configuration values and order of evaluation
75
+
76
+ #### Requesting user input for non-persisted values
77
+
78
+ #### Including common yaml configurations
79
+
80
+ #### Processing node attributes
81
+
82
+ ### Converging a cluster using target nodes
83
+
84
+ * Magic variables
85
+
86
+ ### Dependency management and orchestration
87
+
88
+ ## To Do:
89
+
90
+ * Use Chef Pushy instead of Knife SSH
91
+ * Add option to execute Chef Push jobs on events
92
+
93
+ ## Contributing
94
+
95
+ 1. Fork the repository on Github
96
+ 2. Write your change
97
+ 3. Write tests for your change (if applicable)
98
+ 4. Run the tests, ensuring they all pass
99
+ 5. Submit a Pull Request
100
+
101
+ ## License and Authors
102
+
103
+ Licensed under the Apache License, Version 2.0 (the "License");
104
+ you may not use this file except in compliance with the License.
105
+ You may obtain a copy of the License at
106
+
107
+ http://www.apache.org/licenses/LICENSE-2.0
108
+
109
+ Unless required by applicable law or agreed to in writing, software
110
+ distributed under the License is distributed on an "AS IS" BASIS,
111
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
112
+ See the License for the specific language governing permissions and
113
+ limitations under the License.
114
+
115
+ Author: Mevan Samaratunga (mevansam@gmail.com)
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ $:.unshift(File.expand_path("../../rake", __FILE__))
4
+
5
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __FILE__)
6
+
7
+ require "rubygems"
8
+ require "bundler"
9
+ Bundler.setup(:default, :test)
10
+
11
+ require "rake"
12
+ begin
13
+ require "rspec/core/rake_task"
14
+ rescue LoadError
15
+ end
16
+
17
+ gem_helper = Bundler::GemHelper.new(Dir.pwd)
18
+
19
+ desc "Build gem into the pkg directory"
20
+ task "build" do
21
+ gem_helper.build_gem
22
+ end
23
+
24
+ desc "Build and install into gem environment"
25
+ task "install" do
26
+ Rake::Task["bundler:install"].invoke
27
+ gem_helper.install_gem
28
+ end
29
+
30
+ if defined?(RSpec)
31
+ namespace :spec do
32
+ desc "Run Unit Tests"
33
+ rspec_task = RSpec::Core::RakeTask.new(:unit) do |t|
34
+ t.pattern = "spec/**/*_spec.rb"
35
+ t.rspec_opts = %w(--format progress --colour)
36
+ end
37
+ end
38
+
39
+ desc "Run tests"
40
+ task :spec => %w(spec:unit)
41
+ task :default => :spec
42
+ end
File without changes
@@ -0,0 +1,114 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackBuild < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner 'knife stack build STACK_FILE (options)'
13
+
14
+ option :stack_id,
15
+ :long => "--stack-id STACK_ID",
16
+ :description => "The unique ID for the stack. If a stack with the given" +
17
+ "ID does not exist then a new one will be create. If a stack for the" +
18
+ "given ID exists then it will be initialized with its current state."
19
+
20
+ option :node,
21
+ :long => "--node NODE_TYPE_NAME[:SCALE]",
22
+ :description => "Applies the events to all hosts of a given node type. The " +
23
+ "node type is the value of the node key of a list of stack nodes"
24
+
25
+ option :overrides,
26
+ :long => "--overrides OVERRIDES",
27
+ :description => "JSON string or file ending with .json containing " +
28
+ "attributes to be overridden"
29
+
30
+ option :events,
31
+ :long => "--events EVENTS",
32
+ :description => "List of comma separate events to apply. If no events are " +
33
+ "provided then events 'create', 'install', 'configure' will be applied " +
34
+ "to each new host that is either created or bootstrapped first time. If " +
35
+ "node already exists then only the 'configure' event is applied. When " +
36
+ "the 'configure' event is applied chef-client will be run on each node. " +
37
+ "If the 'update' event is applied then the nodes run list will be updated " +
38
+ "and chef-client will be run."
39
+
40
+ option :repo_path,
41
+ :long => "--repo-path REPO_PATH",
42
+ :description => "The path to the Chef repo. This is required in order " +
43
+ "to copy the correct encryption keys from the 'secrets' folder to " +
44
+ "the target host as well as to read the externalized environment",
45
+ :default => '.'
46
+
47
+ option :show_stack_file,
48
+ :long => "--show-stack-file",
49
+ :description => "Outputs the parsed yaml of the stack file and exits."
50
+
51
+ def run
52
+ time_start = Time.now
53
+
54
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
55
+
56
+ repo_path = getConfig(:repo_path)
57
+ environment = getConfig(:environment) || '_default'
58
+
59
+ stack_file = name_args.first
60
+ if stack_file=~/[-_+=.0-9a-zA-Z]+/
61
+ stack_file = Dir.getwd + '/' + stack_file + (stack_file.end_with?('.yml') ? '' : '.yml')
62
+ end
63
+ unless File.exist?(stack_file)
64
+ puts "Stack file '#{stack_file}' does not exist."
65
+ exit 1
66
+ end
67
+
68
+ provider = StackBuilder::Chef::NodeProvider.new(repo_path, environment)
69
+ if getConfig(:show_stack_file)
70
+
71
+ env_vars = provider.get_env_vars
72
+ stack = StackBuilder::Common.load_yaml(stack_file, env_vars)
73
+ puts("Stack file:\n#{stack.to_yaml}")
74
+
75
+ else
76
+ # Validate repo path and update
77
+ # environment before building the stack
78
+ repo = StackBuilder::Chef::Repo.new(repo_path)
79
+ repo.upload_environments(environment)
80
+
81
+ stack_id = getConfig(:stack_id) || ENV['STACK_ID']
82
+ stack_overrides = getConfig(:overrides) || ENV['STACK_OVERRIDES']
83
+
84
+ stack = StackBuilder::Stack::Stack.new(
85
+ provider,
86
+ stack_file,
87
+ stack_id,
88
+ stack_overrides )
89
+
90
+ node = getConfig(:node)
91
+ unless node.nil?
92
+ node_name = node.split(':')[0]
93
+ node_scale = node.split(':')[1]
94
+ node_scale = node_scale.to_i unless node_scale.nil?
95
+ end
96
+
97
+ events = nil
98
+ if getConfig(:events)
99
+ events = events = Set.new(getConfig(:events).split(','))
100
+ end
101
+
102
+ stack.orchestrate(events, node_name, node_scale)
103
+ end
104
+
105
+ ensure
106
+ time_elapsed = Time.now - time_start
107
+
108
+ $stdout.printf( "\nStack build for '%s' took %d minutes and '%.3f' seconds\n",
109
+ stack_file, time_elapsed/60, time_elapsed%60 ) if !getConfig(:show_stack_file)
110
+ end
111
+ end
112
+
113
+ end
114
+ end
@@ -0,0 +1,50 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackDelete < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner 'knife stack delete STACK_FILE (options)'
13
+
14
+ option :stack_id,
15
+ :long => "--stack-id STACK_ID",
16
+ :description => "The ID of the stack to delete.",
17
+ :required => true
18
+
19
+ option :repo_path,
20
+ :long => "--repo_path REPO_PATH",
21
+ :description => "The path to the Chef repo. This is required " +
22
+ "in order read the externalized environment",
23
+ :default => '.'
24
+
25
+ def run
26
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
27
+
28
+ environment = getConfig(:environment) || '_default'
29
+ stack_file = name_args.first
30
+
31
+ if stack_file=~/[-_+=.0-9a-zA-Z]+/
32
+ stack_file = Dir.getwd + '/' + stack_file + (stack_file.end_with?('.yml') ? '' : '.yml')
33
+ end
34
+
35
+ unless File.exist?(stack_file)
36
+ puts "Stack file '#{stack_file}' does not exist."
37
+ exit 1
38
+ end
39
+
40
+ stack = StackBuilder::Stack::Stack.new(
41
+ StackBuilder::Chef::NodeProvider.new(getConfig(:repo_path), environment),
42
+ stack_file,
43
+ getConfig(:stack_id) )
44
+
45
+ stack.destroy
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,62 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackInitializeRepo < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner 'knife stack initialize repo (options)'
13
+
14
+ option :repo_path,
15
+ :long => "--repo_path REPO_PATH",
16
+ :description => "The path where a skeleton Chef Berkshelf repo will be created. " +
17
+ "If this is no provided the current working directory will be initialized.",
18
+ :default => '.'
19
+
20
+ option :cert_path,
21
+ :long => "--cert_path CERT_PATH",
22
+ :description => "Path containing folders with server certificates. Each folder " +
23
+ "within this path should be named after the server for which the certs are " +
24
+ "meant post-fixed by _{ENV_NAME}. If name is not post-fixed then the cert " +
25
+ "will be uploaded to all environments"
26
+
27
+ option :certs,
28
+ :long => "--certs SERVER_NAMES",
29
+ :description => "Comma separated list of server names for which self-signed " +
30
+ "certificates will be generated."
31
+
32
+ option :envs,
33
+ :long => "--stack_envs ENVIRONMENTS",
34
+ :description => "Comma separated list of environments to generate"
35
+
36
+ option :cookbooks,
37
+ :long => "--cookbooks COOKBOOKS",
38
+ :description => "A comma separated list of cookbooks and their versions to be " +
39
+ "added to the Berksfile i.e. \"mysql:=5.6.1, wordpress:~> 2.3.0\""
40
+
41
+ def run
42
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
43
+
44
+ cert_path = getConfig(:cert_path)
45
+ certs = getConfig(:certs)
46
+
47
+ if !cert_path.nil? && !certs.nil?
48
+ puts "Only one of --cert_path or --certs can be specified."
49
+ show_usage
50
+ exit 1
51
+ end
52
+
53
+ StackBuilder::Chef::Repo.new(
54
+ getConfig(:repo_path),
55
+ cert_path.nil? ? certs : cert_path,
56
+ getConfig(:envs),
57
+ getConfig(:cookbooks) )
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,38 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackUploadCertificates < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner "knife stack upload certificates"
13
+
14
+ option :repo_path,
15
+ :long => "--repo_path REPO_PATH",
16
+ :description => "The path to the Chef Berkshelf repo. All the " +
17
+ "certificates associated with this repository would have " +
18
+ "been copied to a hidden folder '.certs' within this path " +
19
+ "when it was initialized.",
20
+ :default => '.'
21
+
22
+ option :server,
23
+ :long => "--server NAME",
24
+ :description => "The name of the server whose " +
25
+ "certificate is to be uploaded"
26
+
27
+ def run
28
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
29
+
30
+ environment = getConfig(:environment)
31
+
32
+ repo = StackBuilder::Chef::Repo.new(getConfig(:repo_path))
33
+ repo.upload_certificates(environment, getConfig(:server))
34
+ end
35
+ end
36
+
37
+ end
38
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackUploadCookbooks < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner 'knife stack upload cookbooks (options)'
13
+
14
+ option :repo_path,
15
+ :long => "--repo_path REPO_PATH",
16
+ :description => "The path to the Chef repo containing the Berkshelf file.",
17
+ :default => '.'
18
+
19
+ option :cookbook,
20
+ :long => "--cookbook NAME",
21
+ :description => "The cookbook upload/update"
22
+
23
+ option :berks_options,
24
+ :long => "--berks-options options",
25
+ :description => "Comma separated list of berkshelf upload options"
26
+
27
+ option :berks_knife_config,
28
+ :long => "--berks-knife-config options",
29
+ :description => "Knife configuration file to be passed to Berkshelf"
30
+
31
+ def run
32
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
33
+
34
+ repo = StackBuilder::Chef::Repo.new(getConfig(:repo_path))
35
+
36
+ berks_knife_config = getConfig(:berks_knife_config)
37
+ ENV['BERKSHELF_CHEF_CONFIG'] = berks_knife_config unless berks_knife_config.nil?
38
+
39
+ berks_options = getConfig(:berks_options)
40
+ unless berks_options.nil?
41
+ repo.upload_cookbooks(getConfig(:cookbook), berks_options.gsub(/,/, ' '))
42
+ else
43
+ repo.upload_cookbooks(getConfig(:cookbook))
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+ end
@@ -0,0 +1,36 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackUploadDataBags < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner "knife stack upload data bags (options)"
13
+
14
+ option :repo_path,
15
+ :long => "--repo_path REPO_PATH",
16
+ :description => "The path to the Chef repo containing the data_bags " +
17
+ "within a 'data_bags' folder. All data bags will be encrypted with " +
18
+ "keys per environment located in the 'secrets' folder of the repo.",
19
+ :default => '.'
20
+
21
+ option :data_bag,
22
+ :long => "--data_bag NAME",
23
+ :description => "The data bag to upload/update"
24
+
25
+ def run
26
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
27
+
28
+ environment = getConfig(:environment)
29
+
30
+ repo = StackBuilder::Chef::Repo.new(getConfig(:repo_path))
31
+ repo.upload_data_bags(environment, getConfig(:data_bag))
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackUploadEnvironments < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner "knife stack upload environments (options)"
13
+
14
+ option :repo_path,
15
+ :long => "--repo_path REPO_PATH",
16
+ :description => "The path to the Chef repo containing " +
17
+ "the environments within an 'environments' folder.",
18
+ :default => '.'
19
+
20
+ def run
21
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
22
+
23
+ environment = getConfig(:environment)
24
+
25
+ repo = StackBuilder::Chef::Repo.new(getConfig(:repo_path))
26
+ repo.upload_environments(environment)
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackUploadRepo < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner "knife stack upload repo (options)"
13
+
14
+ option :repo_path,
15
+ :long => "--repo_path REPO_PATH",
16
+ :description => "The path to the Chef repo.",
17
+ :default => '.'
18
+
19
+ def run
20
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
21
+
22
+ environment = getConfig(:environment)
23
+
24
+ repo = StackBuilder::Chef::Repo.new(getConfig(:repo_path))
25
+
26
+ berks_knife_config = getConfig(:berks_knife_config)
27
+ ENV['BERKSHELF_CHEF_CONFIG'] = berks_knife_config unless berks_knife_config.nil?
28
+
29
+ repo.upload_cookbooks
30
+ repo.upload_roles
31
+
32
+ repo.upload_environments(environment)
33
+ repo.upload_data_bags(environment)
34
+ repo.upload_certificates(environment)
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ require 'chef/knife/stackbuilder_base'
4
+
5
+ class Chef
6
+ class Knife
7
+
8
+ class StackUploadRoles < Knife
9
+
10
+ include Knife::StackBuilderBase
11
+
12
+ banner "knife stack upload roles (options)"
13
+
14
+ option :repo_path,
15
+ :long => "--repo_path REPO_PATH",
16
+ :description => "The path to the Chef repo containing " +
17
+ "the roles within a 'roles' folder.",
18
+ :default => '.'
19
+
20
+ option :role,
21
+ :long => "--role NAME",
22
+ :description => "The role upload/update"
23
+
24
+ def run
25
+ StackBuilder::Common::Config.logger.level = Chef::Log.logger.level
26
+
27
+ repo = StackBuilder::Chef::Repo.new(getConfig(:repo_path))
28
+ repo.upload_roles(getConfig(:role))
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ # Copyright (c) 2014 Mevan Samaratunga
2
+
3
+ class Chef
4
+ class Knife
5
+
6
+ module StackBuilderBase
7
+
8
+ def self.included(includer)
9
+
10
+ includer.class_eval do
11
+
12
+ deps do
13
+ require 'stackbuilder'
14
+
15
+ config = OpenStruct.new(
16
+ :logger => Chef::Log.logger,
17
+ :enable_caching => false,
18
+ :timeouts => { :CACHE_TIMEOUT => 1800 } )
19
+
20
+ StackBuilder::Common::Config.configure(config)
21
+ end
22
+ end
23
+
24
+ def getConfig(key)
25
+ key = key.to_sym
26
+ config[key] || Chef::Config[:knife][key]
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end