cloud-mu 3.1.6 → 3.4.0
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/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/extras/clean-stock-amis
CHANGED
|
@@ -23,7 +23,7 @@ $opts = Optimist::options do
|
|
|
23
23
|
#{$0} [-c credentials] [-i imagename]
|
|
24
24
|
EOS
|
|
25
25
|
opt :credentials, "Use these AWS credentials from mu.yaml instead of the default set", :required => false, :type => :string
|
|
26
|
-
opt :image, "Purge a specific image, instead of just
|
|
26
|
+
opt :image, "Purge a specific image, instead of just scrubbing old ones", :required => false, :type => :string
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
filters = [
|
|
@@ -33,12 +33,14 @@ filters = [
|
|
|
33
33
|
}
|
|
34
34
|
]
|
|
35
35
|
|
|
36
|
+
in_use = MU::Cloud.getStockImage("AWS").values.flatten.map { |h| h.values }.flatten
|
|
36
37
|
|
|
37
38
|
MU::Cloud::AWS.listRegions.each { | r|
|
|
38
39
|
images = MU::Cloud::AWS.ec2(region: r, credentials: $opts[:credentials]).describe_images(
|
|
39
40
|
filters: filters + [{ "name" => "state", "values" => ["available"]}]
|
|
40
41
|
).images
|
|
41
42
|
images.each { |ami|
|
|
43
|
+
next if in_use.include?(ami)
|
|
42
44
|
if ($opts[:image] and ami.name == $opts[:image]) or
|
|
43
45
|
((DateTime.now.to_time - DateTime.parse(ami.creation_date).to_time) > 15552000 and ami.name.match(/^MU-(PROD|DEV)/))
|
|
44
46
|
snaps = []
|
|
@@ -53,7 +55,13 @@ MU::Cloud::AWS.listRegions.each { | r|
|
|
|
53
55
|
rescue Aws::EC2::Errors::InvalidAMIIDUnavailable
|
|
54
56
|
end
|
|
55
57
|
snaps.each { |snap_id|
|
|
56
|
-
|
|
58
|
+
begin
|
|
59
|
+
MU::Cloud::AWS.ec2(region: r, credentials: $opts[:credentials]).delete_snapshot(snapshot_id: snap_id)
|
|
60
|
+
rescue Aws::EC2::Errors::InvalidSnapshotInUse
|
|
61
|
+
sleep 5
|
|
62
|
+
retry
|
|
63
|
+
rescue Aws::EC2::Errors::InvalidSnapshotNotFound
|
|
64
|
+
end
|
|
57
65
|
}
|
|
58
66
|
end
|
|
59
67
|
}
|
|
@@ -63,6 +63,7 @@ end
|
|
|
63
63
|
now = DateTime.now
|
|
64
64
|
|
|
65
65
|
exitcode = 0
|
|
66
|
+
succeeded = 0
|
|
66
67
|
$opts[:clouds].each { |cloud|
|
|
67
68
|
current_images = MU::Cloud.getStockImage(cloud, fail_hard: true)
|
|
68
69
|
$opts[:platforms].each { |platform|
|
|
@@ -91,6 +92,7 @@ $opts[:clouds].each { |cloud|
|
|
|
91
92
|
end
|
|
92
93
|
next if !needed
|
|
93
94
|
end
|
|
95
|
+
MU.log "Loading "+bok_dir+"/"+cloud+"/"+platform+".yaml"
|
|
94
96
|
conf_engine = MU::Config.new(
|
|
95
97
|
bok_dir+"/"+cloud+"/"+platform+".yaml",
|
|
96
98
|
default_credentials: $opts[(cloud.downcase+"_creds").to_sym]
|
|
@@ -113,6 +115,7 @@ $opts[:clouds].each { |cloud|
|
|
|
113
115
|
# Scrub any loose metadata left over from our image deployment. It's
|
|
114
116
|
# ok, this won't touch the images we just made.
|
|
115
117
|
MU::Cleanup.run(deployer.mommacat.deploy_id, skipsnapshots: true, verbosity: MU::Logger::QUIET)
|
|
118
|
+
succeeded += 1
|
|
116
119
|
rescue Exception => e
|
|
117
120
|
MU.log e.message, MU::ERR
|
|
118
121
|
exitcode = 1
|
|
@@ -121,10 +124,11 @@ $opts[:clouds].each { |cloud|
|
|
|
121
124
|
end
|
|
122
125
|
}
|
|
123
126
|
|
|
124
|
-
if
|
|
127
|
+
if !$opts[:dryrun] and succeeded > 0
|
|
125
128
|
puts current_images.to_yaml
|
|
126
|
-
|
|
127
|
-
|
|
129
|
+
if available_clouds.keys.include?("AWS")
|
|
130
|
+
MU::Cloud::AWS::Bucket.upload($opts[:upload_to]+"/"+cloud+".yaml", data: current_images.to_yaml, credentials: $opts[:aws_creds], acl: "public-read")
|
|
131
|
+
end
|
|
128
132
|
end
|
|
129
133
|
}
|
|
130
134
|
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
2
|
+
appname: mu
|
|
3
|
+
servers:
|
|
4
|
+
- name: centos7
|
|
5
|
+
platform: centos7
|
|
6
|
+
size: m4.large
|
|
7
|
+
vpc:
|
|
8
|
+
name: c7vpc
|
|
9
|
+
scrub_groomer: true
|
|
10
|
+
run_list:
|
|
11
|
+
- recipe[mu-tools::apply_security]
|
|
12
|
+
- recipe[mu-tools::updates]
|
|
13
|
+
- recipe[mu-tools::split_var_partitions]
|
|
14
|
+
create_image:
|
|
15
|
+
image_then_destroy: true
|
|
16
|
+
public: true
|
|
17
|
+
copy_to_regions:
|
|
18
|
+
- "#ALL"
|
|
19
|
+
vpcs:
|
|
20
|
+
- name: c7vpc
|
|
File without changes
|
|
File without changes
|
data/modules/mommacat.ru
CHANGED
|
@@ -387,7 +387,7 @@ app = proc do |env|
|
|
|
387
387
|
|
|
388
388
|
# XXX We can't assume AWS anymore. What does this look like otherwise?
|
|
389
389
|
# If this is an already-groomed instance, try to get a real object for it
|
|
390
|
-
instance = MU::MommaCat.findStray("AWS", "server", cloud_id: req["mu_instance_id"], region: server_cfg["region"], deploy_id: req["mu_id"], name: req["mu_resource_name"], dummy_ok:
|
|
390
|
+
instance = MU::MommaCat.findStray("AWS", "server", cloud_id: req["mu_instance_id"], region: server_cfg["region"], deploy_id: req["mu_id"], name: req["mu_resource_name"], dummy_ok: true, calling_deploy: kittenpile).first
|
|
391
391
|
mu_name = nil
|
|
392
392
|
if instance.nil?
|
|
393
393
|
# Now we're just checking for existence in the cloud provider, really
|
|
@@ -416,7 +416,7 @@ app = proc do |env|
|
|
|
416
416
|
if instance.respond_to?(:addVolume)
|
|
417
417
|
# XXX make sure we handle mangled input safely
|
|
418
418
|
params = JSON.parse(Base64.decode64(req["add_volume"]))
|
|
419
|
-
MU.log "
|
|
419
|
+
MU.log "add_volume request", MU::NOTICE, details: params
|
|
420
420
|
instance.addVolume(params["dev"], params["size"], delete_on_termination: params["delete_on_termination"])
|
|
421
421
|
else
|
|
422
422
|
returnval = throw500 "I don't know how to add a volume for #{instance}"
|
data/modules/mu.rb
CHANGED
|
@@ -79,38 +79,40 @@ class Hash
|
|
|
79
79
|
}
|
|
80
80
|
return 0 if self == other # that was easy!
|
|
81
81
|
# compare elements and decide who's "bigger" based on their totals?
|
|
82
|
-
|
|
82
|
+
|
|
83
|
+
# fine, try some brute force and just hope everything implements to_s
|
|
84
|
+
self.flatten.map { |e| e.to_s }.join() <=> other.flatten.map { |e| e.to_s }.join()
|
|
83
85
|
end
|
|
84
86
|
|
|
85
|
-
# Recursively compare two hashes
|
|
86
|
-
def diff(with, on = self, level: 0, parents: [])
|
|
87
|
+
# Recursively compare two Mu Basket of Kittens hashes and report the differences
|
|
88
|
+
def diff(with, on = self, level: 0, parents: [], report: {}, habitat: nil)
|
|
87
89
|
return if with.nil? and on.nil?
|
|
88
90
|
if with.nil? or on.nil? or with.class != on.class
|
|
89
91
|
return # XXX ...however we're flagging differences
|
|
90
92
|
end
|
|
91
93
|
return if on == with
|
|
92
94
|
|
|
93
|
-
tree = ""
|
|
94
|
-
indentsize = 0
|
|
95
|
-
parents.each { |p|
|
|
96
|
-
tree += (" " * indentsize) + p + " => \n"
|
|
97
|
-
indentsize += 2
|
|
98
|
-
}
|
|
99
|
-
indent = (" " * indentsize)
|
|
100
|
-
|
|
101
95
|
changes = []
|
|
96
|
+
report ||= {}
|
|
102
97
|
if on.is_a?(Hash)
|
|
103
98
|
on_unique = (on.keys - with.keys)
|
|
104
99
|
with_unique = (with.keys - on.keys)
|
|
105
100
|
shared = (with.keys & on.keys)
|
|
106
101
|
shared.each { |k|
|
|
107
|
-
|
|
102
|
+
|
|
103
|
+
report_data = diff(with[k], on[k], level: level+1, parents: parents + [k], report: report[k], habitat: habitat)
|
|
104
|
+
if report_data and !report_data.empty?
|
|
105
|
+
report ||= {}
|
|
106
|
+
report[k] = report_data
|
|
107
|
+
end
|
|
108
108
|
}
|
|
109
109
|
on_unique.each { |k|
|
|
110
|
-
|
|
110
|
+
report[k] = { :action => :removed, :parents => parents, :value => on[k].clone }
|
|
111
|
+
report[k][:habitat] = habitat if habitat
|
|
111
112
|
}
|
|
112
113
|
with_unique.each { |k|
|
|
113
|
-
|
|
114
|
+
report[k] = { :action => :added, :parents => parents, :value => with[k].clone }
|
|
115
|
+
report[k][:habitat] = habitat if habitat
|
|
114
116
|
}
|
|
115
117
|
elsif on.is_a?(Array)
|
|
116
118
|
return if with == on
|
|
@@ -122,29 +124,27 @@ class Hash
|
|
|
122
124
|
# sorting arrays full of weird, non-primitive types.
|
|
123
125
|
done = []
|
|
124
126
|
on.sort.each { |elt|
|
|
125
|
-
if elt.is_a?(Hash) and elt
|
|
126
|
-
|
|
127
|
-
# Figure out what convention this thing is using for resource identification
|
|
128
|
-
compare_a, compare_b = if elt['name'].nil? and elt["id"].nil? and !elt["entity"].nil? and !other_elt["entity"].nil?
|
|
129
|
-
[elt["entity"], other_elt["entity"]]
|
|
130
|
-
else
|
|
131
|
-
[elt, other_elt]
|
|
132
|
-
end
|
|
127
|
+
if elt.is_a?(Hash) and !MU::MommaCat.getChunkName(elt).first.nil?
|
|
128
|
+
elt_namestr, elt_location, elt_location_list = MU::MommaCat.getChunkName(elt)
|
|
133
129
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
130
|
+
with.sort.each { |other_elt|
|
|
131
|
+
other_elt_namestr, other_elt_location, other_elt_location_list = MU::MommaCat.getChunkName(other_elt)
|
|
132
|
+
|
|
133
|
+
# Case 1: The array element exists in both version of this array
|
|
134
|
+
if elt_namestr and other_elt_namestr and
|
|
135
|
+
elt_namestr == other_elt_namestr and
|
|
136
|
+
(elt_location.nil? or other_elt_location.nil? or
|
|
137
|
+
elt_location == other_elt_location or
|
|
138
|
+
!(elt_location_list & other_elt_location_list).empty?
|
|
139
|
+
)
|
|
137
140
|
done << elt
|
|
138
141
|
done << other_elt
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
elt['entity']['id']
|
|
142
|
+
break if elt == other_elt # if they're identical, we're done
|
|
143
|
+
report_data = diff(other_elt, elt, level: level+1, parents: parents + [elt_namestr], habitat: (elt_location || habitat))
|
|
144
|
+
if report_data and !report_data.empty?
|
|
145
|
+
report ||= {}
|
|
146
|
+
report[elt_namestr] = report_data
|
|
145
147
|
end
|
|
146
|
-
|
|
147
|
-
diff(other_elt, elt, level: level+1, parents: parents + [namestr])
|
|
148
148
|
break
|
|
149
149
|
end
|
|
150
150
|
}
|
|
@@ -152,43 +152,34 @@ class Hash
|
|
|
152
152
|
}
|
|
153
153
|
on_unique = (on - with) - done
|
|
154
154
|
with_unique = (with - on) - done
|
|
155
|
-
|
|
156
|
-
#
|
|
157
|
-
# MU.log "A BEFORE", MU::NOTICE, details: before_a
|
|
158
|
-
# MU.log "A AFTER", MU::NOTICE, details: after_a
|
|
159
|
-
# end
|
|
160
|
-
# if before_b != after_b
|
|
161
|
-
# MU.log "B BEFORE", MU::NOTICE, details: before_b
|
|
162
|
-
# MU.log "B AFTER", MU::NOTICE, details: after_b
|
|
163
|
-
# end
|
|
164
|
-
# end
|
|
155
|
+
|
|
156
|
+
# Case 2: This array entry exists in the old version, but not the new one
|
|
165
157
|
on_unique.each { |e|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
158
|
+
namestr, loc = MU::MommaCat.getChunkName(e)
|
|
159
|
+
|
|
160
|
+
report ||= {}
|
|
161
|
+
report[namestr] = { :action => :removed, :parents => parents, :value => e.clone }
|
|
162
|
+
report[namestr][:habitat] = loc if loc
|
|
171
163
|
}
|
|
164
|
+
|
|
165
|
+
# Case 3: This array entry exists in the new version, but not the old one
|
|
172
166
|
with_unique.each { |e|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
167
|
+
namestr, loc = MU::MommaCat.getChunkName(e)
|
|
168
|
+
|
|
169
|
+
report ||= {}
|
|
170
|
+
report[namestr] = { :action => :added, :parents => parents, :value => e.clone }
|
|
171
|
+
report[namestr][:habitat] = loc if loc
|
|
178
172
|
}
|
|
173
|
+
|
|
174
|
+
# A plain old leaf node of data
|
|
179
175
|
else
|
|
180
176
|
if on != with
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
report = { :action => :changed, :parents => parents, :oldvalue => on, :value => with.clone }
|
|
178
|
+
report[:habitat] = habitat if habitat
|
|
183
179
|
end
|
|
184
180
|
end
|
|
185
181
|
|
|
186
|
-
|
|
187
|
-
puts tree
|
|
188
|
-
changes.each { |c|
|
|
189
|
-
puts indent+c
|
|
190
|
-
}
|
|
191
|
-
end
|
|
182
|
+
report.freeze
|
|
192
183
|
end
|
|
193
184
|
|
|
194
185
|
# Implement a merge! that just updates each hash leaf as needed, not
|
|
@@ -212,8 +203,29 @@ class Hash
|
|
|
212
203
|
end
|
|
213
204
|
|
|
214
205
|
ENV['HOME'] = Etc.getpwuid(Process.uid).dir
|
|
206
|
+
module MU
|
|
207
|
+
|
|
208
|
+
# For log entries that should only be logged when we're in verbose mode
|
|
209
|
+
DEBUG = 0.freeze
|
|
210
|
+
# For ordinary log entries
|
|
211
|
+
INFO = 1.freeze
|
|
212
|
+
# For more interesting log entries which are not errors
|
|
213
|
+
NOTICE = 2.freeze
|
|
214
|
+
# Log entries for non-fatal errors
|
|
215
|
+
WARN = 3.freeze
|
|
216
|
+
# Log entries for non-fatal errors
|
|
217
|
+
WARNING = 3.freeze
|
|
218
|
+
# Log entries for fatal errors
|
|
219
|
+
ERR = 4.freeze
|
|
220
|
+
# Log entries for fatal errors
|
|
221
|
+
ERROR = 4.freeze
|
|
222
|
+
# Log entries that will be held and displayed/emailed at the end of deploy,
|
|
223
|
+
# cleanup, etc.
|
|
224
|
+
SUMMARY = 5.freeze
|
|
225
|
+
end
|
|
215
226
|
|
|
216
227
|
require 'mu/logger'
|
|
228
|
+
|
|
217
229
|
module MU
|
|
218
230
|
|
|
219
231
|
# Subclass core thread so we can gracefully handle it when we hit system
|
|
@@ -273,8 +285,9 @@ module MU
|
|
|
273
285
|
# Wrapper class for fatal Exceptions. Gives our internals something to
|
|
274
286
|
# inherit that will log an error message appropriately before bubbling up.
|
|
275
287
|
class MuError < StandardError
|
|
276
|
-
def initialize(message = nil, silent: false)
|
|
277
|
-
|
|
288
|
+
def initialize(message = nil, silent: false, details: nil)
|
|
289
|
+
details ||= caller[2]
|
|
290
|
+
MU.log message, MU::ERR, details: details if !message.nil? and !silent
|
|
278
291
|
if MU.verbosity == MU::Logger::SILENT
|
|
279
292
|
super ""
|
|
280
293
|
else
|
|
@@ -286,8 +299,8 @@ module MU
|
|
|
286
299
|
# Wrapper class for temporary Exceptions. Gives our internals something to
|
|
287
300
|
# inherit that will log a notice message appropriately before bubbling up.
|
|
288
301
|
class MuNonFatal < StandardError
|
|
289
|
-
def initialize(message = nil, silent: false)
|
|
290
|
-
MU.log message, MU::NOTICE if !message.nil? and !silent
|
|
302
|
+
def initialize(message = nil, silent: false, details: nil)
|
|
303
|
+
MU.log message, MU::NOTICE, details: details if !message.nil? and !silent
|
|
291
304
|
if MU.verbosity == MU::Logger::SILENT
|
|
292
305
|
super ""
|
|
293
306
|
else
|
|
@@ -620,25 +633,6 @@ module MU
|
|
|
620
633
|
@@logger.log(msg, level, details: details, html: html, verbosity: verbosity, color: color)
|
|
621
634
|
end
|
|
622
635
|
|
|
623
|
-
# For log entries that should only be logged when we're in verbose mode
|
|
624
|
-
DEBUG = 0.freeze
|
|
625
|
-
# For ordinary log entries
|
|
626
|
-
INFO = 1.freeze
|
|
627
|
-
# For more interesting log entries which are not errors
|
|
628
|
-
NOTICE = 2.freeze
|
|
629
|
-
# Log entries for non-fatal errors
|
|
630
|
-
WARN = 3.freeze
|
|
631
|
-
# Log entries for non-fatal errors
|
|
632
|
-
WARNING = 3.freeze
|
|
633
|
-
# Log entries for fatal errors
|
|
634
|
-
ERR = 4.freeze
|
|
635
|
-
# Log entries for fatal errors
|
|
636
|
-
ERROR = 4.freeze
|
|
637
|
-
# Log entries that will be held and displayed/emailed at the end of deploy,
|
|
638
|
-
# cleanup, etc.
|
|
639
|
-
SUMMARY = 5.freeze
|
|
640
|
-
|
|
641
|
-
|
|
642
636
|
autoload :Cleanup, 'mu/cleanup'
|
|
643
637
|
autoload :Deploy, 'mu/deploy'
|
|
644
638
|
autoload :MommaCat, 'mu/mommacat'
|
|
@@ -652,7 +646,7 @@ module MU
|
|
|
652
646
|
new_cfg = $MU_CFG.dup
|
|
653
647
|
examples = {}
|
|
654
648
|
MU::Cloud.supportedClouds.each { |cloud|
|
|
655
|
-
cloudclass =
|
|
649
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
|
656
650
|
begin
|
|
657
651
|
if cloudclass.hosted? and !$MU_CFG[cloud.downcase]
|
|
658
652
|
cfg_blob = cloudclass.hosted_config
|
|
@@ -808,11 +802,7 @@ module MU
|
|
|
808
802
|
# @param groomer [String]: The grooming agent to load.
|
|
809
803
|
# @return [Class]: The class object implementing this groomer agent
|
|
810
804
|
def self.loadGroomer(groomer)
|
|
811
|
-
|
|
812
|
-
raise MuError, "Requested to use unsupported grooming agent #{groomer}"
|
|
813
|
-
end
|
|
814
|
-
require "mu/groomers/#{groomer.downcase}"
|
|
815
|
-
return Object.const_get("MU").const_get("Groomer").const_get(groomer)
|
|
805
|
+
MU::Groomer.loadGroomer(groomer)
|
|
816
806
|
end
|
|
817
807
|
|
|
818
808
|
@@myRegion_var = nil
|
|
@@ -966,8 +956,7 @@ module MU
|
|
|
966
956
|
|
|
967
957
|
@@myCloudDescriptor = nil
|
|
968
958
|
if MU.myCloud
|
|
969
|
-
|
|
970
|
-
found = svrclass.find(cloud_id: @@myInstanceId, region: MU.myRegion) # XXX need habitat arg for google et al
|
|
959
|
+
found = MU::Cloud.resourceClass(MU.myCloud, "Server").find(cloud_id: @@myInstanceId, region: MU.myRegion) # XXX need habitat arg for google et al
|
|
971
960
|
# found = MU::MommaCat.findStray(MU.myCloud, "server", cloud_id: @@myInstanceId, dummy_ok: true, region: MU.myRegion)
|
|
972
961
|
if !found.nil? and found.size == 1
|
|
973
962
|
@@myCloudDescriptor = found.values.first
|
|
@@ -980,8 +969,7 @@ module MU
|
|
|
980
969
|
def self.myVPCObj
|
|
981
970
|
return nil if MU.myCloud.nil?
|
|
982
971
|
return @@myVPCObj_var if @@myVPCObj_var
|
|
983
|
-
|
|
984
|
-
@@myVPCObj_var ||= cloudclass.myVPCObj
|
|
972
|
+
@@myVPCObj_var ||= MU::Cloud.cloudClass(MU.myCloud).myVPCObj
|
|
985
973
|
@@myVPCObj_var
|
|
986
974
|
end
|
|
987
975
|
|
|
@@ -1106,10 +1094,9 @@ module MU
|
|
|
1106
1094
|
|
|
1107
1095
|
clouds = platform.nil? ? MU::Cloud.supportedClouds : [platform]
|
|
1108
1096
|
clouds.each { |cloud|
|
|
1109
|
-
|
|
1110
|
-
bucketname = cloudclass.adminBucketName(credentials)
|
|
1097
|
+
bucketname = MU::Cloud.cloudClass(cloud).adminBucketName(credentials)
|
|
1111
1098
|
begin
|
|
1112
|
-
if platform or (
|
|
1099
|
+
if platform or (MU::Cloud.cloudClass(cloud).hosted? and platform.nil?) or cloud == MU::Config.defaultCloud
|
|
1113
1100
|
return bucketname
|
|
1114
1101
|
end
|
|
1115
1102
|
end
|
data/modules/mu/adoption.rb
CHANGED
|
@@ -30,7 +30,7 @@ module MU
|
|
|
30
30
|
:omnibus => "Jam everything into one monolothic configuration"
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
def initialize(clouds: MU::Cloud.supportedClouds, types: MU::Cloud.resource_types.keys, parent: nil, billing: nil, sources: nil, credentials: nil, group_by: :logical, savedeploys: false, diff: false, habitats: [], scrub_mu_isms: false)
|
|
33
|
+
def initialize(clouds: MU::Cloud.supportedClouds, types: MU::Cloud.resource_types.keys, parent: nil, billing: nil, sources: nil, credentials: nil, group_by: :logical, savedeploys: false, diff: false, habitats: [], scrub_mu_isms: false, regions: [], merge: false, pattern: nil)
|
|
34
34
|
@scraped = {}
|
|
35
35
|
@clouds = clouds
|
|
36
36
|
@types = types
|
|
@@ -44,8 +44,11 @@ module MU
|
|
|
44
44
|
@savedeploys = savedeploys
|
|
45
45
|
@diff = diff
|
|
46
46
|
@habitats = habitats
|
|
47
|
+
@regions = regions
|
|
47
48
|
@habitats ||= []
|
|
48
49
|
@scrub_mu_isms = scrub_mu_isms
|
|
50
|
+
@merge = merge
|
|
51
|
+
@pattern = pattern
|
|
49
52
|
end
|
|
50
53
|
|
|
51
54
|
# Walk cloud providers with available credentials to discover resources
|
|
@@ -53,7 +56,7 @@ module MU
|
|
|
53
56
|
@default_parent = nil
|
|
54
57
|
|
|
55
58
|
@clouds.each { |cloud|
|
|
56
|
-
cloudclass =
|
|
59
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
|
57
60
|
next if cloudclass.listCredentials.nil?
|
|
58
61
|
|
|
59
62
|
if cloud == "Google" and !@parent and @target_creds
|
|
@@ -65,7 +68,6 @@ module MU
|
|
|
65
68
|
|
|
66
69
|
cloudclass.listCredentials.each { |credset|
|
|
67
70
|
next if @sources and !@sources.include?(credset)
|
|
68
|
-
|
|
69
71
|
cfg = cloudclass.credConfig(credset)
|
|
70
72
|
if cfg and cfg['restrict_to_habitats']
|
|
71
73
|
cfg['restrict_to_habitats'] << cfg['project'] if cfg['project']
|
|
@@ -90,7 +92,7 @@ module MU
|
|
|
90
92
|
|
|
91
93
|
@types.each { |type|
|
|
92
94
|
begin
|
|
93
|
-
resclass =
|
|
95
|
+
resclass = MU::Cloud.resourceClass(cloud, type)
|
|
94
96
|
rescue ::MU::Cloud::MuCloudResourceNotImplemented
|
|
95
97
|
next
|
|
96
98
|
end
|
|
@@ -106,6 +108,7 @@ module MU
|
|
|
106
108
|
credentials: credset,
|
|
107
109
|
allow_multi: true,
|
|
108
110
|
habitats: @habitats.dup,
|
|
111
|
+
region: @regions,
|
|
109
112
|
dummy_ok: true,
|
|
110
113
|
skip_provider_owned: true,
|
|
111
114
|
# debug: false#,
|
|
@@ -114,7 +117,9 @@ module MU
|
|
|
114
117
|
|
|
115
118
|
if found and found.size > 0
|
|
116
119
|
if resclass.cfg_plural == "habitats"
|
|
117
|
-
found.reject! { |h|
|
|
120
|
+
found.reject! { |h|
|
|
121
|
+
!cloudclass.listHabitats(credset).include?(h.cloud_id)
|
|
122
|
+
}
|
|
118
123
|
end
|
|
119
124
|
MU.log "Found #{found.size.to_s} raw #{resclass.cfg_plural} in #{cloud}"
|
|
120
125
|
@scraped[type] ||= {}
|
|
@@ -122,7 +127,12 @@ module MU
|
|
|
122
127
|
if obj.habitat and !cloudclass.listHabitats(credset).include?(obj.habitat)
|
|
123
128
|
next
|
|
124
129
|
end
|
|
130
|
+
|
|
125
131
|
# XXX apply any filters (e.g. MU-ID tags)
|
|
132
|
+
if obj.cloud_id.nil?
|
|
133
|
+
MU.log "This damn thing gave me no cloud id, what do I even do with that", MU::ERR, details: obj
|
|
134
|
+
exit
|
|
135
|
+
end
|
|
126
136
|
@scraped[type][obj.cloud_id] = obj
|
|
127
137
|
}
|
|
128
138
|
end
|
|
@@ -200,7 +210,36 @@ module MU
|
|
|
200
210
|
prefix = "mu" if prefix.empty? # so that appnames aren't ever empty
|
|
201
211
|
end
|
|
202
212
|
|
|
213
|
+
# Find any previous deploys with this particular profile, which we'll use
|
|
214
|
+
# later for --diff.
|
|
215
|
+
@existing_deploys = {}
|
|
216
|
+
@existing_deploys_by_id = {}
|
|
217
|
+
@origins = {}
|
|
218
|
+
@types_found_in = {}
|
|
219
|
+
groupings.each_pair { |appname, types|
|
|
220
|
+
allowed_types = @types.map { |t| MU::Cloud.resource_types[t][:cfg_plural] }
|
|
221
|
+
next if (types & allowed_types).size == 0
|
|
222
|
+
origin = {
|
|
223
|
+
"appname" => prefix+appname,
|
|
224
|
+
"types" => (types & allowed_types).sort,
|
|
225
|
+
"habitats" => @habitats.sort,
|
|
226
|
+
"group_by" => @group_by.to_s
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@existing_deploys[appname] = MU::MommaCat.findMatchingDeploy(origin)
|
|
230
|
+
if @existing_deploys[appname]
|
|
231
|
+
@existing_deploys_by_id[@existing_deploys[appname].deploy_id] = @existing_deploys[appname]
|
|
232
|
+
@origins[appname] = origin
|
|
233
|
+
origin['types'].each { |t|
|
|
234
|
+
@types_found_in[t] = @existing_deploys[appname]
|
|
235
|
+
}
|
|
236
|
+
end
|
|
237
|
+
}
|
|
238
|
+
|
|
203
239
|
groupings.each_pair { |appname, types|
|
|
240
|
+
allowed_types = @types.map { |t| MU::Cloud.resource_types[t][:cfg_plural] }
|
|
241
|
+
next if (types & allowed_types).size == 0
|
|
242
|
+
|
|
204
243
|
bok = { "appname" => prefix+appname }
|
|
205
244
|
if @scrub_mu_isms
|
|
206
245
|
bok["scrub_mu_isms"] = true
|
|
@@ -210,26 +249,23 @@ module MU
|
|
|
210
249
|
end
|
|
211
250
|
|
|
212
251
|
count = 0
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
deploy = MU::MommaCat.findMatchingDeploy(origin)
|
|
223
|
-
if @diff and !deploy
|
|
224
|
-
MU.log "--diff was set but I failed to find a deploy like me to compare to", MU::ERR, details: origin
|
|
225
|
-
exit 1
|
|
252
|
+
if @diff
|
|
253
|
+
if !@existing_deploys[appname]
|
|
254
|
+
MU.log "--diff was set but I failed to find a deploy like '#{appname}' to compare to (have #{@existing_deploys.keys.join(", ")})", MU::ERR, details: @origins[appname]
|
|
255
|
+
exit 1
|
|
256
|
+
else
|
|
257
|
+
MU.log "Will diff current live resources against #{@existing_deploys[appname].deploy_id}", MU::NOTICE, details: @origins[appname]
|
|
258
|
+
end
|
|
226
259
|
end
|
|
227
260
|
|
|
228
261
|
threads = []
|
|
262
|
+
timers = {}
|
|
263
|
+
walltimers = {}
|
|
229
264
|
@clouds.each { |cloud|
|
|
230
265
|
@scraped.each_pair { |type, resources|
|
|
266
|
+
typestart = Time.now
|
|
231
267
|
res_class = begin
|
|
232
|
-
MU::Cloud.
|
|
268
|
+
MU::Cloud.resourceClass(cloud, type)
|
|
233
269
|
rescue MU::Cloud::MuCloudResourceNotImplemented
|
|
234
270
|
# XXX I don't think this can actually happen
|
|
235
271
|
next
|
|
@@ -237,6 +273,7 @@ module MU
|
|
|
237
273
|
next if !types.include?(res_class.cfg_plural)
|
|
238
274
|
|
|
239
275
|
bok[res_class.cfg_plural] ||= []
|
|
276
|
+
timers[type] ||= {}
|
|
240
277
|
|
|
241
278
|
class_semaphore = Mutex.new
|
|
242
279
|
|
|
@@ -253,13 +290,18 @@ module MU
|
|
|
253
290
|
end
|
|
254
291
|
end
|
|
255
292
|
threads << Thread.new(obj_thr) { |obj|
|
|
293
|
+
start = Time.now
|
|
256
294
|
|
|
257
|
-
kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats)
|
|
258
|
-
if kitten_cfg
|
|
295
|
+
kitten_cfg = obj.toKitten(rootparent: @default_parent, billing: @billing, habitats: @habitats, types: @types)
|
|
296
|
+
if kitten_cfg and (!@pattern or @pattern.match(kitten_cfg['name']))
|
|
259
297
|
print "."
|
|
260
298
|
kitten_cfg.delete("credentials") if @target_creds
|
|
261
299
|
class_semaphore.synchronize {
|
|
262
300
|
bok[res_class.cfg_plural] << kitten_cfg
|
|
301
|
+
if !kitten_cfg['cloud_id']
|
|
302
|
+
MU.log "No cloud id in this #{res_class.cfg_name} kitten!", MU::ERR, details: kitten_cfg
|
|
303
|
+
end
|
|
304
|
+
timers[type][kitten_cfg['cloud_id']] = (Time.now - start)
|
|
263
305
|
}
|
|
264
306
|
count += 1
|
|
265
307
|
end
|
|
@@ -270,6 +312,7 @@ module MU
|
|
|
270
312
|
threads.each { |t|
|
|
271
313
|
t.join
|
|
272
314
|
}
|
|
315
|
+
|
|
273
316
|
puts ""
|
|
274
317
|
bok[res_class.cfg_plural].sort! { |a, b|
|
|
275
318
|
strs = [a, b].map { |x|
|
|
@@ -291,24 +334,30 @@ module MU
|
|
|
291
334
|
bok[res_class.cfg_plural].each { |sibling|
|
|
292
335
|
next if kitten_cfg == sibling
|
|
293
336
|
if sibling['name'] == kitten_cfg['name']
|
|
294
|
-
MU.
|
|
295
|
-
if kitten_cfg['parent'] and kitten_cfg['parent'].respond_to?(:id) and kitten_cfg['parent'].id
|
|
296
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['parent'].id
|
|
297
|
-
elsif kitten_cfg['project']
|
|
298
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['project']
|
|
299
|
-
elsif kitten_cfg['region']
|
|
300
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['region']
|
|
301
|
-
elsif kitten_cfg['cloud_id']
|
|
302
|
-
kitten_cfg['name'] = kitten_cfg['name']+kitten_cfg['cloud_id'].gsub(/[^a-z0-9]/i, "-")
|
|
303
|
-
else
|
|
304
|
-
raise MU::Config::DuplicateNameError, "Saw duplicate #{res_class.cfg_name} name #{sibling['name']} and couldn't come up with a good way to differentiate them"
|
|
305
|
-
end
|
|
337
|
+
MU::Adoption.deDuplicateName(kitten_cfg, res_class)
|
|
306
338
|
MU.log "De-duplication: Renamed #{res_class.cfg_name} name '#{sibling['name']}' => '#{kitten_cfg['name']}'", MU::NOTICE
|
|
307
339
|
break
|
|
308
340
|
end
|
|
309
341
|
}
|
|
310
342
|
}
|
|
343
|
+
walltimers[type] ||= 0
|
|
344
|
+
walltimers[type] += (Time.now - typestart)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
timers.each_pair { |type, resources|
|
|
349
|
+
next if resources.empty?
|
|
350
|
+
total = resources.values.sum
|
|
351
|
+
top_5 = resources.keys.sort { |a, b|
|
|
352
|
+
resources[b] <=> resources[a]
|
|
353
|
+
}.slice(0, 5).map { |k|
|
|
354
|
+
k.to_s+": "+sprintf("%.2fs", resources[k])
|
|
311
355
|
}
|
|
356
|
+
if walltimers[type] < 45
|
|
357
|
+
MU.log "Kittened #{resources.size.to_s} eligible #{type}s in #{sprintf("%.2fs", walltimers[type])}"
|
|
358
|
+
else
|
|
359
|
+
MU.log "Kittened #{resources.size.to_s} eligible #{type}s in #{sprintf("%.2fs", walltimers[type])} (CPU time #{sprintf("%.2fs", total)}, avg #{sprintf("%.2fs", total/resources.size)}). Top 5:", MU::NOTICE, details: top_5
|
|
360
|
+
end
|
|
312
361
|
}
|
|
313
362
|
|
|
314
363
|
# No matching resources isn't necessarily an error
|
|
@@ -317,23 +366,36 @@ module MU
|
|
|
317
366
|
# Now walk through all of the Refs in these objects, resolve them, and minimize
|
|
318
367
|
# their config footprint
|
|
319
368
|
MU.log "Minimizing footprint of #{count.to_s} found resources", MU::DEBUG
|
|
320
|
-
@boks[bok['appname']] = vacuum(bok, origin: origin, save: @savedeploys)
|
|
321
369
|
|
|
322
|
-
|
|
370
|
+
generated_deploy = generateStubDeploy(bok)
|
|
371
|
+
@boks[bok['appname']] = vacuum(bok, origin: @origins[appname], deploy: generated_deploy, save: @savedeploys)
|
|
372
|
+
|
|
373
|
+
if @diff and !@existing_deploys[appname]
|
|
323
374
|
MU.log "diff flag set, but no comparable deploy provided for #{bok['appname']}", MU::ERR
|
|
324
375
|
exit 1
|
|
325
376
|
end
|
|
326
377
|
|
|
327
|
-
if
|
|
328
|
-
|
|
378
|
+
if @diff
|
|
379
|
+
prev_vacuumed = vacuum(@existing_deploys[appname].original_config, deploy: @existing_deploys[appname], keep_missing: true, copy_from: generated_deploy)
|
|
380
|
+
prevcfg = MU::Config.manxify(prev_vacuumed)
|
|
329
381
|
if !prevcfg
|
|
330
|
-
MU.log "#{
|
|
382
|
+
MU.log "#{@existing_deploys[appname].deploy_id} didn't have a working original config for me to compare", MU::ERR
|
|
331
383
|
exit 1
|
|
332
384
|
end
|
|
333
385
|
newcfg = MU::Config.manxify(@boks[bok['appname']])
|
|
386
|
+
report = prevcfg.diff(newcfg)
|
|
387
|
+
|
|
388
|
+
if report
|
|
389
|
+
|
|
390
|
+
if MU.muCfg['adopt_change_notify']
|
|
391
|
+
notifyChanges(@existing_deploys[appname], report.freeze)
|
|
392
|
+
end
|
|
393
|
+
if @merge
|
|
394
|
+
MU.log "Saving changes to #{@existing_deploys[appname].deploy_id}"
|
|
395
|
+
@existing_deploys[appname].updateBasketofKittens(newcfg, save_now: true)
|
|
396
|
+
end
|
|
397
|
+
end
|
|
334
398
|
|
|
335
|
-
prevcfg.diff(newcfg)
|
|
336
|
-
exit
|
|
337
399
|
end
|
|
338
400
|
}
|
|
339
401
|
@boks
|
|
@@ -341,6 +403,183 @@ module MU
|
|
|
341
403
|
|
|
342
404
|
private
|
|
343
405
|
|
|
406
|
+
# @param tier [Hash]
|
|
407
|
+
# @param parent_key [String]
|
|
408
|
+
def crawlChangeReport(tier, parent_key = nil, indent: "")
|
|
409
|
+
report = []
|
|
410
|
+
if tier.is_a?(Array)
|
|
411
|
+
tier.each { |a|
|
|
412
|
+
sub_report = crawlChangeReport(a, parent_key)
|
|
413
|
+
report.concat(sub_report) if sub_report and !sub_report.empty?
|
|
414
|
+
}
|
|
415
|
+
elsif tier.is_a?(Hash)
|
|
416
|
+
if tier[:action]
|
|
417
|
+
preposition = if tier[:action] == :added
|
|
418
|
+
"to"
|
|
419
|
+
elsif tier[:action] == :removed
|
|
420
|
+
"from"
|
|
421
|
+
else
|
|
422
|
+
"in"
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
name = ""
|
|
426
|
+
type_of = parent_key.sub(/s$|\[.*/, '') if parent_key
|
|
427
|
+
loc = tier[:habitat]
|
|
428
|
+
|
|
429
|
+
if tier[:value] and tier[:value].is_a?(Hash)
|
|
430
|
+
name, loc = MU::MommaCat.getChunkName(tier[:value], type_of)
|
|
431
|
+
elsif parent_key
|
|
432
|
+
name = parent_key
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
path_str = []
|
|
436
|
+
slack_path_str = ""
|
|
437
|
+
if tier[:parents] and tier[:parents].size > 2
|
|
438
|
+
path = tier[:parents].clone
|
|
439
|
+
slack_path_str += "#{preposition} \*"+path.join(" ⇨ ")+"\*" if path.size > 0
|
|
440
|
+
path.shift
|
|
441
|
+
path.shift
|
|
442
|
+
path.pop if path.last == name
|
|
443
|
+
for c in (0..(path.size-1)) do
|
|
444
|
+
path_str << (" " * (c+2)) + (path[c] || "<nil>")
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
path_str << "" if !path_str.empty?
|
|
448
|
+
|
|
449
|
+
plain = (name ? name : type_of) if name or type_of
|
|
450
|
+
plain ||= "" # XXX but this is a problem
|
|
451
|
+
slack = "`"+plain+"`"
|
|
452
|
+
|
|
453
|
+
plain += " ("+loc+")" if loc and !loc.empty?
|
|
454
|
+
color = plain
|
|
455
|
+
|
|
456
|
+
if tier[:action] == :added
|
|
457
|
+
color = "+ ".green + plain
|
|
458
|
+
plain = "+ " + plain
|
|
459
|
+
slack += " added"
|
|
460
|
+
elsif tier[:action] == :removed
|
|
461
|
+
color = "- ".red + plain
|
|
462
|
+
plain = "- " + plain
|
|
463
|
+
slack += " removed"
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
slack += " #{tier[:action]} #{preposition} \*#{loc}\*" if loc and !loc.empty? and [Array, Hash].include?(tier[:value].class)
|
|
467
|
+
|
|
468
|
+
plain = path_str.join(" => \n") + indent + plain
|
|
469
|
+
color = path_str.join(" => \n") + indent + color
|
|
470
|
+
|
|
471
|
+
slack += " "+slack_path_str if !slack_path_str.empty?
|
|
472
|
+
myreport = {
|
|
473
|
+
"slack" => slack,
|
|
474
|
+
"plain" => plain,
|
|
475
|
+
"color" => color
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
append = ""
|
|
479
|
+
if tier[:value] and (tier[:value].is_a?(Array) or tier[:value].is_a?(Hash))
|
|
480
|
+
if tier[:value].is_a?(Hash)
|
|
481
|
+
if name
|
|
482
|
+
tier[:value].delete("entity")
|
|
483
|
+
tier[:value].delete(name.sub(/\[.*/, '')) if name
|
|
484
|
+
end
|
|
485
|
+
if (tier[:value].keys - ["id", "name", "type"]).size > 0
|
|
486
|
+
myreport["details"] = tier[:value].clone
|
|
487
|
+
append = PP.pp(tier[:value], '').gsub(/(^|\n)/, '\1'+indent)
|
|
488
|
+
end
|
|
489
|
+
else
|
|
490
|
+
append = indent+"["+tier[:value].map { |v| MU::MommaCat.getChunkName(v, type_of).reverse.join("/") || v.to_s.light_blue }.join(", ")+"]"
|
|
491
|
+
slack += " #{tier[:action].to_s}: "+tier[:value].map { |v| MU::MommaCat.getChunkName(v, type_of).reverse.join("/") || v.to_s }.join(", ")
|
|
492
|
+
end
|
|
493
|
+
else
|
|
494
|
+
tier[:value] ||= "<nil>"
|
|
495
|
+
if ![:removed].include?(tier[:action])
|
|
496
|
+
myreport["slack"] += ". New #{tier[:field] ? "`"+tier[:field]+"`" : :value}: \*#{tier[:value]}\*"
|
|
497
|
+
else
|
|
498
|
+
myreport["slack"] += " (was \*#{tier[:value]}\*)"
|
|
499
|
+
end
|
|
500
|
+
append = tier[:value].to_s.bold
|
|
501
|
+
end
|
|
502
|
+
|
|
503
|
+
if append and !append.empty?
|
|
504
|
+
myreport["plain"] += " =>\n "+indent+append
|
|
505
|
+
myreport["color"] += " =>\n "+indent+append
|
|
506
|
+
end
|
|
507
|
+
|
|
508
|
+
report << myreport if tier[:action]
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
# Just because we've got changes at this level doesn't mean there aren't
|
|
512
|
+
# more further down.
|
|
513
|
+
tier.each_pair { |k, v|
|
|
514
|
+
next if !(v.is_a?(Hash) or v.is_a?(Array))
|
|
515
|
+
sub_report = crawlChangeReport(v, k, indent: indent+" ")
|
|
516
|
+
report.concat(sub_report) if sub_report and !sub_report.empty?
|
|
517
|
+
}
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
report
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def notifyChanges(deploy, report)
|
|
525
|
+
snippet_threshold = (MU.muCfg['adopt_change_notify'] && MU.muCfg['adopt_change_notify']['slack_snippet_threshold']) || 5
|
|
526
|
+
|
|
527
|
+
report.each_pair { |res_type, resources|
|
|
528
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(res_type, false)
|
|
529
|
+
next if !shortclass # we don't really care about Mu metadata changes
|
|
530
|
+
resources.each_pair { |name, data|
|
|
531
|
+
if MU::MommaCat.getChunkName(data[:value], res_type).first.nil?
|
|
532
|
+
symbol = if data[:action] == :added
|
|
533
|
+
"+".green
|
|
534
|
+
elsif data[:action] == :removed
|
|
535
|
+
"-".red
|
|
536
|
+
else
|
|
537
|
+
"~".yellow
|
|
538
|
+
end
|
|
539
|
+
puts (symbol+" "+res_type+"["+name+"]")
|
|
540
|
+
end
|
|
541
|
+
|
|
542
|
+
noun = shortclass ? shortclass.to_s : res_type.capitalize
|
|
543
|
+
verb = if data[:action]
|
|
544
|
+
data[:action].to_s
|
|
545
|
+
else
|
|
546
|
+
"modified"
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
changes = crawlChangeReport(data.freeze, res_type)
|
|
550
|
+
|
|
551
|
+
slacktext = "#{noun} \*#{name}\* was #{verb}"
|
|
552
|
+
if data[:habitat]
|
|
553
|
+
slacktext += " in \*#{data[:habitat]}\*"
|
|
554
|
+
end
|
|
555
|
+
snippets = []
|
|
556
|
+
|
|
557
|
+
if [:added, :removed].include?(data[:action]) and data[:value]
|
|
558
|
+
snippets << { text: "```"+JSON.pretty_generate(data[:value])+"```" }
|
|
559
|
+
else
|
|
560
|
+
changes.each { |c|
|
|
561
|
+
slacktext += "\n • "+c["slack"]
|
|
562
|
+
if c["details"]
|
|
563
|
+
details = JSON.pretty_generate(c["details"])
|
|
564
|
+
snippets << { text: "```"+JSON.pretty_generate(c["details"])+"```" }
|
|
565
|
+
end
|
|
566
|
+
}
|
|
567
|
+
end
|
|
568
|
+
|
|
569
|
+
changes.each { |c|
|
|
570
|
+
puts c["color"]
|
|
571
|
+
}
|
|
572
|
+
puts ""
|
|
573
|
+
|
|
574
|
+
if MU.muCfg['adopt_change_notify'] and MU.muCfg['adopt_change_notify']['slack']
|
|
575
|
+
deploy.sendAdminSlack(slacktext, scrub_mu_isms: MU.muCfg['adopt_scrub_mu_isms'], snippets: snippets, noop: false)
|
|
576
|
+
end
|
|
577
|
+
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
end
|
|
582
|
+
|
|
344
583
|
def scrubSchemaDefaults(conf_chunk, schema_chunk, depth = 0, type: nil)
|
|
345
584
|
return if schema_chunk.nil?
|
|
346
585
|
|
|
@@ -372,8 +611,7 @@ module MU
|
|
|
372
611
|
# theory
|
|
373
612
|
realschema = if type and schema_chunk["items"] and schema_chunk["items"]["properties"] and item["cloud"] and MU::Cloud.supportedClouds.include?(item['cloud'])
|
|
374
613
|
|
|
375
|
-
|
|
376
|
-
_toplevel_required, cloudschema = cloudclass.schema(self)
|
|
614
|
+
_toplevel_required, cloudschema = MU::Cloud.resourceClass(item['cloud'], type).schema(self)
|
|
377
615
|
|
|
378
616
|
newschema = schema_chunk["items"].dup
|
|
379
617
|
newschema["properties"].merge!(cloudschema)
|
|
@@ -397,8 +635,7 @@ module MU
|
|
|
397
635
|
# Do the same for our main objects: if they all use the same credentials,
|
|
398
636
|
# for example, remove the explicit +credentials+ attributes and set that
|
|
399
637
|
# value globally, once.
|
|
400
|
-
def vacuum(bok, origin: nil, save: false, deploy: nil)
|
|
401
|
-
deploy ||= generateStubDeploy(bok)
|
|
638
|
+
def vacuum(bok, origin: nil, save: false, deploy: nil, copy_from: nil, keep_missing: false)
|
|
402
639
|
|
|
403
640
|
globals = {
|
|
404
641
|
'cloud' => {},
|
|
@@ -418,11 +655,24 @@ module MU
|
|
|
418
655
|
end
|
|
419
656
|
}
|
|
420
657
|
obj = deploy.findLitterMate(type: attrs[:cfg_plural], name: resource['name'])
|
|
658
|
+
inject_metadata = save
|
|
659
|
+
if obj.nil? and copy_from
|
|
660
|
+
obj = copy_from.findLitterMate(type: attrs[:cfg_plural], name: resource['name'])
|
|
661
|
+
if obj
|
|
662
|
+
inject_metadata = true
|
|
663
|
+
obj.intoDeploy(deploy, force: true)
|
|
664
|
+
end
|
|
665
|
+
end
|
|
666
|
+
|
|
421
667
|
begin
|
|
422
668
|
raise Incomplete if obj.nil?
|
|
669
|
+
if inject_metadata
|
|
670
|
+
deploydata = obj.notify
|
|
671
|
+
deploy.notify(attrs[:cfg_plural], resource['name'], deploydata, triggering_node: obj)
|
|
672
|
+
end
|
|
423
673
|
new_cfg = resolveReferences(resource, deploy, obj)
|
|
424
674
|
new_cfg.delete("cloud_id")
|
|
425
|
-
cred_cfg = MU::Cloud.
|
|
675
|
+
cred_cfg = MU::Cloud.cloudClass(obj.cloud).credConfig(obj.credentials)
|
|
426
676
|
if cred_cfg['region'] == new_cfg['region']
|
|
427
677
|
new_cfg.delete('region')
|
|
428
678
|
end
|
|
@@ -432,6 +682,11 @@ module MU
|
|
|
432
682
|
end
|
|
433
683
|
processed << new_cfg
|
|
434
684
|
rescue Incomplete
|
|
685
|
+
if keep_missing
|
|
686
|
+
processed << resource
|
|
687
|
+
else
|
|
688
|
+
MU.log "#{attrs[:cfg_name]} #{resource['name']} didn't show up from findLitterMate", MU::WARN, details: deploy.original_config[attrs[:cfg_plural]].reject { |r| r['name'] != "" }
|
|
689
|
+
end
|
|
435
690
|
end
|
|
436
691
|
}
|
|
437
692
|
|
|
@@ -442,24 +697,23 @@ module MU
|
|
|
442
697
|
|
|
443
698
|
# Pare out global values like +cloud+ or +region+ that appear to be
|
|
444
699
|
# universal in the deploy we're creating.
|
|
445
|
-
|
|
700
|
+
scrub_globals = Proc.new { |h, field|
|
|
446
701
|
if h.is_a?(Hash)
|
|
447
702
|
newhash = {}
|
|
448
703
|
h.each_pair { |k, v|
|
|
449
704
|
next if k == field
|
|
450
|
-
newhash[k] = scrub_globals(v, field)
|
|
705
|
+
newhash[k] = scrub_globals.call(v, field)
|
|
451
706
|
}
|
|
452
707
|
h = newhash
|
|
453
708
|
elsif h.is_a?(Array)
|
|
454
709
|
newarr = []
|
|
455
710
|
h.each { |v|
|
|
456
|
-
newarr << scrub_globals(v, field)
|
|
711
|
+
newarr << scrub_globals.call(v, field)
|
|
457
712
|
}
|
|
458
|
-
h = newarr
|
|
713
|
+
h = newarr.uniq
|
|
459
714
|
end
|
|
460
|
-
|
|
461
715
|
h
|
|
462
|
-
|
|
716
|
+
}
|
|
463
717
|
|
|
464
718
|
globals.each_pair { |field, counts|
|
|
465
719
|
next if counts.size != 1
|
|
@@ -469,7 +723,7 @@ module MU
|
|
|
469
723
|
if bok[attrs[:cfg_plural]]
|
|
470
724
|
new_resources = []
|
|
471
725
|
bok[attrs[:cfg_plural]].each { |resource|
|
|
472
|
-
new_resources << scrub_globals(resource, field)
|
|
726
|
+
new_resources << scrub_globals.call(resource, field)
|
|
473
727
|
}
|
|
474
728
|
bok[attrs[:cfg_plural]] = new_resources
|
|
475
729
|
end
|
|
@@ -487,11 +741,33 @@ module MU
|
|
|
487
741
|
end
|
|
488
742
|
|
|
489
743
|
def resolveReferences(cfg, deploy, parent)
|
|
744
|
+
mask_deploy_id = false
|
|
745
|
+
|
|
746
|
+
check_deploy_id = Proc.new { |cfgblob|
|
|
747
|
+
(deploy and
|
|
748
|
+
(cfgblob.is_a?(MU::Config::Ref) or cfgblob.is_a?(Hash)) and
|
|
749
|
+
cfgblob['deploy_id'] and
|
|
750
|
+
cfgblob['deploy_id'] != deploy.deploy_id and
|
|
751
|
+
@diff and
|
|
752
|
+
@types_found_in[cfgblob['type']] and
|
|
753
|
+
@types_found_in[cfgblob['type']].deploy_id == cfgblob['deploy_id']
|
|
754
|
+
)
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
mask_deploy_id = check_deploy_id.call(cfg)
|
|
758
|
+
|
|
490
759
|
if cfg.is_a?(MU::Config::Ref)
|
|
491
|
-
|
|
760
|
+
if mask_deploy_id
|
|
761
|
+
cfg.delete("deploy_id")
|
|
762
|
+
cfg.delete("mommacat")
|
|
763
|
+
cfg.kitten(deploy)
|
|
764
|
+
else
|
|
765
|
+
cfg.kitten(deploy) || cfg.kitten
|
|
766
|
+
end
|
|
767
|
+
|
|
492
768
|
hashcfg = cfg.to_h
|
|
493
769
|
|
|
494
|
-
if cfg.kitten
|
|
770
|
+
if cfg.kitten
|
|
495
771
|
littermate = deploy.findLitterMate(type: cfg.type, name: cfg.name, cloud_id: cfg.id, habitat: cfg.habitat)
|
|
496
772
|
|
|
497
773
|
if littermate and littermate.config['name']
|
|
@@ -516,13 +792,12 @@ module MU
|
|
|
516
792
|
elsif hashcfg["id"] and !hashcfg["name"]
|
|
517
793
|
hashcfg.delete("deploy_id")
|
|
518
794
|
else
|
|
519
|
-
|
|
520
|
-
raise Incomplete, "Failed to resolve reference on behalf of #{parent}"
|
|
795
|
+
raise Incomplete.new "Failed to resolve reference on behalf of #{parent}", details: hashcfg
|
|
521
796
|
end
|
|
522
797
|
hashcfg.delete("deploy_id") if hashcfg['deploy_id'] == deploy.deploy_id
|
|
523
798
|
|
|
524
799
|
if parent and parent.config
|
|
525
|
-
cred_cfg = MU::Cloud.
|
|
800
|
+
cred_cfg = MU::Cloud.cloudClass(parent.cloud).credConfig(parent.credentials)
|
|
526
801
|
|
|
527
802
|
if parent.config['region'] == hashcfg['region'] or
|
|
528
803
|
cred_cfg['region'] == hashcfg['region']
|
|
@@ -581,7 +856,12 @@ module MU
|
|
|
581
856
|
MU.log "Dropping unresolved value", MU::WARN, details: value
|
|
582
857
|
end
|
|
583
858
|
}
|
|
584
|
-
cfg = new_array
|
|
859
|
+
cfg = new_array.uniq
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
if mask_deploy_id or check_deploy_id.call(cfg)
|
|
863
|
+
cfg.delete("deploy_id")
|
|
864
|
+
MU.log "#{parent} in #{deploy.deploy_id} references something in #{@types_found_in[cfg['type']].deploy_id}, ditching extraneous deploy_id", MU::DEBUG, details: cfg.to_h
|
|
585
865
|
end
|
|
586
866
|
|
|
587
867
|
cfg
|
|
@@ -631,6 +911,10 @@ module MU
|
|
|
631
911
|
|
|
632
912
|
if !@scraped[typename][kitten['cloud_id']]
|
|
633
913
|
MU.log "No object in scraped tree for #{attrs[:cfg_name]} #{kitten['cloud_id']} (#{kitten['name']})", MU::ERR, details: kitten
|
|
914
|
+
if kitten['cloud_id'].nil?
|
|
915
|
+
pp caller
|
|
916
|
+
exit
|
|
917
|
+
end
|
|
634
918
|
next
|
|
635
919
|
end
|
|
636
920
|
|
|
@@ -641,7 +925,8 @@ module MU
|
|
|
641
925
|
deploy.addKitten(
|
|
642
926
|
attrs[:cfg_plural],
|
|
643
927
|
kitten['name'],
|
|
644
|
-
@scraped[typename][kitten['cloud_id']]
|
|
928
|
+
@scraped[typename][kitten['cloud_id']],
|
|
929
|
+
do_notify: true
|
|
645
930
|
)
|
|
646
931
|
}
|
|
647
932
|
end
|
|
@@ -650,6 +935,21 @@ module MU
|
|
|
650
935
|
deploy
|
|
651
936
|
end
|
|
652
937
|
|
|
938
|
+
def self.deDuplicateName(kitten_cfg, res_class)
|
|
939
|
+
orig_name = kitten_cfg['name'].dup
|
|
940
|
+
if kitten_cfg['parent'] and kitten_cfg['parent'].respond_to?(:id) and kitten_cfg['parent'].id
|
|
941
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['parent'].id
|
|
942
|
+
elsif kitten_cfg['project']
|
|
943
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['project']
|
|
944
|
+
elsif kitten_cfg['region']
|
|
945
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['region']
|
|
946
|
+
elsif kitten_cfg['cloud_id']
|
|
947
|
+
kitten_cfg['name'] = kitten_cfg['name']+"-"+kitten_cfg['cloud_id'].gsub(/[^a-z0-9]/i, "-")
|
|
948
|
+
else
|
|
949
|
+
raise MU::Config::DuplicateNameError, "Saw duplicate #{res_class.cfg_name} name #{orig_name} and couldn't come up with a good way to differentiate them"
|
|
950
|
+
end
|
|
951
|
+
end
|
|
952
|
+
|
|
653
953
|
# Go through everything we've scraped and update our mappings of cloud ids
|
|
654
954
|
# and bare name fields, so that resources can reference one another
|
|
655
955
|
# portably by name.
|