berkshelf 0.6.0.beta4 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,31 +1,46 @@
1
+ require 'chozo/config'
2
+
1
3
  module Berkshelf
2
4
  # @author Justin Campbell <justin@justincampbell.me>
3
- class Config < Hashie::Mash
4
- DEFAULT_PATH = "~/.berkshelf/config.json"
5
-
6
- include ActiveModel::Validations
7
- validates_with ConfigValidator
5
+ # @author Jamie Winsor <jamie@vialstudios.com>
6
+ class Config < Chozo::Config::JSON
7
+ FILENAME = "config.json".freeze
8
8
 
9
9
  class << self
10
- # @return [String, nil]
11
- # the contents of the file
12
- def file
13
- File.read path if File.exists? path
10
+ attr_writer :path
11
+
12
+ # @return [String]
13
+ def path
14
+ File.join(Berkshelf.berkshelf_path, FILENAME)
14
15
  end
15
16
 
16
- # @param [#to_s] json
17
- #
18
- # @return [Config]
19
- def from_json(json)
20
- hash = JSON.parse(json).to_hash
17
+ # @return [String]
18
+ def chef_config_path
19
+ @chef_config_path ||= File.expand_path(ENV["BERKSHELF_CHEF_CONFIG"] || "~/.chef/knife.rb")
20
+ end
21
21
 
22
- new.tap do |config|
23
- hash.each do |key, value|
24
- config[key] = value
25
- end
22
+ # @param [String] value
23
+ def chef_config_path=(value)
24
+ @chef_config = nil
25
+ @chef_config_path = value
26
+ end
27
+
28
+ # @return [Chef::Config]
29
+ def chef_config
30
+ @chef_config ||= begin
31
+ Chef::Config.from_file(File.expand_path(chef_config_path))
32
+ Chef::Config
33
+ rescue
34
+ Chef::Config
26
35
  end
27
36
  end
28
37
 
38
+ # @return [String, nil]
39
+ # the contents of the file
40
+ def file
41
+ File.read(path) if File.exists?(path)
42
+ end
43
+
29
44
  # @return [Config]
30
45
  def instance
31
46
  @instance ||= if file
@@ -34,18 +49,52 @@ module Berkshelf
34
49
  new
35
50
  end
36
51
  end
37
-
38
- # @return [String]
39
- def path
40
- File.expand_path DEFAULT_PATH
41
- end
42
52
  end
43
53
 
44
- # @param [String, Symbol] key
45
- #
46
- # @return [Config, Object]
47
- def [](key)
48
- super or self.class.new
54
+ # @param [String] path
55
+ # @param [Hash] options
56
+ # @see {Chozo::Config::JSON}
57
+ def initialize(path = self.class.path, options = {})
58
+ super(path, options)
49
59
  end
60
+
61
+ attribute 'chef.chef_server_url',
62
+ type: String,
63
+ default: chef_config[:chef_server_url]
64
+ attribute 'chef.validation_client_name',
65
+ type: String,
66
+ default: chef_config[:validation_client_name]
67
+ attribute 'chef.validation_key_path',
68
+ type: String,
69
+ default: chef_config[:validation_key]
70
+ attribute 'chef.client_key',
71
+ type: String,
72
+ default: chef_config[:client_key]
73
+ attribute 'chef.node_name',
74
+ type: String,
75
+ default: chef_config[:node_name]
76
+ attribute 'vagrant.vm.box',
77
+ type: String,
78
+ default: 'Berkshelf-CentOS-6.3-x86_64-minimal',
79
+ required: true
80
+ attribute 'vagrant.vm.box_url',
81
+ type: String,
82
+ default: 'https://dl.dropbox.com/u/31081437/Berkshelf-CentOS-6.3-x86_64-minimal.box',
83
+ required: true
84
+ attribute 'vagrant.vm.forward_port',
85
+ type: Hash,
86
+ default: Hash.new
87
+ attribute 'vagrant.vm.network.bridged',
88
+ type: Boolean,
89
+ default: true
90
+ attribute 'vagrant.vm.network.hostonly',
91
+ type: String,
92
+ default: '33.33.33.10'
93
+ attribute 'vagrant.vm.provision',
94
+ type: String,
95
+ default: 'chef_solo'
96
+ attribute 'ssl.verify',
97
+ type: Boolean,
98
+ default: true
50
99
  end
51
100
  end
