Skip to content
This repository has been archived by the owner on Jul 14, 2021. It is now read-only.

Make chef repo prefer policyfiles #563

Merged
merged 4 commits into from
Oct 19, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/chef-dk/command/generator_commands/cookbook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def setup_context
Generator.add_attr_to_context(:cookbook_root, cookbook_root)
Generator.add_attr_to_context(:cookbook_name, cookbook_name)
Generator.add_attr_to_context(:recipe_name, recipe_name)
Generator.add_attr_to_context(:include_chef_repo_source, false)
Generator.add_attr_to_context(:policy_name, policy_name)
Generator.add_attr_to_context(:policy_run_list, policy_run_list)
Generator.add_attr_to_context(:policy_local_cookbook, ".")
Expand Down
61 changes: 51 additions & 10 deletions lib/chef-dk/command/generator_commands/policyfile.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ class Policyfile < Base

attr_reader :new_file_basename
attr_reader :policyfile_dir
attr_reader :policy_name
attr_reader :policy_run_list

def initialize(*args)
super
@new_file_basename = nil
@policyfile_dir = nil
@policy_name = nil
@policy_run_list = nil
@params_valid = true
end

Expand All @@ -43,8 +49,9 @@ def setup_context
super
Generator.add_attr_to_context(:policyfile_dir, policyfile_dir)
Generator.add_attr_to_context(:new_file_basename, new_file_basename)
Generator.add_attr_to_context(:policy_name, "example-application-service")
Generator.add_attr_to_context(:policy_run_list, "example_cookbook::default")
Generator.add_attr_to_context(:include_chef_repo_source, chef_repo_mode?)
Generator.add_attr_to_context(:policy_name, policy_name)
Generator.add_attr_to_context(:policy_run_list, policy_run_list)
Generator.add_attr_to_context(:policy_local_cookbook, nil)
end

Expand All @@ -62,24 +69,58 @@ def run

def read_and_validate_params
arguments = parse_options(params)
new_file_path =
case arguments.size
when 0
"Policyfile"
when 1
arguments[0]
else

new_file_path = nil
case arguments.size
when 0
if chef_repo_mode?
err("ERROR: You must give a policy name when generating a policy in a chef-repo.")
@params_valid = false
return false
else
use_default_policy_settings
end
when 1
new_file_path = arguments[0]
derive_policy_settings_from_args(arguments[0])
else
@params_valid = false
err("ERROR: too many arguments")
return false
end

end

private

def use_default_policy_settings
@new_file_basename = "Policyfile"
@policy_name = "example-application-service"
@policy_run_list = "example_cookbook::default"
@policyfile_dir = Dir.pwd
end

def derive_policy_settings_from_args(new_file_path)
@new_file_basename = File.basename(new_file_path, ".rb")
@policyfile_dir = File.expand_path(File.dirname(new_file_path))
@policy_name = @new_file_basename
@policy_run_list = "#{policy_name}::default"
given_policy_dirname = File.expand_path(File.dirname(new_file_path))
@policyfile_dir =
if chef_repo_mode? && (given_policy_dirname == Dir.pwd)
File.expand_path("policies")
else
given_policy_dirname
end
end

def params_valid?
@params_valid
end

def chef_repo_mode?
File.exist?(File.expand_path(".chef-repo.txt"))
end

end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/chef-dk/policyfile/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ def set_default_chef_repo_source(path)
if path.nil?
@errors << "You must specify the path to the chef-repo when using a default_source :chef_repo"
else
set_default_source(ChefRepoCookbookSource.new(path))
set_default_source(ChefRepoCookbookSource.new(File.expand_path(path, storage_config.relative_paths_root)))
end
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.chef-repo.txt
==============

This file gives ChefDK's generators a hint that you are using a Chef Repo and
this is the root directory of your Chef Repo. ChefDK's generators use this to
generate code that is designed to work with the Chef Repo workflow.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
Create policyfiles here. When using a chef-repo, give your policyfiles
the same filename as the name set in the policyfile itself, and use the
`.rb` file extension.

Compile the policy with a command like this:

```
chef install policies/my-app-frontend.rb
```

This will create a lockfile `policies/my-app-frontend.lock.json`.

To update locked dependencies, run `chef update` like this:

```
chef update policies/my-app-fronend.rb
```

You can upload the policy (with associated cookbooks) to the server
using a command like:

```
chef push staging policies/my-app-frontend.rb
```
10 changes: 9 additions & 1 deletion lib/chef-dk/skeletons/code_generator/recipes/repo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
helpers(ChefDK::Generator::TemplateHelper)
end

cookbook_file "#{repo_dir}/.chef-repo.txt" do
source "repo/dot-chef-repo.txt"
end

cookbook_file "#{repo_dir}/README.md" do
source "repo/README.md"
end
Expand All @@ -18,7 +22,11 @@
source "chefignore"
end

%w{cookbooks data_bags environments roles}.each do |tlo|
# By default, we now create a policies directory and don't create a roles or
# environments directory. The skeleton files for those still exist, so just add
# roles and environments to the array here to generate a repo with these
# directories.
%w{cookbooks data_bags policies}.each do |tlo|
remote_directory "#{repo_dir}/#{tlo}" do
source "repo/#{tlo}"
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
# A name that describes what the system you're building with Chef does.
name "<%= policy_name %>"

<% if include_chef_repo_source %>
# This lets you source cookbooks from your chef-repo.
default_source :chef_repo, "../"

<% end -%>
# Where to find external cookbooks:
default_source :supermarket

Expand Down
100 changes: 100 additions & 0 deletions spec/unit/command/generator_commands/policyfile_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,106 @@ def generator_context

end

context "when the current working directory is a chef repo" do

let(:chef_repo_dot_txt) { File.join(tempdir, ".chef-repo.txt") }

