cloud-mu 3.1.3 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +15 -3
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
- data/ansible/roles/mu-windows/files/config.xml +76 -0
- data/ansible/roles/mu-windows/handlers/main.yml +2 -0
- data/ansible/roles/mu-windows/meta/main.yml +53 -0
- data/ansible/roles/mu-windows/tasks/main.yml +36 -0
- data/ansible/roles/mu-windows/tests/inventory +2 -0
- data/ansible/roles/mu-windows/tests/test.yml +5 -0
- data/ansible/roles/mu-windows/vars/main.yml +2 -0
- data/bin/mu-adopt +21 -13
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +52 -0
- 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 +4 -4
- data/bin/mu-node-manage +15 -16
- data/bin/mu-run-tests +147 -37
- data/cloud-mu.gemspec +22 -20
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/libraries/helper.rb +3 -2
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/clean-stock-amis +25 -19
- data/extras/generate-stock-images +1 -0
- data/extras/image-generators/AWS/win2k12.yaml +18 -13
- data/extras/image-generators/AWS/win2k16.yaml +18 -13
- data/extras/image-generators/AWS/win2k19.yaml +21 -0
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +6 -16
- data/modules/mu.rb +158 -111
- data/modules/mu/adoption.rb +404 -71
- data/modules/mu/cleanup.rb +221 -306
- data/modules/mu/cloud.rb +129 -1633
- 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 +926 -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 +169 -0
- data/modules/mu/config.rb +171 -1767
- 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 +4 -4
- data/modules/mu/config/container_cluster.rb +9 -4
- data/modules/mu/config/database.rb +84 -105
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +10 -9
- data/modules/mu/config/doc_helpers.rb +516 -0
- data/modules/mu/config/endpoint.rb +5 -4
- data/modules/mu/config/firewall_rule.rb +103 -4
- data/modules/mu/config/folder.rb +4 -4
- data/modules/mu/config/function.rb +19 -10
- data/modules/mu/config/group.rb +4 -4
- data/modules/mu/config/habitat.rb +4 -4
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/loadbalancer.rb +60 -14
- data/modules/mu/config/log.rb +4 -4
- data/modules/mu/config/msg_queue.rb +4 -4
- data/modules/mu/config/nosqldb.rb +4 -4
- data/modules/mu/config/notifier.rb +10 -21
- data/modules/mu/config/ref.rb +411 -0
- data/modules/mu/config/role.rb +4 -4
- data/modules/mu/config/schema_helpers.rb +509 -0
- data/modules/mu/config/search_domain.rb +4 -4
- data/modules/mu/config/server.rb +98 -71
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/config/server_pool.rb +5 -9
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +200 -0
- data/modules/mu/config/user.rb +4 -4
- data/modules/mu/config/vpc.rb +71 -27
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +91 -68
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +3 -2
- data/modules/mu/deploy.rb +43 -26
- data/modules/mu/groomer.rb +17 -2
- data/modules/mu/groomers/ansible.rb +188 -41
- data/modules/mu/groomers/chef.rb +116 -55
- data/modules/mu/logger.rb +127 -148
- data/modules/mu/master.rb +410 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -3
- data/modules/mu/mommacat.rb +218 -2612
- data/modules/mu/mommacat/daemon.rb +403 -0
- data/modules/mu/mommacat/naming.rb +473 -0
- data/modules/mu/mommacat/search.rb +495 -0
- data/modules/mu/mommacat/storage.rb +722 -0
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +380 -122
- data/modules/mu/{clouds → providers}/aws/alarm.rb +7 -5
- data/modules/mu/{clouds → providers}/aws/bucket.rb +297 -59
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +37 -71
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/{clouds → providers}/aws/collection.rb +26 -25
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +724 -744
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +88 -70
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +220 -247
- data/modules/mu/{clouds → providers}/aws/folder.rb +8 -8
- data/modules/mu/{clouds → providers}/aws/function.rb +300 -142
- data/modules/mu/{clouds → providers}/aws/group.rb +31 -29
- data/modules/mu/{clouds → providers}/aws/habitat.rb +18 -15
- data/modules/mu/providers/aws/job.rb +466 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +66 -56
- data/modules/mu/{clouds → providers}/aws/log.rb +17 -14
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +29 -19
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +114 -16
- data/modules/mu/{clouds → providers}/aws/notifier.rb +142 -65
- data/modules/mu/{clouds → providers}/aws/role.rb +158 -118
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +201 -59
- data/modules/mu/{clouds → providers}/aws/server.rb +844 -1139
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +74 -65
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +26 -44
- data/modules/mu/{clouds → providers}/aws/user.rb +24 -25
- 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 +2 -1
- data/modules/mu/{clouds → providers}/aws/vpc.rb +525 -931
- data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
- data/modules/mu/{clouds → providers}/azure.rb +29 -9
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
- data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
- data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
- data/modules/mu/{clouds → providers}/azure/server.rb +97 -49
- data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
- 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 +16 -21
- data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
- 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 +5 -7
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +68 -30
- data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +85 -78
- data/modules/mu/{clouds → providers}/google/database.rb +11 -21
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
- data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
- data/modules/mu/{clouds → providers}/google/function.rb +140 -168
- data/modules/mu/{clouds → providers}/google/group.rb +29 -34
- data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +19 -21
- data/modules/mu/{clouds → providers}/google/role.rb +94 -58
- data/modules/mu/{clouds → providers}/google/server.rb +243 -156
- data/modules/mu/{clouds → providers}/google/server_pool.rb +26 -45
- data/modules/mu/{clouds → providers}/google/user.rb +95 -31
- 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 +103 -79
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/bucket.yml +4 -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 +23 -0
- 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/includes-and-params.yaml +2 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +2 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +3 -5
- data/modules/tests/win2k12.yaml +17 -5
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +240 -154
- data/extras/image-generators/AWS/windows.yaml +0 -18
- data/modules/mu/clouds/aws/database.rb +0 -1985
- data/modules/mu/clouds/aws/endpoint.rb +0 -592
@@ -0,0 +1,722 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2020 eGlobalTech, Inc., all rights reserved
|
2
|
+
#
|
3
|
+
# Licensed under the BSD-3 license (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License in the root of the project or at
|
6
|
+
#
|
7
|
+
# http://egt-labs.com/mu/LICENSE.html
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module MU
|
16
|
+
|
17
|
+
# MommaCat is in charge of managing metadata about resources we've created,
|
18
|
+
# as well as orchestrating amongst them and bootstrapping nodes outside of
|
19
|
+
# the normal synchronous deploy sequence invoked by *mu-deploy*.
|
20
|
+
class MommaCat
|
21
|
+
@myhome = Etc.getpwuid(Process.uid).dir
|
22
|
+
@nagios_home = "/opt/mu/var/nagios_user_home"
|
23
|
+
@locks = Hash.new
|
24
|
+
@deploy_cache = Hash.new
|
25
|
+
|
26
|
+
# Return a {MU::MommaCat} instance for an existing deploy. Use this instead
|
27
|
+
# of using #initialize directly to avoid loading deploys multiple times or
|
28
|
+
# stepping on the global context for the deployment you're really working
|
29
|
+
# on..
|
30
|
+
# @param deploy_id [String]: The deploy ID of the deploy to load.
|
31
|
+
# @param set_context_to_me [Boolean]: Whether new MommaCat objects should overwrite any existing per-thread global deploy variables.
|
32
|
+
# @param use_cache [Boolean]: If we have an existing object for this deploy, use that
|
33
|
+
# @return [MU::MommaCat]
|
34
|
+
def self.getLitter(deploy_id, set_context_to_me: false, use_cache: true)
|
35
|
+
if deploy_id.nil? or deploy_id.empty?
|
36
|
+
raise MuError, "Cannot fetch a deployment without a deploy_id"
|
37
|
+
end
|
38
|
+
|
39
|
+
# XXX this caching may be harmful, causing stale resource objects to stick
|
40
|
+
# around. Have we fixed this? Sort of. Bad entries seem to have no kittens,
|
41
|
+
# so force a reload if we see that. That's probably not the root problem.
|
42
|
+
littercache = nil
|
43
|
+
begin
|
44
|
+
@@litter_semaphore.synchronize {
|
45
|
+
littercache = @@litters.dup
|
46
|
+
}
|
47
|
+
if littercache[deploy_id] and @@litters_loadtime[deploy_id]
|
48
|
+
deploy_root = File.expand_path(MU.dataDir+"/deployments")
|
49
|
+
this_deploy_dir = deploy_root+"/"+deploy_id
|
50
|
+
if File.exist?("#{this_deploy_dir}/deployment.json")
|
51
|
+
lastmod = File.mtime("#{this_deploy_dir}/deployment.json")
|
52
|
+
if lastmod > @@litters_loadtime[deploy_id]
|
53
|
+
MU.log "Deployment metadata for #{deploy_id} was modified on disk, reload", MU::NOTICE
|
54
|
+
use_cache = false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
rescue ThreadError => e
|
59
|
+
# already locked by a parent caller and this is a read op, so this is ok
|
60
|
+
raise e if !e.message.match(/recursive locking/)
|
61
|
+
littercache = @@litters.dup
|
62
|
+
end
|
63
|
+
|
64
|
+
if !use_cache or littercache[deploy_id].nil?
|
65
|
+
need_gc = !littercache[deploy_id].nil?
|
66
|
+
newlitter = MU::MommaCat.new(deploy_id, set_context_to_me: set_context_to_me)
|
67
|
+
# This, we have to synchronize, as it's a write
|
68
|
+
@@litter_semaphore.synchronize {
|
69
|
+
@@litters[deploy_id] = newlitter
|
70
|
+
@@litters_loadtime[deploy_id] = Time.now
|
71
|
+
}
|
72
|
+
GC.start if need_gc
|
73
|
+
elsif set_context_to_me
|
74
|
+
MU::MommaCat.setThreadContext(@@litters[deploy_id])
|
75
|
+
end
|
76
|
+
return @@litters[deploy_id]
|
77
|
+
# MU::MommaCat.new(deploy_id, set_context_to_me: set_context_to_me)
|
78
|
+
end
|
79
|
+
|
80
|
+
# List the currently held flock() locks.
|
81
|
+
def self.trapSafeLocks;
|
82
|
+
@locks
|
83
|
+
end
|
84
|
+
# List the currently held flock() locks.
|
85
|
+
def self.locks;
|
86
|
+
@lock_semaphore.synchronize {
|
87
|
+
@locks
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Overwrite this deployment's configuration with a new version. Save the
|
93
|
+
# previous version as well.
|
94
|
+
# @param new_conf [Hash]: A new configuration, fully resolved by {MU::Config}
|
95
|
+
def updateBasketofKittens(new_conf, skip_validation: false, new_metadata: nil, save_now: false)
|
96
|
+
loadDeploy
|
97
|
+
if new_conf == @original_config
|
98
|
+
return
|
99
|
+
end
|
100
|
+
|
101
|
+
scrub_with = nil
|
102
|
+
|
103
|
+
# Make sure the new config that we were just handed resolves and makes
|
104
|
+
# sense
|
105
|
+
if !skip_validation
|
106
|
+
f = Tempfile.new(@deploy_id)
|
107
|
+
f.write JSON.parse(JSON.generate(new_conf)).to_yaml
|
108
|
+
conf_engine = MU::Config.new(f.path) # will throw an exception if it's bad, adoption should catch this and cope reasonably
|
109
|
+
scrub_with = conf_engine.config
|
110
|
+
f.close
|
111
|
+
end
|
112
|
+
|
113
|
+
backup = "#{deploy_dir}/basket_of_kittens.json.#{Time.now.to_i.to_s}"
|
114
|
+
MU.log "Saving previous config of #{@deploy_id} to #{backup}"
|
115
|
+
config = File.new(backup, File::CREAT|File::TRUNC|File::RDWR, 0600)
|
116
|
+
config.flock(File::LOCK_EX)
|
117
|
+
config.puts JSON.pretty_generate(@original_config)
|
118
|
+
config.flock(File::LOCK_UN)
|
119
|
+
config.close
|
120
|
+
|
121
|
+
@original_config = new_conf.clone
|
122
|
+
|
123
|
+
MU::Cloud.resource_types.each_pair { |res_type, attrs|
|
124
|
+
next if !@deployment.has_key?(attrs[:cfg_plural])
|
125
|
+
deletia = []
|
126
|
+
@deployment[attrs[:cfg_plural]].each_pair { |res_name, data|
|
127
|
+
orig_cfg = findResourceConfig(attrs[:cfg_plural], res_name, (scrub_with || @original_config))
|
128
|
+
|
129
|
+
if orig_cfg.nil?
|
130
|
+
MU.log "#{res_type} #{res_name} no longer configured, will remove deployment metadata", MU::NOTICE
|
131
|
+
deletia << res_name
|
132
|
+
end
|
133
|
+
}
|
134
|
+
@deployment[attrs[:cfg_plural]].reject! { |k, v| deletia.include?(k) }
|
135
|
+
}
|
136
|
+
|
137
|
+
if save_now
|
138
|
+
save!
|
139
|
+
MU.log "New config saved to #{deploy_dir}/basket_of_kittens.json"
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
@lock_semaphore = Mutex.new
|
144
|
+
# Release all flock() locks held by the current thread.
|
145
|
+
def self.unlockAll
|
146
|
+
if !@locks.nil? and !@locks[Thread.current.object_id].nil?
|
147
|
+
# Work from a copy so we can iterate without worrying about contention
|
148
|
+
# in lock() or unlock(). We can't just wrap our iterator block in a
|
149
|
+
# semaphore here, because we're calling another method that uses the
|
150
|
+
# same semaphore.
|
151
|
+
@lock_semaphore.synchronize {
|
152
|
+
delete_list = []
|
153
|
+
@locks[Thread.current.object_id].keys.each { |id|
|
154
|
+
MU.log "Releasing lock on #{deploy_dir(MU.deploy_id)}/locks/#{id}.lock (thread #{Thread.current.object_id})", MU::DEBUG
|
155
|
+
begin
|
156
|
+
@locks[Thread.current.object_id][id].flock(File::LOCK_UN)
|
157
|
+
@locks[Thread.current.object_id][id].close
|
158
|
+
rescue IOError => e
|
159
|
+
MU.log "Got #{e.inspect} unlocking #{id} on #{Thread.current.object_id}", MU::WARN
|
160
|
+
end
|
161
|
+
delete_list << id
|
162
|
+
}
|
163
|
+
# We do this here because we can't mangle a Hash while we're iterating
|
164
|
+
# over it.
|
165
|
+
delete_list.each { |id|
|
166
|
+
@locks[Thread.current.object_id].delete(id)
|
167
|
+
}
|
168
|
+
if @locks[Thread.current.object_id].size == 0
|
169
|
+
@locks.delete(Thread.current.object_id)
|
170
|
+
end
|
171
|
+
}
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Create/hold a flock() lock.
|
176
|
+
# @param id [String]: The lock identifier to release.
|
177
|
+
# @param nonblock [Boolean]: Whether to block while waiting for the lock. In non-blocking mode, we simply return false if the lock is not available.
|
178
|
+
# return [false, nil]
|
179
|
+
def self.lock(id, nonblock = false, global = false, deploy_id: MU.deploy_id)
|
180
|
+
raise MuError, "Can't pass a nil id to MU::MommaCat.lock" if id.nil?
|
181
|
+
|
182
|
+
if !global
|
183
|
+
lockdir = "#{deploy_dir(deploy_id)}/locks"
|
184
|
+
else
|
185
|
+
lockdir = File.expand_path(MU.dataDir+"/locks")
|
186
|
+
end
|
187
|
+
|
188
|
+
if !Dir.exist?(lockdir)
|
189
|
+
MU.log "Creating #{lockdir}", MU::DEBUG
|
190
|
+
Dir.mkdir(lockdir, 0700)
|
191
|
+
end
|
192
|
+
|
193
|
+
@lock_semaphore.synchronize {
|
194
|
+
if @locks[Thread.current.object_id].nil?
|
195
|
+
@locks[Thread.current.object_id] = Hash.new
|
196
|
+
end
|
197
|
+
|
198
|
+
@locks[Thread.current.object_id][id] = File.open("#{lockdir}/#{id}.lock", File::CREAT|File::RDWR, 0600)
|
199
|
+
}
|
200
|
+
MU.log "Getting a lock on #{lockdir}/#{id}.lock (thread #{Thread.current.object_id})...", MU::DEBUG
|
201
|
+
begin
|
202
|
+
if nonblock
|
203
|
+
if !@locks[Thread.current.object_id][id].flock(File::LOCK_EX|File::LOCK_NB)
|
204
|
+
return false
|
205
|
+
end
|
206
|
+
else
|
207
|
+
@locks[Thread.current.object_id][id].flock(File::LOCK_EX)
|
208
|
+
end
|
209
|
+
rescue IOError
|
210
|
+
raise MU::BootstrapTempFail, "Interrupted waiting for lock on thread #{Thread.current.object_id}, probably just a node rebooting as part of a synchronous install"
|
211
|
+
end
|
212
|
+
MU.log "Lock on #{lockdir}/#{id}.lock on thread #{Thread.current.object_id} acquired", MU::DEBUG
|
213
|
+
return true
|
214
|
+
end
|
215
|
+
|
216
|
+
# Release a flock() lock.
|
217
|
+
# @param id [String]: The lock identifier to release.
|
218
|
+
def self.unlock(id, global = false, deploy_id: MU.deploy_id)
|
219
|
+
raise MuError, "Can't pass a nil id to MU::MommaCat.unlock" if id.nil?
|
220
|
+
lockdir = nil
|
221
|
+
if !global
|
222
|
+
lockdir = "#{deploy_dir(deploy_id)}/locks"
|
223
|
+
else
|
224
|
+
lockdir = File.expand_path(MU.dataDir+"/locks")
|
225
|
+
end
|
226
|
+
@lock_semaphore.synchronize {
|
227
|
+
return if @locks.nil? or @locks[Thread.current.object_id].nil? or @locks[Thread.current.object_id][id].nil?
|
228
|
+
}
|
229
|
+
MU.log "Releasing lock on #{lockdir}/#{id}.lock (thread #{Thread.current.object_id})", MU::DEBUG
|
230
|
+
begin
|
231
|
+
@locks[Thread.current.object_id][id].flock(File::LOCK_UN)
|
232
|
+
@locks[Thread.current.object_id][id].close
|
233
|
+
if !@locks[Thread.current.object_id].nil?
|
234
|
+
@locks[Thread.current.object_id].delete(id)
|
235
|
+
end
|
236
|
+
if @locks[Thread.current.object_id].size == 0
|
237
|
+
@locks.delete(Thread.current.object_id)
|
238
|
+
end
|
239
|
+
rescue IOError => e
|
240
|
+
MU.log "Got #{e.inspect} unlocking #{id} on #{Thread.current.object_id}", MU::WARN
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# Remove a deployment's metadata.
|
245
|
+
# @param deploy_id [String]: The deployment identifier to remove.
|
246
|
+
def self.purge(deploy_id)
|
247
|
+
if deploy_id.nil? or deploy_id.empty?
|
248
|
+
raise MuError, "Got nil deploy_id in MU::MommaCat.purge"
|
249
|
+
end
|
250
|
+
# XXX archiving is better than annihilating
|
251
|
+
path = File.expand_path(MU.dataDir+"/deployments")
|
252
|
+
if Dir.exist?(path+"/"+deploy_id)
|
253
|
+
unlockAll
|
254
|
+
MU.log "Purging #{path}/#{deploy_id}" if File.exist?(path+"/"+deploy_id+"/deployment.json")
|
255
|
+
|
256
|
+
FileUtils.rm_rf(path+"/"+deploy_id, :secure => true)
|
257
|
+
end
|
258
|
+
if File.exist?(path+"/unique_ids")
|
259
|
+
File.open(path+"/unique_ids", File::CREAT|File::RDWR, 0600) { |f|
|
260
|
+
newlines = []
|
261
|
+
f.flock(File::LOCK_EX)
|
262
|
+
f.readlines.each { |line|
|
263
|
+
newlines << line if !line.match(/:#{deploy_id}$/)
|
264
|
+
}
|
265
|
+
f.rewind
|
266
|
+
f.truncate(0)
|
267
|
+
f.puts(newlines)
|
268
|
+
f.flush
|
269
|
+
f.flock(File::LOCK_UN)
|
270
|
+
}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Remove the metadata of the currently loaded deployment.
|
275
|
+
def purge!
|
276
|
+
MU::MommaCat.purge(MU.deploy_id)
|
277
|
+
end
|
278
|
+
|
279
|
+
# Return a list of all currently active deploy identifiers.
|
280
|
+
# @return [Array<String>]
|
281
|
+
def self.listDeploys
|
282
|
+
return [] if !Dir.exist?("#{MU.dataDir}/deployments")
|
283
|
+
deploys = []
|
284
|
+
Dir.entries("#{MU.dataDir}/deployments").reverse_each { |muid|
|
285
|
+
next if !Dir.exist?("#{MU.dataDir}/deployments/#{muid}") or muid == "." or muid == ".."
|
286
|
+
deploys << muid
|
287
|
+
}
|
288
|
+
return deploys
|
289
|
+
end
|
290
|
+
|
291
|
+
# Return a list of all nodes in all deployments. Does so without loading
|
292
|
+
# deployments fully.
|
293
|
+
# @return [Hash]
|
294
|
+
def self.listAllNodes
|
295
|
+
nodes = Hash.new
|
296
|
+
MU::MommaCat.deploy_struct_semaphore.synchronize {
|
297
|
+
MU::MommaCat.listDeploys.each { |deploy|
|
298
|
+
if !Dir.exist?(MU::MommaCat.deploy_dir(deploy)) or
|
299
|
+
!File.size?("#{MU::MommaCat.deploy_dir(deploy)}/deployment.json")
|
300
|
+
MU.log "Didn't see deployment metadata for '#{deploy}'", MU::WARN
|
301
|
+
next
|
302
|
+
end
|
303
|
+
data = File.open("#{MU::MommaCat.deploy_dir(deploy)}/deployment.json", File::RDONLY)
|
304
|
+
MU.log "Getting lock to read #{MU::MommaCat.deploy_dir(deploy)}/deployment.json", MU::DEBUG
|
305
|
+
data.flock(File::LOCK_EX)
|
306
|
+
begin
|
307
|
+
deployment = JSON.parse(File.read("#{MU::MommaCat.deploy_dir(deploy)}/deployment.json"))
|
308
|
+
deployment["deploy_id"] = deploy
|
309
|
+
if deployment.has_key?("servers")
|
310
|
+
deployment["servers"].each_key { |nodeclass|
|
311
|
+
deployment["servers"][nodeclass].each_pair { |mu_name, metadata|
|
312
|
+
nodes[mu_name] = metadata
|
313
|
+
}
|
314
|
+
}
|
315
|
+
end
|
316
|
+
rescue JSON::ParserError => e
|
317
|
+
MU.log "JSON parse failed on #{MU::MommaCat.deploy_dir(deploy)}/deployment.json", MU::ERR, details: e.message
|
318
|
+
end
|
319
|
+
data.flock(File::LOCK_UN)
|
320
|
+
data.close
|
321
|
+
}
|
322
|
+
}
|
323
|
+
return nodes
|
324
|
+
end
|
325
|
+
|
326
|
+
# @return [String]: The Mu Master filesystem directory holding metadata for the current deployment
|
327
|
+
def deploy_dir
|
328
|
+
MU::MommaCat.deploy_dir(@deploy_id)
|
329
|
+
end
|
330
|
+
|
331
|
+
# Locate and return the deploy, if any, which matches the provided origin
|
332
|
+
# description
|
333
|
+
# @param origin [Hash]
|
334
|
+
def self.findMatchingDeploy(origin)
|
335
|
+
MU::MommaCat.listDeploys.each { |deploy_id|
|
336
|
+
o_path = deploy_dir(deploy_id)+"/origin.json"
|
337
|
+
next if !File.exist?(o_path)
|
338
|
+
this_origin = JSON.parse(File.read(o_path))
|
339
|
+
if origin == this_origin
|
340
|
+
MU.log "Deploy #{deploy_id} matches origin hash, loading", details: origin
|
341
|
+
return MU::MommaCat.new(deploy_id)
|
342
|
+
end
|
343
|
+
}
|
344
|
+
nil
|
345
|
+
end
|
346
|
+
|
347
|
+
# Synchronize all in-memory information related to this to deployment to
|
348
|
+
# disk.
|
349
|
+
# @param triggering_node [MU::Cloud::Server]: If we're being triggered by the addition/removal/update of a node, this allows us to notify any sibling or dependent nodes of changes
|
350
|
+
# @param force [Boolean]: Save even if +no_artifacts+ is set
|
351
|
+
# @param origin [Hash]: Optional blob of data indicating how this deploy was created
|
352
|
+
def save!(triggering_node = nil, force: false, origin: nil)
|
353
|
+
|
354
|
+
return if @no_artifacts and !force
|
355
|
+
|
356
|
+
MU::MommaCat.deploy_struct_semaphore.synchronize {
|
357
|
+
MU.log "Saving deployment #{MU.deploy_id}", MU::DEBUG
|
358
|
+
|
359
|
+
if !Dir.exist?(deploy_dir)
|
360
|
+
MU.log "Creating #{deploy_dir}", MU::DEBUG
|
361
|
+
Dir.mkdir(deploy_dir, 0700)
|
362
|
+
end
|
363
|
+
|
364
|
+
writeFile("origin.json", JSON.pretty_generate(origin)) if !origin.nil?
|
365
|
+
writeFile("private_key", @private_key) if !@private_key.nil?
|
366
|
+
writeFile("public_key", @public_key) if !@public_key.nil?
|
367
|
+
|
368
|
+
if !@deployment.nil? and @deployment.size > 0
|
369
|
+
@deployment['handle'] = MU.handle if @deployment['handle'].nil? and !MU.handle.nil?
|
370
|
+
[:public_key, :timestamp, :seed, :appname, :handle, :ssh_public_key].each { |var|
|
371
|
+
value = instance_variable_get(("@"+var.to_s).to_sym)
|
372
|
+
@deployment[var.to_s] = value if value
|
373
|
+
}
|
374
|
+
|
375
|
+
begin
|
376
|
+
# XXX doing this to trigger JSON errors before stomping the stored
|
377
|
+
# file...
|
378
|
+
JSON.pretty_generate(@deployment, max_nesting: false)
|
379
|
+
deploy = File.new("#{deploy_dir}/deployment.json", File::CREAT|File::TRUNC|File::RDWR, 0600)
|
380
|
+
MU.log "Getting lock to write #{deploy_dir}/deployment.json", MU::DEBUG
|
381
|
+
deploy.flock(File::LOCK_EX)
|
382
|
+
deploy.puts JSON.pretty_generate(@deployment, max_nesting: false)
|
383
|
+
rescue JSON::NestingError => e
|
384
|
+
MU.log e.inspect, MU::ERR, details: @deployment
|
385
|
+
raise MuError, "Got #{e.message} trying to save deployment"
|
386
|
+
rescue Encoding::UndefinedConversionError => e
|
387
|
+
MU.log e.inspect, MU::ERR, details: @deployment
|
388
|
+
raise MuError, "Got #{e.message} at #{e.error_char.dump} (#{e.source_encoding_name} => #{e.destination_encoding_name}) trying to save deployment"
|
389
|
+
end
|
390
|
+
deploy.flock(File::LOCK_UN)
|
391
|
+
deploy.close
|
392
|
+
@need_deploy_flush = false
|
393
|
+
MU::MommaCat.updateLitter(@deploy_id, self)
|
394
|
+
end
|
395
|
+
|
396
|
+
if !@original_config.nil? and @original_config.is_a?(Hash)
|
397
|
+
writeFile("basket_of_kittens.json", JSON.pretty_generate(MU::Config.manxify(@original_config)))
|
398
|
+
end
|
399
|
+
|
400
|
+
writeFile("node_ssh.key", @ssh_private_key) if !@ssh_private_key.nil?
|
401
|
+
writeFile("node_ssh.pub", @ssh_public_key) if !@ssh_public_key.nil?
|
402
|
+
writeFile("ssh_key_name", @ssh_key_name) if !@ssh_key_name.nil?
|
403
|
+
writeFile("environment_name", @environment) if !@environment.nil?
|
404
|
+
writeFile("deploy_secret", @deploy_secret) if !@deploy_secret.nil?
|
405
|
+
|
406
|
+
if !@secrets.nil?
|
407
|
+
secretdir = "#{deploy_dir}/secrets"
|
408
|
+
if !Dir.exist?(secretdir)
|
409
|
+
MU.log "Creating #{secretdir}", MU::DEBUG
|
410
|
+
Dir.mkdir(secretdir, 0700)
|
411
|
+
end
|
412
|
+
@secrets.each_pair { |type, servers|
|
413
|
+
servers.each_pair { |server, svr_secret|
|
414
|
+
writeFile("secrets/#{type}.#{server}", svr_secret)
|
415
|
+
}
|
416
|
+
}
|
417
|
+
end
|
418
|
+
}
|
419
|
+
|
420
|
+
# Update groomer copies of this metadata
|
421
|
+
syncLitter(@deployment['servers'].keys, triggering_node: triggering_node, save_only: true) if @deployment.has_key?("servers")
|
422
|
+
end
|
423
|
+
|
424
|
+
# Read all of our +deployment.json+ files in and stick them in a hash. Used
|
425
|
+
# by search routines that just need to skim this data without loading
|
426
|
+
# entire {MU::MommaCat} objects.
|
427
|
+
def self.cacheDeployMetadata(deploy_id = nil, use_cache: false)
|
428
|
+
deploy_root = File.expand_path(MU.dataDir+"/deployments")
|
429
|
+
MU::MommaCat.deploy_struct_semaphore.synchronize {
|
430
|
+
@@deploy_cache ||= {}
|
431
|
+
return if !Dir.exist?(deploy_root)
|
432
|
+
|
433
|
+
Dir.entries(deploy_root).each { |deploy|
|
434
|
+
this_deploy_dir = deploy_root+"/"+deploy
|
435
|
+
this_deploy_file = this_deploy_dir+"/deployment.json"
|
436
|
+
|
437
|
+
if deploy == "." or deploy == ".." or !Dir.exist?(this_deploy_dir) or
|
438
|
+
(deploy_id and deploy_id != deploy) or
|
439
|
+
!File.size?(this_deploy_file) or
|
440
|
+
(use_cache and @@deploy_cache[deploy] and @@deploy_cache[deploy]['mtime'] == File.mtime(this_deploy_file))
|
441
|
+
next
|
442
|
+
end
|
443
|
+
|
444
|
+
@@deploy_cache[deploy] ||= {}
|
445
|
+
|
446
|
+
MU.log "Caching deploy #{deploy}", MU::DEBUG
|
447
|
+
lock = File.open(this_deploy_file, File::RDONLY)
|
448
|
+
lock.flock(File::LOCK_EX)
|
449
|
+
@@deploy_cache[deploy]['mtime'] = File.mtime(this_deploy_file)
|
450
|
+
|
451
|
+
begin
|
452
|
+
@@deploy_cache[deploy]['data'] = JSON.parse(File.read(this_deploy_file))
|
453
|
+
next if @@deploy_cache[deploy]['data'].nil?
|
454
|
+
# Populate some generable entries that should be in the deploy
|
455
|
+
# data. Also, bounce out if we realize we've found exactly what
|
456
|
+
# we needed already.
|
457
|
+
MU::Cloud.resource_types.values.each { |attrs|
|
458
|
+
|
459
|
+
next if @@deploy_cache[deploy]['data'][attrs[:cfg_plural]].nil?
|
460
|
+
if attrs[:has_multiples]
|
461
|
+
@@deploy_cache[deploy]['data'][attrs[:cfg_plural]].each_pair { |node_class, nodes|
|
462
|
+
next if nodes.nil? or !nodes.is_a?(Hash)
|
463
|
+
nodes.each_pair { |nodename, data|
|
464
|
+
next if !data.is_a?(Hash)
|
465
|
+
data['#MU_NODE_CLASS'] ||= node_class
|
466
|
+
data['#MU_NAME'] ||= nodename
|
467
|
+
data["cloud"] ||= MU::Config.defaultCloud
|
468
|
+
}
|
469
|
+
}
|
470
|
+
end
|
471
|
+
}
|
472
|
+
rescue JSON::ParserError
|
473
|
+
raise MuError, "JSON parse failed on #{this_deploy_file}\n\n"+File.read(this_deploy_file)
|
474
|
+
ensure
|
475
|
+
lock.flock(File::LOCK_UN)
|
476
|
+
lock.close
|
477
|
+
end
|
478
|
+
}
|
479
|
+
}
|
480
|
+
|
481
|
+
@@deploy_cache
|
482
|
+
end
|
483
|
+
|
484
|
+
# Get the deploy directory
|
485
|
+
# @param deploy_id [String]
|
486
|
+
# @return [String]
|
487
|
+
def self.deploy_dir(deploy_id)
|
488
|
+
raise MuError, "deploy_dir must get a deploy_id if called as class method (from #{caller[0]}; #{caller[1]})" if deploy_id.nil?
|
489
|
+
# XXX this will blow up if someone sticks MU in /
|
490
|
+
path = File.expand_path(MU.dataDir+"/deployments")
|
491
|
+
if !Dir.exist?(path)
|
492
|
+
MU.log "Creating #{path}", MU::DEBUG
|
493
|
+
Dir.mkdir(path, 0700)
|
494
|
+
end
|
495
|
+
path = path+"/"+deploy_id
|
496
|
+
return path
|
497
|
+
end
|
498
|
+
|
499
|
+
# Does the deploy with the given id exist?
|
500
|
+
# @param deploy_id [String]
|
501
|
+
# @return [String]
|
502
|
+
def self.deploy_exists?(deploy_id)
|
503
|
+
if deploy_id.nil? or deploy_id.empty?
|
504
|
+
MU.log "Got nil deploy_id in MU::MommaCat.deploy_exists?", MU::WARN
|
505
|
+
return
|
506
|
+
end
|
507
|
+
path = File.expand_path(MU.dataDir+"/deployments")
|
508
|
+
if !Dir.exist?(path)
|
509
|
+
Dir.mkdir(path, 0700)
|
510
|
+
end
|
511
|
+
deploy_path = File.expand_path(path+"/"+deploy_id)
|
512
|
+
return Dir.exist?(deploy_path)
|
513
|
+
end
|
514
|
+
|
515
|
+
private
|
516
|
+
|
517
|
+
def writeFile(filename, contents)
|
518
|
+
file = File.new("#{deploy_dir}/#{filename}", File::CREAT|File::TRUNC|File::RDWR, 0600)
|
519
|
+
file.puts contents
|
520
|
+
file.close
|
521
|
+
end
|
522
|
+
|
523
|
+
# Helper for +initialize+
|
524
|
+
def setDeploySecret
|
525
|
+
credsets = {}
|
526
|
+
MU::Cloud.resource_types.values.each { |attrs|
|
527
|
+
if !@original_config[attrs[:cfg_plural]].nil? and @original_config[attrs[:cfg_plural]].size > 0
|
528
|
+
@original_config[attrs[:cfg_plural]].each { |resource|
|
529
|
+
|
530
|
+
credsets[resource['cloud']] ||= []
|
531
|
+
credsets[resource['cloud']] << resource['credentials']
|
532
|
+
@clouds[resource['cloud']] = 0 if !@clouds.has_key?(resource['cloud'])
|
533
|
+
@clouds[resource['cloud']] = @clouds[resource['cloud']] + 1
|
534
|
+
|
535
|
+
}
|
536
|
+
end
|
537
|
+
}
|
538
|
+
|
539
|
+
MU.log "Creating deploy secret for #{MU.deploy_id}"
|
540
|
+
@deploy_secret = Password.random(256)
|
541
|
+
if !@original_config['scrub_mu_isms'] and !@no_artifacts
|
542
|
+
credsets.each_pair { |cloud, creds|
|
543
|
+
creds.uniq!
|
544
|
+
creds.each { |credentials|
|
545
|
+
MU::Cloud.cloudClass(cloud).writeDeploySecret(@deploy_id, @deploy_secret, credentials: credentials)
|
546
|
+
}
|
547
|
+
}
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
def loadObjects(delay_descriptor_load)
|
552
|
+
# Load up MU::Cloud objects for all our kittens in this deploy
|
553
|
+
|
554
|
+
MU::Cloud.resource_types.each_pair { |res_type, attrs|
|
555
|
+
type = attrs[:cfg_plural]
|
556
|
+
next if !@deployment.has_key?(type)
|
557
|
+
|
558
|
+
deletia = {}
|
559
|
+
@deployment[type].each_pair { |res_name, data|
|
560
|
+
orig_cfg = findResourceConfig(type, res_name)
|
561
|
+
|
562
|
+
if orig_cfg.nil?
|
563
|
+
MU.log "Failed to locate original config for #{attrs[:cfg_name]} #{res_name} in #{@deploy_id}", MU::WARN if !["firewall_rules", "databases", "storage_pools", "cache_clusters", "alarms"].include?(type) # XXX shaddap
|
564
|
+
next
|
565
|
+
end
|
566
|
+
|
567
|
+
if orig_cfg['vpc']
|
568
|
+
ref = if orig_cfg['vpc']['id'] and orig_cfg['vpc']['id'].is_a?(Hash)
|
569
|
+
orig_cfg['vpc']['id']['mommacat'] = self
|
570
|
+
MU::Config::Ref.get(orig_cfg['vpc']['id'])
|
571
|
+
else
|
572
|
+
orig_cfg['vpc']['mommacat'] = self
|
573
|
+
MU::Config::Ref.get(orig_cfg['vpc'])
|
574
|
+
end
|
575
|
+
orig_cfg['vpc'].delete('mommacat')
|
576
|
+
orig_cfg['vpc'] = ref if ref.kitten(shallow: true)
|
577
|
+
end
|
578
|
+
|
579
|
+
begin
|
580
|
+
if attrs[:has_multiples]
|
581
|
+
data.keys.each { |mu_name|
|
582
|
+
addKitten(type, res_name, attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: mu_name, delay_descriptor_load: delay_descriptor_load))
|
583
|
+
}
|
584
|
+
else
|
585
|
+
addKitten(type, res_name, attrs[:interface].new(mommacat: self, kitten_cfg: orig_cfg, mu_name: data['mu_name'], cloud_id: data['cloud_id']))
|
586
|
+
end
|
587
|
+
rescue StandardError => e
|
588
|
+
if e.class != MU::Cloud::MuCloudResourceNotImplemented
|
589
|
+
MU.log "Failed to load an existing resource of type '#{type}' in #{@deploy_id}: #{e.inspect}", MU::WARN, details: e.backtrace
|
590
|
+
end
|
591
|
+
end
|
592
|
+
}
|
593
|
+
|
594
|
+
}
|
595
|
+
end
|
596
|
+
|
597
|
+
# Helper for +initialize+
|
598
|
+
def initDeployDirectory
|
599
|
+
if !Dir.exist?(MU.dataDir+"/deployments")
|
600
|
+
MU.log "Creating #{MU.dataDir}/deployments", MU::DEBUG
|
601
|
+
Dir.mkdir(MU.dataDir+"/deployments", 0700)
|
602
|
+
end
|
603
|
+
path = File.expand_path(MU.dataDir+"/deployments")+"/"+@deploy_id
|
604
|
+
if !Dir.exist?(path)
|
605
|
+
MU.log "Creating #{path}", MU::DEBUG
|
606
|
+
Dir.mkdir(path, 0700)
|
607
|
+
end
|
608
|
+
|
609
|
+
@ssh_key_name, @ssh_private_key, @ssh_public_key = self.SSHKey
|
610
|
+
if !File.exist?(deploy_dir+"/private_key")
|
611
|
+
@private_key, @public_key = createDeployKey
|
612
|
+
end
|
613
|
+
|
614
|
+
end
|
615
|
+
|
616
|
+
###########################################################################
|
617
|
+
###########################################################################
|
618
|
+
def loadDeployFromCache(set_context_to_me = true)
|
619
|
+
return false if !File.size?(deploy_dir+"/deployment.json")
|
620
|
+
|
621
|
+
deploy = File.open("#{deploy_dir}/deployment.json", File::RDONLY)
|
622
|
+
MU.log "Getting lock to read #{deploy_dir}/deployment.json", MU::DEBUG
|
623
|
+
# deploy.flock(File::LOCK_EX)
|
624
|
+
begin
|
625
|
+
Timeout::timeout(90) {deploy.flock(File::LOCK_EX)}
|
626
|
+
rescue Timeout::Error
|
627
|
+
raise MuError, "Timed out trying to get an exclusive lock on #{deploy_dir}/deployment.json"
|
628
|
+
end
|
629
|
+
|
630
|
+
begin
|
631
|
+
@deployment = JSON.parse(File.read("#{deploy_dir}/deployment.json"))
|
632
|
+
rescue JSON::ParserError => e
|
633
|
+
MU.log "JSON parse failed on #{deploy_dir}/deployment.json", MU::ERR, details: e.message
|
634
|
+
end
|
635
|
+
|
636
|
+
deploy.flock(File::LOCK_UN)
|
637
|
+
deploy.close
|
638
|
+
|
639
|
+
setThreadContextToMe if set_context_to_me
|
640
|
+
|
641
|
+
@timestamp = @deployment['timestamp']
|
642
|
+
@seed = @deployment['seed']
|
643
|
+
@appname = @deployment['appname']
|
644
|
+
@handle = @deployment['handle']
|
645
|
+
|
646
|
+
true
|
647
|
+
end
|
648
|
+
|
649
|
+
###########################################################################
|
650
|
+
###########################################################################
|
651
|
+
def loadDeploy(deployment_json_only = false, set_context_to_me: true)
|
652
|
+
MU::MommaCat.deploy_struct_semaphore.synchronize {
|
653
|
+
success = loadDeployFromCache(set_context_to_me)
|
654
|
+
|
655
|
+
return if deployment_json_only and success
|
656
|
+
|
657
|
+
if File.exist?(deploy_dir+"/private_key")
|
658
|
+
@private_key = File.read("#{deploy_dir}/private_key")
|
659
|
+
@public_key = File.read("#{deploy_dir}/public_key")
|
660
|
+
end
|
661
|
+
|
662
|
+
if File.exist?(deploy_dir+"/basket_of_kittens.json")
|
663
|
+
begin
|
664
|
+
@original_config = JSON.parse(File.read("#{deploy_dir}/basket_of_kittens.json"))
|
665
|
+
rescue JSON::ParserError => e
|
666
|
+
MU.log "JSON parse failed on #{deploy_dir}/basket_of_kittens.json", MU::ERR, details: e.message
|
667
|
+
end
|
668
|
+
end
|
669
|
+
if File.exist?(deploy_dir+"/ssh_key_name")
|
670
|
+
@ssh_key_name = File.read("#{deploy_dir}/ssh_key_name").chomp!
|
671
|
+
end
|
672
|
+
if File.exist?(deploy_dir+"/node_ssh.key")
|
673
|
+
@ssh_private_key = File.read("#{deploy_dir}/node_ssh.key")
|
674
|
+
end
|
675
|
+
if File.exist?(deploy_dir+"/node_ssh.pub")
|
676
|
+
@ssh_public_key = File.read("#{deploy_dir}/node_ssh.pub")
|
677
|
+
end
|
678
|
+
if File.exist?(deploy_dir+"/environment_name")
|
679
|
+
@environment = File.read("#{deploy_dir}/environment_name").chomp!
|
680
|
+
end
|
681
|
+
if File.exist?(deploy_dir+"/deploy_secret")
|
682
|
+
@deploy_secret = File.read("#{deploy_dir}/deploy_secret")
|
683
|
+
end
|
684
|
+
if Dir.exist?("#{deploy_dir}/secrets")
|
685
|
+
@secrets.each_key { |type|
|
686
|
+
Dir.glob("#{deploy_dir}/secrets/#{type}.*") { |filename|
|
687
|
+
server = File.basename(filename).split(/\./)[1]
|
688
|
+
|
689
|
+
@secrets[type][server] = File.read(filename).chomp!
|
690
|
+
}
|
691
|
+
}
|
692
|
+
end
|
693
|
+
}
|
694
|
+
end
|
695
|
+
|
696
|
+
def findResourceConfig(type, name, config = @original_config)
|
697
|
+
orig_cfg = nil
|
698
|
+
if config.has_key?(type)
|
699
|
+
config[type].each { |resource|
|
700
|
+
if resource["name"] == name
|
701
|
+
orig_cfg = resource
|
702
|
+
break
|
703
|
+
end
|
704
|
+
}
|
705
|
+
end
|
706
|
+
|
707
|
+
# Some Server objects originated from ServerPools, get their
|
708
|
+
# configs from there
|
709
|
+
if type == "servers" and orig_cfg.nil? and config.has_key?("server_pools")
|
710
|
+
config["server_pools"].each { |resource|
|
711
|
+
if resource["name"] == name
|
712
|
+
orig_cfg = resource
|
713
|
+
break
|
714
|
+
end
|
715
|
+
}
|
716
|
+
end
|
717
|
+
|
718
|
+
orig_cfg
|
719
|
+
end
|
720
|
+
|
721
|
+
end #class
|
722
|
+
end #module
|