@@ -41,7 +41,7 @@ module Berkshelf
41
41
  class NoSolution < BerkshelfError; status_code(106); end
42
42
  class CookbookSyntaxError < BerkshelfError; status_code(107); end
43
43
  class UploadFailure < BerkshelfError; status_code(108); end
44
- class KnifeConfigNotFound < BerkshelfError; status_code(109); end
44
+ class BerksConfigNotFound < BerkshelfError; status_code(109); end
45
45
 
46
46
  class InvalidGitURI < BerkshelfError
47
47
  status_code(110)
@@ -91,7 +91,7 @@ module Berkshelf
91
91
  def to_s
92
92
  strings = ["Invalid configuration:"]
93
93
 
94
- @errors.messages.each do |key, errors|
94
+ @errors.each do |key, errors|
95
95
  errors.each do |error|
96
96
  strings << " #{key} #{error}"
97
97
  end
@@ -100,4 +100,7 @@ module Berkshelf
100
100
  strings.join "\n"
101
101
  end
102
102
  end
103
+
104
+ class ConfigExists < BerkshelfError; status_code(116); end
105
+ class ConfigurationError < BerkshelfError; status_code(117); end
103
106
  end
@@ -86,9 +86,9 @@ module Berkshelf
86
86
  # @param [Hash] options
87
87
  #
88
88
  # @option options [String, Symbol] :chef_api
89
- # a URL to a Chef API. Alternatively the symbol :knife can be provided
89
+ # a URL to a Chef API. Alternatively the symbol :config can be provided
90
90
  # which will instantiate this location with the values found in your
91
- # knife configuration.
91
+ # Berkshelf configuration.
92
92
  # @option options [String] :node_name
93
93
  # the name of the client to use to communicate with the Chef API.
94
94
  # Default: Chef::Config[:node_name]
@@ -100,17 +100,22 @@ module Berkshelf
100
100
  @version_constraint = version_constraint
101
101
  @downloaded_status = false
102
102
 
103
+ if options[:chef_api] == :knife
104
+ Berkshelf.formatter.deprecation "specifying 'chef_api :knife' is deprecated. Please use 'chef_api :config'."
105
+ options[:chef_api] = :config
106
+ end
107
+
103
108
  validate_options!(options)
104
109
 
105
- if options[:chef_api] == :knife
106
- begin
107
- Berkshelf.load_config
108
- rescue KnifeConfigNotFound => e
109
- raise KnifeConfigNotFound, "A Knife config is required when ':knife' is given for the value of a 'chef_api' location. #{e}"
110
+ if options[:chef_api] == :config
111
+ unless Berkshelf::Config.instance.chef.node_name.present? &&
112
+ Berkshelf::Config.instance.chef.client_key.present? &&
113
+ Berkshelf::Config.instance.chef.chef_server_url.present?
114
+ raise ConfigurationError, "A Berkshelf configuration is required with a 'chef.client_key', 'chef.chef_server_Url', and 'chef.node_name' setting to install or upload cookbooks using 'chef_api :config'."
110
115
  end
111
- @node_name = Chef::Config[:node_name]
112
- @client_key = Chef::Config[:client_key]
113
- @uri = Chef::Config[:chef_server_url]
116
+ @node_name = Berkshelf::Config.instance.chef.node_name
117
+ @client_key = Berkshelf::Config.instance.chef.client_key
118
+ @uri = Berkshelf::Config.instance.chef.chef_server_url
114
119
  else
115
120
  @node_name = options[:node_name]
116
121
  @client_key = options[:client_key]
@@ -250,7 +255,7 @@ module Berkshelf
250
255
  # @raise [InvalidChefAPILocation] if any of the options are missing or their values do not
251
256
  # pass validation
252
257
  def validate_options!(options)
253
- if options[:chef_api] == :knife
258
+ if options[:chef_api] == :config
254
259
  return true
255
260
  end
256
261
 
@@ -4,17 +4,13 @@ module Berkshelf
4
4
  # @author Jamie Winsor <jamie@vialstudios.com>
5
5
  # @author Andrew Garson <andrew.garson@gmail.com>
6
6
  class Install
7
- attr_reader :config
8
7
  attr_reader :shelf
9
8
  attr_reader :berksfile
10
9
 
11
10
  def initialize(app, env)