let(:policies_dir) { File.join(tempdir, "policies") }

let(:expected_policyfile_content) do
<<-POLICYFILE_RB
# Policyfile.rb - Describe how you want Chef to build your system.
#
# For more information on the Policyfile feature, visit
# https://github.com/opscode/chef-dk/blob/master/POLICYFILE_README.md

# A name that describes what the system you're building with Chef does.
name "my-app-frontend"

# This lets you source cookbooks from your chef-repo.
default_source :chef_repo, "../"

# Where to find external cookbooks:
default_source :supermarket

# run_list: chef-client will run these recipes in the order specified.
run_list "my-app-frontend::default"

# Specify a custom source for a single cookbook:
# cookbook "example_cookbook", path: "../cookbooks/example_cookbook"
POLICYFILE_RB
end

before do
FileUtils.touch(chef_repo_dot_txt)
FileUtils.mkdir(policies_dir)
end

context "when ARGV is empty" do

let(:argv) { [] }

it "errors and explains a policy name is required when using a chef-repo" do
Dir.chdir(tempdir) do
expect(generator.run).to eq(1)
end
expect(File).to_not exist(File.join(tempdir, "Policyfile.rb"))
expected_error = "ERROR: You must give a policy name when generating a policy in a chef-repo."
expect(stderr).to include(expected_error)
end

end

context "when ARGV is a single name with no path separators" do

let(:argv) { ["my-app-frontend"] }

let(:expected_policyfile_path) { File.join(policies_dir, "my-app-frontend.rb") }

before do
Dir.chdir(tempdir) do
expect(generator.run).to eq(0)
end
end

it "creates the policy under the policies/ directory" do
expect(File).to exist(expected_policyfile_path)
end

it "adds chef_repo as a default source and uses argv for the policy name" do
expect(IO.read(expected_policyfile_path)).to eq(expected_policyfile_content)
end

end

context "when ARGV looks like a path" do

let(:other_policy_dir) { File.join(tempdir, "other-policies") }

let(:expected_policyfile_path) { File.join(other_policy_dir, "my-app-frontend.rb") }

let(:argv) { [ "other-policies/my-app-frontend" ] }

before do
FileUtils.mkdir(other_policy_dir)

Dir.chdir(tempdir) do
expect(generator.run).to eq(0)
end
end

it "creates the policy in the specified path" do
expect(File).to exist(expected_policyfile_path)
end

it "adds chef_repo as a default source" do
expect(IO.read(expected_policyfile_path)).to eq(expected_policyfile_content)
end

end

end

context "when ARGV has too many arguments" do

let(:argv) { %w{ foo bar baz } }
Expand Down
46 changes: 19 additions & 27 deletions spec/unit/command/generator_commands/repo_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,15 @@ def generator_context
end
end

describe ".chef-repo.txt" do

let(:file) { ".chef-repo.txt" }

it "explains why it's there" do
expect(file_contents).to include("This file gives ChefDK's generators a hint")
end
end

describe "cookbooks" do
describe "README.md" do
let(:file) { "cookbooks/README.md" }
Expand Down Expand Up @@ -241,41 +250,24 @@ def generator_context
end
end

describe "environments" do
describe "policies" do
describe "README.md" do
let(:file) { "environments/README.md" }

it "has the right contents" do
expect(file_contents).to match(/Create environments here, in either the Role Ruby DSL \(\.rb\) or JSON \(\.json\) files\./)
let(:file) { "policies/README.md" }

let(:expected_content) do
<<-README
Create policyfiles here. When using a chef-repo, give your policyfiles
the same filename as the name set in the policyfile itself, and use the
`.rb` file extension.
README
end
end

describe "example.json" do
let(:file) { "environments/example.json" }

it "has the right contents" do
expect(file_contents).to match(/"description": "This is an example environment defined as JSON"/)
expect(file_contents).to include(expected_content)
end
end
end

describe "roles" do
describe "README.md" do
let(:file) { "roles/README.md" }

it "has the right contents" do
expect(file_contents).to match(/Create roles here, in either the Role Ruby DSL \(\.rb\) or JSON \(\.json\) files\./)
end
end

describe "example.json" do
let(:file) { "roles/example.json" }

it "has the right contents" do
expect(file_contents).to match(/"description": "This is an example role defined as JSON"/)
end
end
end
end
end
end
Expand Down
4 changes: 3 additions & 1 deletion spec/unit/policyfile_demands_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -834,8 +834,10 @@
end

it "raises an error describing the conflict" do
repo_path = File.expand_path("path/to/repo")

expected_err = <<-ERROR
Source supermarket(https://supermarket.chef.io) and chef_repo(path/to/repo) contain conflicting cookbooks:
Source supermarket(https://supermarket.chef.io) and chef_repo(#{repo_path}) contain conflicting cookbooks:
- remote-cb
- remote-cb-two
ERROR
Expand Down
21 changes: 21 additions & 0 deletions spec/unit/policyfile_evaluation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,27 @@
expect(policyfile.default_source).to eq(expected)
end

context "when the path to the chef repo is relative" do

let(:policyfile_rb) do
<<-EOH
run_list "foo", "bar"
default_source :chef_repo, "../cookbooks"
EOH
end

# storage_config is created with path to Policyfile.rb in CWD
let(:expected_path) { File.expand_path("../cookbooks") }

it "sets the repo path relative to the directory the policyfile is in" do
expect(policyfile.errors).to eq([])
expect(policyfile.default_source.size).to eq(1)
expect(policyfile.default_source.first).to be_a(ChefDK::Policyfile::ChefRepoCookbookSource)
expect(policyfile.default_source.first.path).to eq(expected_path)
end

end

end

context "with multiple default sources" do
Expand Down