cloud-mu 3.0.0beta → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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?