12
- @app = app
13
- @shelf = Berkshelf::Vagrant.shelf_for(env)
14
- @config = env[:vm].config.berkshelf
15
- Berkshelf.config_path = @config.config_path
16
- Berkshelf.load_config
17
- @berksfile = Berksfile.from_file(@config.berksfile_path)
11
+ @app = app
12
+ @shelf = Berkshelf::Vagrant.shelf_for(env)
13
+ @berksfile = Berksfile.from_file(env[:vm].config.berkshelf.berksfile_path)
18
14
  end
19
15
 
20
16
  def call(env)
@@ -32,7 +28,7 @@ module Berkshelf
32
28
  Berkshelf.formatter.msg "installing cookbooks..."
33
29
  opts = {
34
30
  path: self.shelf
35
- }.merge(self.config.to_hash).symbolize_keys!
31
+ }.merge(env[:vm].config.berkshelf.to_hash).symbolize_keys!
36
32
  berksfile.install(opts)
37
33
  end
38
34
 
@@ -4,16 +4,10 @@ module Berkshelf
4
4
  # @author Jamie Winsor <jamie@vialstudios.com>
5
5
  class Upload
6
6
  attr_reader :berksfile
7
- attr_reader :node_name
8
- attr_reader :client_key
9
- attr_reader :ssl_verify
10
7
 
11
8
  def initialize(app, env)
12
- @app = app
13
- @node_name = env[:vm].config.berkshelf.node_name
14
- @client_key = env[:vm].config.berkshelf.client_key
15
- @ssl_verify = env[:vm].config.berkshelf.ssl_verify
16
- @berksfile = Berksfile.from_file(env[:vm].config.berkshelf.berksfile_path)
9
+ @app = app
10
+ @berksfile = Berksfile.from_file(env[:vm].config.berkshelf.berksfile_path)
17
11
  end
18
12
 
19
13
  def call(env)
@@ -31,10 +25,10 @@ module Berkshelf
31
25
  Berkshelf.formatter.msg "uploading cookbooks to '#{provisioner.config.chef_server_url}'"
32
26
  berksfile.upload(
33
27
  server_url: provisioner.config.chef_server_url,
34
- client_name: self.node_name,
35
- client_key: self.client_key,
28
+ client_name: Berkshelf::Config.instance.chef.node_name,
29
+ client_key: Berkshelf::Config.instance.chef.client_key,
36
30
  ssl: {
37
- verify: self.ssl_verify
31
+ verify: Berkshelf::Config.instance.ssl.verify
38
32
  }
39
33
  )
40
34
  end
@@ -3,24 +3,10 @@ module Berkshelf
3
3
  # @author Jamie Winsor <jamie@vialstudios.com>
4
4
  # @author Andrew Garson <andrew.garson@gmail.com>
5
5
  class Config < ::Vagrant::Config::Base
6
- # @return [String]
7
- # path to a knife configuration file
8
- attr_reader :config_path
9
-
10
6
  # @return [String]
11
7
  # path to the Berksfile to use with Vagrant
12
8
  attr_reader :berksfile_path
13
9
 
14
- # @return [String]
15
- # A path to a client key on disk to use with the Chef Client provisioner to
16
- # upload cookbooks installed by Berkshelf.
17
- attr_reader :client_key
18
-
19
- # @return [String]
20
- # A client name (node_name) to use with the Chef Client provisioner to upload
21
- # cookbooks installed by Berkshelf.
22
- attr_accessor :node_name
23
-
24
10
  # @return [Array<Symbol>]
25
11
  # only cookbooks in these groups will be installed and copied to
26
12
  # Vagrant's shelf
@@ -30,16 +16,11 @@ module Berkshelf
30
16
  # cookbooks in all other groups except for these will be installed
31
17
  # and copied to Vagrant's shelf
32
18
  attr_accessor :except
33
- attr_accessor :ssl_verify
34
19
 
35
20
  def initialize
36
21
  @berksfile_path = File.join(Dir.pwd, Berkshelf::DEFAULT_FILENAME)
37
- @config_path = Berkshelf::DEFAULT_CONFIG
38
- @node_name = nil
39
- @client_key = nil
40
22
  @except = Array.new
41
23
  @only = Array.new
42
- @ssl_verify = true
43
24
  end
44
25
 
45
26
  # @param [String] value
@@ -47,11 +28,6 @@ module Berkshelf
47
28
  @berksfile_path = File.expand_path(value)
48
29
  end
49
30
 
50
- # @param [String] value
51
- def config_path=(value)
52
- @config_path = File.expand_path(value)
53
- end
54
-
55
31
  # @param [String] value
