cloud-mu 3.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +25 -0
  3. data/README.md +2 -2
  4. data/bin/mu-node-manage +1 -1
  5. data/chefignore +1 -0
  6. data/cloud-mu.gemspec +2 -2
  7. data/extras/clean-stock-amis +0 -0
  8. data/extras/generate-stock-images +0 -0
  9. data/extras/list-stock-amis +0 -0
  10. data/extras/vault_tools/export_vaults.sh +0 -0
  11. data/extras/vault_tools/recreate_vaults.sh +0 -0
  12. data/extras/vault_tools/test_vaults.sh +0 -0
  13. data/kitchen.yml +97 -0
  14. data/modules/mu.rb +14 -2
  15. data/modules/mu/cloud.rb +26 -0
  16. data/modules/mu/clouds/aws.rb +1 -2
  17. data/modules/mu/clouds/aws/container_cluster.rb +2 -1
  18. data/modules/mu/clouds/aws/database.rb +2 -2
  19. data/modules/mu/clouds/aws/loadbalancer.rb +1 -1
  20. data/modules/mu/clouds/aws/search_domain.rb +1 -1
  21. data/modules/mu/clouds/aws/server.rb +9 -1
  22. data/modules/mu/clouds/aws/vpc.rb +1 -2
  23. data/modules/mu/config.rb +83 -3
  24. data/modules/mu/config/bucket.yml +1 -1
  25. data/modules/mu/config/cache_cluster.yml +1 -9
  26. data/modules/mu/config/container_cluster.yml +1 -1
  27. data/modules/mu/config/database.yml +3 -3
  28. data/modules/mu/config/log.yml +8 -3
  29. data/modules/mu/config/msg_queue.yml +1 -1
  30. data/modules/mu/config/nosqldb.yml +1 -1
  31. data/modules/mu/config/notifier.yml +1 -1
  32. data/modules/mu/config/search_domain.yml +2 -2
  33. data/modules/mu/config/server.yml +23 -3
  34. data/modules/mu/config/server_pool.yml +5 -2
  35. data/modules/mu/config/storage_pool.yml +1 -1
  36. data/modules/mu/config/vpc.rb +6 -6
  37. data/modules/mu/config/vpc.yml +54 -3
  38. data/modules/mu/groomers/chef.rb +27 -0
  39. data/modules/mu/mommacat.rb +113 -18
  40. metadata +18 -22
  41. data/Berksfile.lock +0 -179
  42. data/bin/mu-azure-tests +0 -43
  43. data/cookbooks/mu-tools/files/default/Mu_CA.pem +0 -33
  44. data/modules/mu/kittens.rb +0 -20651
  45. data/modules/mu/mu.yaml.rb +0 -276
  46. data/modules/scratchpad.erb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec38717ba0e001faf5500c971fad6d2ce978302e11c9b7dfc587b4d7f1e7c7a3
4
- data.tar.gz: 57a212554afb4c30752e471211b515252524dc5a4e4cddabafe29f66bd6a377f
3
+ metadata.gz: c0ab46aed6ed1aaf58e3d8de76de9ea27adc49cbd754b51cc4ef7e6354a78a26
4
+ data.tar.gz: 5b341646d7533692813097af86fb37c46f1ba23fb0faf6acfe09688a3456e13c
5
5
  SHA512:
6
- metadata.gz: 5fa39a5ac28414a186e1a1b620e2f097d3d662989dfd0501e02f01ad8f406f289e397a9b506c79c3511c3a659a316a1920d8ca1b8ecc5995bfe8e5f076e98f6c
7
- data.tar.gz: 663202c112b0cf2c816a578da15c1d82724ddd577077b7d15075d0e1c6c683b8048dbf216f044a6a623cf82d3ba2ce370ff87a66627c052e9fd996a3b372244e
6
+ metadata.gz: e9c62154b428aa93f247fbf61589372744a167814f0403a339640e1e96042c8ece774b57617127860e7cfa46dc95c0c666022c3872beac77987f496cea65ad00
7
+ data.tar.gz: 12a4ced1bb6cbfe64ef666699a34bafe1aaf0228d080d6f8ee3584bcaec967084eca3d3a4167a405e05d1f8bc0d171093f7bab46e5648d1ff3339750a36c60e8
@@ -0,0 +1,25 @@
1
+ FROM ruby:2.5-slim
2
+
3
+ RUN mkdir -p /opt/mu/etc/ /home/mu /usr/local/ruby-current/lib/ruby/gems/2.5.0/gems/var/
4
+
5
+ WORKDIR /home/mu
6
+
7
+ RUN apt-get update
8
+
9
+ RUN apt-get install -y ruby2.5-dev dnsutils ansible build-essential
10
+
11
+ RUN apt-get upgrade -y
12
+
13
+ COPY ./cloud-mu-*.gem /home/mu
14
+
15
+ RUN gem install ./cloud-mu-*.gem thin -N
16
+
17
+ RUN rm cloud-mu-*.gem
18
+
19
+ RUN apt-get remove -y build-essential ruby2.5-dev
20
+
21
+ RUN apt-get autoremove -y
22
+
23
+ EXPOSE 2260
24
+
25
+ CMD /usr/sbin/init
data/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  mu -- Cloudamatic Automation Tooling
2
2
  ===
