cloud-mu 3.0.0beta → 3.0.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/README.md +17 -8
- data/ansible/roles/mu-nat/README.md +33 -0
- data/ansible/roles/mu-nat/defaults/main.yml +3 -0
- data/ansible/roles/mu-nat/handlers/main.yml +2 -0
- data/ansible/roles/mu-nat/meta/main.yml +60 -0
- data/ansible/roles/mu-nat/tasks/main.yml +65 -0
- data/ansible/roles/mu-nat/tests/inventory +2 -0
- data/ansible/roles/mu-nat/tests/test.yml +5 -0
- data/ansible/roles/mu-nat/vars/main.yml +2 -0
- data/bin/mu-cleanup +2 -1
- data/bin/mu-configure +950 -948
- data/bin/mu-gen-docs +6 -0
- data/cloud-mu.gemspec +2 -2
- data/cookbooks/mu-tools/recipes/gcloud.rb +8 -1
- data/modules/mommacat.ru +1 -1
- data/modules/mu.rb +31 -39
- data/modules/mu/cloud.rb +11 -1
- data/modules/mu/clouds/aws.rb +8 -3
- data/modules/mu/clouds/aws/alarm.rb +5 -8
- data/modules/mu/clouds/aws/bucket.rb +15 -9
- data/modules/mu/clouds/aws/cache_cluster.rb +60 -26
- data/modules/mu/clouds/aws/collection.rb +4 -4
- data/modules/mu/clouds/aws/container_cluster.rb +50 -33
- data/modules/mu/clouds/aws/database.rb +25 -21
- data/modules/mu/clouds/aws/dnszone.rb +12 -14
- data/modules/mu/clouds/aws/endpoint.rb +5 -8
- data/modules/mu/clouds/aws/firewall_rule.rb +9 -4
- data/modules/mu/clouds/aws/folder.rb +4 -7
- data/modules/mu/clouds/aws/function.rb +5 -8
- data/modules/mu/clouds/aws/group.rb +5 -8
- data/modules/mu/clouds/aws/habitat.rb +2 -5
- data/modules/mu/clouds/aws/loadbalancer.rb +12 -16
- data/modules/mu/clouds/aws/log.rb +6 -9
- data/modules/mu/clouds/aws/msg_queue.rb +16 -19
- data/modules/mu/clouds/aws/nosqldb.rb +27 -18
- data/modules/mu/clouds/aws/notifier.rb +6 -9
- data/modules/mu/clouds/aws/role.rb +4 -7
- data/modules/mu/clouds/aws/search_domain.rb +50 -23
- data/modules/mu/clouds/aws/server.rb +20 -14
- data/modules/mu/clouds/aws/server_pool.rb +22 -12
- data/modules/mu/clouds/aws/storage_pool.rb +9 -14
- data/modules/mu/clouds/aws/user.rb +5 -8
- data/modules/mu/clouds/aws/userdata/linux.erb +7 -1
- data/modules/mu/clouds/aws/vpc.rb +16 -14
- data/modules/mu/clouds/azure.rb +1 -1
- data/modules/mu/clouds/azure/container_cluster.rb +1 -1
- data/modules/mu/clouds/azure/server.rb +16 -2
- data/modules/mu/clouds/azure/user.rb +1 -1
- data/modules/mu/clouds/azure/userdata/linux.erb +84 -80
- data/modules/mu/clouds/azure/vpc.rb +32 -13
- data/modules/mu/clouds/cloudformation/server.rb +1 -1
- data/modules/mu/clouds/google.rb +2 -3
- data/modules/mu/clouds/google/container_cluster.rb +9 -1
- data/modules/mu/clouds/google/firewall_rule.rb +6 -0
- data/modules/mu/clouds/google/role.rb +1 -3
- data/modules/mu/clouds/google/server.rb +25 -4
- data/modules/mu/clouds/google/user.rb +1 -1
- data/modules/mu/clouds/google/userdata/linux.erb +9 -5
- data/modules/mu/clouds/google/vpc.rb +102 -21
- data/modules/mu/config.rb +250 -49
- data/modules/mu/config/alarm.rb +1 -0
- data/modules/mu/config/container_cluster.yml +0 -1
- data/modules/mu/config/database.yml +4 -1
- data/modules/mu/config/search_domain.yml +4 -3
- data/modules/mu/config/server.rb +7 -3
- data/modules/mu/config/server.yml +4 -1
- data/modules/mu/config/server_pool.yml +2 -0
- data/modules/mu/config/vpc.rb +42 -29
- data/modules/mu/deploy.rb +12 -5
- data/modules/mu/groomers/ansible.rb +4 -1
- data/modules/mu/groomers/chef.rb +5 -1
- data/modules/mu/kittens.rb +60 -11
- data/modules/mu/logger.rb +6 -4
- data/modules/mu/mommacat.rb +39 -19
- data/modules/mu/mu.yaml.rb +276 -0
- metadata +13 -4
data/modules/mu/config.rb
CHANGED
@@ -212,23 +212,25 @@ module MU
|
|
212
212
|
# layers that don't care about the metadata in Tails.
|
213
213
|
# @param config [Hash]: The configuration tree to convert
|
214
214
|
# @return [Hash]: The modified configuration
|
215
|
-
def self.manxify(config)
|
215
|
+
def self.manxify(config, remove_runtime_keys: false)
|
216
216
|
if config.is_a?(Hash)
|
217
217
|
newhash = {}
|
218
218
|
config.each_pair { |key, val|
|
219
|
-
|
219
|
+
next if remove_runtime_keys and key.match(/^#MU_/)
|
220
|
+
next if val.is_a?(Array) and val.empty?
|
221
|
+
newhash[key] = self.manxify(val, remove_runtime_keys: remove_runtime_keys)
|
220
222
|
}
|
221
223
|
config = newhash
|
222
224
|
elsif config.is_a?(Array)
|
223
225
|
newarray = []
|
224
226
|
config.each { |val|
|
225
|
-
newarray << self.manxify(val)
|
227
|
+
newarray << self.manxify(val, remove_runtime_keys: remove_runtime_keys)
|
226
228
|
}
|
227
229
|
config = newarray
|
228
230
|
elsif config.is_a?(MU::Config::Tail)
|
229
231
|
return config.to_s
|
230
232
|
elsif config.is_a?(MU::Config::Ref)
|
231
|
-
return config.to_h
|
233
|
+
return self.manxify(config.to_h, remove_runtime_keys: remove_runtime_keys)
|
232
234
|
end
|
233
235
|
return config
|
234
236
|
end
|
@@ -238,7 +240,7 @@ module MU
|
|
238
240
|
# @param config [Hash]
|
239
241
|
# @return [Hash]
|
240
242
|
def self.stripConfig(config)
|
241
|
-
MU::Config.manxify(Marshal.load(Marshal.dump(MU.structToHash(config.dup))))
|
243
|
+
MU::Config.manxify(Marshal.load(Marshal.dump(MU.structToHash(config.dup))), remove_runtime_keys: true)
|
242
244
|
end
|
243
245
|
|
244
246
|
# A wrapper class for resources to refer to other resources, whether they
|
@@ -334,7 +336,7 @@ module MU
|
|
334
336
|
end
|
335
337
|
|
336
338
|
if @deploy_id and !@mommacat
|
337
|
-
@mommacat = MU::MommaCat.
|
339
|
+
@mommacat = MU::MommaCat.getLitter(@deploy_id, set_context_to_me: false)
|
338
340
|
elsif @mommacat and !@deploy_id
|
339
341
|
@deploy_id = @mommacat.deploy_id
|
340
342
|
end
|
@@ -569,6 +571,7 @@ return
|
|
569
571
|
|
570
572
|
def initialize(name, value, prettyname = nil, cloudtype = "String", valid_values = [], description = "", is_list_element = false, prefix: "", suffix: "", pseudo: false, runtimecode: nil, index: 0)
|
571
573
|
@name = name
|
574
|
+
@bindings = {}
|
572
575
|
@value = value
|
573
576
|
@valid_values = valid_values
|
574
577
|
@pseudo = pseudo
|
@@ -764,7 +767,7 @@ return
|
|
764
767
|
|
765
768
|
# Make sure our parameter values are all available in the local namespace
|
766
769
|
# that ERB will be using, minus any that conflict with existing variables
|
767
|
-
erb_binding = get_binding
|
770
|
+
erb_binding = get_binding(@@tails.keys.sort)
|
768
771
|
@@tails.each_pair { |key, tail|
|
769
772
|
next if !tail.is_a?(MU::Config::Tail) or tail.is_list_element
|
770
773
|
# XXX figure out what to do with lists
|
@@ -801,7 +804,7 @@ return
|
|
801
804
|
|
802
805
|
begin
|
803
806
|
config = JSON.parse(raw_json)
|
804
|
-
if param_pass
|
807
|
+
if param_pass and config.is_a?(Hash)
|
805
808
|
config.keys.each { |key|
|
806
809
|
if key != "parameters"
|
807
810
|
if key == "appname" and @@parameters["myAppName"].nil?
|
@@ -812,7 +815,7 @@ return
|
|
812
815
|
config.delete(key)
|
813
816
|
end
|
814
817
|
}
|
815
|
-
|
818
|
+
elsif config.is_a?(Hash)
|
816
819
|
config.delete("parameters")
|
817
820
|
end
|
818
821
|
rescue JSON::ParserError => e
|
@@ -833,6 +836,7 @@ return
|
|
833
836
|
|
834
837
|
attr_reader :kittens
|
835
838
|
attr_reader :updating
|
839
|
+
attr_reader :existing_deploy
|
836
840
|
attr_reader :kittencfg_semaphore
|
837
841
|
|
838
842
|
# Load, resolve, and validate a configuration file ("Basket of Kittens").
|
@@ -858,6 +862,9 @@ return
|
|
858
862
|
@admin_firewall_rules = []
|
859
863
|
@skipinitialupdates = skipinitialupdates
|
860
864
|
@updating = updating
|
865
|
+
if @updating
|
866
|
+
@existing_deploy = MU::MommaCat.new(@updating)
|
867
|
+
end
|
861
868
|
@default_credentials = default_credentials
|
862
869
|
|
863
870
|
ok = true
|
@@ -1035,21 +1042,80 @@ return
|
|
1035
1042
|
end
|
1036
1043
|
end
|
1037
1044
|
|
1045
|
+
# Generate a documentation-friendly dummy Ruby class for our mu.yaml main
|
1046
|
+
# config.
|
1047
|
+
def self.emitConfigAsRuby
|
1048
|
+
example = %Q{---
|
1049
|
+
public_address: 1.2.3.4
|
1050
|
+
mu_admin_email: egtlabs@eglobaltech.com
|
1051
|
+
mu_admin_name: Joe Schmoe
|
1052
|
+
mommacat_port: 2260
|
1053
|
+
banner: My Example Mu Master
|
1054
|
+
mu_repository: git://github.com/cloudamatic/mu.git
|
1055
|
+
repos:
|
1056
|
+
- https://github.com/cloudamatic/mu_demo_platform
|
1057
|
+
allow_invade_foreign_vpcs: true
|
1058
|
+
ansible_dir:
|
1059
|
+
aws:
|
1060
|
+
egtdev:
|
1061
|
+
region: us-east-1
|
1062
|
+
log_bucket_name: egt-mu-log-bucket
|
1063
|
+
default: true
|
1064
|
+
name: egtdev
|
1065
|
+
personal:
|
1066
|
+
region: us-east-2
|
1067
|
+
log_bucket_name: my-mu-log-bucket
|
1068
|
+
name: personal
|
1069
|
+
google:
|
1070
|
+
egtlabs:
|
1071
|
+
project: egt-labs-admin
|
1072
|
+
credentials_file: /opt/mu/etc/google.json
|
1073
|
+
region: us-east4
|
1074
|
+
log_bucket_name: hexabucket-761234
|
1075
|
+
default: true
|
1076
|
+
}
|
1077
|
+
mu_yaml_schema = eval(%Q{
|
1078
|
+
$NOOP = true
|
1079
|
+
load "#{MU.myRoot}/bin/mu-configure"
|
1080
|
+
$CONFIGURABLES
|
1081
|
+
})
|
1082
|
+
return if mu_yaml_schema.nil? or !mu_yaml_schema.is_a?(Hash)
|
1083
|
+
muyamlpath = "#{MU.myRoot}/modules/mu/mu.yaml.rb"
|
1084
|
+
MU.log "Converting mu.yaml schema to Ruby objects in #{muyamlpath}"
|
1085
|
+
muyaml_rb = File.new(muyamlpath, File::CREAT|File::TRUNC|File::RDWR, 0644)
|
1086
|
+
muyaml_rb.puts "# Configuration schema for mu.yaml. See also {https://github.com/cloudamatic/mu/wiki/Configuration the Mu wiki}."
|
1087
|
+
muyaml_rb.puts "#"
|
1088
|
+
muyaml_rb.puts "# Example:"
|
1089
|
+
muyaml_rb.puts "#"
|
1090
|
+
muyaml_rb.puts "# <pre>"
|
1091
|
+
example.split(/\n/).each { |line|
|
1092
|
+
muyaml_rb.puts "# "+line+" " # markdooooown
|
1093
|
+
}
|
1094
|
+
muyaml_rb.puts "# </pre>"
|
1095
|
+
muyaml_rb.puts "module MuYAML"
|
1096
|
+
muyaml_rb.puts "\t# The configuration file format for Mu's main config file."
|
1097
|
+
self.printMuYamlSchema(muyaml_rb, [], { "subtree" => mu_yaml_schema })
|
1098
|
+
muyaml_rb.puts "end"
|
1099
|
+
muyaml_rb.close
|
1100
|
+
end
|
1101
|
+
|
1038
1102
|
# Take the schema we've defined and create a dummy Ruby class tree out of
|
1039
1103
|
# it, basically so we can leverage Yard to document it.
|
1040
1104
|
def self.emitSchemaAsRuby
|
1041
1105
|
kittenpath = "#{MU.myRoot}/modules/mu/kittens.rb"
|
1042
1106
|
MU.log "Converting Basket of Kittens schema to Ruby objects in #{kittenpath}"
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1107
|
+
kitten_rb = File.new(kittenpath, File::CREAT|File::TRUNC|File::RDWR, 0644)
|
1108
|
+
kitten_rb.puts "### THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT ###"
|
1109
|
+
kitten_rb.puts "#"
|
1110
|
+
kitten_rb.puts "#"
|
1111
|
+
kitten_rb.puts "#"
|
1112
|
+
kitten_rb.puts "module MU"
|
1113
|
+
kitten_rb.puts "class Config"
|
1114
|
+
kitten_rb.puts "\t# The configuration file format for Mu application stacks."
|
1115
|
+
self.printSchema(kitten_rb, ["BasketofKittens"], MU::Config.docSchema)
|
1116
|
+
kitten_rb.puts "end"
|
1117
|
+
kitten_rb.puts "end"
|
1118
|
+
kitten_rb.close
|
1053
1119
|
|
1054
1120
|
end
|
1055
1121
|
|
@@ -1066,7 +1132,6 @@ return
|
|
1066
1132
|
subnet_bits = cidr.netmask.prefix_len
|
1067
1133
|
begin
|
1068
1134
|
subnet_bits += 1
|
1069
|
-
|
1070
1135
|
if subnet_bits > max_mask
|
1071
1136
|
MU.log "Can't subdivide #{cidr.to_s} into #{subnets_desired.to_s}", MU::ERR
|
1072
1137
|
raise MuError, "Subnets smaller than /#{max_mask} not permitted"
|
@@ -1148,7 +1213,7 @@ return
|
|
1148
1213
|
# an extra pass to make sure we get all intra-stack dependencies correct.
|
1149
1214
|
# @param acl [Hash]: The configuration hash for the FirewallRule to check
|
1150
1215
|
# @return [Hash]
|
1151
|
-
def resolveIntraStackFirewallRefs(acl)
|
1216
|
+
def resolveIntraStackFirewallRefs(acl, delay_validation = false)
|
1152
1217
|
acl["rules"].each { |acl_include|
|
1153
1218
|
if acl_include['sgs']
|
1154
1219
|
acl_include['sgs'].each { |sg_ref|
|
@@ -1171,7 +1236,7 @@ return
|
|
1171
1236
|
siblingfw = haveLitterMate?(sg_ref, "firewall_rules")
|
1172
1237
|
if !siblingfw["#MU_VALIDATED"]
|
1173
1238
|
# XXX raise failure somehow
|
1174
|
-
insertKitten(siblingfw, "firewall_rules")
|
1239
|
+
insertKitten(siblingfw, "firewall_rules", delay_validation: delay_validation)
|
1175
1240
|
end
|
1176
1241
|
end
|
1177
1242
|
}
|
@@ -1185,10 +1250,15 @@ return
|
|
1185
1250
|
# @param type [String]: The type of resource being added
|
1186
1251
|
# @param delay_validation [Boolean]: Whether to hold off on calling the resource's validateConfig method
|
1187
1252
|
# @param ignore_duplicates [Boolean]: Do not raise an exception if we attempt to insert a resource with a +name+ field that's already in use
|
1188
|
-
def insertKitten(descriptor, type, delay_validation = false, ignore_duplicates: false)
|
1253
|
+
def insertKitten(descriptor, type, delay_validation = false, ignore_duplicates: false, overwrite: false)
|
1189
1254
|
append = false
|
1190
1255
|
start = Time.now
|
1191
1256
|
shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(type)
|
1257
|
+
MU.log "insertKitten on #{cfg_name} #{descriptor['name']} (delay_validation: #{delay_validation.to_s})", MU::DEBUG, details: caller[0]
|
1258
|
+
|
1259
|
+
if overwrite
|
1260
|
+
removeKitten(descriptor['name'], type)
|
1261
|
+
end
|
1192
1262
|
|
1193
1263
|
if !ignore_duplicates and haveLitterMate?(descriptor['name'], cfg_name)
|
1194
1264
|
# raise DuplicateNameError, "A #{shortclass} named #{descriptor['name']} has already been inserted into this configuration"
|
@@ -1284,7 +1354,7 @@ return
|
|
1284
1354
|
siblingvpc = haveLitterMate?(descriptor["vpc"]["name"], "vpcs")
|
1285
1355
|
|
1286
1356
|
if siblingvpc and siblingvpc['bastion'] and
|
1287
|
-
["server", "server_pool"].include?(cfg_name) and
|
1357
|
+
["server", "server_pool", "container_cluster"].include?(cfg_name) and
|
1288
1358
|
!descriptor['bastion']
|
1289
1359
|
if descriptor['name'] != siblingvpc['bastion'].to_h['name']
|
1290
1360
|
descriptor["dependencies"] << {
|
@@ -1298,7 +1368,7 @@ return
|
|
1298
1368
|
# resolved before we can proceed
|
1299
1369
|
if ["server", "server_pool", "loadbalancer", "database", "cache_cluster", "container_cluster", "storage_pool"].include?(cfg_name)
|
1300
1370
|
if !siblingvpc["#MU_VALIDATED"]
|
1301
|
-
ok = false if !insertKitten(siblingvpc, "vpcs")
|
1371
|
+
ok = false if !insertKitten(siblingvpc, "vpcs", overwrite: overwrite)
|
1302
1372
|
end
|
1303
1373
|
end
|
1304
1374
|
if !MU::Config::VPC.processReference(descriptor['vpc'],
|
@@ -1349,13 +1419,15 @@ return
|
|
1349
1419
|
# Does it have generic ingress rules?
|
1350
1420
|
fwname = cfg_name+descriptor['name']
|
1351
1421
|
|
1352
|
-
if
|
1353
|
-
|
1354
|
-
["server", "server_pool", "database"].include?(cfg_name))
|
1422
|
+
if (descriptor['ingress_rules'] or
|
1423
|
+
["server", "server_pool", "database", "cache_cluster"].include?(cfg_name))
|
1355
1424
|
descriptor['ingress_rules'] ||= []
|
1356
1425
|
fw_classobj = Object.const_get("MU").const_get("Cloud").const_get(descriptor["cloud"]).const_get("FirewallRule")
|
1357
1426
|
|
1358
|
-
acl =
|
1427
|
+
acl = haveLitterMate?(fwname, "firewall_rules")
|
1428
|
+
already_exists = !acl.nil?
|
1429
|
+
|
1430
|
+
acl ||= {
|
1359
1431
|
"name" => fwname,
|
1360
1432
|
"rules" => descriptor['ingress_rules'],
|
1361
1433
|
"region" => descriptor['region'],
|
@@ -1375,10 +1447,11 @@ return
|
|
1375
1447
|
["optional_tags", "tags", "cloud", "project"].each { |param|
|
1376
1448
|
acl[param] = descriptor[param] if descriptor[param]
|
1377
1449
|
}
|
1378
|
-
descriptor["add_firewall_rules"]
|
1450
|
+
descriptor["add_firewall_rules"] ||= []
|
1379
1451
|
descriptor["add_firewall_rules"] << {"rule_name" => fwname, "type" => "firewall_rules" } # XXX why the duck is there a type argument required here?
|
1380
|
-
|
1381
|
-
|
1452
|
+
|
1453
|
+
acl = resolveIntraStackFirewallRefs(acl, delay_validation)
|
1454
|
+
ok = false if !insertKitten(acl, "firewall_rules", delay_validation, overwrite: already_exists)
|
1382
1455
|
end
|
1383
1456
|
|
1384
1457
|
# Does it declare association with any sibling LoadBalancers?
|
@@ -1413,10 +1486,6 @@ return
|
|
1413
1486
|
"type" => "firewall_rule",
|
1414
1487
|
"name" => acl_include["rule_name"]
|
1415
1488
|
}
|
1416
|
-
siblingfw = haveLitterMate?(acl_include["rule_name"], "firewall_rules")
|
1417
|
-
if !siblingfw["#MU_VALIDATED"]
|
1418
|
-
ok = false if !insertKitten(siblingfw, "firewall_rules", delay_validation)
|
1419
|
-
end
|
1420
1489
|
elsif acl_include["rule_name"]
|
1421
1490
|
MU.log shortclass.to_s+" #{descriptor['name']} depends on FirewallRule #{acl_include["rule_name"]}, but no such rule declared.", MU::ERR
|
1422
1491
|
ok = false
|
@@ -1428,13 +1497,14 @@ return
|
|
1428
1497
|
if descriptor["alarms"] && !descriptor["alarms"].empty?
|
1429
1498
|
descriptor["alarms"].each { |alarm|
|
1430
1499
|
alarm["name"] = "#{cfg_name}-#{descriptor["name"]}-#{alarm["name"]}"
|
1431
|
-
alarm['dimensions']
|
1500
|
+
alarm['dimensions'] ||= []
|
1501
|
+
alarm["namespace"] ||= descriptor['name']
|
1432
1502
|
alarm["credentials"] = descriptor["credentials"]
|
1433
1503
|
alarm["#TARGETCLASS"] = cfg_name
|
1434
1504
|
alarm["#TARGETNAME"] = descriptor['name']
|
1435
1505
|
alarm['cloud'] = descriptor['cloud']
|
1436
1506
|
|
1437
|
-
ok = false if !insertKitten(alarm, "alarms", true)
|
1507
|
+
ok = false if !insertKitten(alarm, "alarms", true, overwrite: overwrite)
|
1438
1508
|
}
|
1439
1509
|
descriptor.delete("alarms")
|
1440
1510
|
end
|
@@ -1863,12 +1933,22 @@ return
|
|
1863
1933
|
|
1864
1934
|
# (see #include)
|
1865
1935
|
def include(file)
|
1866
|
-
MU::Config.include(file, get_binding, param_pass = @param_pass)
|
1936
|
+
MU::Config.include(file, get_binding(@@tails.keys.sort), param_pass = @param_pass)
|
1937
|
+
end
|
1938
|
+
|
1939
|
+
@@bindings = {}
|
1940
|
+
# Keep a cache of bindings we've created as sandbox contexts for ERB
|
1941
|
+
# processing, so we don't keep reloading the entire Mu library inside new
|
1942
|
+
# ones.
|
1943
|
+
def self.global_bindings
|
1944
|
+
@@bindings
|
1867
1945
|
end
|
1868
1946
|
|
1869
1947
|
# Namespace magic to pass to ERB's result method.
|
1870
|
-
def get_binding
|
1871
|
-
|
1948
|
+
def get_binding(keyset)
|
1949
|
+
# return MU::Config.global_bindings[keyset] if MU::Config.global_bindings[keyset]
|
1950
|
+
MU::Config.global_bindings[keyset] = binding
|
1951
|
+
MU::Config.global_bindings[keyset]
|
1872
1952
|
end
|
1873
1953
|
|
1874
1954
|
def applySchemaDefaults(conf_chunk = config, schema_chunk = schema, depth = 0, siblings = nil, type: nil)
|
@@ -2231,10 +2311,131 @@ return
|
|
2231
2311
|
# end
|
2232
2312
|
end
|
2233
2313
|
|
2314
|
+
# Emit our mu.yaml schema in a format that YARD can comprehend and turn into
|
2315
|
+
# documentation.
|
2316
|
+
def self.printMuYamlSchema(muyaml_rb, class_hierarchy, schema, in_array = false, required = false, prefix: nil)
|
2317
|
+
return if schema.nil?
|
2318
|
+
if schema["subtree"]
|
2319
|
+
printme = Array.new
|
2320
|
+
# order sub-elements by whether they're required, so we can use YARD's
|
2321
|
+
# grouping tags on them
|
2322
|
+
have_required = schema["subtree"].keys.any? { |k| schema["subtree"][k]["required"] }
|
2323
|
+
prop_list = schema["subtree"].keys.sort { |a, b|
|
2324
|
+
if schema["subtree"][a]["required"] and !schema["subtree"][b]["required"]
|
2325
|
+
-1
|
2326
|
+
elsif !schema["subtree"][a]["required"] and schema["subtree"][b]["required"]
|
2327
|
+
1
|
2328
|
+
else
|
2329
|
+
a <=> b
|
2330
|
+
end
|
2331
|
+
}
|
2332
|
+
|
2333
|
+
req = false
|
2334
|
+
printme << "# @!group Optional parameters" if !have_required
|
2335
|
+
prop_list.each { |name|
|
2336
|
+
prop = schema["subtree"][name]
|
2337
|
+
if prop["required"]
|
2338
|
+
printme << "# @!group Required parameters" if !req
|
2339
|
+
req = true
|
2340
|
+
else
|
2341
|
+
if req
|
2342
|
+
printme << "# @!endgroup"
|
2343
|
+
printme << "# @!group Optional parameters"
|
2344
|
+
end
|
2345
|
+
req = false
|
2346
|
+
end
|
2347
|
+
|
2348
|
+
printme << self.printMuYamlSchema(muyaml_rb, class_hierarchy+ [name], prop, false, req)
|
2349
|
+
}
|
2350
|
+
printme << "# @!endgroup"
|
2351
|
+
|
2352
|
+
desc = (schema['desc'] || schema['title'])
|
2353
|
+
|
2354
|
+
tabs = 1
|
2355
|
+
class_hierarchy.each { |classname|
|
2356
|
+
if classname == class_hierarchy.last and desc
|
2357
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + "# #{desc}\n"
|
2358
|
+
end
|
2359
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + "class #{classname}"
|
2360
|
+
tabs = tabs + 1
|
2361
|
+
}
|
2362
|
+
printme.each { |lines|
|
2363
|
+
if !lines.nil? and lines.is_a?(String)
|
2364
|
+
lines.lines.each { |line|
|
2365
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + line
|
2366
|
+
}
|
2367
|
+
end
|
2368
|
+
}
|
2369
|
+
|
2370
|
+
class_hierarchy.each { |classname|
|
2371
|
+
tabs = tabs - 1
|
2372
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + "end"
|
2373
|
+
}
|
2374
|
+
|
2375
|
+
# And now that we've dealt with our children, pass our own rendered
|
2376
|
+
# commentary back up to our caller.
|
2377
|
+
name = class_hierarchy.last
|
2378
|
+
if in_array
|
2379
|
+
type = "Array<#{class_hierarchy.join("::")}>"
|
2380
|
+
else
|
2381
|
+
type = class_hierarchy.join("::")
|
2382
|
+
end
|
2383
|
+
|
2384
|
+
docstring = "\n"
|
2385
|
+
docstring = docstring + "# **REQUIRED**\n" if required
|
2386
|
+
# docstring = docstring + "# **"+schema["prefix"]+"**\n" if schema["prefix"]
|
2387
|
+
docstring = docstring + "# #{desc.gsub(/\n/, "\n#")}\n" if desc
|
2388
|
+
docstring = docstring + "#\n"
|
2389
|
+
docstring = docstring + "# @return [#{type}]\n"
|
2390
|
+
docstring = docstring + "# @see #{class_hierarchy.join("::")}\n"
|
2391
|
+
docstring = docstring + "attr_accessor :#{name}"
|
2392
|
+
return docstring
|
2393
|
+
|
2394
|
+
else
|
2395
|
+
in_array = schema["array"]
|
2396
|
+
name = class_hierarchy.last
|
2397
|
+
type = if schema['boolean']
|
2398
|
+
"Boolean"
|
2399
|
+
else
|
2400
|
+
"String"
|
2401
|
+
end
|
2402
|
+
if in_array
|
2403
|
+
type = "Array<#{type}>"
|
2404
|
+
end
|
2405
|
+
docstring = "\n"
|
2406
|
+
|
2407
|
+
prefixes = []
|
2408
|
+
prefixes << "# **REQUIRED**" if schema["required"] and schema['default'].nil?
|
2409
|
+
# prefixes << "# **"+schema["prefix"]+"**" if schema["prefix"]
|
2410
|
+
prefixes << "# **Default: `#{schema['default']}`**" if !schema['default'].nil?
|
2411
|
+
if !schema['pattern'].nil?
|
2412
|
+
# XXX unquoted regex chars confuse the hell out of YARD. How do we
|
2413
|
+
# quote {}[] etc in YARD-speak?
|
2414
|
+
prefixes << "# **Must match pattern `#{schema['pattern'].to_s.gsub(/\n/, "\n#")}`**"
|
2415
|
+
end
|
2416
|
+
|
2417
|
+
desc = (schema['desc'] || schema['title'])
|
2418
|
+
if prefixes.size > 0
|
2419
|
+
docstring += prefixes.join(",\n")
|
2420
|
+
if desc and desc.size > 1
|
2421
|
+
docstring += " - "
|
2422
|
+
end
|
2423
|
+
docstring += "\n"
|
2424
|
+
end
|
2425
|
+
|
2426
|
+
docstring = docstring + "# #{desc.gsub(/\n/, "\n#")}\n" if !desc.nil?
|
2427
|
+
docstring = docstring + "#\n"
|
2428
|
+
docstring = docstring + "# @return [#{type}]\n"
|
2429
|
+
docstring = docstring + "attr_accessor :#{name}"
|
2430
|
+
|
2431
|
+
return docstring
|
2432
|
+
end
|
2433
|
+
|
2434
|
+
end
|
2234
2435
|
|
2235
|
-
# Emit our Basket of
|
2436
|
+
# Emit our Basket of Kittens schema in a format that YARD can comprehend
|
2236
2437
|
# and turn into documentation.
|
2237
|
-
def self.printSchema(
|
2438
|
+
def self.printSchema(kitten_rb, class_hierarchy, schema, in_array = false, required = false, prefix: nil)
|
2238
2439
|
return if schema.nil?
|
2239
2440
|
if schema["type"] == "object"
|
2240
2441
|
printme = Array.new
|
@@ -2263,7 +2464,7 @@ return
|
|
2263
2464
|
req = false
|
2264
2465
|
end
|
2265
2466
|
|
2266
|
-
printme << self.printSchema(
|
2467
|
+
printme << self.printSchema(kitten_rb, class_hierarchy+ [name], prop, false, req, prefix: schema["prefix"])
|
2267
2468
|
}
|
2268
2469
|
printme << "# @!endgroup"
|
2269
2470
|
end
|
@@ -2271,22 +2472,22 @@ return
|
|
2271
2472
|
tabs = 1
|
2272
2473
|
class_hierarchy.each { |classname|
|
2273
2474
|
if classname == class_hierarchy.last and !schema['description'].nil?
|
2274
|
-
|
2475
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + "# #{schema['description']}\n"
|
2275
2476
|
end
|
2276
|
-
|
2477
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + "class #{classname}"
|
2277
2478
|
tabs = tabs + 1
|
2278
2479
|
}
|
2279
2480
|
printme.each { |lines|
|
2280
2481
|
if !lines.nil? and lines.is_a?(String)
|
2281
2482
|
lines.lines.each { |line|
|
2282
|
-
|
2483
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + line
|
2283
2484
|
}
|
2284
2485
|
end
|
2285
2486
|
}
|
2286
2487
|
|
2287
2488
|
class_hierarchy.each { |classname|
|
2288
2489
|
tabs = tabs - 1
|
2289
|
-
|
2490
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + "end"
|
2290
2491
|
}
|
2291
2492
|
|
2292
2493
|
# And now that we've dealt with our children, pass our own rendered
|
@@ -2309,7 +2510,7 @@ return
|
|
2309
2510
|
return docstring
|
2310
2511
|
|
2311
2512
|
elsif schema["type"] == "array"
|
2312
|
-
return self.printSchema(
|
2513
|
+
return self.printSchema(kitten_rb, class_hierarchy, schema['items'], true, required, prefix: prefix)
|
2313
2514
|
else
|
2314
2515
|
name = class_hierarchy.last
|
2315
2516
|
if schema['type'].nil?
|