cloud-mu 3.2.0 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Dockerfile +1 -1
- data/ansible/roles/mu-nat/tasks/main.yml +3 -0
- data/bin/mu-adopt +12 -1
- data/bin/mu-aws-setup +41 -7
- data/bin/mu-azure-setup +34 -0
- data/bin/mu-configure +214 -119
- data/bin/mu-gcp-setup +37 -2
- data/bin/mu-load-config.rb +2 -1
- data/bin/mu-node-manage +3 -0
- data/bin/mu-refresh-ssl +67 -0
- data/bin/mu-run-tests +28 -6
- data/bin/mu-self-update +30 -10
- data/bin/mu-upload-chef-artifacts +30 -26
- data/cloud-mu.gemspec +10 -8
- data/cookbooks/mu-master/attributes/default.rb +5 -1
- data/cookbooks/mu-master/metadata.rb +2 -2
- data/cookbooks/mu-master/recipes/default.rb +81 -26
- data/cookbooks/mu-master/recipes/init.rb +197 -62
- data/cookbooks/mu-master/recipes/update_nagios_only.rb +1 -1
- data/cookbooks/mu-master/recipes/vault.rb +78 -77
- data/cookbooks/mu-master/templates/default/mods/rewrite.conf.erb +1 -0
- data/cookbooks/mu-master/templates/default/nagios.conf.erb +103 -0
- data/cookbooks/mu-master/templates/default/web_app.conf.erb +14 -30
- data/cookbooks/mu-tools/attributes/default.rb +12 -0
- data/cookbooks/mu-tools/files/centos-6/CentOS-Base.repo +47 -0
- data/cookbooks/mu-tools/libraries/helper.rb +98 -4
- data/cookbooks/mu-tools/libraries/monkey.rb +1 -1
- data/cookbooks/mu-tools/recipes/apply_security.rb +31 -9
- data/cookbooks/mu-tools/recipes/aws_api.rb +8 -2
- data/cookbooks/mu-tools/recipes/base_repositories.rb +1 -1
- data/cookbooks/mu-tools/recipes/gcloud.rb +2 -9
- data/cookbooks/mu-tools/recipes/google_api.rb +7 -0
- data/cookbooks/mu-tools/recipes/rsyslog.rb +8 -1
- data/cookbooks/mu-tools/resources/disk.rb +113 -42
- data/cookbooks/mu-tools/resources/mommacat_request.rb +1 -2
- data/cookbooks/mu-tools/templates/centos-8/sshd_config.erb +215 -0
- data/extras/Gemfile.lock.bootstrap +394 -0
- data/extras/bucketstubs/error.html +0 -0
- data/extras/bucketstubs/index.html +0 -0
- data/extras/clean-stock-amis +11 -3
- data/extras/generate-stock-images +6 -3
- data/extras/git_rpm/build.sh +20 -0
- data/extras/git_rpm/mugit.spec +53 -0
- data/extras/image-generators/AWS/centos7.yaml +19 -16
- data/extras/image-generators/AWS/{rhel7.yaml → rhel71.yaml} +0 -0
- data/extras/image-generators/AWS/{win2k12.yaml → win2k12r2.yaml} +0 -0
- data/extras/image-generators/VMWare/centos8.yaml +15 -0
- data/extras/openssl_rpm/build.sh +19 -0
- data/extras/openssl_rpm/mussl.spec +46 -0
- data/extras/python_rpm/muthon.spec +14 -4
- data/extras/ruby_rpm/muby.spec +9 -5
- data/extras/sqlite_rpm/build.sh +19 -0
- data/extras/sqlite_rpm/muqlite.spec +47 -0
- data/install/installer +7 -5
- data/modules/mommacat.ru +2 -2
- data/modules/mu.rb +14 -7
- data/modules/mu/adoption.rb +5 -5
- data/modules/mu/cleanup.rb +47 -25
- data/modules/mu/cloud.rb +29 -1
- data/modules/mu/cloud/dnszone.rb +0 -2
- data/modules/mu/cloud/machine_images.rb +1 -1
- data/modules/mu/cloud/providers.rb +6 -1
- data/modules/mu/cloud/resource_base.rb +16 -7
- data/modules/mu/cloud/ssh_sessions.rb +5 -1
- data/modules/mu/cloud/wrappers.rb +20 -7
- data/modules/mu/config.rb +28 -12
- data/modules/mu/config/bucket.rb +31 -2
- data/modules/mu/config/cache_cluster.rb +1 -1
- data/modules/mu/config/cdn.rb +100 -0
- data/modules/mu/config/container_cluster.rb +1 -1
- data/modules/mu/config/database.rb +3 -3
- data/modules/mu/config/dnszone.rb +4 -3
- data/modules/mu/config/endpoint.rb +1 -0
- data/modules/mu/config/firewall_rule.rb +1 -1
- data/modules/mu/config/function.rb +16 -7
- data/modules/mu/config/job.rb +89 -0
- data/modules/mu/config/notifier.rb +7 -18
- data/modules/mu/config/ref.rb +55 -9
- data/modules/mu/config/schema_helpers.rb +12 -3
- data/modules/mu/config/server.rb +11 -5
- data/modules/mu/config/server_pool.rb +2 -2
- data/modules/mu/config/vpc.rb +11 -10
- data/modules/mu/defaults/AWS.yaml +106 -106
- data/modules/mu/deploy.rb +40 -14
- data/modules/mu/groomers/chef.rb +2 -2
- data/modules/mu/master.rb +70 -3
- data/modules/mu/mommacat.rb +28 -9
- data/modules/mu/mommacat/daemon.rb +13 -7
- data/modules/mu/mommacat/naming.rb +2 -2
- data/modules/mu/mommacat/search.rb +16 -5
- data/modules/mu/mommacat/storage.rb +67 -32
- data/modules/mu/providers/aws.rb +298 -85
- data/modules/mu/providers/aws/alarm.rb +5 -5
- data/modules/mu/providers/aws/bucket.rb +284 -50
- data/modules/mu/providers/aws/cache_cluster.rb +26 -26
- data/modules/mu/providers/aws/cdn.rb +782 -0
- data/modules/mu/providers/aws/collection.rb +16 -16
- data/modules/mu/providers/aws/container_cluster.rb +84 -64
- data/modules/mu/providers/aws/database.rb +59 -55
- data/modules/mu/providers/aws/dnszone.rb +29 -12
- data/modules/mu/providers/aws/endpoint.rb +535 -50
- data/modules/mu/providers/aws/firewall_rule.rb +32 -26
- data/modules/mu/providers/aws/folder.rb +1 -1
- data/modules/mu/providers/aws/function.rb +300 -134
- data/modules/mu/providers/aws/group.rb +16 -14
- data/modules/mu/providers/aws/habitat.rb +4 -4
- data/modules/mu/providers/aws/job.rb +469 -0
- data/modules/mu/providers/aws/loadbalancer.rb +67 -45
- data/modules/mu/providers/aws/log.rb +17 -17
- data/modules/mu/providers/aws/msg_queue.rb +22 -13
- data/modules/mu/providers/aws/nosqldb.rb +99 -8
- data/modules/mu/providers/aws/notifier.rb +137 -65
- data/modules/mu/providers/aws/role.rb +119 -83
- data/modules/mu/providers/aws/search_domain.rb +166 -30
- data/modules/mu/providers/aws/server.rb +209 -118
- data/modules/mu/providers/aws/server_pool.rb +95 -130
- data/modules/mu/providers/aws/storage_pool.rb +19 -11
- data/modules/mu/providers/aws/user.rb +5 -5
- data/modules/mu/providers/aws/userdata/linux.erb +5 -4
- data/modules/mu/providers/aws/vpc.rb +109 -54
- data/modules/mu/providers/aws/vpc_subnet.rb +43 -39
- data/modules/mu/providers/azure.rb +78 -12
- data/modules/mu/providers/azure/server.rb +20 -4
- data/modules/mu/providers/cloudformation/server.rb +1 -1
- data/modules/mu/providers/google.rb +21 -5
- data/modules/mu/providers/google/bucket.rb +1 -1
- data/modules/mu/providers/google/container_cluster.rb +1 -1
- data/modules/mu/providers/google/database.rb +1 -1
- data/modules/mu/providers/google/firewall_rule.rb +1 -1
- data/modules/mu/providers/google/folder.rb +7 -3
- data/modules/mu/providers/google/function.rb +66 -31
- data/modules/mu/providers/google/group.rb +1 -1
- data/modules/mu/providers/google/habitat.rb +1 -1
- data/modules/mu/providers/google/loadbalancer.rb +1 -1
- data/modules/mu/providers/google/role.rb +6 -3
- data/modules/mu/providers/google/server.rb +1 -1
- data/modules/mu/providers/google/server_pool.rb +1 -1
- data/modules/mu/providers/google/user.rb +1 -1
- data/modules/mu/providers/google/vpc.rb +28 -3
- data/modules/tests/aws-jobs-functions.yaml +46 -0
- data/modules/tests/aws-servers-with-handrolled-iam.yaml +37 -0
- data/modules/tests/centos6.yaml +4 -0
- data/modules/tests/centos7.yaml +4 -0
- data/modules/tests/ecs.yaml +2 -2
- 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/k8s.yaml +1 -1
- data/modules/tests/microservice_app.yaml +288 -0
- data/modules/tests/rds.yaml +5 -5
- data/modules/tests/regrooms/rds.yaml +5 -5
- data/modules/tests/server-with-scrub-muisms.yaml +1 -1
- data/modules/tests/super_complex_bok.yml +2 -2
- data/modules/tests/super_simple_bok.yml +2 -2
- metadata +42 -17
data/modules/mu/config/bucket.rb
CHANGED
|
@@ -50,6 +50,24 @@ module MU
|
|
|
50
50
|
"default" => "index.html",
|
|
51
51
|
"description" => "If +web_enabled+, return this object when \"diretory\" (a path not ending in a key/object) is invoked."
|
|
52
52
|
},
|
|
53
|
+
"upload" => {
|
|
54
|
+
"type" => "array",
|
|
55
|
+
"items" => {
|
|
56
|
+
"type" => "object",
|
|
57
|
+
"description" => "Upload objects to a bucket, where supported",
|
|
58
|
+
"required" => ["source", "destination"],
|
|
59
|
+
"properties" => {
|
|
60
|
+
"source" => {
|
|
61
|
+
"type" => "string",
|
|
62
|
+
"description" => "A file or directory to upload. If a directory is specified, it will be recursively mirrored to the bucket +destination+."
|
|
63
|
+
},
|
|
64
|
+
"destination" => {
|
|
65
|
+
"type" => "string",
|
|
66
|
+
"description" => "Path to which +source+ file(s) will be uploaded in the bucket, relative to +/+"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
},
|
|
53
71
|
"policies" => {
|
|
54
72
|
"type" => "array",
|
|
55
73
|
"items" => MU::Config::Role.policy_primitive(subobjects: true, grant_to: true, permissions_optional: true, targets_optional: true)
|
|
@@ -59,12 +77,23 @@ module MU
|
|
|
59
77
|
end
|
|
60
78
|
|
|
61
79
|
# Generic pre-processing of {MU::Config::BasketofKittens::buckets}, bare and unvalidated.
|
|
62
|
-
# @param
|
|
80
|
+
# @param bucket [Hash]: The resource to process and validate
|
|
63
81
|
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
64
82
|
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
65
|
-
def self.validate(
|
|
83
|
+
def self.validate(bucket, _configurator)
|
|
66
84
|
ok = true
|
|
67
85
|
|
|
86
|
+
if bucket['upload']
|
|
87
|
+
bucket['upload'].each { |batch|
|
|
88
|
+
if !File.exists?(batch['source'])
|
|
89
|
+
MU.log "Bucket '#{bucket['name']}' specifies upload for file/directory that does not exist", MU::ERR, details: batch
|
|
90
|
+
ok = false
|
|
91
|
+
next
|
|
92
|
+
end
|
|
93
|
+
batch['source'] = File.realpath(File.expand_path(batch['source']))
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
68
97
|
ok
|
|
69
98
|
end
|
|
70
99
|
|
|
@@ -54,7 +54,7 @@ module MU
|
|
|
54
54
|
"type" => "string",
|
|
55
55
|
"default" => "redis"
|
|
56
56
|
},
|
|
57
|
-
"dns_records" => MU::Config::DNSZone.records_primitive(need_target: false, default_type: "CNAME", need_zone: true),
|
|
57
|
+
"dns_records" => MU::Config::DNSZone.records_primitive(need_target: false, default_type: "CNAME", need_zone: true, embedded_type: "cache_cluster"),
|
|
58
58
|
"dns_sync_wait" => {
|
|
59
59
|
"type" => "boolean",
|
|
60
60
|
"description" => "Wait for DNS record to propagate in DNS Zone.",
|
|
@@ -0,0 +1,100 @@
|
|
|
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
|
+
class Config
|
|
17
|
+
# Basket of Kittens config schema and parser logic. See modules/mu/providers/*/job.rb
|
|
18
|
+
class CDN
|
|
19
|
+
|
|
20
|
+
# Base configuration schema for a scheduled job
|
|
21
|
+
# @return [Hash]
|
|
22
|
+
def self.schema
|
|
23
|
+
{
|
|
24
|
+
"type" => "object",
|
|
25
|
+
"additionalProperties" => false,
|
|
26
|
+
"required" => ["origins"],
|
|
27
|
+
"properties" => {
|
|
28
|
+
"name" => {
|
|
29
|
+
"type" => "string"
|
|
30
|
+
},
|
|
31
|
+
"dns_records" => MU::Config::DNSZone.records_primitive(need_target: false, default_type: "CNAME", need_zone: true, embedded_type: "cdn"),
|
|
32
|
+
"default_object" => {
|
|
33
|
+
"type" => "string",
|
|
34
|
+
"default" => "index.html"
|
|
35
|
+
},
|
|
36
|
+
"credentials" => MU::Config.credentials_primitive,
|
|
37
|
+
"aliases" => {
|
|
38
|
+
"type" => "array",
|
|
39
|
+
"items" => {
|
|
40
|
+
"type" => "string"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"origins" => {
|
|
44
|
+
"type" => "array",
|
|
45
|
+
"minItems" => 1,
|
|
46
|
+
"items" => {
|
|
47
|
+
"type" => "object",
|
|
48
|
+
"description" => "One or more back-end sources which this CDN will cache",
|
|
49
|
+
"required" => ["name"],
|
|
50
|
+
"properties" => {
|
|
51
|
+
"name" => {
|
|
52
|
+
"type" => "string",
|
|
53
|
+
"description" => "A unique identifying string which other components of this distribution may use to reference this origin"
|
|
54
|
+
},
|
|
55
|
+
"domain_name" => {
|
|
56
|
+
"type" => "string",
|
|
57
|
+
"description" => "Domain name of the back-end web server or other resource behind this CDN"
|
|
58
|
+
},
|
|
59
|
+
"path" => {
|
|
60
|
+
"type" => "string",
|
|
61
|
+
"default" => "",
|
|
62
|
+
"description" => "Optional path on back-end service to which to map front-end requests"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"behaviors" => {
|
|
68
|
+
"type" => "array",
|
|
69
|
+
"items" => {
|
|
70
|
+
"description" => "Customize the behavior of requests sent to one of this CDN's configured +origins+",
|
|
71
|
+
"type" => "object",
|
|
72
|
+
"properties" => {
|
|
73
|
+
"origin" => {
|
|
74
|
+
"type" => "string",
|
|
75
|
+
"description" => "Which of our +origins+ this set of behaviors should map to, by its +name+ field."
|
|
76
|
+
},
|
|
77
|
+
"path_pattern" => {
|
|
78
|
+
"type" => "string",
|
|
79
|
+
"description" => "The request path or paths for which this behavior should be invoked"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Generic pre-processing of {MU::Config::BasketofKittens::jobs}, bare and unvalidated.
|
|
89
|
+
# @param _job [Hash]: The resource to process and validate
|
|
90
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
91
|
+
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
92
|
+
def self.validate(_job, _configurator)
|
|
93
|
+
ok = true
|
|
94
|
+
|
|
95
|
+
ok
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
@@ -62,7 +62,7 @@ module MU
|
|
|
62
62
|
"default" => false
|
|
63
63
|
},
|
|
64
64
|
"member_of_cluster" => MU::Config::Ref.schema(type: "databases", desc: "Internal use"),
|
|
65
|
-
"dns_records" => MU::Config::DNSZone.records_primitive(need_target: false, default_type: "CNAME", need_zone: true),
|
|
65
|
+
"dns_records" => MU::Config::DNSZone.records_primitive(need_target: false, default_type: "CNAME", need_zone: true, embedded_type: "database"),
|
|
66
66
|
"dns_sync_wait" => {
|
|
67
67
|
"type" => "boolean",
|
|
68
68
|
"description" => "Wait for DNS record to propagate in DNS Zone.",
|
|
@@ -341,7 +341,7 @@ module MU
|
|
|
341
341
|
"region" => db['region'],
|
|
342
342
|
"credentials" => db['credentials'],
|
|
343
343
|
}
|
|
344
|
-
MU::Config.addDependency(replica, db["name"], "database",
|
|
344
|
+
MU::Config.addDependency(replica, db["name"], "database", their_phase: "groom")
|
|
345
345
|
read_replicas << replica
|
|
346
346
|
end
|
|
347
347
|
end
|
|
@@ -367,7 +367,7 @@ module MU
|
|
|
367
367
|
"type" => "databases"
|
|
368
368
|
}
|
|
369
369
|
# AWS will figure out for us which database instance is the writer/master so we can create all of them concurrently.
|
|
370
|
-
MU::Config.addDependency(node, db["name"], "database",
|
|
370
|
+
MU::Config.addDependency(node, db["name"], "database", their_phase: "groom")
|
|
371
371
|
cluster_nodes << node
|
|
372
372
|
|
|
373
373
|
# Alarms are set on each DB cluster node, not on the cluster itself,
|
|
@@ -60,7 +60,7 @@ module MU
|
|
|
60
60
|
# @param default_type [String]: The type of record to make default (e.g. An, CNAME, etc)
|
|
61
61
|
# @param need_zone [Boolean]: Whether to explicitly require a zone be declared
|
|
62
62
|
# @return [Hash]
|
|
63
|
-
def self.records_primitive(need_target: true, default_type: nil, need_zone: false)
|
|
63
|
+
def self.records_primitive(need_target: true, default_type: nil, need_zone: false, embedded_type: nil)
|
|
64
64
|
dns_records_primitive = {
|
|
65
65
|
"type" => "array",
|
|
66
66
|
"maxItems" => 100,
|
|
@@ -107,8 +107,9 @@ module MU
|
|
|
107
107
|
},
|
|
108
108
|
"mu_type" => {
|
|
109
109
|
"type" => "string",
|
|
110
|
-
"description" => "The
|
|
111
|
-
|
|
110
|
+
"description" => "The mu type of a resource being targeted.",
|
|
111
|
+
"enum" => embedded_type ? [embedded_type] : ["loadbalancer", "server", "database", "cache_cluster", "endpoint", "cdn"],
|
|
112
|
+
"default" => embedded_type
|
|
112
113
|
},
|
|
113
114
|
"target_type" => {
|
|
114
115
|
"description" => "If the target is a public or a private resource. This only applies to servers/server_pools when using automatic DNS registration. If set to public but the target only has a private address, the private address will be used",
|
|
@@ -32,6 +32,7 @@ module MU
|
|
|
32
32
|
"iam_role" => {"type" => "string"},
|
|
33
33
|
"region" => MU::Config.region_primitive,
|
|
34
34
|
"vpc" => MU::Config::VPC.reference(MU::Config::VPC::NO_SUBNETS, MU::Config::VPC::NO_NAT_OPTS),
|
|
35
|
+
"dns_records" => MU::Config::DNSZone.records_primitive(need_target: false, default_type: "CNAME", need_zone: true, embedded_type: "endpoint"),
|
|
35
36
|
"methods" => {
|
|
36
37
|
"type" => "array",
|
|
37
38
|
"items" => {
|
|
@@ -119,7 +119,7 @@ module MU
|
|
|
119
119
|
if acl_include['sgs']
|
|
120
120
|
acl_include['sgs'].each { |sg_ref|
|
|
121
121
|
if haveLitterMate?(sg_ref, "firewall_rules")
|
|
122
|
-
MU::Config.addDependency(acl, sg_ref, "firewall_rule",
|
|
122
|
+
MU::Config.addDependency(acl, sg_ref, "firewall_rule", my_phase: "groom")
|
|
123
123
|
siblingfw = haveLitterMate?(sg_ref, "firewall_rules")
|
|
124
124
|
if !siblingfw["#MU_VALIDATED"]
|
|
125
125
|
# XXX raise failure somehow
|
|
@@ -71,6 +71,10 @@ module MU
|
|
|
71
71
|
"zip_file" => {
|
|
72
72
|
"type" => "string",
|
|
73
73
|
"description" => "Path to a zipped deployment package to upload."
|
|
74
|
+
},
|
|
75
|
+
"path" => {
|
|
76
|
+
"type" => "string",
|
|
77
|
+
"description" => "Path to a directory that can be zipped into deployment package to upload."
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
80
|
},
|
|
@@ -106,13 +110,18 @@ module MU
|
|
|
106
110
|
if !function['code']
|
|
107
111
|
ok = false
|
|
108
112
|
end
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
113
|
+
|
|
114
|
+
if function['code']
|
|
115
|
+
['zip_file', 'path'].each { |src|
|
|
116
|
+
if function['code'][src]
|
|
117
|
+
if !File.readable?(function['code'][src]) and !Dir.exists?(function['code'][src])
|
|
118
|
+
MU.log "Function '#{function['name']}' specifies a deployment package that I can't read at #{function['code'][src]}", MU::ERR
|
|
119
|
+
ok = false
|
|
120
|
+
else
|
|
121
|
+
function['code'][src] = File.realpath(File.expand_path(function['code'][src]))
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
}
|
|
116
125
|
end
|
|
117
126
|
|
|
118
127
|
ok
|
|
@@ -0,0 +1,89 @@
|
|
|
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
|
+
class Config
|
|
17
|
+
# Basket of Kittens config schema and parser logic. See modules/mu/providers/*/job.rb
|
|
18
|
+
class Job
|
|
19
|
+
|
|
20
|
+
# Base configuration schema for a scheduled job
|
|
21
|
+
# @return [Hash]
|
|
22
|
+
def self.schema
|
|
23
|
+
{
|
|
24
|
+
"type" => "object",
|
|
25
|
+
"additionalProperties" => false,
|
|
26
|
+
"description" => "A cloud provider-specific facility for triggered or scheduled tasks, such as AWS CloudWatch Events or Google Cloud Scheduler.",
|
|
27
|
+
"properties" => {
|
|
28
|
+
"name" => {
|
|
29
|
+
"type" => "string"
|
|
30
|
+
},
|
|
31
|
+
"region" => MU::Config.region_primitive,
|
|
32
|
+
"credentials" => MU::Config.credentials_primitive,
|
|
33
|
+
"description" => {
|
|
34
|
+
"type" => "string",
|
|
35
|
+
"description" => "Human-readable description field for this job (this will field be overriden with the Mu deploy id on most providers unless +scrub_mu_isms+ is set)"
|
|
36
|
+
},
|
|
37
|
+
"schedule" => {
|
|
38
|
+
"type" => "object",
|
|
39
|
+
"description" => "A schedule on which to invoke this task, typically unix crontab style.",
|
|
40
|
+
"properties" => {
|
|
41
|
+
"minute" => {
|
|
42
|
+
"type" => "string",
|
|
43
|
+
"description" => "The minute of the hour at which to invoke this job, typically an integer between 0 and 59. This will be validated by the cloud provider, where other more human-readable values may be supported.",
|
|
44
|
+
"default" => "0"
|
|
45
|
+
},
|
|
46
|
+
"hour" => {
|
|
47
|
+
"type" => "string",
|
|
48
|
+
"description" => "The hour at which to invoke this job, typically an integer between 0 and 23. This will be validated by the cloud provider, where other more human-readable values may be supported.",
|
|
49
|
+
"default" => "*"
|
|
50
|
+
},
|
|
51
|
+
"day_of_month" => {
|
|
52
|
+
"type" => "string",
|
|
53
|
+
"description" => "The day of the month which to invoke this job, typically an integer between 1 and 31. This will be validated by the cloud provider, where other more human-readable values may be supported.",
|
|
54
|
+
"default" => "*"
|
|
55
|
+
},
|
|
56
|
+
"month" => {
|
|
57
|
+
"type" => "string",
|
|
58
|
+
"description" => "The month in which to invoke this job, typically an integer between 1 and 12. This will be validated by the cloud provider, where other more human-readable values may be supported.",
|
|
59
|
+
"default" => "*"
|
|
60
|
+
},
|
|
61
|
+
"day_of_week" => {
|
|
62
|
+
"type" => "string",
|
|
63
|
+
"description" => "The day of the week on which to invoke this job, typically an integer between 0 and 6. This will be validated by the cloud provider, where other more human-readable values may be supported.",
|
|
64
|
+
"default" => "*"
|
|
65
|
+
},
|
|
66
|
+
"year" => {
|
|
67
|
+
"type" => "string",
|
|
68
|
+
"description" => "The year in which to invoke this job. Not honored by all cloud providers.",
|
|
69
|
+
"default" => "*"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Generic pre-processing of {MU::Config::BasketofKittens::jobs}, bare and unvalidated.
|
|
78
|
+
# @param _job [Hash]: The resource to process and validate
|
|
79
|
+
# @param _configurator [MU::Config]: The overall deployment configurator of which this resource is a member
|
|
80
|
+
# @return [Boolean]: True if validation succeeded, False otherwise
|
|
81
|
+
def self.validate(_job, _configurator)
|
|
82
|
+
ok = true
|
|
83
|
+
|
|
84
|
+
ok
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -36,12 +36,12 @@ module MU
|
|
|
36
36
|
"items" => {
|
|
37
37
|
"type" => "object",
|
|
38
38
|
"description" => "A list of people or resources which should receive notifications",
|
|
39
|
-
"required" => ["endpoint"],
|
|
40
39
|
"properties" => {
|
|
41
40
|
"endpoint" => {
|
|
42
41
|
"type" => "string",
|
|
43
|
-
"description" => "
|
|
44
|
-
}
|
|
42
|
+
"description" => "Shorthand for an endpoint which should be subscribed to this notifier, typically an email address or SMS-enabled phone number. For complex cases, such as referencing an AWS Lambda function defined elsewhere in your Mu stack, use +resource+ instead."
|
|
43
|
+
},
|
|
44
|
+
"resource" => MU::Config::Ref.schema(desc: "A cloud resource that is a valid notification target for this notifier. For simple use cases, such as external email addresses or SMS, use +endpoint+ instead.")
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -56,23 +56,12 @@ module MU
|
|
|
56
56
|
def self.validate(notifier, _configurator)
|
|
57
57
|
ok = true
|
|
58
58
|
|
|
59
|
+
|
|
59
60
|
if notifier['subscriptions']
|
|
60
61
|
notifier['subscriptions'].each { |sub|
|
|
61
|
-
if !sub[
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
elsif sub["endpoint"].match(/^https:/i)
|
|
65
|
-
sub["type"] = "https"
|
|
66
|
-
elsif sub["endpoint"].match(/^sqs:/i)
|
|
67
|
-
sub["type"] = "sqs"
|
|
68
|
-
elsif sub["endpoint"].match(/^\+?[\d\-]+$/)
|
|
69
|
-
sub["type"] = "sms"
|
|
70
|
-
elsif sub["endpoint"].match(/\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i)
|
|
71
|
-
sub["type"] = "email"
|
|
72
|
-
else
|
|
73
|
-
MU.log "Notifier #{notifier['name']} subscription #{sub['endpoint']} did not specify a type, and I'm unable to guess one", MU::ERR
|
|
74
|
-
ok = false
|
|
75
|
-
end
|
|
62
|
+
if !sub['endpoint'] and !sub['resource']
|
|
63
|
+
MU.log "Notifier '#{notifier['name']}' must specify either resource or endpoint in subscription", MU::ERR, details: sub
|
|
64
|
+
ok = false
|
|
76
65
|
end
|
|
77
66
|
}
|
|
78
67
|
end
|
data/modules/mu/config/ref.rb
CHANGED
|
@@ -121,6 +121,10 @@ module MU
|
|
|
121
121
|
@deploy_id = @mommacat.deploy_id
|
|
122
122
|
end
|
|
123
123
|
|
|
124
|
+
# canonicalize the 'type' argument
|
|
125
|
+
_shortclass, _cfg_name, cfg_plural, _classname, _attrs = MU::Cloud.getResourceNames(@type, false)
|
|
126
|
+
@type = cfg_plural if cfg_plural
|
|
127
|
+
|
|
124
128
|
kitten(shallow: true) if @mommacat # try to populate the actual cloud object for this
|
|
125
129
|
end
|
|
126
130
|
|
|
@@ -140,6 +144,13 @@ module MU
|
|
|
140
144
|
end
|
|
141
145
|
end
|
|
142
146
|
|
|
147
|
+
# Lets callers set attributes like a {Hash}
|
|
148
|
+
# @param attribute [String,Symbol]
|
|
149
|
+
def []=(attribute, value)
|
|
150
|
+
instance_variable_set("@#{attribute.to_s}".to_sym, value)
|
|
151
|
+
self.class.define_reader(attribute)
|
|
152
|
+
end
|
|
153
|
+
|
|
143
154
|
# Unset an attribute. Sort of. We can't actually do that, so nil it out
|
|
144
155
|
# and we get the behavior we want.
|
|
145
156
|
def delete(attribute)
|
|
@@ -150,7 +161,7 @@ module MU
|
|
|
150
161
|
# Base configuration schema for declared kittens referencing other cloud objects. This is essentially a set of filters that we're going to pass to {MU::MommaCat.findStray}.
|
|
151
162
|
# @param aliases [Array<Hash>]: Key => value mappings to set backwards-compatibility aliases for attributes, such as the ubiquitous +vpc_id+ (+vpc_id+ => +id+).
|
|
152
163
|
# @return [Hash]
|
|
153
|
-
def self.schema(aliases = [], type: nil, parent_obj: nil, desc: nil, omit_fields: [])
|
|
164
|
+
def self.schema(aliases = [], type: nil, parent_obj: nil, desc: nil, omit_fields: [], any_type: false)
|
|
154
165
|
parent_obj ||= caller[1].gsub(/.*?\/([^\.\/]+)\.rb:.*/, '\1')
|
|
155
166
|
desc ||= "Reference a #{type ? "'#{type}' resource" : "resource" } from this #{parent_obj ? "'#{parent_obj}'" : "" } resource"
|
|
156
167
|
schema = {
|
|
@@ -205,7 +216,9 @@ module MU
|
|
|
205
216
|
}
|
|
206
217
|
end
|
|
207
218
|
|
|
208
|
-
if
|
|
219
|
+
if any_type
|
|
220
|
+
schema["properties"]["type"].delete("enum")
|
|
221
|
+
elsif !type.nil?
|
|
209
222
|
schema["required"] = ["type"]
|
|
210
223
|
schema["properties"]["type"]["default"] = type
|
|
211
224
|
schema["properties"]["type"]["enum"] = [type]
|
|
@@ -225,6 +238,13 @@ module MU
|
|
|
225
238
|
schema
|
|
226
239
|
end
|
|
227
240
|
|
|
241
|
+
# Is our +@type+ attribute a Mu-supported type, or some rando string?
|
|
242
|
+
# @return [Boolean]
|
|
243
|
+
def is_mu_type?
|
|
244
|
+
_shortclass, _cfg_name, type, _classname, _attrs = MU::Cloud.getResourceNames(@type, false)
|
|
245
|
+
!type.nil?
|
|
246
|
+
end
|
|
247
|
+
|
|
228
248
|
# Decompose into a plain-jane {MU::Config::BasketOfKittens} hash fragment,
|
|
229
249
|
# of the sort that would have been used to declare this reference in the
|
|
230
250
|
# first place.
|
|
@@ -266,10 +286,23 @@ module MU
|
|
|
266
286
|
# called in a live deploy, which is to say that if called during initial
|
|
267
287
|
# configuration parsing, results may be incorrect.
|
|
268
288
|
# @param mommacat [MU::MommaCat]: A deploy object which will be searched for the referenced resource if provided, before restoring to broader, less efficient searches.
|
|
269
|
-
def kitten(mommacat = @mommacat, shallow: false, debug: false)
|
|
270
|
-
|
|
289
|
+
def kitten(mommacat = @mommacat, shallow: false, debug: false, cloud: nil)
|
|
290
|
+
cloud ||= @cloud
|
|
291
|
+
return nil if !cloud or !@type
|
|
292
|
+
|
|
293
|
+
_shortclass, _cfg_name, cfg_plural, _classname, _attrs = MU::Cloud.getResourceNames(@type, false)
|
|
294
|
+
if cfg_plural
|
|
295
|
+
@type = cfg_plural # make sure this is the thing we expect
|
|
296
|
+
else
|
|
297
|
+
return nil # we don't do non-muish resources
|
|
298
|
+
end
|
|
299
|
+
|
|
271
300
|
loglevel = debug ? MU::NOTICE : MU::DEBUG
|
|
272
301
|
|
|
302
|
+
if debug
|
|
303
|
+
MU.log "this mf kitten", MU::WARN, details: caller
|
|
304
|
+
end
|
|
305
|
+
|
|
273
306
|
if @obj
|
|
274
307
|
@deploy_id ||= @obj.deploy_id
|
|
275
308
|
@id ||= @obj.cloud_id
|
|
@@ -277,7 +310,7 @@ module MU
|
|
|
277
310
|
return @obj
|
|
278
311
|
end
|
|
279
312
|
|
|
280
|
-
if mommacat and
|
|
313
|
+
if mommacat and caller.grep(/`findLitterMate'/).empty? # XXX the dumbest
|
|
281
314
|
MU.log "Looking for #{@type} #{@name} #{@id} in deploy #{mommacat.deploy_id}", loglevel
|
|
282
315
|
begin
|
|
283
316
|
@obj = mommacat.findLitterMate(type: @type, name: @name, cloud_id: @id, credentials: @credentials, debug: debug)
|
|
@@ -309,7 +342,7 @@ end
|
|
|
309
342
|
end
|
|
310
343
|
end
|
|
311
344
|
|
|
312
|
-
if !@obj and !(
|
|
345
|
+
if !@obj and !(cloud == "Google" and @id and @type == "users" and MU::Cloud.resourceClass("Google", "User").cannedServiceAcctName?(@id)) and !shallow
|
|
313
346
|
try_deploy_id = @deploy_id
|
|
314
347
|
|
|
315
348
|
begin
|
|
@@ -323,8 +356,20 @@ end
|
|
|
323
356
|
[@habitat.to_s]
|
|
324
357
|
end
|
|
325
358
|
|
|
359
|
+
MU.log "Ref#kitten calling findStray", loglevel, details: {
|
|
360
|
+
cloud: cloud,
|
|
361
|
+
type: @type,
|
|
362
|
+
name: @name,
|
|
363
|
+
cloud_id: @id,
|
|
364
|
+
deploy_id: try_deploy_id,
|
|
365
|
+
region: @region,
|
|
366
|
+
habitats: hab_arg,
|
|
367
|
+
credentials: @credentials,
|
|
368
|
+
dummy_ok: (["habitats", "folders", "users", "groups", "vpcs"].include?(@type) or @id)
|
|
369
|
+
}
|
|
370
|
+
|
|
326
371
|
found = MU::MommaCat.findStray(
|
|
327
|
-
|
|
372
|
+
cloud,
|
|
328
373
|
@type,
|
|
329
374
|
name: @name,
|
|
330
375
|
cloud_id: @id,
|
|
@@ -332,12 +377,13 @@ end
|
|
|
332
377
|
region: @region,
|
|
333
378
|
habitats: hab_arg,
|
|
334
379
|
credentials: @credentials,
|
|
335
|
-
dummy_ok: (["habitats", "folders", "users", "groups", "vpcs"].include?(@type))
|
|
380
|
+
dummy_ok: (["habitats", "folders", "users", "groups", "vpcs"].include?(@type) or @id)
|
|
336
381
|
)
|
|
382
|
+
MU.log "Ref#kitten results from findStray", loglevel, details: found
|
|
337
383
|
@obj ||= found.first if found
|
|
338
384
|
rescue MU::MommaCat::MultipleMatches => e
|
|
339
385
|
if try_deploy_id.nil? and MU.deploy_id
|
|
340
|
-
MU.log "Attempting to narrow down #{
|
|
386
|
+
MU.log "Attempting to narrow down #{cloud} #{@type} to #{MU.deploy_id}", MU::NOTICE
|
|
341
387
|
try_deploy_id = MU.deploy_id
|
|
342
388
|
retry
|
|
343
389
|
else
|