chef-workflow 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|