56
32
  def client_key=(value)
57
33
  @client_key = File.expand_path(value)
@@ -63,12 +39,12 @@ module Berkshelf
63
39
  end
64
40
 
65
41
  if Berkshelf::Vagrant.chef_client?(env.config.global)
66
- if node_name.nil?
67
- errors.add("A value for berkshelf.node_name is required when using the chef_client provisioner.")
42
+ if Berkshelf::Config.instance.chef.node_name.nil?
43
+ errors.add("A configuration must be set for chef.node_name when using the chef_client provisioner. Run 'berks configure' or edit your configuration.")
68
44
  end
69
45
 
70
- if client_key.nil?
71
- errors.add("A value for berkshelf.client_key is required when using the chef_client provisioner.")
46
+ if Berkshelf::Config.instance.chef.client_key.nil?
47
+ errors.add("A configuration must be set for chef.client_key when using the chef_client provisioner. Run 'berks configure' or edit your configuration.")
72
48
  end
73
49
  end
74
50
  end
@@ -1,3 +1,3 @@
1
1
  module Berkshelf
2
- VERSION = "0.6.0.beta4"
2
+ VERSION = "1.0.0.rc1"
3
3
  end
@@ -1,91 +1,51 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Berkshelf::Config do
4
- subject { config }
5
-
6
- let(:config) { klass.new }
7
4
  let(:klass) { described_class }
8
5
 
9
- it { should be_valid }
10
-
11
- its(:present?) { should be_false }
12
-
13
- it "set and gets hash keys" do
14
- config[:a] = 1
15
- config[:a].should == 1
16
- end
6
+ describe "ClassMethods" do
7
+ subject { klass }
17
8
 
18
- it "does not raise an error for nested hash keys that have not been set" do
19
- config[:d][:e]
20
- end
9
+ describe "::file" do
10
+ subject { klass.file }
21
11
 
22
- it "has indifferent access" do
23
- config[:a] = 1
24
- config['b'] = 2
12
+ context "when the file does not exist" do
13
+ before :each do
14
+ File.stub exists?: false
15
+ end
25
16
 
26
- config['a'].should == 1
27
- config[:b].should == 2
28
- end
29
-
30
- describe ".file" do
31
- subject { klass.file }
32
-
33
- context "when the file does not exist" do
34
- before :each do
35
- File.stub exists?: false
17
+ it { should be_nil }
36
18
  end
37
-
38
- it { should be_nil }
39
19
  end
40
- end
41
-
42
- describe ".from_json" do
43
- subject(:config) { klass.from_json json }
44
20
 
45
- let(:json) {
46
- <<-JSON
47
- {
48
- "a": 1,
49
- "b": {
50
- "c": 2
51
- }
52
- }
53
- JSON
54
- }
21
+ describe "::instance" do
22
+ subject { klass.instance }
55
23
 
56
- it "has data" do
57
- config[:a].should == 1
24
+ it { should be_a klass }
58
25
  end
59
26
 
60
- it "has nested data" do
61
- config[:b][:c].should == 2
62
- end
63
-
64
- it "does not raise an error for nested hash keys that have not been set" do
65
- config[:d][:e]
66
- end
27
+ describe "::path" do
28
+ subject { klass.path }
67
29
 
68
- it "has indifferent access" do
69
- config['a'].should == 1
70
- config[:a].should == 1
71
- end
30
+ it { should be_a String }
72
31
 
73
- context "with an invalid configuration" do
74
- let(:json) { '{ "wat": 1 }' }
32
+ it "points to a location within ENV['BERKSHELF_PATH']" do
33
+ ENV.stub(:[]).with('BERKSHELF_PATH').and_return('/tmp')
75
34
 
76
- it { should_not be_valid }
35
+ subject.should eql("/tmp/config.json")
36
+ end
77
37
  end
78
- end
79
38
 
80
- describe ".instance" do
81
- subject { klass.instance }
82
-
83
- it { should be_a klass }
84
- end
39
+ describe "::chef_config" do
40
+ it "returns the Chef::Config" do
41
+ subject.chef_config.should eql(Chef::Config)
42
+ end
43
+ end
85
44
 
86
- describe ".path" do
87
- subject { klass.path }
45
+ describe "::chef_config_path" do
46
+ subject { klass.chef_config_path }
88
47
 
89
- it { should be_a String }
48
+ it { should be_a String }
49
+ end
90
50
  end
91
51
  end