chef-dk 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +2 -2
  3. data/README.md +25 -0
  4. data/lib/chef-dk/builtin_commands.rb +4 -0
  5. data/lib/chef-dk/cli.rb +46 -0
  6. data/lib/chef-dk/command/base.rb +4 -0
  7. data/lib/chef-dk/command/generator_commands/template.rb +2 -1
  8. data/lib/chef-dk/command/install.rb +105 -0
  9. data/lib/chef-dk/command/push.rb +123 -0
  10. data/lib/chef-dk/cookbook_profiler/identifiers.rb +5 -0
  11. data/lib/chef-dk/exceptions.rb +38 -0
  12. data/lib/chef-dk/generator.rb +16 -1
  13. data/lib/chef-dk/helpers.rb +1 -1
  14. data/lib/chef-dk/policyfile/cookbook_location_specification.rb +4 -0
  15. data/lib/chef-dk/policyfile/cookbook_locks.rb +73 -0
  16. data/lib/chef-dk/policyfile/reports/install.rb +70 -0
  17. data/lib/chef-dk/policyfile/reports/table_printer.rb +58 -0
  18. data/lib/chef-dk/policyfile/reports/upload.rb +70 -0
  19. data/lib/chef-dk/policyfile/solution_dependencies.rb +102 -8
  20. data/lib/chef-dk/policyfile/uploader.rb +37 -6
  21. data/lib/chef-dk/policyfile_compiler.rb +19 -5
  22. data/lib/chef-dk/policyfile_lock.rb +122 -9
  23. data/lib/chef-dk/policyfile_services/install.rb +131 -0
  24. data/lib/chef-dk/policyfile_services/push.rb +121 -0
  25. data/lib/chef-dk/skeletons/code_generator/recipes/cookbook.rb +6 -4
  26. data/lib/chef-dk/ui.rb +50 -0
  27. data/lib/chef-dk/version.rb +1 -1
  28. data/spec/shared/a_file_generator.rb +4 -1
  29. data/spec/test_helpers.rb +21 -0
  30. data/spec/unit/cli_spec.rb +100 -1
  31. data/spec/unit/command/base_spec.rb +23 -0
  32. data/spec/unit/command/exec_spec.rb +2 -2
  33. data/spec/unit/command/install_spec.rb +159 -0
  34. data/spec/unit/command/push_spec.rb +203 -0
  35. data/spec/unit/command/shell_init_spec.rb +1 -1
  36. data/spec/unit/policyfile/cookbook_location_specification_spec.rb +7 -0
  37. data/spec/unit/policyfile/cookbook_locks_spec.rb +13 -2
  38. data/spec/unit/policyfile/reports/install_spec.rb +115 -0
  39. data/spec/unit/policyfile/reports/upload_spec.rb +96 -0
  40. data/spec/unit/policyfile/solution_dependencies_spec.rb +1 -1
  41. data/spec/unit/policyfile/uploader_spec.rb +9 -12
  42. data/spec/unit/policyfile_lock_serialization_spec.rb +292 -0
  43. data/spec/unit/policyfile_services/install_spec.rb +170 -0
  44. data/spec/unit/policyfile_services/push_spec.rb +202 -0
  45. metadata +48 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 71929ebb4b2845757688d9de6a8519e2984de9e3
4
- data.tar.gz: cbf10aabf6125995c29fe7199ca37e22a5b1d5a8
3
+ metadata.gz: f843be984f4748b386cfc76d5b13fc53a015ffeb
4
+ data.tar.gz: ff6284980c5d4db06395d5264fae6de79dd858f3
5
5
  SHA512:
