knife-sharp 0.4.5 → 0.5.1
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.
- 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
|