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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -8
  3. data/ansible/roles/mu-nat/README.md +33 -0
  4. data/ansible/roles/mu-nat/defaults/main.yml +3 -0
  5. data/ansible/roles/mu-nat/handlers/main.yml +2 -0
  6. data/ansible/roles/mu-nat/meta/main.yml +60 -0
  7. data/ansible/roles/mu-nat/tasks/main.yml +65 -0
  8. data/ansible/roles/mu-nat/tests/inventory +2 -0
  9. data/ansible/roles/mu-nat/tests/test.yml +5 -0
  10. data/ansible/roles/mu-nat/vars/main.yml +2 -0
  11. data/bin/mu-cleanup +2 -1
  12. data/bin/mu-configure +950 -948
  13. data/bin/mu-gen-docs +6 -0
  14. data/cloud-mu.gemspec +2 -2
  15. data/cookbooks/mu-tools/recipes/gcloud.rb +8 -1
  16. data/modules/mommacat.ru +1 -1
  17. data/modules/mu.rb +31 -39
  18. data/modules/mu/cloud.rb +11 -1
  19. data/modules/mu/clouds/aws.rb +8 -3
  20. data/modules/mu/clouds/aws/alarm.rb +5 -8
  21. data/modules/mu/clouds/aws/bucket.rb +15 -9
  22. data/modules/mu/clouds/aws/cache_cluster.rb +60 -26
  23. data/modules/mu/clouds/aws/collection.rb +4 -4
  24. data/modules/mu/clouds/aws/container_cluster.rb +50 -33
  25. data/modules/mu/clouds/aws/database.rb +25 -21
  26. data/modules/mu/clouds/aws/dnszone.rb +12 -14
  27. data/modules/mu/clouds/aws/endpoint.rb +5 -8
  28. data/modules/mu/clouds/aws/firewall_rule.rb +9 -4
  29. data/modules/mu/clouds/aws/folder.rb +4 -7
  30. data/modules/mu/clouds/aws/function.rb +5 -8
  31. data/modules/mu/clouds/aws/group.rb +5 -8
  32. data/modules/mu/clouds/aws/habitat.rb +2 -5
  33. data/modules/mu/clouds/aws/loadbalancer.rb +12 -16
  34. data/modules/mu/clouds/aws/log.rb +6 -9
  35. data/modules/mu/clouds/aws/msg_queue.rb +16 -19
  36. data/modules/mu/clouds/aws/nosqldb.rb +27 -18
  37. data/modules/mu/clouds/aws/notifier.rb +6 -9
  38. data/modules/mu/clouds/aws/role.rb +4 -7
  39. data/modules/mu/clouds/aws/search_domain.rb +50 -23
  40. data/modules/mu/clouds/aws/server.rb +20 -14
  41. data/modules/mu/clouds/aws/server_pool.rb +22 -12
  42. data/modules/mu/clouds/aws/storage_pool.rb +9 -14
  43. data/modules/mu/clouds/aws/user.rb +5 -8
  44. data/modules/mu/clouds/aws/userdata/linux.erb +7 -1
  45. data/modules/mu/clouds/aws/vpc.rb +16 -14
  46. data/modules/mu/clouds/azure.rb +1 -1
  47. data/modules/mu/clouds/azure/container_cluster.rb +1 -1
  48. data/modules/mu/clouds/azure/server.rb +16 -2
  49. data/modules/mu/clouds/azure/user.rb +1 -1
  50. data/modules/mu/clouds/azure/userdata/linux.erb +84 -80
  51. data/modules/mu/clouds/azure/vpc.rb +32 -13
  52. data/modules/mu/clouds/cloudformation/server.rb +1 -1
  53. data/modules/mu/clouds/google.rb +2 -3
  54. data/modules/mu/clouds/google/container_cluster.rb +9 -1
  55. data/modules/mu/clouds/google/firewall_rule.rb +6 -0
  56. data/modules/mu/clouds/google/role.rb +1 -3
  57. data/modules/mu/clouds/google/server.rb +25 -4
  58. data/modules/mu/clouds/google/user.rb +1 -1
  59. data/modules/mu/clouds/google/userdata/linux.erb +9 -5
  60. data/modules/mu/clouds/google/vpc.rb +102 -21
  61. data/modules/mu/config.rb +250 -49
  62. data/modules/mu/config/alarm.rb +1 -0
  63. data/modules/mu/config/container_cluster.yml +0 -1
  64. data/modules/mu/config/database.yml +4 -1
  65. data/modules/mu/config/search_domain.yml +4 -3
  66. data/modules/mu/config/server.rb +7 -3
  67. data/modules/mu/config/server.yml +4 -1
  68. data/modules/mu/config/server_pool.yml +2 -0
  69. data/modules/mu/config/vpc.rb +42 -29
  70. data/modules/mu/deploy.rb +12 -5
  71. data/modules/mu/groomers/ansible.rb +4 -1
  72. data/modules/mu/groomers/chef.rb +5 -1
  73. data/modules/mu/kittens.rb +60 -11
  74. data/modules/mu/logger.rb +6 -4
  75. data/modules/mu/mommacat.rb +39 -19
  76. data/modules/mu/mu.yaml.rb +276 -0
  77. metadata +13 -4
@@ -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
- newhash[key] = self.manxify(val)
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.new(@deploy_id, set_context_to_me: false, create: false)
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
- else
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
- dummy_kitten_class = File.new(kittenpath, File::CREAT|File::TRUNC|File::RDWR, 0644)
1044
- dummy_kitten_class.puts "### THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT ###"
1045
- dummy_kitten_class.puts ""
1046
- dummy_kitten_class.puts "module MU"
1047
- dummy_kitten_class.puts "class Config"
1048
- dummy_kitten_class.puts "\t# The configuration file format for Mu application stacks."
1049
- self.printSchema(dummy_kitten_class, ["BasketofKittens"], MU::Config.docSchema)
1050
- dummy_kitten_class.puts "end"
1051
- dummy_kitten_class.puts "end"
1052
- dummy_kitten_class.close
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 !haveLitterMate?(fwname, "firewall_rules") and
1353
- (descriptor['ingress_rules'] or
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"] = [] if descriptor["add_firewall_rules"].nil?
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
- acl = resolveIntraStackFirewallRefs(acl)
1381
- ok = false if !insertKitten(acl, "firewall_rules", delay_validation)
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'] = [] if !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
- binding
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 Kittesn schema in a format that YARD can comprehend
2436
+ # Emit our Basket of Kittens schema in a format that YARD can comprehend
2236
2437
  # and turn into documentation.
2237
- def self.printSchema(dummy_kitten_class, class_hierarchy, schema, in_array = false, required = false, prefix: nil)
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(dummy_kitten_class, class_hierarchy+ [name], prop, false, req, prefix: schema["prefix"])
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
- dummy_kitten_class.puts ["\t"].cycle(tabs).to_a.join('') + "# #{schema['description']}\n"
2475
+ kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + "# #{schema['description']}\n"
2275
2476
  end
2276
- dummy_kitten_class.puts ["\t"].cycle(tabs).to_a.join('') + "class #{classname}"
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
- dummy_kitten_class.puts ["\t"].cycle(tabs).to_a.join('') + line
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
- dummy_kitten_class.puts ["\t"].cycle(tabs).to_a.join('') + "end"
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(dummy_kitten_class, class_hierarchy, schema['items'], true, required, prefix: prefix)
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?