6
- metadata.gz: 93381f6a0deb08de22ef67c5605adf8221f470523de25b6ae5f6207daddaf4cb8d4414cfc5f2bbd597085fc2e39dc29d11539d1fe8e2f250c131e2fff48eb83a
7
- data.tar.gz: a90008e558fb76709c8ca8159532e7132416c24af750538aff94855201479fd7a876a467c3732cbaf5eb66e3cb7f2e99df00d6ecf795c762b3fdb2353c773c8d
6
+ metadata.gz: 2c7ebbe3baf7bae4ca25072f6f62da8ee3c6cf14aa38d4bf7af8632338bed6f3b9949c06ee0e7283b958b1a61e38178a9bec9bbf9f04b3e0ad672e1c18bf99bf
7
+ data.tar.gz: 0d0c18793a5a724ba719d4237a3f8e58ae1a6ed9bb07020277df9c9ce96caac5ba5632728004d6e91caa2a080fc0b150ef32906a305c2326d697889d202a6fd7
@@ -23,8 +23,8 @@ Chef is built to last. We strive to ensure high quality throughout the Chef expe
23
23
  this, we require a couple of things for all pull requests to Chef:
24
24
 
25
25
  1. **Tests:** To ensure high quality code and protect against future regressions, we require all the
26
- code in Chef to have at least unit test coverage. See the [spec/unit](https://github.com/opscode/chef/tree/master/spec/unit)
27
- directory for the existing tests and use ```bundle exec rake spec``` to run them.
26
+ code in Chef to have at least unit test coverage. Run ```bundle exec rspec``` from the project root
27
+ to execute the tests.
28
28
  2. **Green Travis Run:** We use [Travis CI](https://travis-ci.org/) in order to run our tests
29
29
  continuously on all the pull requests. We require the Travis runs to succeed on every pull
30
30
  request before being merged.
data/README.md CHANGED
@@ -108,6 +108,29 @@ environment to make ChefDK your primary ruby. For more information to
108
108
  help you decide if this is desirable and instructions, see "Using ChefDK
109
109
  as Your Primary Development Environment" below.
110
110
 
111
+ ### `chef install`
112
+ `chef install` reads a Policyfile.rb document, which contains a
113
+ `run_list` and optional cookbook version constraints, finds a set of
114
+ cookbooks that provide the desired recipes and meet dependency
115
+ constraints, and emits a Policyfile.lock.json describing the expanded
116
+ run list and locked cookbook set. The Policyfile.lock.json can be used
117
+ to install the cookbooks on another machine. The policy lock can be
118
+ uploaded to a Chef Server (via the `chef push` command) to apply the
119
+ expanded run list and locked cookbook set to nodes in your
120
+ infrastructure. The Policyfile feature is currently incomplete and of
121
+ beta quality; changes to the Chef Server APIs will need to be
122
+ implemented before the feature is production-ready. The feature
123
+ currently operates in a compatibility mode. See the POLICYFILE_README.md
124
+ for further details.
125
+
126
+ ### `chef push`
127
+ `chef push POLICY_GROUP` uploads a Policyfile.lock.json along with the cookbooks it
128
+ references to a Chef Server. The policy lock is applied to a
129
+ `POLICY_GROUP`, which is a set of nodes that share the same run list and
130
+ cookbook set. This command operates in compatibility mode and has the
131
+ same caveats as `chef install`. See the POLICYFILE_README.md for further
132
+ details.
133
+
111
134
  ### Using ChefDK as Your Primary Development Environment
112
135
 
113
136
  By default, ChefDK only adds a few select applications to your `PATH`
@@ -173,6 +196,8 @@ You can use `rpm` to uninstall Chef Development Kit on RHEL based systems:
173
196
  ```
174
197
  rpm -qa *chefdk*
175
198
  yum remove <package>
199
+ rm -rf /opt/chefdk
200
+ rm -rf ~/.chefdk
176
201
  ```
177
202
 
178
203
  ### Ubuntu
@@ -27,5 +27,9 @@ ChefDK.commands do |c|
27
27
 
28
28
  c.builtin "shell-init", :ShellInit, desc: "Initialize your shell to use ChefDK as your primary ruby"
29
29
 
30
+ c.builtin "install", :Install, desc: "Install cookbooks from a Policyfile and generate a locked cookbook set"
31
+
32
+ c.builtin "push", :Push, desc: "Push a local policy lock to a policy group on the server"
33
+
30
34
  c.builtin "verify", :Verify, desc: "Test the embedded ChefDK applications"
31
35
  end
@@ -20,6 +20,8 @@ require 'chef-dk/version'
20
20
  require 'chef-dk/commands_map'
21
21
  require 'chef-dk/builtin_commands'
22
22
  require 'chef-dk/helpers'
23
+ require 'chef-dk/ui'
24
+ require 'chef/util/path_helper'
23
25
 
24
26
  module ChefDK
25
27
  class CLI
@@ -53,6 +55,8 @@ BANNER
53
55
  end
54
56
 
55
57
  def run
58
+ sanity_check!
59
+
56
60
  subcommand_name, *subcommand_params = argv
57
61
 
58
62
  #
@@ -70,6 +74,10 @@ BANNER
70
74
  show_help
71
75
  exit 1
72
76
  end
77
+ rescue OptionParser::InvalidOption => e
78
+ err(e.message)
79
+ show_help
80
+ exit 1
73
81
  end
74
82
 
75
83
  # If no subcommand is given, then this class is handling the CLI request.
@@ -131,5 +139,43 @@ BANNER
131
139
  end
132
140
  end
133
141
 
142
+ # Find PATH or Path correctly if we are on Windows
143
+ def path_key
144
+ ENV.keys.grep(/\Apath\Z/i).first
145
+ end
146
+
147
+ # upcase drive letters for comparison since ruby has a String#capitalize function
148
+ def drive_upcase(path)
149
+ if Chef::Platform.windows? && path[0] =~ /^[A-Za-z]$/ && path[1,2] == ":\\"
150
+ path.capitalize
151
+ else
152
+ path
153
+ end
154
+ end
155
+
156
+ def env
157
+ ENV
158
+ end
159
+
160
+ # catch the cases where users setup only the embedded_bin_dir in their path, or
161
+ # when they have the embedded_bin_dir before the omnibus_bin_dir -- both of which will
162
+ # defeat appbundler and interact very badly with our intent.
163
+ def sanity_check!
164
+ paths = env[path_key].split(File::PATH_SEPARATOR)
165
+ paths.map! { |p| drive_upcase(Chef::Util::PathHelper.cleanpath(p)) }
166
+ embed_index = paths.index(drive_upcase(Chef::Util::PathHelper.cleanpath(omnibus_embedded_bin_dir)))
167
+ bin_index = paths.index(drive_upcase(Chef::Util::PathHelper.cleanpath(omnibus_bin_dir)))
168
+ if embed_index
169
+ if bin_index
170
+ if embed_index < bin_index
171
+ msg("WARN: #{omnibus_embedded_bin_dir} is before #{omnibus_bin_dir} in your #{path_key}, please reverse that order.")
172
+ msg("WARN: consider using the correct `chef shell-init <shell>` command to setup your environment correctly.")
173
+ end
174
+ else
175
+ msg("WARN: only #{omnibus_embedded_bin_dir} is present in your path, you must add #{omnibus_bin_dir} before that directory.")
176
+ msg("WARN: consider using the correct `chef shell-init <shell>` command to setup your environment correctly.")
177
+ end
178
+ end
179
+ end
134
180
  end
135
181
  end
@@ -56,6 +56,10 @@ module ChefDK
56
56
  else
57
57
  run(params)
58
58
  end
59
+ rescue OptionParser::InvalidOption => e
60
+ err(e.message)
61
+ msg(opt_parser)
62
+ 1
59
63
  end
60
64
 
61
65
  def needs_help?(params)
@@ -23,7 +23,7 @@ module ChefDK
23
23
  # chef generate template [path/to/cookbook_root] name --source=source_file
24
24
  class Template < CookbookCodeFile
25
25
 
26
- option :content_source,
26
+ option :source,
27
27
  :short => "-s SOURCE_FILE",
28
28
  :long => "--source SOURCE_FILE",
29
29
  :description => "Copy content from SOURCE_FILE"
@@ -38,6 +38,7 @@ module ChefDK
38
38
 
39
39
  def setup_context
40
40
  super
41
+ Generator.add_attr_to_context(:content_source, config[:source])
41
42
  end
42
43
  end
43
44
  end
@@ -0,0 +1,105 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef-dk/command/base'
19
+ require 'chef-dk/ui'
20
+ require 'chef-dk/policyfile_services/install'
21
+
22
+ module ChefDK
23
+ module Command
24
+
25
+ class Install < Base
26
+
27
+ banner(<<-E)
28
+ Usage: chef install [ POLICY_FILE ] [options]
29
+
30
+ `chef install` evaluates a `Policyfile.rb` to find a compatible set of
31
+ cookbooks for the policy's run_list and caches them locally. It emits a
32
+ Policyfile.lock.json describing the locked cookbook set. You can use the
33
+ lockfile to install the locked cookbooks on another machine. You can also push
34
+ the lockfile to a "policy group" on a Chef Server and apply that exact set of
35
+ cookbooks to nodes in your infrastructure.
36
+
37
+ The Policyfile feature is incomplete and beta quality. See our detailed README
38
+ for more information.
39
+
40
+ https://github.com/opscode/chef-dk/blob/master/POLICYFILE_README.md
41
+
42
+ Options:
43
+
44
+ E
45
+
46
+ option :debug,
47
+ short: "-D",
48
+ long: "--debug",
49
+ description: "Enable stacktraces and other debug output",
50
+ default: false
51
+
52
+ attr_reader :policyfile_relative_path
53
+
54
+ attr_accessor :ui
55
+
56
+ def initialize(*args)
57
+ super
58
+ @ui = UI.new
59
+
60
+ @policyfile_relative_path = nil
61
+ @installer = nil
62
+ end
63
+
64
+ def run(params = [])
65
+ apply_params!(params)
66
+ installer.run
67
+ 0
68
+ rescue PolicyfileServiceError => e
69
+ handle_error(e)
70
+ 1
71
+ end
72
+
73
+ def installer
74
+ @installer ||= PolicyfileServices::Install.new(policyfile: policyfile_relative_path, ui: ui, root_dir: Dir.pwd)
75
+ end
76
+
77
+ def debug?
78
+ !!config[:debug]
79
+ end
80
+
81
+ def handle_error(error)
82
+ ui.err("Error: #{error.message}")
83
+ if error.respond_to?(:cause) && error.cause
84
+ cause = error.cause
85
+ ui.err("Reason: #{cause.class.name}")
86
+ ui.err("")
87
+ ui.err(cause.message)
88
+ ui.err(cause.backtrace.join("\n")) if debug?
89
+ end
90
+ end
91
+
92
+ def apply_params!(params)
93
+ remaining_args = parse_options(params)
94
+ if remaining_args.size > 1
95
+ ui.err(banner)
96
+ return 1
97
+ else
98
+ @policyfile_relative_path = remaining_args.first
99
+ end
100
+ end
101
+
102
+ end
103
+ end
104
+ end
105
+
@@ -0,0 +1,123 @@
1
+ #
2
+ # Copyright:: Copyright (c) 2014 Chef Software Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require 'chef-dk/command/base'
19
+ require 'chef-dk/ui'
20
+ require 'chef-dk/policyfile_services/push'
21
+
22
+ module ChefDK
23
+ module Command
24
+
25
+ class Push < Base
26
+
27
+ banner(<<-E)
28
+ Usage: chef push POLICY_GROUP [ POLICY_FILE ] [options]
29
+
30
+ `chef push` Uploads an existing Policyfile.lock.json to a Chef Server, along
31
+ with all the cookbooks contained in the policy lock. The policy lock is applied
32
+ to a specific POLICY_GROUP, which is a set of nodes that share the same
33
+ run_list and cookbooks.
34
+
35
+ The Policyfile feature is incomplete and beta quality. See our detailed README
36
+ for more information.
37
+
38
+ https://github.com/opscode/chef-dk/blob/master/POLICYFILE_README.md
39
+
40
+ Options:
41
+
42
+ E
43
+
44
+ option :config_file,
45
+ short: "-c CONFIG_FILE",
46
+ long: "--config CONFIG_FILE",
47
+ description: "Path to configuration file"
48
+
49
+ option :debug,
50
+ short: "-D",
51
+ long: "--debug",
52
+ description: "Enable stacktraces and other debug output",
53
+ default: false
54
+
55
+ attr_reader :policyfile_relative_path
56
+ attr_reader :policy_group
57
+
58
+ attr_accessor :ui
59
+
60
+ def initialize(*args)
61
+ super
62
+ @push = nil
63
+ @ui = nil
64
+ @policy_group = nil
65
+ @policyfile_relative_path = nil
66
+ @chef_config = nil
67
+ @ui = UI.new
68
+ end
69
+
70
+ def run(params = [])
71
+ return 1 unless apply_params!(params)
72
+ push.run
73
+ 0
74
+ rescue PolicyfileServiceError => e
75
+ handle_error(e)
76
+ 1
77
+ end
78
+
79
+ def debug?
80
+ !!config[:debug]
81
+ end
82
+
83
+ def chef_config
84
+ return @chef_config if @chef_config
85
+ Chef::WorkstationConfigLoader.new(config[:config_file]).load
86
+ @chef_config = Chef::Config
87
+ end
88
+
89
+ def push
90
+ @push ||= PolicyfileServices::Push.new(policyfile: policyfile_relative_path,
91
+ ui: ui,
92
+ policy_group: policy_group,
93
+ config: chef_config,
94
+ root_dir: Dir.pwd)
95
+ end
96
+
97
+ def handle_error(error)
98
+ ui.err("Error: #{error.message}")
99
+ if error.respond_to?(:cause) && error.cause
100
+ cause = error.cause
101
+ ui.err("Reason: #{cause.class.name}")
102
+ ui.err("")
103
+ ui.err(cause.message)
104
+ ui.err(cause.backtrace.join("\n")) if debug?
105
+ end
106
+ end
107
+
108
+ def apply_params!(params)
109
+ remaining_args = parse_options(params)
110
+ if remaining_args.size < 1 or remaining_args.size > 2
111
+ ui.err(banner)
112
+ return false
113
+ else
114
+ @policy_group = remaining_args[0]
115
+ @policyfile_relative_path = remaining_args[1]
116
+ end
117
+ true
118
+ end
119
+
120
+ end
121
+ end
122
+ end
123
+
@@ -15,10 +15,15 @@
15
15
  # limitations under the License.
16
16
  #
17
17
 
18
+ # TODO: Chef should require its dependency correctly.
19
+ require 'singleton'
18
20
  require 'chef/cookbook/cookbook_version_loader'
19
21
  require 'digest/sha1'
22
+
20
23
  require 'chef/digester'
21
24
 
25
+ require 'chef-dk/exceptions'
26
+
22
27
  module ChefDK
23
28
  module CookbookProfiler
24
29
  class Identifiers
@@ -17,6 +17,40 @@
17
17
 
18
18
  module ChefDK
19
19
 
20
+ # Base class for errors raised by ChefDK::PolicyfileServices objects. Don't
21
+ # raise this directly, create a descriptively-named subclass. You can rescue
22
+ # this to catch all errors from PolicyfileServices objects though.
23
+ class PolicyfileServiceError < StandardError
24
+ end
25
+
26
+ class PolicyfileNotFound < PolicyfileServiceError
27
+ end
28
+
29
+ class LockfileNotFound < PolicyfileServiceError
30
+ end
31
+
32
+ class PolicyfileInstallError < PolicyfileServiceError
33
+
34
+ attr_reader :cause
35
+
36
+ def initialize(message, cause)
37
+ super(message)
38
+ @cause = cause
39
+ end
40
+
41
+ end
42
+
43
+ class PolicyfilePushError < PolicyfileServiceError
44
+
45
+ attr_reader :cause
46
+
47
+ def initialize(message, cause)
48
+ super(message)
49
+ @cause = cause
50
+ end
51
+
52
+ end
53
+
20
54
  class CachedCookbookNotFound < StandardError
21
55
  end
22
56
 
@@ -58,4 +92,8 @@ module ChefDK
58
92
 
59
93
  class MissingCookbookLockData < StandardError
60
94
  end
95
+
96
+ class InvalidLockfile < StandardError
97
+ end
98
+
61
99
  end