cloud-mu 3.1.3 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Dockerfile +15 -3
- data/ansible/roles/mu-windows/README.md +33 -0
- data/ansible/roles/mu-windows/defaults/main.yml +2 -0
- data/ansible/roles/mu-windows/files/LaunchConfig.json +9 -0
- data/ansible/roles/mu-windows/files/config.xml +76 -0
- data/ansible/roles/mu-windows/handlers/main.yml +2 -0
- data/ansible/roles/mu-windows/meta/main.yml +53 -0
- data/ansible/roles/mu-windows/tasks/main.yml +36 -0
- data/ansible/roles/mu-windows/tests/inventory +2 -0
- data/ansible/roles/mu-windows/tests/test.yml +5 -0
- data/ansible/roles/mu-windows/vars/main.yml +2 -0
- data/bin/mu-adopt +21 -13
- data/bin/mu-azure-tests +57 -0
- data/bin/mu-cleanup +2 -4
- data/bin/mu-configure +52 -0
- data/bin/mu-deploy +3 -3
- data/bin/mu-findstray-tests +25 -0
- data/bin/mu-gen-docs +2 -4
- data/bin/mu-load-config.rb +4 -4
- data/bin/mu-node-manage +15 -16
- data/bin/mu-run-tests +147 -37
- data/cloud-mu.gemspec +22 -20
- data/cookbooks/mu-activedirectory/resources/domain.rb +4 -4
- data/cookbooks/mu-activedirectory/resources/domain_controller.rb +4 -4
- data/cookbooks/mu-tools/libraries/helper.rb +3 -2
- data/cookbooks/mu-tools/libraries/monkey.rb +35 -0
- data/cookbooks/mu-tools/recipes/apply_security.rb +14 -14
- data/cookbooks/mu-tools/recipes/aws_api.rb +9 -0
- data/cookbooks/mu-tools/recipes/eks.rb +2 -2
- data/cookbooks/mu-tools/recipes/google_api.rb +2 -2
- data/cookbooks/mu-tools/recipes/selinux.rb +2 -1
- data/cookbooks/mu-tools/recipes/windows-client.rb +163 -164
- data/cookbooks/mu-tools/resources/disk.rb +1 -1
- data/cookbooks/mu-tools/resources/windows_users.rb +44 -43
- data/extras/clean-stock-amis +25 -19
- data/extras/generate-stock-images +1 -0
- data/extras/image-generators/AWS/win2k12.yaml +18 -13
- data/extras/image-generators/AWS/win2k16.yaml +18 -13
- data/extras/image-generators/AWS/win2k19.yaml +21 -0
- data/extras/image-generators/Google/centos6.yaml +1 -0
- data/extras/image-generators/Google/centos7.yaml +1 -1
- data/modules/mommacat.ru +6 -16
- data/modules/mu.rb +158 -111
- data/modules/mu/adoption.rb +404 -71
- data/modules/mu/cleanup.rb +221 -306
- data/modules/mu/cloud.rb +129 -1633
- data/modules/mu/cloud/database.rb +49 -0
- data/modules/mu/cloud/dnszone.rb +44 -0
- data/modules/mu/cloud/machine_images.rb +212 -0
- data/modules/mu/cloud/providers.rb +81 -0
- data/modules/mu/cloud/resource_base.rb +926 -0
- data/modules/mu/cloud/server.rb +40 -0
- data/modules/mu/cloud/server_pool.rb +1 -0
- data/modules/mu/cloud/ssh_sessions.rb +228 -0
- data/modules/mu/cloud/winrm_sessions.rb +237 -0
- data/modules/mu/cloud/wrappers.rb +169 -0
- data/modules/mu/config.rb +171 -1767
- data/modules/mu/config/alarm.rb +2 -6
- data/modules/mu/config/bucket.rb +32 -3
- data/modules/mu/config/cache_cluster.rb +2 -2
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/collection.rb +4 -4
- data/modules/mu/config/container_cluster.rb +9 -4
- data/modules/mu/config/database.rb +84 -105
- data/modules/mu/config/database.yml +1 -2
- data/modules/mu/config/dnszone.rb +10 -9
- data/modules/mu/config/doc_helpers.rb +516 -0
- data/modules/mu/config/endpoint.rb +5 -4
- data/modules/mu/config/firewall_rule.rb +103 -4
- data/modules/mu/config/folder.rb +4 -4
- data/modules/mu/config/function.rb +19 -10
- data/modules/mu/config/group.rb +4 -4
- data/modules/mu/config/habitat.rb +4 -4
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/loadbalancer.rb +60 -14
- data/modules/mu/config/log.rb +4 -4
- data/modules/mu/config/msg_queue.rb +4 -4
- data/modules/mu/config/nosqldb.rb +4 -4
- data/modules/mu/config/notifier.rb +10 -21
- data/modules/mu/config/ref.rb +411 -0
- data/modules/mu/config/role.rb +4 -4
- data/modules/mu/config/schema_helpers.rb +509 -0
- data/modules/mu/config/search_domain.rb +4 -4
- data/modules/mu/config/server.rb +98 -71
- data/modules/mu/config/server.yml +1 -0
- data/modules/mu/config/server_pool.rb +5 -9
- data/modules/mu/config/storage_pool.rb +1 -1
- data/modules/mu/config/tail.rb +200 -0
- data/modules/mu/config/user.rb +4 -4
- data/modules/mu/config/vpc.rb +71 -27
- data/modules/mu/config/vpc.yml +0 -1
- data/modules/mu/defaults/AWS.yaml +91 -68
- data/modules/mu/defaults/Azure.yaml +1 -0
- data/modules/mu/defaults/Google.yaml +3 -2
- data/modules/mu/deploy.rb +43 -26
- data/modules/mu/groomer.rb +17 -2
- data/modules/mu/groomers/ansible.rb +188 -41
- data/modules/mu/groomers/chef.rb +116 -55
- data/modules/mu/logger.rb +127 -148
- data/modules/mu/master.rb +410 -2
- data/modules/mu/master/chef.rb +3 -4
- data/modules/mu/master/ldap.rb +3 -3
- data/modules/mu/master/ssl.rb +12 -3
- data/modules/mu/mommacat.rb +218 -2612
- data/modules/mu/mommacat/daemon.rb +403 -0
- data/modules/mu/mommacat/naming.rb +473 -0
- data/modules/mu/mommacat/search.rb +495 -0
- data/modules/mu/mommacat/storage.rb +722 -0
- data/modules/mu/{clouds → providers}/README.md +1 -1
- data/modules/mu/{clouds → providers}/aws.rb +380 -122
- data/modules/mu/{clouds → providers}/aws/alarm.rb +7 -5
- data/modules/mu/{clouds → providers}/aws/bucket.rb +297 -59
- data/modules/mu/{clouds → providers}/aws/cache_cluster.rb +37 -71
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/{clouds → providers}/aws/collection.rb +26 -25
- data/modules/mu/{clouds → providers}/aws/container_cluster.rb +724 -744
- data/modules/mu/providers/aws/database.rb +1744 -0
- data/modules/mu/{clouds → providers}/aws/dnszone.rb +88 -70
- data/modules/mu/providers/aws/endpoint.rb +1072 -0
- data/modules/mu/{clouds → providers}/aws/firewall_rule.rb +220 -247
- data/modules/mu/{clouds → providers}/aws/folder.rb +8 -8
- data/modules/mu/{clouds → providers}/aws/function.rb +300 -142
- data/modules/mu/{clouds → providers}/aws/group.rb +31 -29
- data/modules/mu/{clouds → providers}/aws/habitat.rb +18 -15
- data/modules/mu/providers/aws/job.rb +466 -0
- data/modules/mu/{clouds → providers}/aws/loadbalancer.rb +66 -56
- data/modules/mu/{clouds → providers}/aws/log.rb +17 -14
- data/modules/mu/{clouds → providers}/aws/msg_queue.rb +29 -19
- data/modules/mu/{clouds → providers}/aws/nosqldb.rb +114 -16
- data/modules/mu/{clouds → providers}/aws/notifier.rb +142 -65
- data/modules/mu/{clouds → providers}/aws/role.rb +158 -118
- data/modules/mu/{clouds → providers}/aws/search_domain.rb +201 -59
- data/modules/mu/{clouds → providers}/aws/server.rb +844 -1139
- data/modules/mu/{clouds → providers}/aws/server_pool.rb +74 -65
- data/modules/mu/{clouds → providers}/aws/storage_pool.rb +26 -44
- data/modules/mu/{clouds → providers}/aws/user.rb +24 -25
- data/modules/mu/{clouds → providers}/aws/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/aws/userdata/linux.erb +5 -4
- data/modules/mu/{clouds → providers}/aws/userdata/windows.erb +2 -1
- data/modules/mu/{clouds → providers}/aws/vpc.rb +525 -931
- data/modules/mu/providers/aws/vpc_subnet.rb +286 -0
- data/modules/mu/{clouds → providers}/azure.rb +29 -9
- data/modules/mu/{clouds → providers}/azure/container_cluster.rb +3 -8
- data/modules/mu/{clouds → providers}/azure/firewall_rule.rb +18 -11
- data/modules/mu/{clouds → providers}/azure/habitat.rb +8 -6
- data/modules/mu/{clouds → providers}/azure/loadbalancer.rb +5 -5
- data/modules/mu/{clouds → providers}/azure/role.rb +8 -10
- data/modules/mu/{clouds → providers}/azure/server.rb +97 -49
- data/modules/mu/{clouds → providers}/azure/user.rb +6 -8
- data/modules/mu/{clouds → providers}/azure/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/azure/vpc.rb +16 -21
- data/modules/mu/{clouds → providers}/cloudformation.rb +18 -7
- data/modules/mu/{clouds → providers}/cloudformation/alarm.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/cache_cluster.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/collection.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/database.rb +6 -17
- data/modules/mu/{clouds → providers}/cloudformation/dnszone.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/firewall_rule.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/loadbalancer.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/log.rb +3 -3
- data/modules/mu/{clouds → providers}/cloudformation/server.rb +7 -7
- data/modules/mu/{clouds → providers}/cloudformation/server_pool.rb +5 -5
- data/modules/mu/{clouds → providers}/cloudformation/vpc.rb +5 -7
- data/modules/mu/{clouds → providers}/docker.rb +0 -0
- data/modules/mu/{clouds → providers}/google.rb +68 -30
- data/modules/mu/{clouds → providers}/google/bucket.rb +13 -15
- data/modules/mu/{clouds → providers}/google/container_cluster.rb +85 -78
- data/modules/mu/{clouds → providers}/google/database.rb +11 -21
- data/modules/mu/{clouds → providers}/google/firewall_rule.rb +15 -14
- data/modules/mu/{clouds → providers}/google/folder.rb +20 -17
- data/modules/mu/{clouds → providers}/google/function.rb +140 -168
- data/modules/mu/{clouds → providers}/google/group.rb +29 -34
- data/modules/mu/{clouds → providers}/google/habitat.rb +21 -22
- data/modules/mu/{clouds → providers}/google/loadbalancer.rb +19 -21
- data/modules/mu/{clouds → providers}/google/role.rb +94 -58
- data/modules/mu/{clouds → providers}/google/server.rb +243 -156
- data/modules/mu/{clouds → providers}/google/server_pool.rb +26 -45
- data/modules/mu/{clouds → providers}/google/user.rb +95 -31
- data/modules/mu/{clouds → providers}/google/userdata/README.md +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/linux.erb +0 -0
- data/modules/mu/{clouds → providers}/google/userdata/windows.erb +0 -0
- data/modules/mu/{clouds → providers}/google/vpc.rb +103 -79
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/bucket.yml +4 -0
- data/modules/tests/centos6.yaml +15 -0
- data/modules/tests/centos7.yaml +15 -0
- data/modules/tests/centos8.yaml +12 -0
- data/modules/tests/ecs.yaml +23 -0
- data/modules/tests/eks.yaml +1 -1
- data/modules/tests/functions/node-function/lambda_function.js +10 -0
- data/modules/tests/functions/python-function/lambda_function.py +12 -0
- data/modules/tests/includes-and-params.yaml +2 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +108 -0
- data/modules/tests/regrooms/aws-iam.yaml +201 -0
- data/modules/tests/regrooms/bucket.yml +19 -0
- data/modules/tests/regrooms/rds.yaml +123 -0
- data/modules/tests/server-with-scrub-muisms.yaml +2 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +3 -5
- data/modules/tests/win2k12.yaml +17 -5
- data/modules/tests/win2k16.yaml +25 -0
- data/modules/tests/win2k19.yaml +25 -0
- data/requirements.txt +1 -0
- data/spec/mu/clouds/azure_spec.rb +2 -2
- metadata +240 -154
- data/extras/image-generators/AWS/windows.yaml +0 -18
- data/modules/mu/clouds/aws/database.rb +0 -1985
- data/modules/mu/clouds/aws/endpoint.rb +0 -592
data/modules/mu/config/role.rb
CHANGED
@@ -14,7 +14,7 @@
|
|
14
14
|
|
15
15
|
module MU
|
16
16
|
class Config
|
17
|
-
# Basket of Kittens config schema and parser logic. See modules/mu/
|
17
|
+
# Basket of Kittens config schema and parser logic. See modules/mu/providers/*/role.rb
|
18
18
|
class Role
|
19
19
|
|
20
20
|
# Base configuration schema for a Group
|
@@ -131,10 +131,10 @@ module MU
|
|
131
131
|
end
|
132
132
|
|
133
133
|
# Generic pre-processing of {MU::Config::BasketofKittens::role}, bare and unvalidated.
|
134
|
-
# @param
|
135
|
-
# @param
|
134
|
+
# @param _role [Hash]: The resource to process and validate
|
135
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
136
136
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
137
|
-
def self.validate(
|
137
|
+
def self.validate(_role, _configurator)
|
138
138
|
ok = true
|
139
139
|
ok
|
140
140
|
end
|
@@ -0,0 +1,509 @@
|
|
1
|
+
# Copyright:: Copyright (c) 2014 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
|
+
# The default cloud provider for new resources. Must exist in MU.supportedClouds
|
21
|
+
# return [String]
|
22
|
+
def self.defaultCloud
|
23
|
+
configured = {}
|
24
|
+
MU::Cloud.supportedClouds.each { |cloud|
|
25
|
+
if $MU_CFG[cloud.downcase] and !$MU_CFG[cloud.downcase].empty?
|
26
|
+
configured[cloud] = $MU_CFG[cloud.downcase].size
|
27
|
+
configured[cloud] += 0.5 if MU::Cloud.cloudClass(cloud).hosted? # tiebreaker
|
28
|
+
end
|
29
|
+
}
|
30
|
+
if configured.size > 0
|
31
|
+
return configured.keys.sort { |a, b|
|
32
|
+
configured[b] <=> configured[a]
|
33
|
+
}.first
|
34
|
+
else
|
35
|
+
MU::Cloud.supportedClouds.each { |cloud|
|
36
|
+
return cloud if MU::Cloud.cloudClass(cloud).hosted?
|
37
|
+
}
|
38
|
+
return MU::Cloud.supportedClouds.first
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# The default grooming agent for new resources. Must exist in MU.supportedGroomers.
|
43
|
+
def self.defaultGroomer
|
44
|
+
MU.localOnly ? "Ansible" : "Chef"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Accessor for our Basket of Kittens schema definition
|
48
|
+
def self.schema
|
49
|
+
@@schema
|
50
|
+
end
|
51
|
+
|
52
|
+
# Deep merge a configuration hash so we can meld different cloud providers'
|
53
|
+
# schemas together, while preserving documentation differences
|
54
|
+
def self.schemaMerge(orig, new, cloud)
|
55
|
+
if new.is_a?(Hash)
|
56
|
+
new.each_pair { |k, v|
|
57
|
+
if cloud and k == "description" and v.is_a?(String) and !v.match(/\b#{Regexp.quote(cloud.upcase)}\b/) and !v.empty?
|
58
|
+
new[k] = "+"+cloud.upcase+"+: "+v
|
59
|
+
end
|
60
|
+
if orig and orig.has_key?(k)
|
61
|
+
elsif orig
|
62
|
+
orig[k] = new[k]
|
63
|
+
else
|
64
|
+
orig = new
|
65
|
+
end
|
66
|
+
schemaMerge(orig[k], new[k], cloud)
|
67
|
+
}
|
68
|
+
elsif orig.is_a?(Array) and new
|
69
|
+
orig.concat(new)
|
70
|
+
orig.uniq!
|
71
|
+
elsif new.is_a?(String)
|
72
|
+
orig ||= ""
|
73
|
+
orig += "\n" if !orig.empty?
|
74
|
+
orig += "+#{cloud.upcase}+: "+new
|
75
|
+
else
|
76
|
+
# XXX I think this is a NOOP?
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
@@allregions = []
|
81
|
+
@@loadfails = []
|
82
|
+
MU::Cloud.availableClouds.each { |cloud|
|
83
|
+
next if @@loadfails.include?(cloud)
|
84
|
+
begin
|
85
|
+
regions = MU::Cloud.cloudClass(cloud).listRegions()
|
86
|
+
@@allregions.concat(regions) if regions
|
87
|
+
rescue MU::MuError => e
|
88
|
+
@@loadfails << cloud
|
89
|
+
MU.log e.message, MU::WARN
|
90
|
+
end
|
91
|
+
}
|
92
|
+
|
93
|
+
# Configuration chunk for choosing a provider region
|
94
|
+
# @return [Hash]
|
95
|
+
def self.region_primitive
|
96
|
+
if !@@allregions or @@allregions.empty?
|
97
|
+
@@allregions = []
|
98
|
+
MU::Cloud.availableClouds.each { |cloud|
|
99
|
+
next if @@loadfails.include?(cloud)
|
100
|
+
cloudclass = MU::Cloud.cloudClass(cloud)
|
101
|
+
begin
|
102
|
+
return @@allregions if !cloudclass.listRegions()
|
103
|
+
@@allregions.concat(cloudclass.listRegions())
|
104
|
+
rescue MU::MuError => e
|
105
|
+
@@loadfails << cloud
|
106
|
+
MU.log e.message, MU::WARN
|
107
|
+
end
|
108
|
+
}
|
109
|
+
end
|
110
|
+
{
|
111
|
+
"type" => "string",
|
112
|
+
"enum" => @@allregions
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
# Configuration chunk for choosing a set of cloud credentials
|
117
|
+
# @return [Hash]
|
118
|
+
def self.credentials_primitive
|
119
|
+
{
|
120
|
+
"type" => "string",
|
121
|
+
"description" => "Specify a non-default set of credentials to use when authenticating to cloud provider APIs, as listed in `mu.yaml` under each provider's subsection. If "
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
# Configuration chunk for creating resource tags as an array of key/value
|
126
|
+
# pairs.
|
127
|
+
# @return [Hash]
|
128
|
+
def self.optional_tags_primitive
|
129
|
+
{
|
130
|
+
"type" => "boolean",
|
131
|
+
"description" => "Tag the resource with our optional tags (+MU-HANDLE+, +MU-MASTER-NAME+, +MU-OWNER+).",
|
132
|
+
"default" => true
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
# Configuration chunk for creating resource tags as an array of key/value
|
137
|
+
# pairs.
|
138
|
+
# @return [Hash]
|
139
|
+
def self.tags_primitive
|
140
|
+
{
|
141
|
+
"type" => "array",
|
142
|
+
"minItems" => 1,
|
143
|
+
"items" => {
|
144
|
+
"description" => "Tags to apply to this resource. Will apply at the cloud provider level and in node groomers, where applicable.",
|
145
|
+
"type" => "object",
|
146
|
+
"title" => "tags",
|
147
|
+
"required" => ["key", "value"],
|
148
|
+
"additionalProperties" => false,
|
149
|
+
"properties" => {
|
150
|
+
"key" => {
|
151
|
+
"type" => "string",
|
152
|
+
},
|
153
|
+
"value" => {
|
154
|
+
"type" => "string",
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
# Configuration chunk for choosing a cloud provider
|
162
|
+
# @return [Hash]
|
163
|
+
def self.cloud_primitive
|
164
|
+
{
|
165
|
+
"type" => "string",
|
166
|
+
# "default" => MU::Config.defaultCloud, # applyInheritedDefaults does this better
|
167
|
+
"enum" => MU::Cloud.supportedClouds
|
168
|
+
}
|
169
|
+
end
|
170
|
+
|
171
|
+
|
172
|
+
# JSON-schema for resource dependencies
|
173
|
+
# @return [Hash]
|
174
|
+
def self.dependencies_primitive
|
175
|
+
{
|
176
|
+
"type" => "array",
|
177
|
+
"items" => {
|
178
|
+
"type" => "object",
|
179
|
+
"description" => "Declare other objects which this resource requires. This resource will wait until the others are available to create itself.",
|
180
|
+
"required" => ["name", "type"],
|
181
|
+
"additionalProperties" => false,
|
182
|
+
"properties" => {
|
183
|
+
"name" => {"type" => "string"},
|
184
|
+
"type" => {
|
185
|
+
"type" => "string",
|
186
|
+
"enum" => MU::Cloud.resource_types.values.map { |v| v[:cfg_name] }
|
187
|
+
},
|
188
|
+
"phase" => {
|
189
|
+
"type" => "string",
|
190
|
+
"description" => "Which part of the creation process of the resource we depend on should we wait for before starting our own creation? Defaults are usually sensible, but sometimes you want, say, a Server to wait on another Server to be completely ready (through its groom phase) before starting up.",
|
191
|
+
"enum" => ["create", "groom"]
|
192
|
+
},
|
193
|
+
"no_create_wait" => {
|
194
|
+
"type" => "boolean",
|
195
|
+
"default" => false,
|
196
|
+
"description" => "By default, it's assumed that we want to wait on our parents' creation phase, in addition to whatever is declared in this stanza. Setting this flag will bypass waiting on our parent resource's creation, so that our create or groom phase can instead depend only on the parent's groom phase. "
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
}
|
201
|
+
end
|
202
|
+
|
203
|
+
# Have a default value available for config schema elements that take an
|
204
|
+
# email address.
|
205
|
+
# @return [String]
|
206
|
+
def self.notification_email
|
207
|
+
if MU.chef_user == "mu"
|
208
|
+
ENV['MU_ADMIN_EMAIL']
|
209
|
+
else
|
210
|
+
MU.userEmail
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Load and validate the schema for an individual resource class, optionally
|
215
|
+
# merging cloud-specific schema components.
|
216
|
+
# @param type [String]: The resource type to load
|
217
|
+
# @param cloud [String]: A specific cloud, whose implementation's schema of this resource we will merge
|
218
|
+
# @return [Hash]
|
219
|
+
def self.loadResourceSchema(type, cloud: nil)
|
220
|
+
valid = true
|
221
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(type)
|
222
|
+
schemaclass = Object.const_get("MU").const_get("Config").const_get(shortclass)
|
223
|
+
|
224
|
+
[:schema, :validate].each { |method|
|
225
|
+
if !schemaclass.respond_to?(method)
|
226
|
+
MU.log "MU::Config::#{type}.#{method.to_s} doesn't seem to be implemented", MU::ERR
|
227
|
+
return [nil, false] if method == :schema
|
228
|
+
valid = false
|
229
|
+
end
|
230
|
+
}
|
231
|
+
|
232
|
+
schema = schemaclass.schema.dup
|
233
|
+
|
234
|
+
schema["properties"]["virtual_name"] = {
|
235
|
+
"description" => "Internal use.",
|
236
|
+
"type" => "string"
|
237
|
+
}
|
238
|
+
schema["properties"]["dependencies"] = MU::Config.dependencies_primitive
|
239
|
+
schema["properties"]["cloud"] = MU::Config.cloud_primitive
|
240
|
+
schema["properties"]["credentials"] = MU::Config.credentials_primitive
|
241
|
+
schema["title"] = type.to_s
|
242
|
+
|
243
|
+
if cloud
|
244
|
+
cloudclass = MU::Cloud.resourceClass(cloud, type)
|
245
|
+
|
246
|
+
if cloudclass.respond_to?(:schema)
|
247
|
+
_reqd, cloudschema = cloudclass.schema
|
248
|
+
cloudschema.each { |key, cfg|
|
249
|
+
if schema["properties"][key]
|
250
|
+
schemaMerge(schema["properties"][key], cfg, cloud)
|
251
|
+
else
|
252
|
+
schema["properties"][key] = cfg.dup
|
253
|
+
end
|
254
|
+
}
|
255
|
+
else
|
256
|
+
MU.log "MU::Cloud::#{cloud}::#{type}.#{method.to_s} doesn't seem to be implemented", MU::ERR
|
257
|
+
valid = false
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
return [schema, valid]
|
263
|
+
end
|
264
|
+
|
265
|
+
private
|
266
|
+
|
267
|
+
def applySchemaDefaults(conf_chunk = config, schema_chunk = schema, depth = 0, siblings = nil, type: nil)
|
268
|
+
return if schema_chunk.nil?
|
269
|
+
|
270
|
+
if conf_chunk != nil and schema_chunk["properties"].kind_of?(Hash) and conf_chunk.is_a?(Hash)
|
271
|
+
|
272
|
+
if schema_chunk["properties"]["creation_style"].nil? or
|
273
|
+
schema_chunk["properties"]["creation_style"] != "existing"
|
274
|
+
schema_chunk["properties"].each_pair { |key, subschema|
|
275
|
+
shortclass = if conf_chunk[key]
|
276
|
+
shortclass, _cfg_name, _cfg_plural, _classname = MU::Cloud.getResourceNames(key, false)
|
277
|
+
shortclass
|
278
|
+
else
|
279
|
+
nil
|
280
|
+
end
|
281
|
+
|
282
|
+
new_val = applySchemaDefaults(conf_chunk[key], subschema, depth+1, conf_chunk, type: shortclass).dup
|
283
|
+
if !new_val.nil?
|
284
|
+
begin
|
285
|
+
conf_chunk[key] = Marshal.load(Marshal.dump(new_val))
|
286
|
+
rescue TypeError
|
287
|
+
conf_chunk[key] = new_val.clone
|
288
|
+
end
|
289
|
+
end
|
290
|
+
}
|
291
|
+
end
|
292
|
+
elsif schema_chunk["type"] == "array" and conf_chunk.kind_of?(Array)
|
293
|
+
conf_chunk.map! { |item|
|
294
|
+
# If we're working on a resource type, go get implementation-specific
|
295
|
+
# schema information so that we set those defaults correctly.
|
296
|
+
realschema = if type and schema_chunk["items"] and schema_chunk["items"]["properties"] and item["cloud"] and MU::Cloud.supportedClouds.include?(item['cloud'])
|
297
|
+
|
298
|
+
_toplevel_required, cloudschema = MU::Cloud.resourceClass(item["cloud"], type).schema(self)
|
299
|
+
|
300
|
+
newschema = schema_chunk["items"].dup
|
301
|
+
MU::Config.schemaMerge(newschema["properties"], cloudschema, item["cloud"])
|
302
|
+
newschema
|
303
|
+
else
|
304
|
+
schema_chunk["items"].dup
|
305
|
+
end
|
306
|
+
|
307
|
+
applySchemaDefaults(item, realschema, depth+1, conf_chunk, type: type).dup
|
308
|
+
}
|
309
|
+
else
|
310
|
+
if conf_chunk.nil? and !schema_chunk["default_if"].nil? and !siblings.nil?
|
311
|
+
schema_chunk["default_if"].each { |cond|
|
312
|
+
if siblings[cond["key_is"]] == cond["value_is"]
|
313
|
+
return Marshal.load(Marshal.dump(cond["set"]))
|
314
|
+
end
|
315
|
+
}
|
316
|
+
end
|
317
|
+
if conf_chunk.nil? and schema_chunk["default"] != nil
|
318
|
+
return Marshal.load(Marshal.dump(schema_chunk["default"]))
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
return conf_chunk
|
323
|
+
end
|
324
|
+
|
325
|
+
# Given a bare hash describing a resource, insert default values which can
|
326
|
+
# be inherited from its parent or from the root of the BoK.
|
327
|
+
# @param kitten [Hash]: A resource descriptor
|
328
|
+
# @param type [String]: The type of resource this is ("servers" etc)
|
329
|
+
def applyInheritedDefaults(kitten, type)
|
330
|
+
return if !kitten.is_a?(Hash)
|
331
|
+
kitten['cloud'] ||= @config['cloud']
|
332
|
+
kitten['cloud'] ||= MU::Config.defaultCloud
|
333
|
+
|
334
|
+
if !MU::Cloud.supportedClouds.include?(kitten['cloud'])
|
335
|
+
return
|
336
|
+
end
|
337
|
+
|
338
|
+
cloudclass = MU::Cloud.cloudClass(kitten['cloud'])
|
339
|
+
|
340
|
+
resclass = MU::Cloud.resourceClass(kitten['cloud'], type)
|
341
|
+
|
342
|
+
schema_fields = ["us_only", "scrub_mu_isms", "credentials", "billing_acct"]
|
343
|
+
if !resclass.isGlobal?
|
344
|
+
kitten['region'] ||= @config['region']
|
345
|
+
kitten['region'] ||= cloudclass.myRegion(kitten['credentials'])
|
346
|
+
schema_fields << "region"
|
347
|
+
end
|
348
|
+
|
349
|
+
kitten['credentials'] ||= @config['credentials']
|
350
|
+
kitten['credentials'] ||= cloudclass.credConfig(name_only: true)
|
351
|
+
|
352
|
+
kitten['us_only'] ||= @config['us_only']
|
353
|
+
kitten['us_only'] ||= false
|
354
|
+
|
355
|
+
kitten['scrub_mu_isms'] ||= @config['scrub_mu_isms']
|
356
|
+
kitten['scrub_mu_isms'] ||= false
|
357
|
+
|
358
|
+
if kitten['cloud'] == "Google"
|
359
|
+
# TODO this should be cloud-generic (handle AWS accounts, Azure subscriptions)
|
360
|
+
if resclass.canLiveIn.include?(:Habitat)
|
361
|
+
kitten["project"] ||= MU::Cloud::Google.defaultProject(kitten['credentials'])
|
362
|
+
schema_fields << "project"
|
363
|
+
end
|
364
|
+
if kitten['region'].nil? and !kitten['#MU_CLOUDCLASS'].nil? and
|
365
|
+
!resclass.isGlobal? and
|
366
|
+
![MU::Cloud::VPC, MU::Cloud::FirewallRule].include?(kitten['#MU_CLOUDCLASS'])
|
367
|
+
if MU::Cloud::Google.myRegion((kitten['credentials'])).nil?
|
368
|
+
raise ValidationError, "Google '#{type}' resource '#{kitten['name']}' declared without a region, but no default Google region declared in mu.yaml under #{kitten['credentials'].nil? ? "default" : kitten['credentials']} credential set"
|
369
|
+
end
|
370
|
+
kitten['region'] ||= MU::Cloud::Google.myRegion
|
371
|
+
end
|
372
|
+
elsif kitten["cloud"] == "AWS" and !resclass.isGlobal? and !kitten['region']
|
373
|
+
if MU::Cloud::AWS.myRegion.nil?
|
374
|
+
raise ValidationError, "AWS resource declared without a region, but no default AWS region found"
|
375
|
+
end
|
376
|
+
kitten['region'] ||= MU::Cloud::AWS.myRegion
|
377
|
+
end
|
378
|
+
|
379
|
+
|
380
|
+
kitten['billing_acct'] ||= @config['billing_acct'] if @config['billing_acct']
|
381
|
+
|
382
|
+
kitten["dependencies"] ||= []
|
383
|
+
|
384
|
+
# Make sure the schema knows about these "new" fields, so that validation
|
385
|
+
# doesn't trip over them.
|
386
|
+
schema_fields.each { |field|
|
387
|
+
if @@schema["properties"][field]
|
388
|
+
MU.log "Adding #{field} to schema for #{type} #{kitten['cloud']}", MU::DEBUG, details: @@schema["properties"][field]
|
389
|
+
@@schema["properties"][type]["items"]["properties"][field] ||= @@schema["properties"][field]
|
390
|
+
end
|
391
|
+
}
|
392
|
+
end
|
393
|
+
|
394
|
+
CIDR_PATTERN = "^\\d+\\.\\d+\\.\\d+\\.\\d+\/[0-9]{1,2}$"
|
395
|
+
CIDR_DESCRIPTION = "CIDR-formatted IP block, e.g. 1.2.3.4/32"
|
396
|
+
CIDR_PRIMITIVE = {
|
397
|
+
"type" => "string",
|
398
|
+
"pattern" => CIDR_PATTERN,
|
399
|
+
"description" => CIDR_DESCRIPTION
|
400
|
+
}
|
401
|
+
|
402
|
+
|
403
|
+
@@schema = {
|
404
|
+
"$schema" => "http://json-schema.org/draft-04/schema#",
|
405
|
+
"title" => "MU Application",
|
406
|
+
"type" => "object",
|
407
|
+
"description" => "A MU application stack, consisting of at least one resource.",
|
408
|
+
"required" => ["admins", "appname"],
|
409
|
+
"properties" => {
|
410
|
+
"appname" => {
|
411
|
+
"type" => "string",
|
412
|
+
"description" => "A name for your application stack. Should be short, but easy to differentiate from other applications.",
|
413
|
+
},
|
414
|
+
"scrub_mu_isms" => {
|
415
|
+
"type" => "boolean",
|
416
|
+
"description" => "When 'cloud' is set to 'CloudFormation,' use this flag to strip out Mu-specific artifacts (tags, standard userdata, naming conventions, etc) to yield a clean, source-agnostic template. Setting this flag here will override declarations in individual resources."
|
417
|
+
},
|
418
|
+
"project" => {
|
419
|
+
"type" => "string",
|
420
|
+
"description" => "**GOOGLE ONLY**: The project into which to deploy resources"
|
421
|
+
},
|
422
|
+
"billing_acct" => {
|
423
|
+
"type" => "string",
|
424
|
+
"description" => "**GOOGLE ONLY**: Billing account ID to associate with a newly-created Google Project. If not specified, will attempt to locate a billing account associated with the default project for our credentials.",
|
425
|
+
},
|
426
|
+
"region" => MU::Config.region_primitive,
|
427
|
+
"credentials" => MU::Config.credentials_primitive,
|
428
|
+
"us_only" => {
|
429
|
+
"type" => "boolean",
|
430
|
+
"description" => "For resources which span regions, restrict to regions inside the United States",
|
431
|
+
"default" => false
|
432
|
+
},
|
433
|
+
"conditions" => {
|
434
|
+
"type" => "array",
|
435
|
+
"items" => {
|
436
|
+
"type" => "object",
|
437
|
+
"required" => ["name", "cloudcode"],
|
438
|
+
"description" => "CloudFormation-specific. Define Conditions as in http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/conditions-section-structure.html. Arguments must use the cloudCode() macro.",
|
439
|
+
"properties" => {
|
440
|
+
"name" => { "required" => true, "type" => "string" },
|
441
|
+
"cloudcode" => { "required" => true, "type" => "string" },
|
442
|
+
}
|
443
|
+
}
|
444
|
+
},
|
445
|
+
"parameters" => {
|
446
|
+
"type" => "array",
|
447
|
+
"items" => {
|
448
|
+
"type" => "object",
|
449
|
+
"title" => "parameter",
|
450
|
+
"description" => "Parameters to be substituted elsewhere in this Basket of Kittens as ERB variables (<%= varname %>)",
|
451
|
+
"additionalProperties" => false,
|
452
|
+
"properties" => {
|
453
|
+
"name" => { "required" => true, "type" => "string" },
|
454
|
+
"default" => { "type" => "string" },
|
455
|
+
"list_of" => {
|
456
|
+
"type" => "string",
|
457
|
+
"description" => "Treat the value as a comma-separated list of values with this key name, equivalent to CloudFormation's various List<> types. For example, set to 'subnet_id' to pass values as an array of subnet identifiers as the 'subnets' argument of a VPC stanza."
|
458
|
+
},
|
459
|
+
"prettyname" => {
|
460
|
+
"type" => "string",
|
461
|
+
"description" => "An alternative name to use when generating parameter fields in, for example, CloudFormation templates"
|
462
|
+
},
|
463
|
+
"description" => {"type" => "string"},
|
464
|
+
"cloudtype" => {
|
465
|
+
"type" => "string",
|
466
|
+
"description" => "A platform-specific string describing the type of validation to use for this parameter. E.g. when generating a CloudFormation template, set to AWS::EC2::Image::Id to validate input as an AMI identifier."
|
467
|
+
},
|
468
|
+
"required" => {
|
469
|
+
"type" => "boolean",
|
470
|
+
"default" => true
|
471
|
+
},
|
472
|
+
"valid_values" => {
|
473
|
+
"type" => "array",
|
474
|
+
"description" => "List of valid values for this parameter. Can only be a list of static strings, for now.",
|
475
|
+
"items" => {
|
476
|
+
"type" => "string"
|
477
|
+
}
|
478
|
+
}
|
479
|
+
}
|
480
|
+
}
|
481
|
+
},
|
482
|
+
# TODO availability zones (or an array thereof)
|
483
|
+
|
484
|
+
"admins" => {
|
485
|
+
"type" => "array",
|
486
|
+
"items" => {
|
487
|
+
"type" => "object",
|
488
|
+
"title" => "admin",
|
489
|
+
"description" => "Administrative contacts for this application stack. Will be automatically set to invoking Mu user, if not specified.",
|
490
|
+
"required" => ["name", "email"],
|
491
|
+
"additionalProperties" => false,
|
492
|
+
"properties" => {
|
493
|
+
"name" => {"type" => "string"},
|
494
|
+
"email" => {"type" => "string"},
|
495
|
+
"public_key" => {
|
496
|
+
"type" => "string",
|
497
|
+
"description" => "An OpenSSH-style public key string. This will be installed on all instances created in this deployment."
|
498
|
+
}
|
499
|
+
}
|
500
|
+
},
|
501
|
+
"minItems" => 1,
|
502
|
+
"uniqueItems" => true
|
503
|
+
}
|
504
|
+
},
|
505
|
+
"additionalProperties" => false
|
506
|
+
}
|
507
|
+
|
508
|
+
end #class
|
509
|
+
end #module
|