3
3
  [![pipeline status](https://gitlab.com/cloudamatic/mu/badges/master/pipeline.svg)](https://gitlab.com/cloudamatic/mu/commits/master)
4
- [![Gem Version](https://badge.fury.io/rb/cloud-mu.svg)](https://badge.fury.io/rb/cloud-mu)
5
4
  [![Maintainability](https://api.codeclimate.com/v1/badges/dd4e5d867890336accd1/maintainability)](https://codeclimate.com/github/cloudamatic/mu/maintainability)
6
- [![Inline docs](http://inch-ci.org/github/cloudamatic/mu.svg?branch=master)](http://inch-ci.org/github/cloudamatic/mu)
5
+ [![Gem Version](https://badge.fury.io/rb/cloud-mu.svg)](https://badge.fury.io/rb/cloud-mu)
6
+ [![Docker Version](https://images.microbadger.com/badges/version/egtlabs/mu.svg)](https://microbadger.com/images/egtlabs/mu)
7
7
 
8
8
  # About mu
9
9
  **Mu** is the deployer and developer toolset for the Cloudamatic suite of services, designed to provision, orchestrate and manage complex platforms and applications. At [eGT Labs](https://www.eglobaltech.com/egt-labs/), we use mu for rapid prototyping of cloud migration efforts for federal customers, for managing cloud applications throughout their lifecycles, and as a tools library for cloud maintenance tasks.
@@ -599,7 +599,7 @@ def updateAWSMetaData(deploys = MU::MommaCat.listDeploys, nodes = [])
599
599
 
600
600
  MU.log "Updating #{nodename} userdata (#{server["conf"]["platform"]})"
601
601
  begin
602
- MU::Cloud::AWS.ec2(server['region']).modify_instance_attribute(
602
+ MU::Cloud::AWS.ec2(region: server['region']).modify_instance_attribute(
603
603
  instance_id: id,
604
604
  attribute: "userData",
605
605
  value: Base64.encode64(userdata)
@@ -0,0 +1 @@
1
+ .kitchen
@@ -17,8 +17,8 @@ end
17
17
 
18
18
  Gem::Specification.new do |s|
19
19
  s.name = 'cloud-mu'
20
- s.version = '3.0.0'
21
- s.date = '2019-11-11'
20
+ s.version = '3.0.1'
21
+ s.date = '2019-11-22'
22
22
  s.require_paths = ['modules']
23
23
  s.required_ruby_version = '>= 2.4'
24
24
  s.summary = "The eGTLabs Mu toolkit for unified cloud deployments"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -0,0 +1,97 @@
1
+ driver:
2
+ name: ec2
3
+ region: us-east-1
4
+ subnet_id: subnet-00f6ebfde53bbdccd
5
+ instance_type: t2.medium
6
+ iam_profile_name: mu-master-role
7
+ associate_public_ip: true
8
+ interface: dns
9
+ shared_credentials_profile: test_kitchen
10
+ instance_initiated_shutdown_behavior: terminate
11
+ tags:
12
+ Name: kitchen-mu-node
13
+ created-by: mu-pipeline
14
+ sudo: true
15
+
16
+ provisioner:
17
+ name: chef_zero
18
+ roles_path: roles
19
+ chef_license: accept
20
+
21
+ verifier:
22
+ name: shell
23
+
24
+ platforms:
25
+ - name: centos-7
26
+ vm_tags:
27
+ osdistro: centos7
28
+
29
+ - name: amazon2
30
+ vm_tags:
31
+ osdistro: amazon2
32
+
33
+ - name: centos-7-az
34
+ driver:
35
+ name: azurerm
36
+ subscription_id: '3d20ddd8-4652-4074-adda-0d127ef1f0e0'
37
+ location: 'East US'
38
+ #image_urn: 'tunnelbiz:centos70-min:centos7-min:0.1.1'
39
+ machine_size: 'Standard_B2s'
40
+ vm_name: mu-install
41
+ vm_tags:
42
+ osdistro: centos7
43
+
44
+ suites:
45
+ - name: mu-install-aws
46
+ provisioner:
47
+ name: shell
48
+ script:
49
+ - "./kitchen_vars"
50
+ - "./install/installer"
51
+ - "./install/mu-master.yaml"
52
+ command:
53
+ - sudo yum install -y bind-utils
54
+ - sudo chown root:root /tmp/installer
55
+ - sudo chmod u+x /tmp/installer
56
+ - sudo chown root:root /tmp/mu-master.yaml
57
+ - source /tmp/kitchen_vars
58
+ - env
59
+ - myip="$(dig +short myip.opendns.com @resolver1.opendns.com)"
60
+ - sudo /tmp/installer -p $myip -m zach@zach.systems -o 2260 -h "$(echo $HOSTNAME | sed s/\\./-/g)" -n
61
+ root_path: '/tmp/'
62
+ includes:
63
+ - centos-7
64
+ - amazon2
65
+
66
+ - name: mu-install-azure
67
+ provisioner:
68
+ name: shell
69
+ script:
70
+ - "./install/installer"
71
+ - "./install/mu-master.yaml"
72
+ command:
73
+ - myip="$(dig +short myip.opendns.com @resolver1.opendns.com)"
74
+ - sudo ll /tmp/ && sudo MU_BRANCH=development /tmp/installer -p $myip -m zach@zach.systems -o 2260 -h "$(echo $HOSTNAME | sed s/\\./-/g)" -n
75
+ - sudo mu-deploy /tmp/mu-master.yaml -p name=stange-mu -p cloud=Azure
76
+ root_path: '/tmp/'
77
+ includes:
78
+ - centos-7-az
79
+
80
+ #- name: mu-node
81
+ # run_list:
82
+ # - recipe[mu-tools::newclient]
83
+ # - recipe[mu-tools::gcloud]
84
+ # - role[mu-node]
85
+ # includes:
86
+ # - ubuntu
87
+ # - centos-7
88
+ # - centos-6
89
+ # - rhel-7
90
+ # - rhel-6
91
+ # - amazon
92
+ # - amazon2
93
+ # - windows
94
+
95
+ # - name: mu-master
96
+ # run_list:
97
+ # - role[mu-master]
@@ -343,6 +343,17 @@ module MU
343
343
  ((Gem.paths and Gem.paths.home and File.realpath(File.expand_path(File.dirname(__FILE__))).match(/^#{Gem.paths.home}/)) or !Dir.exist?("/opt/mu"))
344
344
  end
345
345
 
346
+ # Are we operating in a gem?
347
+ def self.inGem?
348
+ return @in_gem if defined? @in_gem
349
+
350
+ if Gem.paths and Gem.paths.home and File.dirname(__FILE__).match(/^#{Gem.paths.home}/)
351
+ @in_gem = true
352
+ else
353
+ @in_gem = false
354
+ end
355
+ end
356
+
346
357
  # The main (root) Mu user's data directory.
347
358
  @@mainDataDir = File.expand_path(@@myRoot+"/../var")
348
359
  # The main (root) Mu user's data directory.
@@ -631,8 +642,9 @@ module MU
631
642
  !$MU_CFG['public_address'].empty? and @@my_public_ip != $MU_CFG['public_address']
632
643
  @@mu_public_addr = $MU_CFG['public_address']
633
644
  if !@@mu_public_addr.match(/^\d+\.\d+\.\d+\.\d+$/)
634
- resolver = Resolv::DNS.new
635
- @@mu_public_ip = resolver.getaddress(@@mu_public_addr).to_s
645
+ hostname = IO.readlines("/etc/hostname")[0].gsub /\n/, ''
646
+
647
+ @@mu_public_ip = File.open('/etc/hosts').grep(/.*#{hostname}.*/).first.match(/^\d+\.\d+\.\d+\.\d+/)[0]
636
648
  else
637
649
  @@mu_public_ip = @@mu_public_addr
638
650
  end
@@ -1142,6 +1142,30 @@ module MU
1142
1142
 
1143
1143
  # Remove all metadata and cloud resources associated with this object
1144
1144
  def destroy
1145
+ if self.class.cfg_name == "server"
1146
+ begin
1147
+ ip = canonicalIP
1148
+ MU::MommaCat.removeIPFromSSHKnownHosts(ip) if ip
1149
+ if @deploy and @deploy.deployment and
1150
+ @deploy.deployment['servers'] and @config['name'] and
1151
+ me = @deploy.deployment['servers'][@config['name']][@mu_name]
1152
+ if me
1153
+ ["private_ip_address", "public_ip_address"].each { |field|
1154
+ if me[field]
1155
+ MU::MommaCat.removeIPFromSSHKnownHosts(me[field])
1156
+ end
1157
+ }
1158
+ if me["private_ip_list"]
1159
+ me["private_ip_list"].each { |ip|
1160
+ MU::MommaCat.removeIPFromSSHKnownHosts(ip)
1161
+ }
1162
+ end
1163
+ end
1164
+ end
1165
+ rescue MU::MuError => e
1166
+ MU.log e.message, MU::WARN
1167
+ end
1168
+ end
1145
1169
  if !@cloudobj.nil? and !@cloudobj.groomer.nil?
1146
1170
  @cloudobj.groomer.cleanup
1147
1171
  elsif !@groomer.nil?
@@ -1952,6 +1976,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1952
1976
  :keys => [ssh_keydir+"/"+nat_ssh_key, ssh_keydir+"/"+@deploy.ssh_key_name],
1953
1977
  :verify_host_key => false,
1954
1978
  # :verbose => :info,
1979
+ :host_key => "ssh-rsa",
1955
1980
  :port => 22,
1956
1981
  :auth_methods => ['publickey'],
1957
1982
  :proxy => proxy
@@ -1967,6 +1992,7 @@ puts "CHOOSING #{@vpc.to_s} 'cause it has #{@config['vpc']['subnet_name']}"
1967
1992
  :keys => [ssh_keydir+"/"+@deploy.ssh_key_name],
1968
1993
  :verify_host_key => false,
1969
1994
  # :verbose => :info,
1995
+ :host_key => "ssh-rsa",
1970
1996
  :port => 22,
1971
1997
  :auth_methods => ['publickey']
1972
1998
  )
@@ -164,7 +164,6 @@ module MU
164
164
  # @param r [String]
165
165
  # @return [String]
166
166
  def self.validate_region(r, credentials: nil)
167
- require "aws-sdk-core"
168
167
  begin
169
168
  MU::Cloud::AWS.ec2(region: r, credentials: credentials).describe_availability_zones.availability_zones.first.region_name
170
169
  rescue ::Aws::EC2::Errors::UnauthorizedOperation => e
@@ -1339,8 +1338,8 @@ module MU
1339
1338
  # @param region [String]: Amazon region so we know what endpoint to use
1340
1339
  # @param api [String]: Which API are we wrapping?
1341
1340
  def initialize(region: MU.curRegion, api: "EC2", credentials: nil)
1342
- @credentials = MU::Cloud::AWS.credConfig(credentials, name_only: true)
1343
1341
  @cred_obj = MU::Cloud::AWS.loadCredentials(credentials)
1342
+ @credentials = MU::Cloud::AWS.credConfig(credentials, name_only: true)
1344
1343
 
1345
1344
  if !@cred_obj
1346
1345
  raise MuError, "Unable to locate valid AWS credentials for #{api} API. #{credentials ? "Credentials requested were '#{credentials}'": ""}"
@@ -66,6 +66,7 @@ module MU
66
66
  ]
67
67
  }
68
68
  end
69
+ params.delete(:version) if params[:version] == "latest"
69
70
 
70
71
  MU.log "Creating EKS cluster #{@mu_name}", details: params
71
72
  resp = MU::Cloud::AWS.eks(region: @config['region'], credentials: @config['credentials']).create_cluster(params)
@@ -91,7 +92,7 @@ module MU
91
92
  sleep 5
92
93
  retry
93
94
  else
94
- MU.log e.message, MU::WARN, details: role_arn
95
+ MU.log e.message, MU::WARN, details: params
95
96
  sleep 5
96
97
  retry
97
98
  end
@@ -928,7 +928,7 @@ module MU
928
928
  basename[0..29].gsub(/[^a-z0-9]/i, "")
929
929
  elsif config["engine"].match(/^sqlserver/)
930
930
  basename[0..127].gsub(/[^a-z0-9]/i, "")
931
- elsif config["engine"].match(/^mysql/)
931
+ elsif config["engine"].match(/^(mysql|maria)/)
932
932
  basename[0..15].gsub(/[^a-z0-9]/i, "")
933
933
  elsif config["engine"].match(/^aurora/)
934
934
  basename[0..15].gsub(/[^a-z0-9]/i, "")
@@ -1603,7 +1603,7 @@ module MU
1603
1603
  db["license_model"] ||=
1604
1604
  if ["postgres", "postgresql", "aurora-postgresql"].include?(db["engine"])
1605
1605
  "postgresql-license"
1606
- elsif db["engine"] == "mysql"
1606
+ elsif ["mysql", "mariadb"].include?(db["engine"])
1607
1607
  "general-public-license"
1608
1608
  else
1609
1609
  "license-included"
@@ -188,7 +188,7 @@ module MU
188
188
  if @config['targetgroups']
189
189
  MU.log "Configuring target groups and health checks check for ELB #{@mu_name}", details: @config['healthcheck']
190
190
  @config['targetgroups'].each { |tg|
191
- tg_name = @deploy.getResourceName(tg["name"], max_length: 32)
191
+ tg_name = @deploy.getResourceName(tg["name"], max_length: 32, allowed_chars: /[A-Za-z0-9-]/)
192
192
  tg_descriptor = {
193
193
  :name => tg_name,
194
194
  :protocol => tg['proto'],
@@ -67,7 +67,7 @@ module MU
67
67
  domain_name: @deploydata['domain_name']
68
68
  ).domain_status
69
69
  else
70
- raise MU::MuError "#{@mu_name} can't find its official Elasticsearch domain name!"
70
+ raise MuError "#{@mu_name} can't find its official Elasticsearch domain name!"
71
71
  end
72
72
  end
73
73
 
@@ -120,8 +120,10 @@ module MU
120
120
  @config['mu_name'] = @mu_name
121
121
 
122
122
  end
123
+
123
124
  @config['instance_secret'] ||= Password.random(50)
124
125
 
126
+ @groomer = MU::Groomer.new(self) unless MU.inGem?
125
127
  end
126
128
 
127
129
  @@userdata_semaphore = Mutex.new
@@ -938,11 +940,17 @@ module MU
938
940
 
939
941
  # See if this node already exists in our config management. If it does,
940
942
  # we're done.
941
- if @groomer.haveBootstrapped?
943
+ if MU.inGem?
944
+ MU.log "Deploying from a gem, not grooming"
945
+
946
+ return true
947
+ elsif @groomer.haveBootstrapped?
942
948
  MU.log "Node #{node} has already been bootstrapped, skipping groomer setup.", MU::NOTICE
949
+
943
950
  if @config['groom'].nil? or @config['groom']
944
951
  @groomer.saveDeployData
945
952
  end
953
+
946
954
  MU::MommaCat.unlock(instance.instance_id+"-orchestrate")
947
955
  MU::MommaCat.unlock(instance.instance_id+"-groom")
948
956
  return true
@@ -1161,7 +1161,6 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
1161
1161
  # @param region [String]: The cloud provider region
1162
1162
  # @return [void]
1163
1163
  def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
1164
-
1165
1164
  tagfilters = [
1166
1165
  {name: "tag:MU-ID", values: [MU.deploy_id]}
1167
1166
  ]
@@ -1172,7 +1171,7 @@ MU.log "wtf", MU::ERR, details: peer if peer_obj.nil? or peer_obj.first.nil?
1172
1171
  vpcs = []
1173
1172
  retries = 0
1174
1173
  begin
1175
- resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(filters: tagfilters).vpcs
1174
+ resp = MU::Cloud::AWS.ec2(region: region, credentials: credentials).describe_vpcs(filters: tagfilters, max_results: 1000).vpcs
1176
1175
  vpcs = resp if !resp.empty?
1177
1176
  rescue Aws::EC2::Errors::InvalidVpcIDNotFound => e
1178
1177
  if retries < 5
@@ -317,6 +317,13 @@ module MU
317
317
  }
318
318
  end
319
319
 
320
+ # A way of dynamically defining +attr_reader+ without leaking memory
321
+ def self.define_reader(name)
322
+ define_method(name) {
323
+ instance_variable_get("@#{name.to_s}")
324
+ }
325
+ end
326
+
320
327
  # @param cfg [Hash]: A Basket of Kittens configuration hash containing
321
328
  # lookup information for a cloud object
322
329
  def initialize(cfg)
@@ -327,7 +334,7 @@ module MU
327
334
  elsif !cfg[field.to_sym].nil?
328
335
  self.instance_variable_set("@#{field.to_s}".to_sym, cfg[field.to_sym])
329
336
  end
330
- self.singleton_class.instance_eval { attr_reader field.to_sym }
337
+ MU::Config::Ref.define_reader(field)
331
338
  }
332
339
  if cfg['tag'] and cfg['tag']['key'] and
333
340
  !cfg['tag']['key'].empty? and cfg['tag']['value']
@@ -985,6 +992,15 @@ return
985
992
 
986
993
  @config['credentials'] ||= @default_credentials
987
994
 
995
+ if @config['cloud'] and !MU::Cloud.availableClouds.include?(@config['cloud'])
996
+ if MU::Cloud.supportedClouds.include?(@config['cloud'])
997
+ MU.log "Cloud provider #{@config['cloud']} declared, but no #{@config['cloud']} credentials available", MU::ERR
998
+ else
999
+ MU.log "Cloud provider #{@config['cloud']} is not supported", MU::ERR, details: MU::Cloud.supportedClouds
1000
+ end
1001
+ exit 1
1002
+ end
1003
+
988
1004
  types = MU::Cloud.resource_types.values.map { |v| v[:cfg_plural] }
989
1005
 
990
1006
  MU::Cloud.resource_types.values.map { |v| v[:cfg_plural] }.each { |type|
@@ -1274,6 +1290,16 @@ $CONFIGURABLES
1274
1290
  }
1275
1291
  ok = true
1276
1292
 
1293
+ if descriptor['cloud'] and
1294
+ !MU::Cloud.availableClouds.include?(descriptor['cloud'])
1295
+ if MU::Cloud.supportedClouds.include?(descriptor['cloud'])
1296
+ MU.log "#{cfg_name} #{descriptor['name']} is configured with cloud #{descriptor['cloud']}, but no #{descriptor['cloud']} credentials available", MU::ERR
1297
+ else
1298
+ MU.log "#{cfg_name} #{descriptor['name']}: Cloud provider #{descriptor['cloud']} is not supported", MU::ERR, details: MU::Cloud.supportedClouds
1299
+ end
1300
+ return false
1301
+ end
1302
+
1277
1303
  descriptor["#MU_CLOUDCLASS"] = classname
1278
1304
 
1279
1305
  applyInheritedDefaults(descriptor, cfg_plural)
@@ -1975,7 +2001,7 @@ $CONFIGURABLES
1975
2001
  conf_chunk.map! { |item|
1976
2002
  # If we're working on a resource type, go get implementation-specific
1977
2003
  # schema information so that we set those defaults correctly.
1978
- realschema = if type and schema_chunk["items"] and schema_chunk["items"]["properties"] and item["cloud"]
2004
+ realschema = if type and schema_chunk["items"] and schema_chunk["items"]["properties"] and item["cloud"] and MU::Cloud.supportedClouds.include?(item['cloud'])
1979
2005
 
1980
2006
  cloudclass = Object.const_get("MU").const_get("Cloud").const_get(item["cloud"]).const_get(type)
1981
2007
  toplevel_required, cloudschema = cloudclass.schema(self)
@@ -2126,6 +2152,10 @@ $CONFIGURABLES
2126
2152
  kitten['cloud'] ||= @config['cloud']
2127
2153
  kitten['cloud'] ||= MU::Config.defaultCloud
2128
2154
 
2155
+ if !MU::Cloud.supportedClouds.include?(kitten['cloud'])
2156
+ return
2157
+ end
2158
+
2129
2159
  cloudclass = Object.const_get("MU").const_get("Cloud").const_get(kitten['cloud'])
2130
2160
  shortclass, cfg_name, cfg_plural, classname = MU::Cloud.getResourceNames(type)
2131
2161
  resclass = Object.const_get("MU").const_get("Cloud").const_get(kitten['cloud']).const_get(shortclass)
@@ -2198,6 +2228,7 @@ $CONFIGURABLES
2198
2228
  count = count + @kittens[type].size
2199
2229
  }
2200
2230
 
2231
+
2201
2232
  if count == 0
2202
2233
  MU.log "You must declare at least one resource to create", MU::ERR
2203
2234
  ok = false
@@ -2437,8 +2468,10 @@ $CONFIGURABLES
2437
2468
  # and turn into documentation.
2438
2469
  def self.printSchema(kitten_rb, class_hierarchy, schema, in_array = false, required = false, prefix: nil)
2439
2470
  return if schema.nil?
2471
+
2440
2472
  if schema["type"] == "object"
2441
- printme = Array.new
2473
+ printme = []
2474
+
2442
2475
  if !schema["properties"].nil?
2443
2476
  # order sub-elements by whether they're required, so we can use YARD's
2444
2477
  # grouping tags on them
@@ -2453,6 +2486,53 @@ $CONFIGURABLES
2453
2486
  printme << "# @!group Optional parameters" if schema["required"].nil? or schema["required"].size == 0
2454
2487
  prop_list.each { |name|
2455
2488
  prop = schema["properties"][name]
2489
+
2490
+ if class_hierarchy.size == 1
2491
+
2492
+ _shortclass, cfg_name, cfg_plural, _classname = MU::Cloud.getResourceNames(name)
2493
+ if cfg_name
2494
+ example_path = MU.myRoot+"/modules/mu/config/"+cfg_name+".yml"
2495
+ if File.exist?(example_path)
2496
+ example = "#\n# Examples:\n#\n"
2497
+ # XXX these variables are all parameters from the BoKs in
2498
+ # modules/tests. A really clever implementation would read
2499
+ # and parse them to get default values, perhaps, instead of
2500
+ # hard-coding them here.
2501
+ instance_type = "t2.medium"
2502
+ db_size = "db.t2.medium"
2503
+ vpc_name = "some_vpc"
2504
+ logs_name = "some_loggroup"
2505
+ queues_name = "some_queue"
2506
+ server_pools_name = "some_server_pool"
2507
+ ["simple", "complex"].each { |complexity|
2508
+ erb = ERB.new(File.read(example_path), nil, "<>")
2509
+ example += "# !!!yaml\n"
2510
+ example += "# ---\n"
2511
+ example += "# appname: #{complexity}\n"
2512
+ example += "# #{cfg_plural}:\n"
2513
+ firstline = true
2514
+ erb.result(binding).split(/\n/).each { |l|
2515
+ l.sub!(/#.*/, "")
2516
+ next if l.empty? or l.match(/^\s+$/)
2517
+ if firstline
2518
+ l = "- "+l
2519
+ firstline = false
2520
+ else
2521
+ l = " "+l
2522
+ end
2523
+ example += "# "+l+" "+"\n"
2524
+ }
2525
+ example += "# &nbsp;\n#\n" if complexity == "simple"
2526
+ }
2527
+ schema["properties"][name]["items"]["description"] ||= ""
2528
+ if !schema["properties"][name]["items"]["description"].empty?
2529
+ schema["properties"][name]["items"]["description"] += "\n"
2530
+ end
2531
+ schema["properties"][name]["items"]["description"] += example
2532
+ end
2533
+ end
2534
+ end
2535
+
2456
2536
  if !schema["required"].nil? and schema["required"].include?(name)
2457
2537
  printme << "# @!group Required parameters" if !req
2458
2538
  req = true