cloud-mu 3.1.3 → 3.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +10 -2
- data/bin/mu-adopt +5 -1
- data/bin/mu-load-config.rb +2 -3
- data/bin/mu-run-tests +112 -27
- data/cloud-mu.gemspec +20 -20
- data/cookbooks/mu-tools/libraries/helper.rb +2 -1
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +5 -15
- data/modules/mu.rb +10 -14
- data/modules/mu/adoption.rb +20 -14
- data/modules/mu/cleanup.rb +13 -9
- data/modules/mu/cloud.rb +26 -26
- data/modules/mu/clouds/aws.rb +100 -59
- data/modules/mu/clouds/aws/alarm.rb +4 -2
- data/modules/mu/clouds/aws/bucket.rb +25 -21
- data/modules/mu/clouds/aws/cache_cluster.rb +25 -23
- data/modules/mu/clouds/aws/collection.rb +21 -20
- data/modules/mu/clouds/aws/container_cluster.rb +47 -26
- data/modules/mu/clouds/aws/database.rb +57 -68
- data/modules/mu/clouds/aws/dnszone.rb +14 -14
- data/modules/mu/clouds/aws/endpoint.rb +20 -16
- data/modules/mu/clouds/aws/firewall_rule.rb +19 -16
- data/modules/mu/clouds/aws/folder.rb +7 -7
- data/modules/mu/clouds/aws/function.rb +15 -12
- data/modules/mu/clouds/aws/group.rb +14 -10
- data/modules/mu/clouds/aws/habitat.rb +16 -13
- data/modules/mu/clouds/aws/loadbalancer.rb +16 -15
- data/modules/mu/clouds/aws/log.rb +13 -10
- data/modules/mu/clouds/aws/msg_queue.rb +15 -8
- data/modules/mu/clouds/aws/nosqldb.rb +18 -11
- data/modules/mu/clouds/aws/notifier.rb +11 -6
- data/modules/mu/clouds/aws/role.rb +87 -70
- data/modules/mu/clouds/aws/search_domain.rb +30 -19
- data/modules/mu/clouds/aws/server.rb +102 -72
- data/modules/mu/clouds/aws/server_pool.rb +47 -28
- data/modules/mu/clouds/aws/storage_pool.rb +5 -6
- data/modules/mu/clouds/aws/user.rb +13 -10
- data/modules/mu/clouds/aws/vpc.rb +135 -121
- data/modules/mu/clouds/azure.rb +16 -9
- data/modules/mu/clouds/azure/container_cluster.rb +2 -3
- data/modules/mu/clouds/azure/firewall_rule.rb +10 -10
- data/modules/mu/clouds/azure/habitat.rb +8 -6
- data/modules/mu/clouds/azure/loadbalancer.rb +5 -5
- data/modules/mu/clouds/azure/role.rb +8 -10
- data/modules/mu/clouds/azure/server.rb +65 -25
- data/modules/mu/clouds/azure/user.rb +5 -7
- data/modules/mu/clouds/azure/vpc.rb +12 -15
- data/modules/mu/clouds/cloudformation.rb +8 -7
- data/modules/mu/clouds/cloudformation/vpc.rb +2 -4
- data/modules/mu/clouds/google.rb +39 -24
- data/modules/mu/clouds/google/bucket.rb +9 -11
- data/modules/mu/clouds/google/container_cluster.rb +27 -42
- data/modules/mu/clouds/google/database.rb +6 -9
- data/modules/mu/clouds/google/firewall_rule.rb +11 -10
- data/modules/mu/clouds/google/folder.rb +16 -9
- data/modules/mu/clouds/google/function.rb +127 -161
- data/modules/mu/clouds/google/group.rb +21 -18
- data/modules/mu/clouds/google/habitat.rb +18 -15
- data/modules/mu/clouds/google/loadbalancer.rb +14 -16
- data/modules/mu/clouds/google/role.rb +48 -31
- data/modules/mu/clouds/google/server.rb +105 -105
- data/modules/mu/clouds/google/server_pool.rb +12 -31
- data/modules/mu/clouds/google/user.rb +67 -13
- data/modules/mu/clouds/google/vpc.rb +58 -65
- data/modules/mu/config.rb +89 -1738
- data/modules/mu/config/bucket.rb +3 -3
- data/modules/mu/config/collection.rb +3 -3
- data/modules/mu/config/container_cluster.rb +2 -2
- data/modules/mu/config/dnszone.rb +5 -5
- data/modules/mu/config/doc_helpers.rb +517 -0
- data/modules/mu/config/endpoint.rb +3 -3
- data/modules/mu/config/firewall_rule.rb +118 -3
- data/modules/mu/config/folder.rb +3 -3
- data/modules/mu/config/function.rb +2 -2
- data/modules/mu/config/group.rb +3 -3
- data/modules/mu/config/habitat.rb +3 -3
- data/modules/mu/config/loadbalancer.rb +3 -3
- data/modules/mu/config/log.rb +3 -3
- data/modules/mu/config/msg_queue.rb +3 -3
- data/modules/mu/config/nosqldb.rb +3 -3
- data/modules/mu/config/notifier.rb +2 -2
- data/modules/mu/config/ref.rb +333 -0
- data/modules/mu/config/role.rb +3 -3
- data/modules/mu/config/schema_helpers.rb +508 -0
- data/modules/mu/config/search_domain.rb +3 -3
- data/modules/mu/config/server.rb +86 -58
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/tail.rb +189 -0
- data/modules/mu/config/user.rb +3 -3
- data/modules/mu/config/vpc.rb +44 -4
- data/modules/mu/defaults/Google.yaml +2 -2
- data/modules/mu/deploy.rb +13 -10
- data/modules/mu/groomer.rb +1 -1
- data/modules/mu/groomers/ansible.rb +69 -24
- data/modules/mu/groomers/chef.rb +52 -44
- data/modules/mu/logger.rb +17 -14
- data/modules/mu/master.rb +317 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -2
- data/modules/mu/mommacat.rb +85 -1766
- data/modules/mu/mommacat/daemon.rb +394 -0
- data/modules/mu/mommacat/naming.rb +366 -0
- data/modules/mu/mommacat/storage.rb +689 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/{win2k12.yaml → needwork/win2k12.yaml} +0 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- metadata +112 -102
data/modules/mu/config/bucket.rb
CHANGED
|
@@ -59,10 +59,10 @@ module MU
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
# Generic pre-processing of {MU::Config::BasketofKittens::buckets}, bare and unvalidated.
|
|
62
|
-
# @param
|
|
63
|
-
# @param
|
|
62
|
+
# @param _bucket [Hash]: The resource to process and validate
|
|
63
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
64
64
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
65
|
-
def self.validate(
|
|
65
|
+
def self.validate(_bucket, _configurator)
|
|
66
66
|
ok = true
|
|
67
67
|
|
|
68
68
|
ok
|
|
@@ -74,10 +74,10 @@ module MU
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
# Generic pre-processing of {MU::Config::BasketofKittens::collections}, bare and unvalidated.
|
|
77
|
-
# @param
|
|
78
|
-
# @param
|
|
77
|
+
# @param _stack [Hash]: The resource to process and validate
|
|
78
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
79
79
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
80
|
-
def self.validate(
|
|
80
|
+
def self.validate(_stack, _configurator)
|
|
81
81
|
ok = true
|
|
82
82
|
ok
|
|
83
83
|
end
|
|
@@ -94,9 +94,9 @@ module MU
|
|
|
94
94
|
|
|
95
95
|
# Generic pre-processing of {MU::Config::BasketofKittens::container_clusters}, bare and unvalidated.
|
|
96
96
|
# @param cluster [Hash]: The resource to process and validate
|
|
97
|
-
# @param
|
|
97
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
98
98
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
99
|
-
def self.validate(cluster,
|
|
99
|
+
def self.validate(cluster, _configurator)
|
|
100
100
|
ok = true
|
|
101
101
|
|
|
102
102
|
if cluster["max_size"] or cluster["min_size"]
|
|
@@ -312,15 +312,15 @@ module MU
|
|
|
312
312
|
end
|
|
313
313
|
|
|
314
314
|
# Generic pre-processing of {MU::Config::BasketofKittens::dnszones}, bare and unvalidated.
|
|
315
|
-
# @param
|
|
316
|
-
# @param
|
|
315
|
+
# @param _zone [Hash]: The resource to process and validate
|
|
316
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
317
317
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
318
|
-
def self.validate(
|
|
318
|
+
def self.validate(_zone, _configurator)
|
|
319
319
|
ok = true
|
|
320
|
-
ok
|
|
321
|
-
end
|
|
322
320
|
# TODO non-local VPCs are valid, but require an account field, which insertKitten doesn't know anything about
|
|
323
321
|
# if !zone['account'].nil? and zone['account'] != MU.account_number
|
|
322
|
+
ok
|
|
323
|
+
end
|
|
324
324
|
|
|
325
325
|
end
|
|
326
326
|
end
|
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
# Copyright:: Copyright (c) 2020 eGlobalTech, Inc., all rights reserved
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the BSD-3 license (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License in the root of the project or at
|
|
6
|
+
#
|
|
7
|
+
# http://egt-labs.com/mu/LICENSE.html
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
module MU
|
|
16
|
+
|
|
17
|
+
# Methods and structures for parsing Mu's configuration files. See also {MU::Config::BasketofKittens}.
|
|
18
|
+
class Config
|
|
19
|
+
|
|
20
|
+
# Accessor for our Basket of Kittens schema definition, with various
|
|
21
|
+
# cloud-specific details merged so we can generate documentation for them.
|
|
22
|
+
def self.docSchema
|
|
23
|
+
docschema = Marshal.load(Marshal.dump(@@schema))
|
|
24
|
+
only_children = {}
|
|
25
|
+
MU::Cloud.resource_types.each_pair { |classname, attrs|
|
|
26
|
+
MU::Cloud.supportedClouds.each { |cloud|
|
|
27
|
+
begin
|
|
28
|
+
require "mu/clouds/#{cloud.downcase}/#{attrs[:cfg_name]}"
|
|
29
|
+
rescue LoadError
|
|
30
|
+
next
|
|
31
|
+
end
|
|
32
|
+
res_class = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(classname)
|
|
33
|
+
_required, res_schema = res_class.schema(self)
|
|
34
|
+
docschema["properties"][attrs[:cfg_plural]]["items"]["description"] ||= ""
|
|
35
|
+
docschema["properties"][attrs[:cfg_plural]]["items"]["description"] += "\n#\n# `#{cloud}`: "+res_class.quality
|
|
36
|
+
res_schema.each { |key, cfg|
|
|
37
|
+
if !docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key]
|
|
38
|
+
only_children[attrs[:cfg_plural]] ||= {}
|
|
39
|
+
only_children[attrs[:cfg_plural]][key] ||= {}
|
|
40
|
+
only_children[attrs[:cfg_plural]][key][cloud] = cfg
|
|
41
|
+
end
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# recursively chase down description fields in arrays and objects of our
|
|
47
|
+
# schema and prepend stuff to them for documentation
|
|
48
|
+
def self.prepend_descriptions(prefix, cfg)
|
|
49
|
+
cfg["prefix"] = prefix
|
|
50
|
+
if cfg["type"] == "array" and cfg["items"]
|
|
51
|
+
cfg["items"] = prepend_descriptions(prefix, cfg["items"])
|
|
52
|
+
elsif cfg["type"] == "object" and cfg["properties"]
|
|
53
|
+
cfg["properties"].keys.each { |key|
|
|
54
|
+
cfg["properties"][key] = prepend_descriptions(prefix, cfg["properties"][key])
|
|
55
|
+
}
|
|
56
|
+
end
|
|
57
|
+
cfg
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
MU::Cloud.resource_types.each_pair { |classname, attrs|
|
|
61
|
+
MU::Cloud.supportedClouds.each { |cloud|
|
|
62
|
+
res_class = nil
|
|
63
|
+
begin
|
|
64
|
+
res_class = Object.const_get("MU").const_get("Cloud").const_get(cloud).const_get(classname)
|
|
65
|
+
rescue MU::Cloud::MuCloudResourceNotImplemented
|
|
66
|
+
next
|
|
67
|
+
end
|
|
68
|
+
required, res_schema = res_class.schema(self)
|
|
69
|
+
next if required.size == 0 and res_schema.size == 0
|
|
70
|
+
res_schema.each { |key, cfg|
|
|
71
|
+
cfg["description"] ||= ""
|
|
72
|
+
if !cfg["description"].empty?
|
|
73
|
+
cfg["description"] = "\n# +"+cloud.upcase+"+: "+cfg["description"]
|
|
74
|
+
end
|
|
75
|
+
if docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key]
|
|
76
|
+
schemaMerge(docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key], cfg, cloud)
|
|
77
|
+
docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key]["description"] ||= ""
|
|
78
|
+
docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key]["description"] += "\n"+(cfg["description"].match(/^#/) ? "" : "# ")+cfg["description"]
|
|
79
|
+
MU.log "Munging #{cloud}-specific #{classname.to_s} schema into BasketofKittens => #{attrs[:cfg_plural]} => #{key}", MU::DEBUG, details: docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key]
|
|
80
|
+
else
|
|
81
|
+
if only_children[attrs[:cfg_plural]][key]
|
|
82
|
+
prefix = only_children[attrs[:cfg_plural]][key].keys.map{ |x| x.upcase }.join(" & ")+" ONLY"
|
|
83
|
+
cfg["description"].gsub!(/^\n#/, '') # so we don't leave the description blank in the "optional parameters" section
|
|
84
|
+
cfg = prepend_descriptions(prefix, cfg)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key] = cfg
|
|
88
|
+
end
|
|
89
|
+
docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key]["clouds"] = {}
|
|
90
|
+
docschema["properties"][attrs[:cfg_plural]]["items"]["properties"][key]["clouds"][cloud] = cfg
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
docschema['required'].concat(required)
|
|
94
|
+
docschema['required'].uniq!
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
docschema
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Output the dependencies of this BoK stack as a directed acyclic graph.
|
|
102
|
+
# Very useful for debugging.
|
|
103
|
+
def visualizeDependencies
|
|
104
|
+
# GraphViz won't like MU::Config::Tail, pare down to plain Strings
|
|
105
|
+
config = MU::Config.stripConfig(@config)
|
|
106
|
+
begin
|
|
107
|
+
g = GraphViz.new(:G, :type => :digraph)
|
|
108
|
+
# Generate a GraphViz node for each resource in this stack
|
|
109
|
+
nodes = {}
|
|
110
|
+
MU::Cloud.resource_types.each_pair { |classname, attrs|
|
|
111
|
+
nodes[attrs[:cfg_name]] = {}
|
|
112
|
+
if config.has_key?(attrs[:cfg_plural]) and config[attrs[:cfg_plural]]
|
|
113
|
+
config[attrs[:cfg_plural]].each { |resource|
|
|
114
|
+
nodes[attrs[:cfg_name]][resource['name']] = g.add_nodes("#{classname}: #{resource['name']}")
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
}
|
|
118
|
+
# Now add edges corresponding to the dependencies they list
|
|
119
|
+
MU::Cloud.resource_types.values.each { |attrs|
|
|
120
|
+
if config.has_key?(attrs[:cfg_plural]) and config[attrs[:cfg_plural]]
|
|
121
|
+
config[attrs[:cfg_plural]].each { |resource|
|
|
122
|
+
if resource.has_key?("dependencies")
|
|
123
|
+
me = nodes[attrs[:cfg_name]][resource['name']]
|
|
124
|
+
resource["dependencies"].each { |dep|
|
|
125
|
+
parent = nodes[dep['type']][dep['name']]
|
|
126
|
+
g.add_edges(me, parent)
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
}
|
|
130
|
+
end
|
|
131
|
+
}
|
|
132
|
+
# Spew some output?
|
|
133
|
+
MU.log "Emitting dependency graph as /tmp/#{config['appname']}.jpg", MU::NOTICE
|
|
134
|
+
g.output(:jpg => "/tmp/#{config['appname']}.jpg")
|
|
135
|
+
rescue StandardError => e
|
|
136
|
+
MU.log "Failed to generate GraphViz dependency tree: #{e.inspect}. This should only matter to developers.", MU::WARN, details: e.backtrace
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Generate a documentation-friendly dummy Ruby class for our mu.yaml main
|
|
141
|
+
# config.
|
|
142
|
+
def self.emitConfigAsRuby
|
|
143
|
+
example = %Q{---
|
|
144
|
+
public_address: 1.2.3.4
|
|
145
|
+
mu_admin_email: egtlabs@eglobaltech.com
|
|
146
|
+
mu_admin_name: Joe Schmoe
|
|
147
|
+
mommacat_port: 2260
|
|
148
|
+
banner: My Example Mu Master
|
|
149
|
+
mu_repository: git://github.com/cloudamatic/mu.git
|
|
150
|
+
repos:
|
|
151
|
+
- https://github.com/cloudamatic/mu_demo_platform
|
|
152
|
+
allow_invade_foreign_vpcs: true
|
|
153
|
+
ansible_dir:
|
|
154
|
+
aws:
|
|
155
|
+
egtdev:
|
|
156
|
+
region: us-east-1
|
|
157
|
+
log_bucket_name: egt-mu-log-bucket
|
|
158
|
+
default: true
|
|
159
|
+
name: egtdev
|
|
160
|
+
personal:
|
|
161
|
+
region: us-east-2
|
|
162
|
+
log_bucket_name: my-mu-log-bucket
|
|
163
|
+
name: personal
|
|
164
|
+
google:
|
|
165
|
+
egtlabs:
|
|
166
|
+
project: egt-labs-admin
|
|
167
|
+
credentials_file: /opt/mu/etc/google.json
|
|
168
|
+
region: us-east4
|
|
169
|
+
log_bucket_name: hexabucket-761234
|
|
170
|
+
default: true
|
|
171
|
+
}
|
|
172
|
+
mu_yaml_schema = eval(%Q{
|
|
173
|
+
$NOOP = true
|
|
174
|
+
load "#{MU.myRoot}/bin/mu-configure"
|
|
175
|
+
$CONFIGURABLES
|
|
176
|
+
})
|
|
177
|
+
return if mu_yaml_schema.nil? or !mu_yaml_schema.is_a?(Hash)
|
|
178
|
+
muyamlpath = "#{MU.myRoot}/modules/mu/mu.yaml.rb"
|
|
179
|
+
MU.log "Converting mu.yaml schema to Ruby objects in #{muyamlpath}"
|
|
180
|
+
muyaml_rb = File.new(muyamlpath, File::CREAT|File::TRUNC|File::RDWR, 0644)
|
|
181
|
+
muyaml_rb.puts "# Configuration schema for mu.yaml. See also {https://github.com/cloudamatic/mu/wiki/Configuration the Mu wiki}."
|
|
182
|
+
muyaml_rb.puts "#"
|
|
183
|
+
muyaml_rb.puts "# Example:"
|
|
184
|
+
muyaml_rb.puts "#"
|
|
185
|
+
muyaml_rb.puts "# <pre>"
|
|
186
|
+
example.split(/\n/).each { |line|
|
|
187
|
+
muyaml_rb.puts "# "+line+" " # markdooooown
|
|
188
|
+
}
|
|
189
|
+
muyaml_rb.puts "# </pre>"
|
|
190
|
+
muyaml_rb.puts "module MuYAML"
|
|
191
|
+
muyaml_rb.puts "\t# The configuration file format for Mu's main config file."
|
|
192
|
+
MU::Config.printMuYamlSchema(muyaml_rb, [], { "subtree" => mu_yaml_schema })
|
|
193
|
+
muyaml_rb.puts "end"
|
|
194
|
+
muyaml_rb.close
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Take the schema we've defined and create a dummy Ruby class tree out of
|
|
198
|
+
# it, basically so we can leverage Yard to document it.
|
|
199
|
+
def self.emitSchemaAsRuby
|
|
200
|
+
kittenpath = "#{MU.myRoot}/modules/mu/kittens.rb"
|
|
201
|
+
MU.log "Converting Basket of Kittens schema to Ruby objects in #{kittenpath}"
|
|
202
|
+
kitten_rb = File.new(kittenpath, File::CREAT|File::TRUNC|File::RDWR, 0644)
|
|
203
|
+
kitten_rb.puts "### THIS FILE IS AUTOMATICALLY GENERATED, DO NOT EDIT ###"
|
|
204
|
+
kitten_rb.puts "#"
|
|
205
|
+
kitten_rb.puts "#"
|
|
206
|
+
kitten_rb.puts "#"
|
|
207
|
+
kitten_rb.puts "module MU"
|
|
208
|
+
kitten_rb.puts "class Config"
|
|
209
|
+
kitten_rb.puts "\t# The configuration file format for Mu application stacks."
|
|
210
|
+
self.printSchema(kitten_rb, ["BasketofKittens"], MU::Config.docSchema)
|
|
211
|
+
kitten_rb.puts "end"
|
|
212
|
+
kitten_rb.puts "end"
|
|
213
|
+
kitten_rb.close
|
|
214
|
+
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Emit our Basket of Kittens schema in a format that YARD can comprehend
|
|
218
|
+
# and turn into documentation.
|
|
219
|
+
def self.printSchema(kitten_rb, class_hierarchy, schema, in_array = false, required = false, prefix: nil)
|
|
220
|
+
return if schema.nil?
|
|
221
|
+
|
|
222
|
+
if schema["type"] == "object"
|
|
223
|
+
printme = []
|
|
224
|
+
|
|
225
|
+
if !schema["properties"].nil?
|
|
226
|
+
# order sub-elements by whether they're required, so we can use YARD's
|
|
227
|
+
# grouping tags on them
|
|
228
|
+
if !schema["required"].nil? and schema["required"].size > 0
|
|
229
|
+
prop_list = schema["properties"].keys.sort_by { |name|
|
|
230
|
+
schema["required"].include?(name) ? 0 : 1
|
|
231
|
+
}
|
|
232
|
+
else
|
|
233
|
+
prop_list = schema["properties"].keys
|
|
234
|
+
end
|
|
235
|
+
req = false
|
|
236
|
+
printme << "# @!group Optional parameters" if schema["required"].nil? or schema["required"].size == 0
|
|
237
|
+
prop_list.each { |name|
|
|
238
|
+
prop = schema["properties"][name]
|
|
239
|
+
|
|
240
|
+
if class_hierarchy.size == 1
|
|
241
|
+
|
|
242
|
+
_shortclass, cfg_name, cfg_plural, _classname = MU::Cloud.getResourceNames(name)
|
|
243
|
+
if cfg_name
|
|
244
|
+
example_path = MU.myRoot+"/modules/mu/config/"+cfg_name+".yml"
|
|
245
|
+
if File.exist?(example_path)
|
|
246
|
+
example = "#\n# Examples:\n#\n"
|
|
247
|
+
# XXX these variables are all parameters from the BoKs in
|
|
248
|
+
# modules/tests. A really clever implementation would read
|
|
249
|
+
# and parse them to get default values, perhaps, instead of
|
|
250
|
+
# hard-coding them here.
|
|
251
|
+
instance_type = "t2.medium"
|
|
252
|
+
db_size = "db.t2.medium"
|
|
253
|
+
vpc_name = "some_vpc"
|
|
254
|
+
logs_name = "some_loggroup"
|
|
255
|
+
queues_name = "some_queue"
|
|
256
|
+
server_pools_name = "some_server_pool"
|
|
257
|
+
["simple", "complex"].each { |complexity|
|
|
258
|
+
erb = ERB.new(File.read(example_path), nil, "<>")
|
|
259
|
+
example += "# !!!yaml\n"
|
|
260
|
+
example += "# ---\n"
|
|
261
|
+
example += "# appname: #{complexity}\n"
|
|
262
|
+
example += "# #{cfg_plural}:\n"
|
|
263
|
+
firstline = true
|
|
264
|
+
erb.result(binding).split(/\n/).each { |l|
|
|
265
|
+
l.chomp!
|
|
266
|
+
l.sub!(/#.*/, "") if !l.match(/#(?:INTERNET|NAT|DENY)/)
|
|
267
|
+
next if l.empty? or l.match(/^\s+$/)
|
|
268
|
+
if firstline
|
|
269
|
+
l = "- "+l
|
|
270
|
+
firstline = false
|
|
271
|
+
else
|
|
272
|
+
l = " "+l
|
|
273
|
+
end
|
|
274
|
+
example += "# "+l+" "+"\n"
|
|
275
|
+
}
|
|
276
|
+
example += "# \n#\n" if complexity == "simple"
|
|
277
|
+
}
|
|
278
|
+
schema["properties"][name]["items"]["description"] ||= ""
|
|
279
|
+
if !schema["properties"][name]["items"]["description"].empty?
|
|
280
|
+
schema["properties"][name]["items"]["description"] += "\n"
|
|
281
|
+
end
|
|
282
|
+
schema["properties"][name]["items"]["description"] += example
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
if !schema["required"].nil? and schema["required"].include?(name)
|
|
288
|
+
printme << "# @!group Required parameters" if !req
|
|
289
|
+
req = true
|
|
290
|
+
else
|
|
291
|
+
if req
|
|
292
|
+
printme << "# @!endgroup"
|
|
293
|
+
printme << "# @!group Optional parameters"
|
|
294
|
+
end
|
|
295
|
+
req = false
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
printme << self.printSchema(kitten_rb, class_hierarchy+ [name], prop, false, req, prefix: schema["prefix"])
|
|
299
|
+
}
|
|
300
|
+
printme << "# @!endgroup"
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
tabs = 1
|
|
304
|
+
class_hierarchy.each { |classname|
|
|
305
|
+
if classname == class_hierarchy.last and !schema['description'].nil?
|
|
306
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + "# #{schema['description']}\n"
|
|
307
|
+
end
|
|
308
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + "class #{classname}"
|
|
309
|
+
tabs = tabs + 1
|
|
310
|
+
}
|
|
311
|
+
printme.each { |lines|
|
|
312
|
+
if !lines.nil? and lines.is_a?(String)
|
|
313
|
+
lines.lines.each { |line|
|
|
314
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + line
|
|
315
|
+
}
|
|
316
|
+
end
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
i = class_hierarchy.size
|
|
320
|
+
until i == 0 do
|
|
321
|
+
tabs = tabs - 1
|
|
322
|
+
kitten_rb.puts ["\t"].cycle(tabs).to_a.join('') + "end"
|
|
323
|
+
i -= 1
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# And now that we've dealt with our children, pass our own rendered
|
|
327
|
+
# commentary back up to our caller.
|
|
328
|
+
name = class_hierarchy.last
|
|
329
|
+
if in_array
|
|
330
|
+
type = "Array<#{class_hierarchy.join("::")}>"
|
|
331
|
+
else
|
|
332
|
+
type = class_hierarchy.join("::")
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
docstring = "\n"
|
|
336
|
+
docstring = docstring + "# **REQUIRED**\n" if required
|
|
337
|
+
docstring = docstring + "# **"+schema["prefix"]+"**\n" if schema["prefix"]
|
|
338
|
+
docstring = docstring + "# #{schema['description'].gsub(/\n/, "\n#")}\n" if !schema['description'].nil?
|
|
339
|
+
docstring = docstring + "#\n"
|
|
340
|
+
docstring = docstring + "# @return [#{type}]\n"
|
|
341
|
+
docstring = docstring + "# @see #{class_hierarchy.join("::")}\n"
|
|
342
|
+
docstring = docstring + "attr_accessor :#{name}"
|
|
343
|
+
return docstring
|
|
344
|
+
|
|
345
|
+
elsif schema["type"] == "array"
|
|
346
|
+
return self.printSchema(kitten_rb, class_hierarchy, schema['items'], true, required, prefix: prefix)
|
|
347
|
+
else
|
|
348
|
+
name = class_hierarchy.last
|
|
349
|
+
if schema['type'].nil?
|
|
350
|
+
MU.log "Couldn't determine schema type in #{class_hierarchy.join(" => ")}", MU::WARN, details: schema
|
|
351
|
+
return nil
|
|
352
|
+
end
|
|
353
|
+
if in_array
|
|
354
|
+
type = "Array<#{schema['type'].capitalize}>"
|
|
355
|
+
else
|
|
356
|
+
type = schema['type'].capitalize
|
|
357
|
+
end
|
|
358
|
+
docstring = "\n"
|
|
359
|
+
|
|
360
|
+
prefixes = []
|
|
361
|
+
prefixes << "# **REQUIRED**" if required and schema['default'].nil?
|
|
362
|
+
prefixes << "# **"+schema["prefix"]+"**" if schema["prefix"]
|
|
363
|
+
prefixes << "# **Default: `#{schema['default']}`**" if !schema['default'].nil?
|
|
364
|
+
if !schema['enum'].nil? and !schema["enum"].empty?
|
|
365
|
+
prefixes << "# **Must be one of: `#{schema['enum'].join(', ')}`**"
|
|
366
|
+
elsif !schema['pattern'].nil?
|
|
367
|
+
# XXX unquoted regex chars confuse the hell out of YARD. How do we
|
|
368
|
+
# quote {}[] etc in YARD-speak?
|
|
369
|
+
prefixes << "# **Must match pattern `#{schema['pattern'].gsub(/\n/, "\n#")}`**"
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
if prefixes.size > 0
|
|
373
|
+
docstring += prefixes.join(",\n")
|
|
374
|
+
if schema['description'] and schema['description'].size > 1
|
|
375
|
+
docstring += " - "
|
|
376
|
+
end
|
|
377
|
+
docstring += "\n"
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
docstring = docstring + "# #{schema['description'].gsub(/\n/, "\n#")}\n" if !schema['description'].nil?
|
|
381
|
+
docstring = docstring + "#\n"
|
|
382
|
+
docstring = docstring + "# @return [#{type}]\n"
|
|
383
|
+
docstring = docstring + "attr_accessor :#{name}"
|
|
384
|
+
|
|
385
|
+
return docstring
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# Emit our mu.yaml schema in a format that YARD can comprehend and turn into
|
|
390
|
+
# documentation.
|
|
391
|
+
def self.printMuYamlSchema(muyaml_rb, class_hierarchy, schema, in_array = false, required = false)
|
|
392
|
+
return if schema.nil?
|
|
393
|
+
if schema["subtree"]
|
|
394
|
+
printme = Array.new
|
|
395
|
+
# order sub-elements by whether they're required, so we can use YARD's
|
|
396
|
+
# grouping tags on them
|
|
397
|
+
have_required = schema["subtree"].keys.any? { |k| schema["subtree"][k]["required"] }
|
|
398
|
+
prop_list = schema["subtree"].keys.sort { |a, b|
|
|
399
|
+
if schema["subtree"][a]["required"] and !schema["subtree"][b]["required"]
|
|
400
|
+
-1
|
|
401
|
+
elsif !schema["subtree"][a]["required"] and schema["subtree"][b]["required"]
|
|
402
|
+
1
|
|
403
|
+
else
|
|
404
|
+
a <=> b
|
|
405
|
+
end
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
req = false
|
|
409
|
+
printme << "# @!group Optional parameters" if !have_required
|
|
410
|
+
prop_list.each { |name|
|
|
411
|
+
prop = schema["subtree"][name]
|
|
412
|
+
if prop["required"]
|
|
413
|
+
printme << "# @!group Required parameters" if !req
|
|
414
|
+
req = true
|
|
415
|
+
else
|
|
416
|
+
if req
|
|
417
|
+
printme << "# @!endgroup"
|
|
418
|
+
printme << "# @!group Optional parameters"
|
|
419
|
+
end
|
|
420
|
+
req = false
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
printme << self.printMuYamlSchema(muyaml_rb, class_hierarchy+ [name], prop, false, req)
|
|
424
|
+
}
|
|
425
|
+
printme << "# @!endgroup"
|
|
426
|
+
|
|
427
|
+
desc = (schema['desc'] || schema['title'])
|
|
428
|
+
|
|
429
|
+
tabs = 1
|
|
430
|
+
class_hierarchy.each { |classname|
|
|
431
|
+
if classname == class_hierarchy.last and desc
|
|
432
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + "# #{desc}\n"
|
|
433
|
+
end
|
|
434
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + "class #{classname}"
|
|
435
|
+
tabs = tabs + 1
|
|
436
|
+
}
|
|
437
|
+
printme.each { |lines|
|
|
438
|
+
if !lines.nil? and lines.is_a?(String)
|
|
439
|
+
lines.lines.each { |line|
|
|
440
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + line
|
|
441
|
+
}
|
|
442
|
+
end
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
# class_hierarchy.each { |classname|
|
|
446
|
+
# tabs = tabs - 1
|
|
447
|
+
# muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + "end"
|
|
448
|
+
# }
|
|
449
|
+
i = class_hierarchy.size
|
|
450
|
+
until i == 0 do
|
|
451
|
+
tabs = tabs - 1
|
|
452
|
+
muyaml_rb.puts ["\t"].cycle(tabs).to_a.join('') + "end"
|
|
453
|
+
i -= 1
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# And now that we've dealt with our children, pass our own rendered
|
|
457
|
+
# commentary back up to our caller.
|
|
458
|
+
name = class_hierarchy.last
|
|
459
|
+
if in_array
|
|
460
|
+
type = "Array<#{class_hierarchy.join("::")}>"
|
|
461
|
+
else
|
|
462
|
+
type = class_hierarchy.join("::")
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
docstring = "\n"
|
|
466
|
+
docstring = docstring + "# **REQUIRED**\n" if required
|
|
467
|
+
# docstring = docstring + "# **"+schema["prefix"]+"**\n" if schema["prefix"]
|
|
468
|
+
docstring = docstring + "# #{desc.gsub(/\n/, "\n#")}\n" if desc
|
|
469
|
+
docstring = docstring + "#\n"
|
|
470
|
+
docstring = docstring + "# @return [#{type}]\n"
|
|
471
|
+
docstring = docstring + "# @see #{class_hierarchy.join("::")}\n"
|
|
472
|
+
docstring = docstring + "attr_accessor :#{name}"
|
|
473
|
+
return docstring
|
|
474
|
+
|
|
475
|
+
else
|
|
476
|
+
in_array = schema["array"]
|
|
477
|
+
name = class_hierarchy.last
|
|
478
|
+
type = if schema['boolean']
|
|
479
|
+
"Boolean"
|
|
480
|
+
else
|
|
481
|
+
"String"
|
|
482
|
+
end
|
|
483
|
+
if in_array
|
|
484
|
+
type = "Array<#{type}>"
|
|
485
|
+
end
|
|
486
|
+
docstring = "\n"
|
|
487
|
+
|
|
488
|
+
prefixes = []
|
|
489
|
+
prefixes << "# **REQUIRED**" if schema["required"] and schema['default'].nil?
|
|
490
|
+
# prefixes << "# **"+schema["prefix"]+"**" if schema["prefix"]
|
|
491
|
+
prefixes << "# **Default: `#{schema['default']}`**" if !schema['default'].nil?
|
|
492
|
+
if !schema['pattern'].nil?
|
|
493
|
+
# XXX unquoted regex chars confuse the hell out of YARD. How do we
|
|
494
|
+
# quote {}[] etc in YARD-speak?
|
|
495
|
+
prefixes << "# **Must match pattern `#{schema['pattern'].to_s.gsub(/\n/, "\n#")}`**"
|
|
496
|
+
end
|
|
497
|
+
|
|
498
|
+
desc = (schema['desc'] || schema['title'])
|
|
499
|
+
if prefixes.size > 0
|
|
500
|
+
docstring += prefixes.join(",\n")
|
|
501
|
+
if desc and desc.size > 1
|
|
502
|
+
docstring += " - "
|
|
503
|
+
end
|
|
504
|
+
docstring += "\n"
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
docstring = docstring + "# #{desc.gsub(/\n/, "\n#")}\n" if !desc.nil?
|
|
508
|
+
docstring = docstring + "#\n"
|
|
509
|
+
docstring = docstring + "# @return [#{type}]\n"
|
|
510
|
+
docstring = docstring + "attr_accessor :#{name}"
|
|
511
|
+
|
|
512
|
+
return docstring
|
|
513
|
+
end
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
end #class
|
|
517
|
+
end #module
|