cloud-mu 3.1.6 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/bin/mu-adopt +15 -12
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +37 -1
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-load-config.rb +2 -1
- data/bin/mu-run-tests +37 -12
- data/cloud-mu.gemspec +4 -4
- data/cookbooks/mu-tools/attributes/default.rb +7 -0
- data/cookbooks/mu-tools/libraries/helper.rb +87 -3
- data/cookbooks/mu-tools/recipes/apply_security.rb +39 -23
- data/cookbooks/mu-tools/recipes/aws_api.rb +13 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +4 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
- data/cookbooks/mu-tools/resources/disk.rb +33 -12
- data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
- data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
- data/extras/clean-stock-amis +10 -2
- data/extras/generate-stock-images +7 -3
- data/extras/image-generators/AWS/centos7.yaml +19 -16
- data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
- data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
- data/modules/mommacat.ru +2 -2
- data/modules/mu.rb +84 -97
- data/modules/mu/adoption.rb +359 -59
- data/modules/mu/cleanup.rb +67 -44
- data/modules/mu/cloud.rb +108 -1754
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +44 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +929 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +178 -0
- data/modules/mu/config.rb +122 -80
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +32 -3
- data/modules/mu/config/cache_cluster.rb +2 -2
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/collection.rb +1 -1
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/database.rb +84 -105
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +5 -4
- data/modules/mu/config/doc_helpers.rb +4 -5
- data/modules/mu/config/endpoint.rb +2 -1
- data/modules/mu/config/firewall_rule.rb +3 -19
- data/modules/mu/config/folder.rb +1 -1
- data/modules/mu/config/function.rb +17 -8
- data/modules/mu/config/group.rb +1 -1
- data/modules/mu/config/habitat.rb +1 -1
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/loadbalancer.rb +57 -11
- data/modules/mu/config/log.rb +1 -1
- data/modules/mu/config/msg_queue.rb +1 -1
- data/modules/mu/config/nosqldb.rb +1 -1
- data/modules/mu/config/notifier.rb +8 -19
- data/modules/mu/config/ref.rb +81 -9
- data/modules/mu/config/role.rb +1 -1
- data/modules/mu/config/schema_helpers.rb +30 -34
- data/modules/mu/config/search_domain.rb +1 -1
- data/modules/mu/config/server.rb +5 -13
- data/modules/mu/config/server_pool.rb +3 -7
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +10 -0
- data/modules/mu/config/user.rb +1 -1
- data/modules/mu/config/vpc.rb +13 -17
- data/modules/mu/defaults/AWS.yaml +106 -106
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +1 -0
- data/modules/mu/deploy.rb +33 -19
- data/modules/mu/groomer.rb +15 -0
- data/modules/mu/groomers/chef.rb +3 -0
- data/modules/mu/logger.rb +120 -144
- data/modules/mu/master.rb +22 -1
- data/modules/mu/mommacat.rb +71 -26
- data/modules/mu/mommacat/daemon.rb +23 -14
- data/modules/mu/mommacat/naming.rb +82 -3
- data/modules/mu/mommacat/search.rb +59 -16
- data/modules/mu/mommacat/storage.rb +119 -48
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +248 -62
- data/modules/mu/{clouds → providers}/aws/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/aws/bucket.rb +275 -41
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +14 -50
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/{clouds → providers}/aws/collection.rb +5 -5
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +65 -63
- data/modules/mu/providers/aws/database.rb +1747 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +26 -12
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +39 -32
- data/modules/mu/{clouds → providers}/aws/folder.rb +1 -1
- data/modules/mu/{clouds → providers}/aws/function.rb +291 -133
- data/modules/mu/{clouds → providers}/aws/group.rb +18 -20
- data/modules/mu/{clouds → providers}/aws/habitat.rb +3 -3
- data/modules/mu/providers/aws/job.rb +469 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +77 -47
- data/modules/mu/{clouds → providers}/aws/log.rb +5 -5
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +14 -11
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +96 -5
- data/modules/mu/{clouds → providers}/aws/notifier.rb +135 -63
- data/modules/mu/{clouds → providers}/aws/role.rb +112 -78
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +172 -41
- data/modules/mu/{clouds → providers}/aws/server.rb +120 -145
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +42 -60
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +21 -38
- data/modules/mu/{clouds → providers}/aws/user.rb +12 -16
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/aws/vpc.rb +141 -73
- data/modules/mu/{clouds → providers}/aws/vpc_subnet.rb +0 -0
- data/modules/mu/{clouds → providers}/azure.rb +4 -1
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +1 -5
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +8 -1
- data/modules/mu/{clouds → providers}/azure/habitat.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/role.rb +0 -0
- data/modules/mu/{clouds → providers}/azure/server.rb +32 -24
- data/modules/mu/{clouds → providers}/azure/user.rb +1 -1
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +4 -6
- data/modules/mu/{clouds → providers}/cloudformation.rb +1 -1
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +3 -3
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +15 -6
- data/modules/mu/{clouds → providers}/google/bucket.rb +2 -2
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +29 -14
- data/modules/mu/{clouds → providers}/google/database.rb +2 -9
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/google/folder.rb +5 -9
- data/modules/mu/{clouds → providers}/google/function.rb +4 -4
- data/modules/mu/{clouds → providers}/google/group.rb +9 -17
- data/modules/mu/{clouds → providers}/google/habitat.rb +4 -8
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +2 -2
- data/modules/mu/{clouds → providers}/google/role.rb +46 -35
- data/modules/mu/{clouds → providers}/google/server.rb +26 -11
- data/modules/mu/{clouds → providers}/google/server_pool.rb +11 -11
- data/modules/mu/{clouds → providers}/google/user.rb +32 -22
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +38 -3
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/centos6.yaml +15 -0
- data/modules/tests/centos7.yaml +15 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/ecs.yaml +2 -2
- data/modules/tests/eks.yaml +1 -1
- data/modules/tests/functions/node-function/lambda_function.js +10 -0
- data/modules/tests/functions/python-function/lambda_function.py +12 -0
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +1 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +2 -2
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +126 -98
- data/modules/mu/clouds/aws/database.rb +0 -1974
- data/modules/mu/clouds/aws/endpoint.rb +0 -596
data/modules/mu/groomer.rb
CHANGED
@@ -30,6 +30,21 @@ module MU
|
|
30
30
|
["Chef", "Ansible"]
|
31
31
|
end
|
32
32
|
|
33
|
+
# List of known/supported groomers which are installed and appear to be working
|
34
|
+
# @return [Array<String>]
|
35
|
+
def self.availableGroomers
|
36
|
+
available = []
|
37
|
+
MU::Groomer.supportedGroomers.each { |groomer|
|
38
|
+
begin
|
39
|
+
groomerbase = loadGroomer(groomer)
|
40
|
+
available << groomer if groomerbase.available?
|
41
|
+
rescue LoadError
|
42
|
+
end
|
43
|
+
}
|
44
|
+
|
45
|
+
available
|
46
|
+
end
|
47
|
+
|
33
48
|
# Instance methods that any Groomer plugin must implement
|
34
49
|
def self.requiredMethods
|
35
50
|
[:preClean, :bootstrap, :haveBootstrapped?, :run, :saveDeployData, :getSecret, :saveSecret, :deleteSecret, :reinstall]
|
data/modules/mu/groomers/chef.rb
CHANGED
@@ -805,6 +805,9 @@ retry
|
|
805
805
|
end
|
806
806
|
end
|
807
807
|
|
808
|
+
# Purge Chef resources matching a particular deploy
|
809
|
+
# @param deploy_id [String]
|
810
|
+
# @param noop [Boolean]
|
808
811
|
def self.cleanup(deploy_id, noop = false)
|
809
812
|
return nil if deploy_id.nil? or deploy_id.empty?
|
810
813
|
begin
|
data/modules/mu/logger.rb
CHANGED
@@ -33,6 +33,33 @@ module MU
|
|
33
33
|
# Show DEBUG log entries and extra call stack and threading info
|
34
34
|
LOUD = 2.freeze
|
35
35
|
|
36
|
+
# stash a hash map for color outputs
|
37
|
+
COLORMAP = {
|
38
|
+
MU::DEBUG => { :html => "orange", :ansi => :yellow },
|
39
|
+
MU::INFO => { :html => "green", :ansi => :green },
|
40
|
+
MU::NOTICE => { :html => "yellow", :ansi => :yellow },
|
41
|
+
MU::WARN => { :html => "orange", :ansi => :light_red },
|
42
|
+
MU::ERR => { :html => "red", :ansi => :red }
|
43
|
+
}.freeze
|
44
|
+
|
45
|
+
# minimum log verbosity at which we'll print various types of messages
|
46
|
+
PRINT_MSG_IF = {
|
47
|
+
MU::DEBUG => { :msg => LOUD, :details => LOUD },
|
48
|
+
MU::INFO => { :msg => NORMAL, :details => LOUD },
|
49
|
+
MU::NOTICE => { :msg => nil, :details => QUIET },
|
50
|
+
MU::WARN => { :msg => nil, :details => SILENT },
|
51
|
+
MU::ERR => { :msg => nil, :details => nil }
|
52
|
+
}.freeze
|
53
|
+
|
54
|
+
# Syslog equivalents of our log levels
|
55
|
+
SYSLOG_MAP = {
|
56
|
+
MU::DEBUG => Syslog::LOG_DEBUG,
|
57
|
+
MU::INFO => Syslog::LOG_NOTICE,
|
58
|
+
MU::NOTICE => Syslog::LOG_NOTICE,
|
59
|
+
MU::WARN => Syslog::LOG_WARNING,
|
60
|
+
MU::ERR => Syslog::LOG_ERR
|
61
|
+
}.freeze
|
62
|
+
|
36
63
|
attr_accessor :verbosity
|
37
64
|
@verbosity = MU::Logger::NORMAL
|
38
65
|
@quiet = false
|
@@ -76,59 +103,28 @@ module MU
|
|
76
103
|
html ||= @html
|
77
104
|
handle ||= @handle
|
78
105
|
color ||= @color
|
79
|
-
return if verbosity == MU::Logger::SILENT
|
80
|
-
return if verbosity < MU::Logger::LOUD and level == DEBUG
|
81
|
-
return if verbosity < MU::Logger::NORMAL and level == INFO
|
82
106
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
mod_root = Regexp.quote("#{ENV['MU_LIBDIR']}/modules/mu/")
|
87
|
-
bin_root = Regexp.quote("#{ENV['MU_INSTALLDIR']}/bin/")
|
88
|
-
caller_name = caller[1]
|
107
|
+
if verbosity == MU::Logger::SILENT or (verbosity < MU::Logger::LOUD and level == DEBUG) or (verbosity < MU::Logger::NORMAL and level == INFO)
|
108
|
+
return
|
109
|
+
end
|
89
110
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
caller_name
|
96
|
-
caller_name.sub!(/^modules\//, "")
|
111
|
+
if level == SUMMARY
|
112
|
+
@summary << msg
|
113
|
+
return
|
114
|
+
end
|
115
|
+
|
116
|
+
caller_name = extract_caller_name(caller[1])
|
97
117
|
|
98
118
|
time = Time.now.strftime("%b %d %H:%M:%S").to_s
|
99
119
|
|
100
120
|
Syslog.open("Mu/"+caller_name, Syslog::LOG_PID, Syslog::LOG_DAEMON | Syslog::LOG_LOCAL3) if !Syslog.opened?
|
101
|
-
|
102
|
-
|
103
|
-
details = details[:details]
|
104
|
-
end
|
105
|
-
details = PP.pp(details, '') if !details.is_a?(String)
|
106
|
-
end
|
107
|
-
details = "<pre>"+details+"</pre>" if html
|
108
|
-
# We get passed literal quoted newlines sometimes, fix 'em. Get Windows'
|
109
|
-
# ugly line feeds too.
|
110
|
-
if !details.nil?
|
111
|
-
details = details.dup # in case it's frozen or something
|
112
|
-
details.gsub!(/\\n/, "\n")
|
113
|
-
details.gsub!(/(\\r|\r)/, "")
|
114
|
-
end
|
121
|
+
|
122
|
+
details = format_details(details, html)
|
115
123
|
|
116
124
|
msg = msg.first if msg.is_a?(Array)
|
117
125
|
msg = "" if msg == nil
|
118
126
|
msg = msg.to_s if !msg.is_a?(String) and msg.respond_to?(:to_s)
|
119
127
|
|
120
|
-
# wrapper for writing a log entry to multiple filehandles
|
121
|
-
# @param handles [Array<IO>]
|
122
|
-
# @param msgs [Array<String>]
|
123
|
-
def write(handles = [], msgs = [])
|
124
|
-
return if handles.nil? or msgs.nil?
|
125
|
-
handles.each { |h|
|
126
|
-
msgs.each { |m|
|
127
|
-
h.puts m
|
128
|
-
}
|
129
|
-
}
|
130
|
-
end
|
131
|
-
|
132
128
|
@@log_semaphere.synchronize {
|
133
129
|
handles = [handle]
|
134
130
|
extra_logfile = if deploy and deploy.deploy_dir and Dir.exist?(deploy.deploy_dir)
|
@@ -137,110 +133,41 @@ module MU
|
|
137
133
|
handles << extra_logfile if extra_logfile
|
138
134
|
msgs = []
|
139
135
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
end
|
155
|
-
Syslog.log(Syslog::LOG_DEBUG, msg.gsub(/%/, ''))
|
156
|
-
Syslog.log(Syslog::LOG_DEBUG, details.gsub(/%/, '')) if details
|
157
|
-
end
|
158
|
-
when INFO
|
159
|
-
if verbosity >= MU::Logger::NORMAL
|
160
|
-
if html
|
161
|
-
html_out "#{time} - #{caller_name} - #{msg}", "green"
|
162
|
-
elsif color
|
163
|
-
msgs << "#{time} - #{caller_name} - #{msg}".green.on_black
|
164
|
-
else
|
165
|
-
msgs << "#{time} - #{caller_name} - #{msg}"
|
166
|
-
end
|
167
|
-
if verbosity >= MU::Logger::LOUD
|
168
|
-
if html
|
169
|
-
html_out " #{details}"
|
170
|
-
elsif color
|
171
|
-
msgs << "#{details}".white.on_black if details
|
172
|
-
else
|
173
|
-
msgs << "#{details}" if details
|
174
|
-
end
|
175
|
-
end
|
176
|
-
Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
177
|
-
Syslog.log(Syslog::LOG_NOTICE, details.gsub(/%/, '')) if details
|
178
|
-
end
|
179
|
-
when NOTICE
|
180
|
-
if html
|
181
|
-
html_out "#{time} - #{caller_name} - #{msg}", "yellow"
|
182
|
-
elsif color
|
183
|
-
msgs << "#{time} - #{caller_name} - #{msg}".yellow.on_black
|
184
|
-
else
|
185
|
-
msgs << "#{time} - #{caller_name} - #{msg}"
|
186
|
-
end
|
187
|
-
if verbosity >= MU::Logger::QUIET
|
188
|
-
if html
|
189
|
-
html_out "#{caller_name} - #{msg}"
|
190
|
-
elsif color
|
191
|
-
msgs << "#{details}".white.on_black if details
|
192
|
-
else
|
193
|
-
msgs << "#{details}" if details
|
194
|
-
end
|
195
|
-
end
|
196
|
-
Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
197
|
-
Syslog.log(Syslog::LOG_NOTICE, details.gsub(/%/, '')) if details
|
198
|
-
when WARN
|
199
|
-
if html
|
200
|
-
html_out "#{time} - #{caller_name} - #{msg}", "orange"
|
201
|
-
elsif color
|
202
|
-
msgs << "#{time} - #{caller_name} - #{msg}".light_red.on_black
|
203
|
-
else
|
204
|
-
msgs << "#{time} - #{caller_name} - #{msg}"
|
205
|
-
end
|
206
|
-
if verbosity >= MU::Logger::SILENT
|
207
|
-
if html
|
208
|
-
html_out "#{caller_name} - #{msg}"
|
209
|
-
elsif color
|
210
|
-
msgs << "#{details}".white.on_black if details
|
211
|
-
else
|
212
|
-
msgs << "#{details}" if details
|
213
|
-
end
|
214
|
-
end
|
215
|
-
Syslog.log(Syslog::LOG_WARNING, msg.gsub(/%/, ''))
|
216
|
-
Syslog.log(Syslog::LOG_WARNING, details.gsub(/%/, '')) if details
|
217
|
-
when ERR
|
218
|
-
if html
|
219
|
-
html_out "#{time} - #{caller_name} - #{msg}", "red"
|
220
|
-
html_out " #{details}" if details
|
221
|
-
elsif color
|
222
|
-
msgs << "#{time} - #{caller_name} - #{msg}".red.on_black
|
223
|
-
msgs << "#{details}".white.on_black if details
|
224
|
-
else
|
225
|
-
msgs << "#{time} - #{caller_name} - #{msg}"
|
226
|
-
msgs << "#{details}" if details
|
227
|
-
end
|
228
|
-
Syslog.log(Syslog::LOG_ERR, msg.gsub(/%/, ''))
|
229
|
-
Syslog.log(Syslog::LOG_ERR, details.gsub(/%/, '')) if details
|
136
|
+
if !PRINT_MSG_IF[level][:msg] or level >= PRINT_MSG_IF[level][:msg]
|
137
|
+
if html
|
138
|
+
html_out "#{time} - #{caller_name} - #{msg}", COLORMAP[level][:html]
|
139
|
+
else
|
140
|
+
str = "#{time} - #{caller_name} - #{msg}"
|
141
|
+
str = str.send(COLORMAP[level][:ansi]).on_black if color
|
142
|
+
msgs << str
|
143
|
+
end
|
144
|
+
Syslog.log(SYSLOG_MAP[level], msg.gsub(/%/, ''))
|
145
|
+
end
|
146
|
+
|
147
|
+
if details and (!PRINT_MSG_IF[level][:details] or level >= PRINT_MSG_IF[level][:details])
|
148
|
+
if html
|
149
|
+
html_out " #{details}"
|
230
150
|
else
|
231
|
-
if
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
msgs << "#{time} - #{caller_name} - #{msg}".white.on_black
|
236
|
-
msgs << "#{details}".white.on_black if details
|
237
|
-
else
|
238
|
-
msgs << "#{time} - #{caller_name} - #{msg}"
|
239
|
-
msgs << "#{details}" if details
|
240
|
-
end
|
241
|
-
Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
242
|
-
Syslog.log(Syslog::LOG_NOTICE, details.gsub(/%/, '')) if details
|
151
|
+
details = details.white.on_black if color
|
152
|
+
msgs << details
|
153
|
+
end
|
154
|
+
Syslog.log(SYSLOG_MAP[level], details.gsub(/%/, ''))
|
243
155
|
end
|
156
|
+
|
157
|
+
# else
|
158
|
+
# if html
|
159
|
+
# html_out "#{time} - #{caller_name} - #{msg}"
|
160
|
+
# html_out " #{details}" if details
|
161
|
+
# elsif color
|
162
|
+
# msgs << "#{time} - #{caller_name} - #{msg}".white.on_black
|
163
|
+
# msgs << "#{details}".white.on_black if details
|
164
|
+
# else
|
165
|
+
# msgs << "#{time} - #{caller_name} - #{msg}"
|
166
|
+
# msgs << "#{details}" if details
|
167
|
+
# end
|
168
|
+
# Syslog.log(Syslog::LOG_NOTICE, msg.gsub(/%/, ''))
|
169
|
+
# Syslog.log(Syslog::LOG_NOTICE, details.gsub(/%/, '')) if details
|
170
|
+
|
244
171
|
write(handles, msgs)
|
245
172
|
|
246
173
|
extra_logfile.close if extra_logfile
|
@@ -250,6 +177,43 @@ module MU
|
|
250
177
|
|
251
178
|
private
|
252
179
|
|
180
|
+
def format_details(details, html = false)
|
181
|
+
return if details.nil?
|
182
|
+
|
183
|
+
if details.is_a?(Hash) and details.has_key?(:details)
|
184
|
+
details = details[:details]
|
185
|
+
end
|
186
|
+
details = PP.pp(details, '') if !details.is_a?(String)
|
187
|
+
|
188
|
+
details = "<pre>"+details+"</pre>" if html
|
189
|
+
# We get passed literal quoted newlines sometimes, fix 'em. Get Windows'
|
190
|
+
# ugly line feeds too.
|
191
|
+
|
192
|
+
details = details.dup # in case it's frozen or something
|
193
|
+
details.gsub!(/\\n/, "\n")
|
194
|
+
details.gsub!(/(\\r|\r)/, "")
|
195
|
+
|
196
|
+
details
|
197
|
+
end
|
198
|
+
|
199
|
+
# By which we mean, "get the filename (with the .rb stripped off) which
|
200
|
+
# originated the call to this method. Which, for our purposes, is the
|
201
|
+
# MU subclass that called us. Useful information. And it looks like Perl.
|
202
|
+
def extract_caller_name(caller_name)
|
203
|
+
return nil if !caller_name or !caller_name.is_a?(String)
|
204
|
+
mod_root = Regexp.quote("#{ENV['MU_LIBDIR']}/modules/mu/")
|
205
|
+
bin_root = Regexp.quote("#{ENV['MU_INSTALLDIR']}/bin/")
|
206
|
+
|
207
|
+
caller_name.sub!(/:.*/, "")
|
208
|
+
caller_name.sub!(/^\.\//, "")
|
209
|
+
caller_name.sub!(/^#{mod_root}/, "")
|
210
|
+
caller_name.sub!(/^#{bin_root}/, "")
|
211
|
+
caller_name.sub!(/\.r[ub]$/, "")
|
212
|
+
caller_name.sub!(/#{Regexp.quote(MU.myRoot)}\//, "")
|
213
|
+
caller_name.sub!(/^modules\//, "")
|
214
|
+
caller_name
|
215
|
+
end
|
216
|
+
|
253
217
|
# Output a log message as HTML.
|
254
218
|
#
|
255
219
|
# @param msg [String]: The log message to print
|
@@ -259,5 +223,17 @@ module MU
|
|
259
223
|
@handle.puts "<span style='color:#{rgb.css_rgb};'>#{msg}</span>"
|
260
224
|
end
|
261
225
|
|
226
|
+
# wrapper for writing a log entry to multiple filehandles
|
227
|
+
# @param handles [Array<IO>]
|
228
|
+
# @param msgs [Array<String>]
|
229
|
+
def write(handles = [], msgs = [])
|
230
|
+
return if handles.nil? or msgs.nil?
|
231
|
+
handles.each { |h|
|
232
|
+
msgs.each { |m|
|
233
|
+
h.puts m
|
234
|
+
}
|
235
|
+
}
|
236
|
+
end
|
237
|
+
|
262
238
|
end #class
|
263
239
|
end #module
|
data/modules/mu/master.rb
CHANGED
@@ -602,7 +602,7 @@ module MU
|
|
602
602
|
return
|
603
603
|
end
|
604
604
|
if ssh_key_name.nil? or ssh_key_name.empty?
|
605
|
-
MU.log "Failed to extract ssh_key_name for #{
|
605
|
+
MU.log "Failed to extract ssh_key_name for #{server.mu_name} in addHostToSSHConfig", MU::ERR
|
606
606
|
return
|
607
607
|
end
|
608
608
|
|
@@ -880,5 +880,26 @@ module MU
|
|
880
880
|
end
|
881
881
|
end
|
882
882
|
|
883
|
+
# Recursively zip a directory
|
884
|
+
# @param srcdir [String]
|
885
|
+
# @param outfile [String]
|
886
|
+
def self.zipDir(srcdir, outfile)
|
887
|
+
require 'zip'
|
888
|
+
::Zip::File.open(outfile, ::Zip::File::CREATE) { |zipfile|
|
889
|
+
addpath = Proc.new { |zip_path, parent_path|
|
890
|
+
Dir.entries(parent_path).reject{ |d| [".", ".."].include?(d) }.each { |entry|
|
891
|
+
src = File.join(parent_path, entry)
|
892
|
+
dst = File.join(zip_path, entry).sub(/^\//, '')
|
893
|
+
if File.directory?(src)
|
894
|
+
addpath.call(dst, src)
|
895
|
+
else
|
896
|
+
zipfile.add(dst, src)
|
897
|
+
end
|
898
|
+
}
|
899
|
+
}
|
900
|
+
addpath.call("", srcdir)
|
901
|
+
}
|
902
|
+
end
|
903
|
+
|
883
904
|
end
|
884
905
|
end
|
data/modules/mu/mommacat.rb
CHANGED
@@ -167,6 +167,7 @@ module MU
|
|
167
167
|
@need_deploy_flush = false
|
168
168
|
@node_cert_semaphore = Mutex.new
|
169
169
|
@deployment = deployment_data
|
170
|
+
|
170
171
|
@deployment['mu_public_ip'] = MU.mu_public_ip
|
171
172
|
@private_key = nil
|
172
173
|
@public_key = nil
|
@@ -182,6 +183,7 @@ module MU
|
|
182
183
|
@appname ||= @original_config['name'] if @original_config
|
183
184
|
@timestamp = timestamp
|
184
185
|
@environment = environment
|
186
|
+
@original_config['environment'] ||= @environment if @original_config
|
185
187
|
|
186
188
|
if set_context_to_me
|
187
189
|
MU::MommaCat.setThreadContext(self)
|
@@ -253,8 +255,7 @@ module MU
|
|
253
255
|
seen << resource['credentials']
|
254
256
|
else
|
255
257
|
cloudconst = @original_config['cloud'] ? @original_config['cloud'] : MU::Config.defaultCloud
|
256
|
-
|
257
|
-
seen << cloudclass.credConfig(name_only: true)
|
258
|
+
seen << MU::Cloud.cloudClass(cloudconst).credConfig(name_only: true)
|
258
259
|
end
|
259
260
|
}
|
260
261
|
end
|
@@ -289,11 +290,10 @@ module MU
|
|
289
290
|
habitats << hab_ref.id
|
290
291
|
end
|
291
292
|
elsif resource['cloud']
|
292
|
-
cloudclass = Object.const_get("MU").const_get("Cloud").const_get(resource['cloud'])
|
293
293
|
# XXX this should be a general method implemented by each cloud
|
294
294
|
# provider
|
295
295
|
if resource['cloud'] == "Google"
|
296
|
-
habitats <<
|
296
|
+
habitats << MU::Cloud.cloudClass(resource['cloud']).defaultProject(resource['credentials'])
|
297
297
|
end
|
298
298
|
end
|
299
299
|
}
|
@@ -317,13 +317,11 @@ module MU
|
|
317
317
|
if @original_config[type]
|
318
318
|
@original_config[type].each { |resource|
|
319
319
|
if resource['cloud']
|
320
|
-
|
321
|
-
resclass = Object.const_get("MU").const_get("Cloud").const_get(resource['cloud']).const_get(res_type.to_s)
|
322
|
-
if resclass.isGlobal?
|
320
|
+
if MU::Cloud.resourceClass(resource['cloud'], res_type).isGlobal?
|
323
321
|
# XXX why was I doing this, urgh
|
324
322
|
next
|
325
323
|
elsif !resource['region']
|
326
|
-
regions <<
|
324
|
+
regions << MU::Cloud.cloudClass(resource['cloud']).myRegion(resource['credentials'])
|
327
325
|
end
|
328
326
|
end
|
329
327
|
if resource['region']
|
@@ -401,7 +399,7 @@ module MU
|
|
401
399
|
# @param type [String]:
|
402
400
|
# @param name [String]:
|
403
401
|
# @param object [MU::Cloud]:
|
404
|
-
def addKitten(type, name, object)
|
402
|
+
def addKitten(type, name, object, do_notify: false)
|
405
403
|
if !type or !name or !object or !object.mu_name
|
406
404
|
raise MuError, "Nil arguments to addKitten are not allowed (got type: #{type}, name: #{name}, and '#{object}' to add)"
|
407
405
|
end
|
@@ -409,7 +407,7 @@ module MU
|
|
409
407
|
_shortclass, _cfg_name, type, _classname, attrs = MU::Cloud.getResourceNames(type)
|
410
408
|
object.intoDeploy(self)
|
411
409
|
|
412
|
-
|
410
|
+
add_block = Proc.new {
|
413
411
|
@kittens[type] ||= {}
|
414
412
|
@kittens[type][object.habitat] ||= {}
|
415
413
|
if attrs[:has_multiples]
|
@@ -418,7 +416,20 @@ module MU
|
|
418
416
|
else
|
419
417
|
@kittens[type][object.habitat][name] = object
|
420
418
|
end
|
419
|
+
if do_notify
|
420
|
+
notify(type, name, object.notify, triggering_node: object, delayed_save: true)
|
421
|
+
end
|
421
422
|
}
|
423
|
+
|
424
|
+
begin
|
425
|
+
@kitten_semaphore.synchronize {
|
426
|
+
add_block.call()
|
427
|
+
}
|
428
|
+
rescue ThreadError => e
|
429
|
+
# already locked by a parent call to this method, so this should be safe
|
430
|
+
raise e if !e.message.match(/recursive locking/)
|
431
|
+
add_block.call()
|
432
|
+
end
|
422
433
|
end
|
423
434
|
|
424
435
|
# Encrypt a string with the deployment's public key.
|
@@ -536,16 +547,26 @@ module MU
|
|
536
547
|
# @param remove [Boolean]: Remove this resource from the deploy structure, instead of adding it.
|
537
548
|
# @return [void]
|
538
549
|
def notify(type, key, data, mu_name: nil, remove: false, triggering_node: nil, delayed_save: false)
|
539
|
-
|
550
|
+
no_write = (@no_artifacts or !caller.grep(/\/mommacat\.rb:\d+:in `notify'/).empty?)
|
540
551
|
|
541
552
|
begin
|
542
|
-
|
553
|
+
if !no_write
|
554
|
+
if !MU::MommaCat.lock("deployment-notification", deploy_id: @deploy_id, retries: 10)
|
555
|
+
raise MuError, "Failed to get deployment-notifcation lock for #{@deploy_id}"
|
556
|
+
end
|
557
|
+
end
|
543
558
|
|
544
559
|
if !@need_deploy_flush or @deployment.nil? or @deployment.empty?
|
545
560
|
loadDeploy(true) # make sure we're saving the latest and greatest
|
546
561
|
end
|
547
562
|
|
548
|
-
|
563
|
+
@timestamp ||= @deployment['timestamp']
|
564
|
+
@seed ||= @deployment['seed']
|
565
|
+
@appname ||= @deployment['appname']
|
566
|
+
@handle ||= @deployment['handle']
|
567
|
+
|
568
|
+
_shortclass, _cfg_name, mu_type, _classname, attrs = MU::Cloud.getResourceNames(type, false)
|
569
|
+
type = mu_type if mu_type
|
549
570
|
has_multiples = attrs[:has_multiples] ? true : false
|
550
571
|
|
551
572
|
mu_name ||= if !data.nil? and !data["mu_name"].nil?
|
@@ -559,6 +580,7 @@ module MU
|
|
559
580
|
end
|
560
581
|
|
561
582
|
@need_deploy_flush = true
|
583
|
+
@last_modified = Time.now
|
562
584
|
|
563
585
|
if !remove
|
564
586
|
if data.nil?
|
@@ -578,7 +600,9 @@ module MU
|
|
578
600
|
@deployment[type][key] = data
|
579
601
|
MU.log "Adding to @deployment[#{type}][#{key}]", MU::DEBUG, details: data
|
580
602
|
end
|
581
|
-
|
603
|
+
if !delayed_save and !no_write
|
604
|
+
save!(key)
|
605
|
+
end
|
582
606
|
else
|
583
607
|
have_deploy = true
|
584
608
|
if @deployment[type].nil? or @deployment[type][key].nil?
|
@@ -603,10 +627,10 @@ module MU
|
|
603
627
|
end
|
604
628
|
}
|
605
629
|
end
|
606
|
-
save! if !delayed_save
|
630
|
+
save! if !delayed_save and !no_write
|
607
631
|
end
|
608
632
|
ensure
|
609
|
-
MU::MommaCat.unlock("deployment-notification")
|
633
|
+
MU::MommaCat.unlock("deployment-notification", deploy_id: @deploy_id) if !no_write
|
610
634
|
end
|
611
635
|
end
|
612
636
|
|
@@ -614,18 +638,37 @@ module MU
|
|
614
638
|
# @param subject [String]: The subject line of the message.
|
615
639
|
# @param msg [String]: The message body.
|
616
640
|
# @return [void]
|
617
|
-
def sendAdminSlack(subject, msg: "")
|
618
|
-
if
|
619
|
-
(
|
641
|
+
def sendAdminSlack(subject, msg: "", scrub_mu_isms: true, snippets: [], noop: false)
|
642
|
+
if MU.muCfg['slack'] and MU.muCfg['slack']['webhook'] and
|
643
|
+
(!MU.muCfg['slack']['skip_environments'] or !MU.muCfg['slack']['skip_environments'].any?{ |s| s.casecmp(MU.environment)==0 })
|
620
644
|
require 'slack-notifier'
|
621
|
-
|
645
|
+
slackargs = nil
|
646
|
+
keyword_args = { channel: MU.muCfg['slack']['channel'] }
|
647
|
+
begin
|
648
|
+
slack = Slack::Notifier.new MU.muCfg['slack']['webhook']
|
649
|
+
prefix = scrub_mu_isms ? subject : "#{MU.appname} \*\"#{MU.handle}\"\* (`#{MU.deploy_id}`) - #{subject}"
|
650
|
+
|
651
|
+
text = if msg and !msg.empty?
|
652
|
+
"#{prefix}:\n\n```#{msg}```"
|
653
|
+
else
|
654
|
+
prefix
|
655
|
+
end
|
622
656
|
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
657
|
+
if snippets and snippets.size > 0
|
658
|
+
keyword_args[:attachments] = snippets
|
659
|
+
end
|
660
|
+
|
661
|
+
if !noop
|
662
|
+
slack.ping(text, **keyword_args)
|
663
|
+
else
|
664
|
+
MU.log "Would send to #{MU.muCfg['slack']['channel']}", MU::NOTICE, details: [ text, keyword_args ]
|
665
|
+
end
|
666
|
+
rescue Slack::Notifier::APIError => e
|
667
|
+
MU.log "Failed to send message to slack: #{e.message}", MU::ERR, details: keyword_args
|
668
|
+
return false
|
627
669
|
end
|
628
670
|
end
|
671
|
+
true
|
629
672
|
end
|
630
673
|
|
631
674
|
# Send an email notification to a deployment's administrators.
|
@@ -754,7 +797,7 @@ MAIL_HEAD_END
|
|
754
797
|
end
|
755
798
|
|
756
799
|
siblings = findLitterMate(type: "server", return_all: true)
|
757
|
-
return if siblings.nil? or siblings.empty?
|
800
|
+
return if siblings.nil? or (siblings.respond_to?(:empty?) and siblings.empty?)
|
758
801
|
|
759
802
|
update_servers = []
|
760
803
|
siblings.each_pair { |mu_name, node|
|
@@ -782,6 +825,7 @@ MAIL_HEAD_END
|
|
782
825
|
|
783
826
|
threads = []
|
784
827
|
update_servers.each { |sibling|
|
828
|
+
next if sibling.config.has_key?("groom") and !sibling.config["groom"]
|
785
829
|
threads << Thread.new {
|
786
830
|
Thread.abort_on_exception = true
|
787
831
|
Thread.current.thread_variable_set("name", "sync-"+sibling.mu_name.downcase)
|
@@ -838,7 +882,7 @@ MAIL_HEAD_END
|
|
838
882
|
end
|
839
883
|
|
840
884
|
if resource and resource.config and resource.config['cloud']
|
841
|
-
cloudclass =
|
885
|
+
cloudclass = MU::Cloud.cloudClass(resource.config['cloud'])
|
842
886
|
|
843
887
|
cloudclass.writeDeploySecret(@deploy_id, cert.to_pem, cert_cn+".crt", credentials: resource.config['credentials'])
|
844
888
|
cloudclass.writeDeploySecret(@deploy_id, key.to_pem, cert_cn+".key", credentials: resource.config['credentials'])
|
@@ -866,6 +910,7 @@ MAIL_HEAD_END
|
|
866
910
|
###########################################################################
|
867
911
|
###########################################################################
|
868
912
|
def setThreadContextToMe
|
913
|
+
|
869
914
|
["appname", "environment", "timestamp", "seed", "handle"].each { |var|
|
870
915
|
@deployment[var] ||= instance_variable_get("@#{var}".to_sym)
|
871
916
|
if @deployment[var]
|