chef-workflow 0.1.1 → 0.2.0
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.
- data/CHANGELOG.md +19 -0
- data/LICENSE.txt +2 -2
- data/README.md +31 -142
- data/bin/chef-workflow-bootstrap +6 -0
- data/chef-workflow.gemspec +4 -1
- data/lib/chef-workflow.rb +41 -39
- data/lib/chef-workflow/support/attr.rb +28 -26
- data/lib/chef-workflow/support/db.rb +26 -0
- data/lib/chef-workflow/support/db/basic.rb +225 -0
- data/lib/chef-workflow/support/db/group.rb +72 -0
- data/lib/chef-workflow/support/debug.rb +47 -45
- data/lib/chef-workflow/support/ec2.rb +136 -134
- data/lib/chef-workflow/support/general.rb +46 -54
- data/lib/chef-workflow/support/generic.rb +27 -23
- data/lib/chef-workflow/support/ip.rb +89 -103
- data/lib/chef-workflow/support/knife-plugin.rb +26 -24
- data/lib/chef-workflow/support/knife.rb +76 -102
- data/lib/chef-workflow/support/scheduler.rb +319 -324
- data/lib/chef-workflow/support/ssh.rb +100 -0
- data/lib/chef-workflow/support/vagrant.rb +34 -30
- data/lib/chef-workflow/support/vm.rb +25 -54
- data/lib/chef-workflow/support/vm/chef_server.rb +28 -19
- data/lib/chef-workflow/support/vm/ec2.rb +135 -106
- data/lib/chef-workflow/support/vm/helpers/knife.rb +26 -0
- data/lib/chef-workflow/support/vm/knife.rb +218 -189
- data/lib/chef-workflow/support/vm/vagrant.rb +90 -74
- data/lib/chef-workflow/version.rb +3 -5
- metadata +57 -4
@@ -1,63 +1,55 @@
|
|
1
1
|
require 'chef-workflow/support/generic'
|
2
2
|
require 'chef-workflow/support/attr'
|
3
|
-
require 'chef-workflow/support/vm/ec2'
|
4
|
-
require 'chef-workflow/support/vm/vagrant'
|
5
|
-
|
6
|
-
#
|
7
|
-
# General configuration, typically global to all chef-workflow related things.
|
8
|
-
# See `GenericSupport` for a rundown of usage.
|
9
|
-
#
|
10
|
-
class GeneralSupport
|
11
|
-
# Standard chef-workflow dir.
|
12
|
-
DEFAULT_CHEF_WORKFLOW_DIR = File.join(Dir.pwd, '.chef-workflow')
|
13
|
-
# Location of the VM database.
|
14
|
-
DEFAULT_CHEF_VM_FILE = File.join(DEFAULT_CHEF_WORKFLOW_DIR, 'vms')
|
15
|
-
# Location of the chef-server prison file (vagrant only).
|
16
|
-
DEFAULT_CHEF_SERVER_PRISON = File.join(DEFAULT_CHEF_WORKFLOW_DIR, 'chef-server')
|
17
|
-
|
18
|
-
extend AttrSupport
|
19
|
-
|
20
|
-
##
|
21
|
-
# :attr:
|
22
|
-
#
|
23
|
-
# configure the workflow directory
|
24
|
-
fancy_attr :workflow_dir
|
25
|
-
|
26
|
-
##
|
27
|
-
# :attr:
|
28
|
-
#
|
29
|
-
# configure the location of the vm file
|
30
|
-
fancy_attr :vm_file
|
31
3
|
|
32
|
-
|
33
|
-
# :attr:
|
4
|
+
module ChefWorkflow
|
34
5
|
#
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
6
|
+
# General configuration, typically global to all chef-workflow related things.
|
7
|
+
# See `GenericSupport` for a rundown of usage.
|
8
|
+
#
|
9
|
+
class GeneralSupport
|
10
|
+
extend ChefWorkflow::AttrSupport
|
11
|
+
include ChefWorkflow::GenericSupport
|
12
|
+
|
13
|
+
# Standard chef-workflow dir.
|
14
|
+
DEFAULT_CHEF_WORKFLOW_DIR = File.join(Dir.pwd, '.chef-workflow')
|
15
|
+
# Location of the VM database.
|
16
|
+
DEFAULT_CHEF_VM_FILE = File.join(DEFAULT_CHEF_WORKFLOW_DIR, 'state.db')
|
17
|
+
|
18
|
+
##
|
19
|
+
# :attr:
|
20
|
+
#
|
21
|
+
# configure the workflow directory
|
22
|
+
fancy_attr :workflow_dir
|
23
|
+
|
24
|
+
##
|
25
|
+
# :attr:
|
26
|
+
#
|
27
|
+
# configure the location of the vm file
|
28
|
+
fancy_attr :vm_file
|
29
|
+
|
30
|
+
def initialize(opts={})
|
31
|
+
@workflow_dir = opts[:workflow_dir] || DEFAULT_CHEF_WORKFLOW_DIR
|
32
|
+
@vm_file = opts[:vm_file] || DEFAULT_CHEF_VM_FILE
|
33
|
+
machine_provisioner :vagrant
|
55
34
|
end
|
56
35
|
|
57
|
-
|
36
|
+
def machine_provisioner(*args)
|
37
|
+
if args.count > 0
|
38
|
+
@machine_provisioner = case args.first
|
39
|
+
when :ec2
|
40
|
+
require 'chef-workflow/support/vm/ec2'
|
41
|
+
ChefWorkflow::VM::EC2Provisioner
|
42
|
+
when :vagrant
|
43
|
+
require 'chef-workflow/support/vm/vagrant'
|
44
|
+
ChefWorkflow::VM::VagrantProvisioner
|
45
|
+
else
|
46
|
+
args.first
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
@machine_provisioner
|
51
|
+
end
|
58
52
|
end
|
59
|
-
|
60
|
-
include GenericSupport
|
61
53
|
end
|
62
54
|
|
63
|
-
GeneralSupport.configure
|
55
|
+
ChefWorkflow::GeneralSupport.configure
|
@@ -1,30 +1,34 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
#
|
1
|
+
require 'singleton'
|
2
|
+
require 'deprecated'
|
4
3
|
|
5
|
-
module
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
def self.included(klass)
|
10
|
-
class << klass
|
11
|
-
# The singleton object that is supplying the current configuration.
|
12
|
-
# Always reference this when working with classes that use this
|
13
|
-
# interface.
|
14
|
-
attr_reader :singleton
|
4
|
+
module ChefWorkflow
|
5
|
+
#
|
6
|
+
# mixin for supplying a consistent interface to singleton configuration classes.
|
7
|
+
#
|
15
8
|
|
16
|
-
|
17
|
-
|
9
|
+
module GenericSupport
|
10
|
+
def self.included(klass)
|
11
|
+
klass.instance_eval do
|
12
|
+
include Singleton
|
18
13
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
14
|
+
def self.configure(&block)
|
15
|
+
instance.instance_eval(&block) if block
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.method_missing(sym, *args)
|
19
|
+
instance.send(sym, *args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.singleton
|
23
|
+
instance
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
include Deprecated
|
28
|
+
end
|
29
|
+
|
30
|
+
self.singleton_class.deprecated :singleton, "#{klass.name} class methods"
|
25
31
|
end
|
26
32
|
end
|
27
|
-
|
28
|
-
klass.supported_class = klass
|
29
33
|
end
|
30
34
|
end
|
@@ -1,129 +1,115 @@
|
|
1
|
-
require 'delegate'
|
2
1
|
require 'fileutils'
|
3
|
-
require 'chef-workflow/support/generic'
|
4
2
|
require 'chef-workflow/support/attr'
|
3
|
+
require 'chef-workflow/support/db'
|
4
|
+
require 'chef-workflow/support/generic'
|
5
5
|
|
6
6
|
ENV["TEST_CHEF_SUBNET"] ||= "10.10.10.0"
|
7
7
|
|
8
|
-
|
9
|
-
# IP allocation database. Uses `GenericSupport`.
|
10
|
-
#
|
11
|
-
class IPSupport < DelegateClass(Hash)
|
12
|
-
extend AttrSupport
|
13
|
-
|
14
|
-
##
|
15
|
-
# :attr:
|
16
|
-
#
|
17
|
-
# The subnet used for calculating assignable IP addresses. You really want to
|
18
|
-
# set `TEST_CHEF_SUBNET` in your environment instead of changing this.
|
19
|
-
#
|
20
|
-
fancy_attr :subnet
|
21
|
-
|
22
|
-
##
|
23
|
-
# :attr:
|
8
|
+
module ChefWorkflow
|
24
9
|
#
|
25
|
-
#
|
10
|
+
# IP allocation database. Uses `GenericSupport`.
|
26
11
|
#
|
27
|
-
|
12
|
+
class IPSupport
|
13
|
+
extend ChefWorkflow::AttrSupport
|
14
|
+
include ChefWorkflow::GenericSupport
|
28
15
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
16
|
+
##
|
17
|
+
# :attr:
|
18
|
+
#
|
19
|
+
# The subnet used for calculating assignable IP addresses. You really want to
|
20
|
+
# set `TEST_CHEF_SUBNET` in your environment instead of changing this.
|
21
|
+
#
|
22
|
+
fancy_attr :subnet
|
35
23
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
24
|
+
def initialize(subnet=ENV["TEST_CHEF_SUBNET"])
|
25
|
+
@subnet = subnet
|
26
|
+
@db = ChefWorkflow::DatabaseSupport.instance
|
27
|
+
create_table
|
28
|
+
end
|
42
29
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
30
|
+
def create_table
|
31
|
+
@db.execute <<-EOF
|
32
|
+
create table if not exists ips (
|
33
|
+
id integer not null primary key autoincrement,
|
34
|
+
role_name varchar(255) not null,
|
35
|
+
ip_addr varchar(255) not null,
|
36
|
+
UNIQUE(role_name, ip_addr)
|
37
|
+
)
|
38
|
+
EOF
|
49
39
|
end
|
50
|
-
end
|
51
40
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
41
|
+
#
|
42
|
+
# Gets the next unallocated IP, given an IP to start with.
|
43
|
+
#
|
44
|
+
def next_ip(arg)
|
45
|
+
octets = arg.split(/\./, 4).map(&:to_i)
|
46
|
+
octets[3] += 1
|
47
|
+
raise "out of ips!" if octets[3] > 255
|
48
|
+
return octets.map(&:to_s).join(".")
|
49
|
+
end
|
59
50
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
raise "out of ips!" if octets[3] > 255
|
67
|
-
return octets.map(&:to_s).join(".")
|
68
|
-
end
|
51
|
+
#
|
52
|
+
# Gets the next un-used IP. This basically calls `next_ip` with knowledge of
|
53
|
+
# the database.
|
54
|
+
#
|
55
|
+
def unused_ip
|
56
|
+
ip = next_ip(@subnet)
|
69
57
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
#
|
74
|
-
def unused_ip
|
75
|
-
ip = next_ip(@subnet)
|
58
|
+
while ip_used?(ip)
|
59
|
+
ip = next_ip(ip)
|
60
|
+
end
|
76
61
|
|
77
|
-
|
78
|
-
ip = next_ip(ip)
|
62
|
+
return ip
|
79
63
|
end
|
80
64
|
|
81
|
-
|
82
|
-
|
65
|
+
#
|
66
|
+
# Predicate to determine if an IP is in use.
|
67
|
+
#
|
68
|
+
def ip_used?(ip)
|
69
|
+
@db.execute("select count(*) from ips where ip_addr=?", [ip]).first.first > 0 rescue nil
|
70
|
+
end
|
83
71
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
72
|
+
#
|
73
|
+
# Appends an IP to a role.
|
74
|
+
#
|
75
|
+
def assign_role_ip(role, ip)
|
76
|
+
@db.execute("insert into ips (role_name, ip_addr) values (?, ?)", [role, ip])
|
77
|
+
end
|
90
78
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
79
|
+
#
|
80
|
+
# Removes the role and all associated IPs.
|
81
|
+
#
|
82
|
+
def delete_role(role)
|
83
|
+
@db.execute("delete from ips where role_name=?", [role])
|
84
|
+
end
|
98
85
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
86
|
+
#
|
87
|
+
# Get all the known roles
|
88
|
+
#
|
89
|
+
def roles
|
90
|
+
@db.execute("select distinct role_name from ips").map(&:first);
|
91
|
+
end
|
105
92
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
93
|
+
#
|
94
|
+
# Gets all the IPs for a role, as an array of strings.
|
95
|
+
#
|
96
|
+
def get_role_ips(role)
|
97
|
+
@db.execute("select ip_addr from ips where role_name=? order by id", [role]).map(&:first)
|
98
|
+
end
|
112
99
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
100
|
+
#
|
101
|
+
# Helper method for vagrant. Vagrant always occupies .1 of any subnet it
|
102
|
+
# configures host-only networking on. This takes care of doing that.
|
103
|
+
#
|
104
|
+
def seed_vagrant_ips
|
105
|
+
# vagrant requires that .1 be used by vagrant. ugh.
|
106
|
+
dot_one_ip = @subnet.gsub(/\.\d+$/, '.1')
|
107
|
+
unless ip_used?(dot_one_ip)
|
108
|
+
assign_role_ip("vagrant-reserved", dot_one_ip)
|
109
|
+
end
|
122
110
|
end
|
123
|
-
end
|
124
111
|
|
125
|
-
|
112
|
+
end
|
126
113
|
end
|
127
114
|
|
128
|
-
IPSupport.configure
|
129
|
-
IPSupport.singleton.load
|
115
|
+
ChefWorkflow::IPSupport.configure
|
@@ -2,32 +2,34 @@ require 'chef/application/knife'
|
|
2
2
|
require 'chef/knife'
|
3
3
|
require 'stringio'
|
4
4
|
|
5
|
-
|
6
|
-
# Mixin to add methods to assist with creating knife plugins.
|
7
|
-
#
|
8
|
-
module KnifePluginSupport
|
9
|
-
|
10
|
-
#
|
11
|
-
# Given a class name for a plugin compatible with the Chef::Knife interface,
|
12
|
-
# initializes it and makes it available for execution. It also overrides the
|
13
|
-
# `ui` object to use `StringIO` objects, which allow you to choose when and
|
14
|
-
# if you display the output of the commands by referencing
|
15
|
-
# `obj.ui.stdout.string` and similar calls.
|
5
|
+
module ChefWorkflow
|
16
6
|
#
|
17
|
-
#
|
18
|
-
# would be presented to a command line tool as `ARGV`.
|
7
|
+
# Mixin to add methods to assist with creating knife plugins.
|
19
8
|
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
9
|
+
module KnifePluginSupport
|
10
|
+
|
11
|
+
#
|
12
|
+
# Given a class name for a plugin compatible with the Chef::Knife interface,
|
13
|
+
# initializes it and makes it available for execution. It also overrides the
|
14
|
+
# `ui` object to use `StringIO` objects, which allow you to choose when and
|
15
|
+
# if you display the output of the commands by referencing
|
16
|
+
# `obj.ui.stdout.string` and similar calls.
|
17
|
+
#
|
18
|
+
# The second argument is an array of arguments to the command, such as they
|
19
|
+
# would be presented to a command line tool as `ARGV`.
|
20
|
+
#
|
21
|
+
def init_knife_plugin(klass, args)
|
22
|
+
klass.options = Chef::Application::Knife.options.merge(klass.options)
|
23
|
+
klass.load_deps
|
24
|
+
cli = klass.new(args)
|
25
|
+
cli.ui = Chef::Knife::UI.new(
|
26
|
+
StringIO.new('', 'w'),
|
27
|
+
StringIO.new('', 'w'),
|
28
|
+
StringIO.new('', 'r'),
|
29
|
+
cli.config
|
30
|
+
)
|
30
31
|
|
31
|
-
|
32
|
+
return cli
|
33
|
+
end
|
32
34
|
end
|
33
35
|
end
|
@@ -3,120 +3,94 @@ require 'erb'
|
|
3
3
|
require 'chef-workflow/support/generic'
|
4
4
|
require 'chef-workflow/support/general'
|
5
5
|
require 'chef-workflow/support/debug'
|
6
|
+
require 'chef-workflow/support/attr'
|
6
7
|
|
7
|
-
|
8
|
-
# Configuration class for chef tooling and SSH interaction. Uses `GenericSupport`.
|
9
|
-
#
|
10
|
-
class KnifeSupport
|
11
|
-
include GenericSupport
|
12
|
-
include DebugSupport
|
13
|
-
|
14
|
-
# defaults, yo
|
15
|
-
DEFAULTS = {
|
16
|
-
:search_index_wait => 60,
|
17
|
-
:cookbooks_path => File.join(Dir.pwd, 'cookbooks'),
|
18
|
-
:chef_config_path => File.join(GeneralSupport.singleton.workflow_dir, 'chef'),
|
19
|
-
:knife_config_path => File.join(GeneralSupport.singleton.workflow_dir, 'chef', 'knife.rb'),
|
20
|
-
:roles_path => File.join(Dir.pwd, 'roles'),
|
21
|
-
:environments_path => File.join(Dir.pwd, 'environments'),
|
22
|
-
:data_bags_path => File.join(Dir.pwd, 'data_bags'),
|
23
|
-
:ssh_user => "vagrant",
|
24
|
-
:ssh_password => "vagrant",
|
25
|
-
:ssh_identity_file => nil,
|
26
|
-
:use_sudo => true,
|
27
|
-
:test_environment => "vagrant",
|
28
|
-
:test_recipes => []
|
29
|
-
}
|
30
|
-
|
31
|
-
DEFAULTS[:knife_config_template] = <<-EOF
|
32
|
-
log_level :info
|
33
|
-
log_location STDOUT
|
34
|
-
node_name 'test-user'
|
35
|
-
client_key File.join('<%= KnifeSupport.singleton.chef_config_path %>', 'admin.pem')
|
36
|
-
validation_client_name 'chef-validator'
|
37
|
-
validation_key File.join('<%= KnifeSupport.singleton.chef_config_path %>', 'validation.pem')
|
38
|
-
chef_server_url 'http://<%= IPSupport.singleton.get_role_ips("chef-server").first %>:4000'
|
39
|
-
environment '<%= KnifeSupport.singleton.test_environment %>'
|
40
|
-
cache_type 'BasicFile'
|
41
|
-
cache_options( :path => File.join('<%= KnifeSupport.singleton.chef_config_path %>', 'checksums' ))
|
42
|
-
cookbook_path [ '<%= KnifeSupport.singleton.cookbooks_path %>' ]
|
43
|
-
EOF
|
44
|
-
|
8
|
+
module ChefWorkflow
|
45
9
|
#
|
46
|
-
#
|
47
|
-
# probably be replaced by `AttrSupport`. Takes an attribute name and a
|
48
|
-
# default which will be set initially, intended to be overridden by the user
|
49
|
-
# if necessary.
|
10
|
+
# Configuration class for chef tooling and SSH interaction. Uses `GenericSupport`.
|
50
11
|
#
|
51
|
-
|
52
|
-
|
12
|
+
class KnifeSupport
|
13
|
+
include ChefWorkflow::DebugSupport
|
14
|
+
extend ChefWorkflow::AttrSupport
|
15
|
+
include ChefWorkflow::GenericSupport
|
53
16
|
|
54
|
-
|
17
|
+
# defaults, yo
|
18
|
+
DEFAULTS = {
|
19
|
+
:search_index_wait => 60,
|
20
|
+
:cookbooks_path => File.join(Dir.pwd, 'cookbooks'),
|
21
|
+
:chef_config_path => File.join(ChefWorkflow::GeneralSupport.workflow_dir, 'chef'),
|
22
|
+
:knife_config_path => File.join(ChefWorkflow::GeneralSupport.workflow_dir, 'chef', 'knife.rb'),
|
23
|
+
:roles_path => File.join(Dir.pwd, 'roles'),
|
24
|
+
:environments_path => File.join(Dir.pwd, 'environments'),
|
25
|
+
:data_bags_path => File.join(Dir.pwd, 'data_bags'),
|
26
|
+
:ssh_user => "vagrant",
|
27
|
+
:ssh_password => "vagrant",
|
28
|
+
:ssh_identity_file => nil,
|
29
|
+
:use_sudo => true,
|
30
|
+
:test_environment => "vagrant",
|
31
|
+
:test_recipes => []
|
32
|
+
}
|
55
33
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
34
|
+
DEFAULTS[:knife_config_template] = <<-EOF
|
35
|
+
log_level :info
|
36
|
+
log_location STDOUT
|
37
|
+
node_name 'test-user'
|
38
|
+
client_key File.join('<%= KnifeSupport.chef_config_path %>', 'admin.pem')
|
39
|
+
validation_client_name 'chef-validator'
|
40
|
+
validation_key File.join('<%= KnifeSupport.chef_config_path %>', 'validation.pem')
|
41
|
+
chef_server_url 'http://<%= IPSupport.get_role_ips("chef-server").first %>:4000'
|
42
|
+
environment '<%= KnifeSupport.test_environment %>'
|
43
|
+
cache_type 'BasicFile'
|
44
|
+
cache_options( :path => File.join('<%= KnifeSupport.chef_config_path %>', 'checksums' ))
|
45
|
+
cookbook_path [ '<%= KnifeSupport.cookbooks_path %>' ]
|
46
|
+
EOF
|
64
47
|
|
65
|
-
|
66
|
-
if arg
|
67
|
-
@#{attr_name} = arg
|
68
|
-
ENV["CHEF_CONFIG"] = arg
|
69
|
-
end
|
70
|
-
|
71
|
-
@#{attr_name}
|
72
|
-
end
|
73
|
-
EOF
|
74
|
-
else
|
75
|
-
str = <<-EOF
|
76
|
-
def #{attr_name}=(arg)
|
77
|
-
@#{attr_name} = arg
|
78
|
-
end
|
48
|
+
attr_reader :attributes
|
79
49
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
50
|
+
def initialize
|
51
|
+
@attributes = { }
|
52
|
+
|
53
|
+
DEFAULTS.each do |key, value|
|
54
|
+
add_attribute(key, value)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Helper method to allow extensions to add attributes to this class.
|
60
|
+
# Takes an attribute name and a default which will be set initially,
|
61
|
+
# intended to be overridden by the user if necessary.
|
62
|
+
#
|
63
|
+
#--
|
64
|
+
# FIXME Move all the user-configurable stuff to its own support system
|
65
|
+
#++
|
66
|
+
def add_attribute(attr_name, default)
|
67
|
+
@attributes[attr_name] = default
|
88
68
|
end
|
89
69
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
DEFAULTS.each { |key, value| add_attribute(key, value) }
|
70
|
+
def method_missing(sym, *args)
|
71
|
+
attr_name = sym.to_s.sub(/=$/, '').to_sym
|
72
|
+
assignment = sym.to_s.end_with?("=")
|
95
73
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
74
|
+
if @attributes.has_key?(attr_name)
|
75
|
+
if assignment or args.count > 0
|
76
|
+
@attributes[attr_name] = args[0]
|
77
|
+
else
|
78
|
+
@attributes[attr_name]
|
79
|
+
end
|
80
|
+
else
|
81
|
+
raise "Attribute #{attr_name} does not exist"
|
82
|
+
end
|
102
83
|
end
|
103
|
-
end
|
104
84
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
85
|
+
#
|
86
|
+
# Writes out a knife.rb based on the settings in this configuration. Uses the
|
87
|
+
# `knife_config_path` and `chef_config_path` to determine where to write it.
|
88
|
+
#
|
89
|
+
def build_knife_config
|
90
|
+
FileUtils.mkdir_p(chef_config_path)
|
91
|
+
File.binwrite(knife_config_path, ERB.new(knife_config_template).result(binding))
|
111
92
|
end
|
112
93
|
end
|
113
|
-
|
114
|
-
#
|
115
|
-
# Writes out a knife.rb based on the settings in this configuration. Uses the
|
116
|
-
# `knife_config_path` and `chef_config_path` to determine where to write it.
|
117
|
-
#
|
118
|
-
def build_knife_config
|
119
|
-
FileUtils.mkdir_p(chef_config_path)
|
120
|
-
File.binwrite(knife_config_path, ERB.new(knife_config_template).result(binding))
|
121
|
-
end
|
122
94
|
end
|
95
|
+
|
96
|
+
ChefWorkflow::KnifeSupport.configure
|