knife-sharp 0.4.5 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +92 -0
- data/Rakefile +35 -0
- data/knife-sharp.gemspec +20 -0
- data/lib/chef/knife/sharp-align.rb +26 -465
- data/lib/chef/knife/sharp-backup.rb +8 -32
- data/lib/chef/knife/sharp-cookbook-align.rb +149 -0
- data/lib/chef/knife/sharp-data_bag-align.rb +141 -0
- data/lib/chef/knife/sharp-history.rb +6 -34
- data/lib/chef/knife/sharp-role-align.rb +134 -0
- data/lib/chef/knife/sharp-rollback.rb +7 -30
- data/lib/knife-sharp.rb +1 -1
- data/lib/knife-sharp/common.rb +113 -0
- metadata +16 -7
@@ -1,56 +1,32 @@
|
|
1
1
|
require 'chef/knife'
|
2
|
+
require 'knife-sharp/common'
|
2
3
|
|
3
4
|
module KnifeSharp
|
4
5
|
class SharpBackup < Chef::Knife
|
6
|
+
include KnifeSharp::Common
|
5
7
|
|
6
8
|
banner "knife sharp backup"
|
7
9
|
|
8
10
|
deps do
|
9
|
-
require 'chef/
|
10
|
-
require 'chef/
|
11
|
+
require 'chef/environment'
|
12
|
+
require 'chef/role'
|
13
|
+
require 'chef/data_bag'
|
14
|
+
require 'chef/data_bag_item'
|
11
15
|
end
|
12
16
|
|
13
17
|
def run
|
14
|
-
setup()
|
15
18
|
backup()
|
16
19
|
end
|
17
20
|
|
18
|
-
def setup
|
19
|
-
# Sharp config
|
20
|
-
cfg_files = [ "/etc/sharp-config.yml", "~/.chef/sharp-config.yml" ]
|
21
|
-
loaded = false
|
22
|
-
cfg_files.each do |cfg_file|
|
23
|
-
begin
|
24
|
-
@cfg = YAML::load_file(File.expand_path(cfg_file))
|
25
|
-
loaded = true
|
26
|
-
rescue Exception => e
|
27
|
-
ui.error "Error on loading config : #{e.inspect}" if config[:debug]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
unless loaded == true
|
31
|
-
ui.error "config could not be loaded ! Tried the following files : #{cfg_files.join(", ")}"
|
32
|
-
exit 1
|
33
|
-
end
|
34
|
-
|
35
|
-
# Knife config
|
36
|
-
if (ENV['HOME'] && File.exist?(File.join(ENV['HOME'], '.chef', 'knife.rb')))
|
37
|
-
Chef::Config.from_file(File.join(ENV['HOME'], '.chef', 'knife.rb'))
|
38
|
-
else
|
39
|
-
ui.error "Cannot find knife.rb config file"
|
40
|
-
exit 1
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
21
|
def backup
|
46
22
|
timestamp = Time.now.to_i
|
47
23
|
|
48
|
-
unless
|
24
|
+
unless sharp_config["global"]["backupdir"]
|
49
25
|
ui.error "You need to add global/backupdir to your config file"
|
50
26
|
exit 1
|
51
27
|
end
|
52
28
|
|
53
|
-
backup_path =
|
29
|
+
backup_path = sharp_config["global"]["backupdir"] + "/backup-#{timestamp}"
|
54
30
|
|
55
31
|
if File.exist?(backup_path)
|
56
32
|
ui.error "Backup path (#{backup_path}) exists. Will not overwrite."
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
require 'knife-sharp/common'
|
3
|
+
|
4
|
+
module KnifeSharp
|
5
|
+
class SharpCookbookAlign < Chef::Knife
|
6
|
+
include KnifeSharp::Common
|
7
|
+
|
8
|
+
banner "knife sharp cookbook align BRANCH ENVIRONMENT [OPTS]"
|
9
|
+
|
10
|
+
deps do
|
11
|
+
require 'chef/cookbook/metadata'
|
12
|
+
require 'chef/cookbook_loader'
|
13
|
+
require 'chef/cookbook_uploader'
|
14
|
+
require 'chef/environment'
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
ui.error "Not implemented yet. Use ```knife sharp align -C```"
|
19
|
+
end
|
20
|
+
|
21
|
+
### Cookbook methods ###
|
22
|
+
|
23
|
+
def check_cookbooks(env)
|
24
|
+
to_update = Array.new
|
25
|
+
|
26
|
+
unless File.exists?(cookbook_path)
|
27
|
+
ui.warn "Bad cookbook path, skipping cookbook sync."
|
28
|
+
return to_update
|
29
|
+
end
|
30
|
+
|
31
|
+
ui.msg(ui.color("== Cookbooks ==", :bold))
|
32
|
+
|
33
|
+
updated_versions = Hash.new
|
34
|
+
local_versions = local_cookbook_versions
|
35
|
+
remote_versions = remote_cookbook_versions(env)
|
36
|
+
|
37
|
+
if local_versions.empty?
|
38
|
+
ui.warn "No local cookbooks found, is the cookbook path correct ? (#{cookbook_path})"
|
39
|
+
return to_update
|
40
|
+
end
|
41
|
+
|
42
|
+
# get local-only cookbooks
|
43
|
+
(local_versions.keys - remote_versions.keys).each do |cb|
|
44
|
+
updated_versions[cb] = local_versions[cb]
|
45
|
+
ui.msg "* #{cb} is local only (version #{local_versions[cb]})"
|
46
|
+
end
|
47
|
+
|
48
|
+
# get cookbooks not up-to-date
|
49
|
+
(remote_versions.keys & local_versions.keys).each do |cb|
|
50
|
+
if Chef::VersionConstraint.new("> #{remote_versions[cb]}").include?(local_versions[cb])
|
51
|
+
updated_versions[cb] = local_versions[cb]
|
52
|
+
ui.msg "* #{cb} is not up-to-date (local: #{local_versions[cb]}/remote: #{remote_versions[cb]})"
|
53
|
+
elsif Chef::VersionConstraint.new("> #{local_versions[cb]}").include?(remote_versions[cb]) and config[:force_align]
|
54
|
+
updated_versions[cb] = local_versions[cb]
|
55
|
+
ui.msg "* #{cb} is to be downgraded (local: #{local_versions[cb]}/remote: #{remote_versions[cb]})"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if sharp_config[chef_server] and sharp_config[chef_server].has_key?("ignore_cookbooks")
|
60
|
+
(updated_versions.keys & sharp_config[chef_server]["ignore_cookbooks"]).each do |cb|
|
61
|
+
updated_versions.delete(cb)
|
62
|
+
ui.msg "* Skipping #{cb} cookbook (ignore list)"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if !updated_versions.empty?
|
67
|
+
all = false
|
68
|
+
updated_versions.each_pair do |cb,version|
|
69
|
+
answer = ui.ask_question("> Update #{cb} cookbook to #{version} on server ? Y/N/(A)ll/(Q)uit ", :default => "N").upcase unless all
|
70
|
+
|
71
|
+
if answer == "A"
|
72
|
+
all = true
|
73
|
+
elsif answer == "Q"
|
74
|
+
ui.msg "* Skipping next cookbooks alignment."
|
75
|
+
break
|
76
|
+
end
|
77
|
+
|
78
|
+
if all or answer == "Y"
|
79
|
+
to_update << cb
|
80
|
+
else
|
81
|
+
ui.msg "* Skipping #{cb} cookbook"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
ui.msg "* Environment #{env} is up-to-date."
|
86
|
+
end
|
87
|
+
|
88
|
+
to_update
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
def bump_cookbooks(env_name, cookbook_list)
|
93
|
+
unless cookbook_list.empty?
|
94
|
+
env = Chef::Environment.load(env_name)
|
95
|
+
cbs = Array.new
|
96
|
+
backup_data = Hash.new
|
97
|
+
backup_data["environment"] = env.name
|
98
|
+
backup_data["cookbook_versions"] = Hash.new
|
99
|
+
cookbook_list.each do |cb_name|
|
100
|
+
cb = cookbook_loader[cb_name]
|
101
|
+
if sharp_config["rollback"] && sharp_config["rollback"]["enabled"] == true
|
102
|
+
backup_data["cookbook_versions"][cb_name] = env.cookbook_versions[cb_name]
|
103
|
+
end
|
104
|
+
# Force "= a.b.c" in cookbook version, as chef11 will not accept "a.b.c"
|
105
|
+
env.cookbook_versions[cb_name] = "= #{cb.version}"
|
106
|
+
cbs << cb
|
107
|
+
end
|
108
|
+
|
109
|
+
ui.msg "* Uploading cookbook(s) #{cookbook_list.join(", ")}"
|
110
|
+
cookbook_uploader(cbs).upload_cookbooks
|
111
|
+
|
112
|
+
if env.save
|
113
|
+
cbs.each do |cb|
|
114
|
+
ui.msg "* Bumping #{cb.name} to #{cb.version} for environment #{env.name}"
|
115
|
+
log_action("bumping #{cb.name} to #{cb.version} for environment #{env.name}")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
if sharp_config["rollback"] && sharp_config["rollback"]["enabled"] == true
|
120
|
+
identifier = Time.now.to_i
|
121
|
+
Dir.mkdir(sharp_config["rollback"]["destination"]) unless File.exists?(sharp_config["rollback"]["destination"])
|
122
|
+
fp = open(File.join(sharp_config["rollback"]["destination"], "#{identifier}.json"), "w")
|
123
|
+
fp.write(JSON.pretty_generate(backup_data))
|
124
|
+
fp.close()
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def cookbook_loader
|
130
|
+
@cookbook_loader ||= Chef::CookbookLoader.new(Chef::Config.cookbook_path)
|
131
|
+
end
|
132
|
+
|
133
|
+
def cookbook_uploader(cookbooks)
|
134
|
+
if Gem::Version.new(Chef::VERSION).release >= Gem::Version.new('12.0.0')
|
135
|
+
uploader = Chef::CookbookUploader.new(cookbooks)
|
136
|
+
else
|
137
|
+
uploader = Chef::CookbookUploader.new(cookbooks, Chef::Config.cookbook_path)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def local_cookbook_versions
|
142
|
+
Hash[Dir.glob("#{cookbook_path}/*").select {|cb| File.directory?(cb)}.map {|cb| [File.basename(cb), cookbook_loader[File.basename(cb)].version] }]
|
143
|
+
end
|
144
|
+
|
145
|
+
def remote_cookbook_versions(env)
|
146
|
+
Chef::Environment.load(env).cookbook_versions.each_value {|v| v.gsub!("= ", "")}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
require 'knife-sharp/common'
|
3
|
+
|
4
|
+
module KnifeSharp
|
5
|
+
class SharpDataBagAlign < Chef::Knife
|
6
|
+
include KnifeSharp::Common
|
7
|
+
|
8
|
+
banner "knife sharp data bag align BRANCH [OPTS]"
|
9
|
+
|
10
|
+
deps do
|
11
|
+
require 'chef/data_bag'
|
12
|
+
require 'chef/data_bag_item'
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
ui.error "Not implemented yet. Use ```knife sharp align -D```"
|
17
|
+
end
|
18
|
+
|
19
|
+
### Databag methods ###
|
20
|
+
|
21
|
+
def check_databags
|
22
|
+
to_update = Hash.new
|
23
|
+
|
24
|
+
unless File.exists?(data_bag_path)
|
25
|
+
ui.warn "Bad data bag path, skipping data bag sync."
|
26
|
+
return to_update
|
27
|
+
end
|
28
|
+
|
29
|
+
ui.msg(ui.color("== Data bags ==", :bold))
|
30
|
+
|
31
|
+
updated_dbs = Hash.new
|
32
|
+
local_dbs = Dir.glob(File.join(data_bag_path, "**/*.json")).map {|f| [File.dirname(f).split("/").last, File.basename(f, ".json")]}
|
33
|
+
remote_dbs = Chef::DataBag.list.keys.map {|db| Chef::DataBag.load(db).keys.map{|dbi| [db, dbi]}}.flatten(1)
|
34
|
+
|
35
|
+
if local_dbs.empty?
|
36
|
+
ui.warn "No local data bags found, is the data bag path correct ? (#{data_bag_path})"
|
37
|
+
return to_update
|
38
|
+
end
|
39
|
+
|
40
|
+
# Dump missing data bags locally
|
41
|
+
(remote_dbs - local_dbs).each do |db|
|
42
|
+
ui.msg "* #{db.join("/")} data bag item is remote only"
|
43
|
+
if config[:dump_remote_only]
|
44
|
+
ui.msg "* Dumping to #{File.join(data_bag_path, "#{db.join("/")}.json")}"
|
45
|
+
begin
|
46
|
+
remote_db = Chef::DataBagItem.load(db.first, db.last).raw_data
|
47
|
+
Dir.mkdir(File.join(data_bag_path, db.first)) unless File.exists?(File.join(data_bag_path, db.first))
|
48
|
+
File.open(File.join(data_bag_path, "#{db.join("/")}.json"), "w") do |file|
|
49
|
+
file.puts JSON.pretty_generate(remote_db)
|
50
|
+
end
|
51
|
+
rescue Exception => e
|
52
|
+
ui.error "Unable to dump #{db.join("/")} data bag item (#{e.message})"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Create new data bags on server
|
58
|
+
(local_dbs - remote_dbs).each do |db|
|
59
|
+
begin
|
60
|
+
local_db = JSON::load(File.read(File.join(data_bag_path, "#{db.join("/")}.json")))
|
61
|
+
updated_dbs[db] = local_db
|
62
|
+
ui.msg "* #{db.join("/")} data bag item is local only"
|
63
|
+
rescue Exception => e
|
64
|
+
ui.error "Unable to load #{db.join("/")} data bag item (#{e.message})"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Compare roles common to local and remote
|
69
|
+
(remote_dbs & local_dbs).each do |db|
|
70
|
+
begin
|
71
|
+
remote_db = Chef::DataBagItem.load(db.first, db.last).raw_data
|
72
|
+
local_db = JSON::load(File.read(File.join(data_bag_path, "#{db.join("/")}.json")))
|
73
|
+
if remote_db != local_db
|
74
|
+
updated_dbs[db] = local_db
|
75
|
+
ui.msg("* #{db.join("/")} data bag item is not up-to-date")
|
76
|
+
end
|
77
|
+
rescue Exception => e
|
78
|
+
ui.error "Unable to load #{db.join("/")} data bag item (#{e.message})"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if sharp_config[chef_server] and sharp_config[chef_server].has_key?("ignore_databags")
|
83
|
+
(updated_dbs.keys.map{|k| k.join("/")} & sharp_config[chef_server]["ignore_databags"]).each do |db|
|
84
|
+
updated_dbs.delete(db.split("/"))
|
85
|
+
ui.msg "* Skipping #{db} data bag (ignore list)"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
if !updated_dbs.empty?
|
90
|
+
all = false
|
91
|
+
updated_dbs.each do |name, obj|
|
92
|
+
answer = nil
|
93
|
+
answer = ui.ask_question("> Update #{name.join("/")} data bag item on server ? Y/N/(A)ll/(Q)uit ", :default => "N").upcase unless all
|
94
|
+
|
95
|
+
if answer == "A"
|
96
|
+
all = true
|
97
|
+
elsif answer == "Q"
|
98
|
+
ui.msg "* Aborting data bag alignment."
|
99
|
+
break
|
100
|
+
end
|
101
|
+
|
102
|
+
if all or answer == "Y"
|
103
|
+
to_update[name] = obj
|
104
|
+
else
|
105
|
+
ui.msg "* Skipping #{name.join("/")} data bag item"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
else
|
109
|
+
ui.msg "* Data bags are up-to-date."
|
110
|
+
end
|
111
|
+
|
112
|
+
to_update
|
113
|
+
end
|
114
|
+
|
115
|
+
def update_databags(databag_list)
|
116
|
+
parent_databags = Chef::DataBag.list.keys
|
117
|
+
databag_list.each do |name, obj|
|
118
|
+
begin
|
119
|
+
# create the parent if needed
|
120
|
+
unless parent_databags.include?(name.first)
|
121
|
+
db = Chef::DataBag.new
|
122
|
+
db.name(name.first)
|
123
|
+
db.create
|
124
|
+
# add it to the list to avoid trying to recreate it
|
125
|
+
parent_databags.push(name.first)
|
126
|
+
ui.msg("* Creating data bag #{name.first}")
|
127
|
+
log_action("creating data bag #{name.first}")
|
128
|
+
end
|
129
|
+
db = Chef::DataBagItem.new
|
130
|
+
db.data_bag(name.first)
|
131
|
+
db.raw_data = obj
|
132
|
+
db.save
|
133
|
+
ui.msg "* Updating #{name.join("/")} data bag item"
|
134
|
+
log_action("updating #{name.join("/")} data bag item")
|
135
|
+
rescue Exception => e
|
136
|
+
ui.error "Unable to update #{name.join("/")} data bag item"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -1,49 +1,23 @@
|
|
1
|
+
require 'knife-sharp/common'
|
2
|
+
|
1
3
|
module KnifeSharp
|
2
4
|
class SharpHistory < Chef::Knife
|
5
|
+
include KnifeSharp::Common
|
6
|
+
|
3
7
|
banner "knife sharp history"
|
4
|
-
|
8
|
+
|
5
9
|
option :debug,
|
6
10
|
:long => '--debug',
|
7
11
|
:description => "turn debug on",
|
8
12
|
:default => false
|
9
13
|
|
10
|
-
deps do
|
11
|
-
require 'chef/data_bag'
|
12
|
-
require 'chef/data_bag_item'
|
13
|
-
require 'chef/json_compat'
|
14
|
-
require 'chef/knife/search'
|
15
|
-
require 'chef/environment'
|
16
|
-
require 'chef/cookbook/metadata'
|
17
|
-
require 'chef/knife/core/object_loader'
|
18
|
-
end
|
19
|
-
|
20
|
-
@@cfg_files = [ "/etc/sharp-config.yml", "~/.chef/sharp-config.yml" ]
|
21
|
-
|
22
|
-
def load_config
|
23
|
-
loaded = false
|
24
|
-
@@cfg_files.each do |cfg_file|
|
25
|
-
begin
|
26
|
-
@@cfg=YAML::load_file(File.expand_path(cfg_file))
|
27
|
-
loaded = true
|
28
|
-
rescue Exception => e
|
29
|
-
puts "Error on loading config : #{e.inspect}" if config[:debug]
|
30
|
-
end
|
31
|
-
end
|
32
|
-
unless loaded == true
|
33
|
-
ui.error "config could not be loaded ! Tried the following files : #{@@cfg_files.join(", ")}"
|
34
|
-
exit 1
|
35
|
-
end
|
36
|
-
puts @@cfg.inspect if config[:debug]
|
37
|
-
end
|
38
|
-
|
39
14
|
def run
|
40
|
-
load_config()
|
41
15
|
show_logs()
|
42
16
|
end
|
43
17
|
|
44
18
|
def show_logs()
|
45
19
|
begin
|
46
|
-
fp = File.open(File.expand_path(
|
20
|
+
fp = File.open(File.expand_path(sharp_config["logging"]["destination"]), "r")
|
47
21
|
fp.readlines.each do |line|
|
48
22
|
puts line
|
49
23
|
end
|
@@ -51,7 +25,5 @@ module KnifeSharp
|
|
51
25
|
ui.error "oops ! #{e.inspect}"
|
52
26
|
end
|
53
27
|
end
|
54
|
-
|
55
|
-
|
56
28
|
end
|
57
29
|
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'chef/knife'
|
2
|
+
require 'knife-sharp/common'
|
3
|
+
|
4
|
+
module KnifeSharp
|
5
|
+
class SharpRoleAlign < Chef::Knife
|
6
|
+
include KnifeSharp::Common
|
7
|
+
|
8
|
+
banner "knife sharp role align BRANCH [OPTS]"
|
9
|
+
|
10
|
+
deps do
|
11
|
+
require 'chef/role'
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
ui.error "Not implemented yet. Use ```knife sharp align -R```"
|
16
|
+
end
|
17
|
+
|
18
|
+
### Role methods ###
|
19
|
+
|
20
|
+
def check_roles
|
21
|
+
to_update = Hash.new
|
22
|
+
|
23
|
+
unless File.exists?(role_path)
|
24
|
+
ui.warn "Bad role path, skipping role sync."
|
25
|
+
return to_update
|
26
|
+
end
|
27
|
+
|
28
|
+
ui.msg(ui.color("== Roles ==", :bold))
|
29
|
+
|
30
|
+
updated_roles = Hash.new
|
31
|
+
local_roles = Dir.glob(File.join(role_path, "*.json")).map {|file| File.basename(file, ".json")}
|
32
|
+
remote_roles = Chef::Role.list.keys
|
33
|
+
|
34
|
+
if local_roles.empty?
|
35
|
+
ui.warn "No local roles found, is the role path correct ? (#{role_path})"
|
36
|
+
return to_update
|
37
|
+
end
|
38
|
+
|
39
|
+
# Dump missing roles locally
|
40
|
+
(remote_roles - local_roles).each do |role|
|
41
|
+
ui.msg "* #{role} role is remote only"
|
42
|
+
if config[:dump_remote_only]
|
43
|
+
ui.msg "* Dumping to #{File.join(role_path, "#{role}.json")}"
|
44
|
+
begin
|
45
|
+
remote_role = Chef::Role.load(role)
|
46
|
+
File.open(File.join(role_path, "#{role}.json"), "w") do |file|
|
47
|
+
file.puts JSON.pretty_generate(remote_role)
|
48
|
+
end
|
49
|
+
rescue Exception => e
|
50
|
+
ui.error "Unable to dump #{role} role (#{e.message})"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Create new roles on server
|
56
|
+
(local_roles - remote_roles).each do |role|
|
57
|
+
begin
|
58
|
+
local_role = Chef::Role.from_disk(role)
|
59
|
+
updated_roles[role] = local_role
|
60
|
+
ui.msg "* #{role} role is local only"
|
61
|
+
rescue Exception => e
|
62
|
+
ui.error "Unable to load #{role} role (#{e.message})"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Compare roles common to local and remote
|
67
|
+
(remote_roles & local_roles).each do |role|
|
68
|
+
remote_role = Chef::Role.load(role)
|
69
|
+
local_role = Chef::Role.from_disk(role)
|
70
|
+
|
71
|
+
diffs = Array.new
|
72
|
+
relevant_role_keys.each do |method, display|
|
73
|
+
if remote_role.send(method) != local_role.send(method)
|
74
|
+
updated_roles[role] = local_role
|
75
|
+
diffs << display
|
76
|
+
end
|
77
|
+
end
|
78
|
+
ui.msg("* #{role} role is not up-to-date (#{diffs.join(",")})") unless diffs.empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
if sharp_config[chef_server] and sharp_config[chef_server].has_key?("ignore_roles")
|
82
|
+
(updated_roles.keys & sharp_config[chef_server]["ignore_roles"]).each do |r|
|
83
|
+
updated_roles.delete(r)
|
84
|
+
ui.msg "* Skipping #{r} role (ignore list)"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
if !updated_roles.empty?
|
89
|
+
all = false
|
90
|
+
updated_roles.each do |name, obj|
|
91
|
+
answer = ui.ask_question("> Update #{name} role on server ? Y/N/(A)ll/(Q)uit ", :default => "N").upcase unless all
|
92
|
+
|
93
|
+
if answer == "A"
|
94
|
+
all = true
|
95
|
+
elsif answer == "Q"
|
96
|
+
ui.msg "* Aborting role alignment."
|
97
|
+
break
|
98
|
+
end
|
99
|
+
|
100
|
+
if all or answer == "Y"
|
101
|
+
to_update[name] = obj
|
102
|
+
else
|
103
|
+
ui.msg "* Skipping #{name} role"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
else
|
107
|
+
ui.msg "* Roles are up-to-date."
|
108
|
+
end
|
109
|
+
|
110
|
+
to_update
|
111
|
+
end
|
112
|
+
|
113
|
+
def update_roles(role_list)
|
114
|
+
role_list.each do |name, obj|
|
115
|
+
begin
|
116
|
+
obj.save
|
117
|
+
ui.msg "* Updating #{name} role"
|
118
|
+
log_action("updating #{name} role")
|
119
|
+
rescue Exception => e
|
120
|
+
ui.error "Unable to update #{name} role"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def relevant_role_keys
|
126
|
+
# role sections to compare (methods)
|
127
|
+
{
|
128
|
+
"env_run_lists" => "run list",
|
129
|
+
"default_attributes" => "default attributes",
|
130
|
+
"override_attributes" => "override attributes"
|
131
|
+
}
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|