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
|
@@ -52,14 +52,14 @@ module MU
|
|
|
52
52
|
begin
|
|
53
53
|
MU.log "Creating EC2 Security Group #{groupname}", details: sg_struct
|
|
54
54
|
|
|
55
|
-
secgroup = MU::Cloud::AWS.ec2(region: @
|
|
55
|
+
secgroup = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).create_security_group(sg_struct)
|
|
56
56
|
@cloud_id = secgroup.group_id
|
|
57
57
|
rescue Aws::EC2::Errors::InvalidGroupDuplicate
|
|
58
58
|
MU.log "EC2 Security Group #{groupname} already exists, using it", MU::NOTICE
|
|
59
59
|
filters = [{name: "group-name", values: [groupname]}]
|
|
60
60
|
filters << {name: "vpc-id", values: [vpc_id]} if !vpc_id.nil?
|
|
61
61
|
|
|
62
|
-
secgroup = MU::Cloud::AWS.ec2(region: @
|
|
62
|
+
secgroup = MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_security_groups(filters: filters).security_groups.first
|
|
63
63
|
if secgroup.nil?
|
|
64
64
|
raise MuError, "Failed to locate security group named #{groupname}, even though EC2 says it already exists", caller
|
|
65
65
|
end
|
|
@@ -67,25 +67,25 @@ module MU
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
begin
|
|
70
|
-
MU::Cloud::AWS.ec2(region: @
|
|
70
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).describe_security_groups(group_ids: [secgroup.group_id])
|
|
71
71
|
rescue Aws::EC2::Errors::InvalidGroupNotFound
|
|
72
72
|
MU.log "#{secgroup.group_id} not yet ready, waiting...", MU::NOTICE
|
|
73
73
|
sleep 10
|
|
74
74
|
retry
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
MU::Cloud::AWS.createStandardTags(secgroup.group_id, region: @
|
|
78
|
-
MU::Cloud::AWS.createTag(secgroup.group_id, "Name", groupname, region: @
|
|
77
|
+
MU::Cloud::AWS.createStandardTags(secgroup.group_id, region: @region, credentials: @credentials)
|
|
78
|
+
MU::Cloud::AWS.createTag(secgroup.group_id, "Name", groupname, region: @region, credentials: @credentials)
|
|
79
79
|
|
|
80
80
|
if @config['optional_tags']
|
|
81
81
|
MU::MommaCat.listOptionalTags.each { |key, value|
|
|
82
|
-
MU::Cloud::AWS.createTag(secgroup.group_id, key, value, region: @
|
|
82
|
+
MU::Cloud::AWS.createTag(secgroup.group_id, key, value, region: @region, credentials: @credentials)
|
|
83
83
|
}
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
if @config['tags']
|
|
87
87
|
@config['tags'].each { |tag|
|
|
88
|
-
MU::Cloud::AWS.createTag(secgroup.group_id, tag['key'], tag['value'], region: @
|
|
88
|
+
MU::Cloud::AWS.createTag(secgroup.group_id, tag['key'], tag['value'], region: @region, credentials: @credentials)
|
|
89
89
|
}
|
|
90
90
|
end
|
|
91
91
|
|
|
@@ -123,7 +123,7 @@ module MU
|
|
|
123
123
|
# Log metadata about this ruleset to the currently running deployment
|
|
124
124
|
def notify
|
|
125
125
|
sg_data = MU.structToHash(
|
|
126
|
-
MU::Cloud::FirewallRule.find(cloud_id: @cloud_id, region: @
|
|
126
|
+
MU::Cloud::FirewallRule.find(cloud_id: @cloud_id, region: @region)
|
|
127
127
|
)
|
|
128
128
|
sg_data["group_id"] = @cloud_id
|
|
129
129
|
sg_data["cloud_id"] = @cloud_id
|
|
@@ -151,8 +151,11 @@ module MU
|
|
|
151
151
|
rule["firewall_rules"].concat(sgs.map { |s|
|
|
152
152
|
MU::Config::Ref.get(
|
|
153
153
|
id: s,
|
|
154
|
+
region: @region,
|
|
155
|
+
credentials: @credentials,
|
|
154
156
|
cloud: "AWS",
|
|
155
|
-
type: "firewall_rule"
|
|
157
|
+
type: "firewall_rule",
|
|
158
|
+
dummy_ok: true
|
|
156
159
|
)
|
|
157
160
|
})
|
|
158
161
|
end
|
|
@@ -169,12 +172,12 @@ module MU
|
|
|
169
172
|
|
|
170
173
|
begin
|
|
171
174
|
if egress
|
|
172
|
-
MU::Cloud::AWS.ec2(region: @
|
|
175
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).authorize_security_group_egress(
|
|
173
176
|
group_id: @cloud_id,
|
|
174
177
|
ip_permissions: ec2_rule
|
|
175
178
|
)
|
|
176
179
|
else
|
|
177
|
-
MU::Cloud::AWS.ec2(region: @
|
|
180
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).authorize_security_group_ingress(
|
|
178
181
|
group_id: @cloud_id,
|
|
179
182
|
ip_permissions: ec2_rule
|
|
180
183
|
)
|
|
@@ -185,12 +188,12 @@ module MU
|
|
|
185
188
|
# existing rules
|
|
186
189
|
if comment
|
|
187
190
|
if egress
|
|
188
|
-
MU::Cloud::AWS.ec2(region: @
|
|
191
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).update_security_group_rule_descriptions_egress(
|
|
189
192
|
group_id: @cloud_id,
|
|
190
193
|
ip_permissions: ec2_rule
|
|
191
194
|
)
|
|
192
195
|
else
|
|
193
|
-
MU::Cloud::AWS.ec2(region: @
|
|
196
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).update_security_group_rule_descriptions_ingress(
|
|
194
197
|
group_id: @cloud_id,
|
|
195
198
|
ip_permissions: ec2_rule
|
|
196
199
|
)
|
|
@@ -202,7 +205,7 @@ module MU
|
|
|
202
205
|
# Canonical Amazon Resource Number for this resource
|
|
203
206
|
# @return [String]
|
|
204
207
|
def arn
|
|
205
|
-
"arn:"+(MU::Cloud::AWS.isGovCloud?(@
|
|
208
|
+
"arn:"+(MU::Cloud::AWS.isGovCloud?(@region) ? "aws-us-gov" : "aws")+":ec2:"+@region+":"+MU::Cloud::AWS.credToAcct(@credentials)+":security-group/"+@cloud_id
|
|
206
209
|
end
|
|
207
210
|
|
|
208
211
|
# Locate an existing security group or groups and return an array containing matching AWS resource descriptors for those that match.
|
|
@@ -248,9 +251,9 @@ module MU
|
|
|
248
251
|
def toKitten(**_args)
|
|
249
252
|
bok = {
|
|
250
253
|
"cloud" => "AWS",
|
|
251
|
-
"credentials" => @
|
|
254
|
+
"credentials" => @credentials,
|
|
252
255
|
"cloud_id" => @cloud_id,
|
|
253
|
-
"region" => @
|
|
256
|
+
"region" => @region
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
if !cloud_desc
|
|
@@ -381,14 +384,14 @@ module MU
|
|
|
381
384
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
|
382
385
|
# @param region [String]: The cloud provider region
|
|
383
386
|
# @return [void]
|
|
384
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
|
387
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
|
385
388
|
filters = if flags and flags["vpc_id"]
|
|
386
389
|
[
|
|
387
390
|
{name: "vpc-id", values: [flags["vpc_id"]]}
|
|
388
391
|
]
|
|
389
392
|
else
|
|
390
393
|
filters = [
|
|
391
|
-
{name: "tag:MU-ID", values: [
|
|
394
|
+
{name: "tag:MU-ID", values: [deploy_id]}
|
|
392
395
|
]
|
|
393
396
|
if !ignoremaster
|
|
394
397
|
filters << {name: "tag:MU-MASTER-IP", values: [MU.mu_public_ip]}
|
|
@@ -649,7 +652,7 @@ module MU
|
|
|
649
652
|
if rule['firewall_rules']
|
|
650
653
|
rule['firewall_rules'].each { |sg|
|
|
651
654
|
if sg['name'] and !sg['deploy_id']
|
|
652
|
-
MU::Config.addDependency(acl, sg['name'], "firewall_rule",
|
|
655
|
+
MU::Config.addDependency(acl, sg['name'], "firewall_rule", my_phase: "groom")
|
|
653
656
|
end
|
|
654
657
|
}
|
|
655
658
|
end
|
|
@@ -657,7 +660,7 @@ module MU
|
|
|
657
660
|
if rule['loadbalancers']
|
|
658
661
|
rule['loadbalancers'].each { |lb|
|
|
659
662
|
if lb['name'] and !lb['deploy_id']
|
|
660
|
-
MU::Config.addDependency(acl, lb['name'], "loadbalancer",
|
|
663
|
+
MU::Config.addDependency(acl, lb['name'], "loadbalancer", their_phase: "groom")
|
|
661
664
|
end
|
|
662
665
|
}
|
|
663
666
|
end
|
|
@@ -731,7 +734,7 @@ module MU
|
|
|
731
734
|
end
|
|
732
735
|
}
|
|
733
736
|
MU.log "Removing unconfigured rule in #{@mu_name}", MU::WARN, details: ext_rule
|
|
734
|
-
MU::Cloud::AWS.ec2(region: @
|
|
737
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).revoke_security_group_ingress(
|
|
735
738
|
group_id: @cloud_id,
|
|
736
739
|
ip_permissions: [ext_rule]
|
|
737
740
|
)
|
|
@@ -797,7 +800,7 @@ module MU
|
|
|
797
800
|
if ingress
|
|
798
801
|
if haverule
|
|
799
802
|
begin
|
|
800
|
-
MU::Cloud::AWS.ec2(region: @
|
|
803
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).revoke_security_group_ingress(
|
|
801
804
|
group_id: @cloud_id,
|
|
802
805
|
ip_permissions: [haverule]
|
|
803
806
|
)
|
|
@@ -805,7 +808,7 @@ module MU
|
|
|
805
808
|
end
|
|
806
809
|
end
|
|
807
810
|
begin
|
|
808
|
-
MU::Cloud::AWS.ec2(region: @
|
|
811
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).authorize_security_group_ingress(
|
|
809
812
|
group_id: @cloud_id,
|
|
810
813
|
ip_permissions: [rule]
|
|
811
814
|
)
|
|
@@ -818,14 +821,14 @@ module MU
|
|
|
818
821
|
if egress
|
|
819
822
|
if haverule
|
|
820
823
|
begin
|
|
821
|
-
MU::Cloud::AWS.ec2(region: @
|
|
824
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).revoke_security_group_egress(
|
|
822
825
|
group_id: @cloud_id,
|
|
823
826
|
ip_permissions: [haverule]
|
|
824
827
|
)
|
|
825
828
|
rescue Aws::EC2::Errors::InvalidPermissionNotFound
|
|
826
829
|
end
|
|
827
830
|
end
|
|
828
|
-
MU::Cloud::AWS.ec2(region: @
|
|
831
|
+
MU::Cloud::AWS.ec2(region: @region, credentials: @credentials).authorize_security_group_egress(
|
|
829
832
|
group_id: @cloud_id,
|
|
830
833
|
ip_permissions: [rule]
|
|
831
834
|
)
|
|
@@ -860,8 +863,11 @@ module MU
|
|
|
860
863
|
p_start = rule['port'].to_i
|
|
861
864
|
p_end = rule['port'].to_i
|
|
862
865
|
elsif rule['proto'] != "icmp"
|
|
863
|
-
|
|
866
|
+
MU.log "Can't create a TCP or UDP security group rule without specifying ports, assuming 'all'", MU::WARN, details: rule
|
|
867
|
+
p_start = "0"
|
|
868
|
+
p_end = "65535"
|
|
864
869
|
end
|
|
870
|
+
|
|
865
871
|
if rule['proto'] != "icmp"
|
|
866
872
|
if p_start.nil? or p_end.nil?
|
|
867
873
|
raise MuError, "Got nil ports out of rule #{rule}"
|
|
@@ -59,7 +59,7 @@ module MU
|
|
|
59
59
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
|
60
60
|
# @param region [String]: The cloud provider region
|
|
61
61
|
# @return [void]
|
|
62
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
|
62
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
# Locate an existing AWS organization. If no identifying parameters are specified, this will return a description of the Organization which owns the account for our credentials.
|
|
@@ -18,6 +18,18 @@ module MU
|
|
|
18
18
|
# A function as configured in {MU::Config::BasketofKittens::functions}
|
|
19
19
|
class Function < MU::Cloud::Function
|
|
20
20
|
|
|
21
|
+
# If we have sibling resources in our deployment, automatically inject
|
|
22
|
+
# interesting things about them into our function's environment
|
|
23
|
+
# variables.
|
|
24
|
+
SIBLING_VARS = {
|
|
25
|
+
"servers" => ["private_ip_address", "public_ip_address"],
|
|
26
|
+
"search_domains" => ["endpoint"],
|
|
27
|
+
"databases" => ["endpoint"],
|
|
28
|
+
"endpoints" => ["url"],
|
|
29
|
+
"notifiers" => ["TopicArn"],
|
|
30
|
+
"nosqldbs" => ["table_arn"]
|
|
31
|
+
}
|
|
32
|
+
|
|
21
33
|
# Initialize this cloud resource object. Calling +super+ will invoke the initializer defined under {MU::Cloud}, which should set the attribtues listed in {MU::Cloud::PUBLIC_ATTRS} as well as applicable dependency shortcuts, like +@vpc+, for us.
|
|
22
34
|
# @param args [Hash]: Hash of named arguments passed via Ruby's double-splat
|
|
23
35
|
def initialize(**args)
|
|
@@ -26,10 +38,10 @@ module MU
|
|
|
26
38
|
end
|
|
27
39
|
|
|
28
40
|
# Tag this Lambda function
|
|
29
|
-
def assign_tag(resource_arn, tag_list, region=@
|
|
41
|
+
def assign_tag(resource_arn, tag_list, region=@region)
|
|
30
42
|
begin
|
|
31
43
|
tag_list.each do |each_pair|
|
|
32
|
-
MU::Cloud::AWS.lambda(region: region, credentials: @
|
|
44
|
+
MU::Cloud::AWS.lambda(region: region, credentials: @credentials).tag_resource({
|
|
33
45
|
resource: resource_arn,
|
|
34
46
|
tags: each_pair
|
|
35
47
|
})
|
|
@@ -42,92 +54,47 @@ module MU
|
|
|
42
54
|
|
|
43
55
|
# Called automatically by {MU::Deploy#createResources}
|
|
44
56
|
def create
|
|
45
|
-
role_arn = get_role_arn(@config['iam_role'])
|
|
46
|
-
|
|
47
|
-
lambda_properties = {
|
|
48
|
-
code: {},
|
|
49
|
-
function_name: @mu_name,
|
|
50
|
-
handler: @config['handler'],
|
|
51
|
-
publish: true,
|
|
52
|
-
role: role_arn,
|
|
53
|
-
runtime: @config['runtime'],
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if @config['code']['zip_file']
|
|
57
|
-
zip = File.read(@config['code']['zip_file'])
|
|
58
|
-
MU.log "Uploading deployment package from #{@config['code']['zip_file']}"
|
|
59
|
-
lambda_properties[:code][:zip_file] = zip
|
|
60
|
-
else
|
|
61
|
-
lambda_properties[:code][:s3_bucket] = @config['code']['s3_bucket']
|
|
62
|
-
lambda_properties[:code][:s3_key] = @config['code']['s3_key']
|
|
63
|
-
if @config['code']['s3_object_version']
|
|
64
|
-
lambda_properties[:code][:s3_object_version] = @config['code']['s3_object_version']
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
if @config.has_key?('timeout')
|
|
69
|
-
lambda_properties[:timeout] = @config['timeout'].to_i ## secs
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
if @config.has_key?('memory')
|
|
73
|
-
lambda_properties[:memory_size] = @config['memory'].to_i
|
|
74
|
-
end
|
|
75
57
|
|
|
76
|
-
|
|
77
|
-
lambda_properties[:environment] = {
|
|
78
|
-
variables: {@config['environment_variables'][0]['key'] => @config['environment_variables'][0]['value']}
|
|
79
|
-
}
|
|
80
|
-
end
|
|
58
|
+
lambda_properties = get_properties
|
|
81
59
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
60
|
+
MU.retrier([Aws::Lambda::Errors::InvalidParameterValueException], max: 5, wait: 10) {
|
|
61
|
+
resp = MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).create_function(lambda_properties)
|
|
62
|
+
@cloud_id = resp.function_name
|
|
85
63
|
}
|
|
86
|
-
if @config['tags']
|
|
87
|
-
@config['tags'].each { |tag|
|
|
88
|
-
lambda_properties[:tags][tag.key.first] = tag.values.first
|
|
89
|
-
}
|
|
90
|
-
end
|
|
91
64
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if !@vpc
|
|
101
|
-
raise MuError, "Function #{@config['name']} had a VPC configured, but none was loaded"
|
|
102
|
-
end
|
|
103
|
-
lambda_properties[:vpc_config] = {
|
|
104
|
-
:subnet_ids => @vpc.subnets.map { |s| s.cloud_id },
|
|
105
|
-
:security_group_ids => sgs
|
|
106
|
-
}
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
retries = 0
|
|
110
|
-
resp = begin
|
|
111
|
-
MU::Cloud::AWS.lambda(region: @config['region'], credentials: @config['credentials']).create_function(lambda_properties)
|
|
112
|
-
rescue Aws::Lambda::Errors::InvalidParameterValueException => e
|
|
113
|
-
# Freshly-made IAM roles sometimes aren't really ready
|
|
114
|
-
if retries < 5
|
|
115
|
-
sleep 10
|
|
116
|
-
retries += 1
|
|
117
|
-
retry
|
|
118
|
-
end
|
|
119
|
-
raise e
|
|
65
|
+
# the console does this and docs expect it to be there, so mimic the
|
|
66
|
+
# behavior
|
|
67
|
+
begin
|
|
68
|
+
MU::Cloud::AWS.cloudwatchlogs(region: @region, credentials: @credentials).create_log_group(
|
|
69
|
+
log_group_name: "/aws/lambda/#{@cloud_id}",
|
|
70
|
+
tags: @tags
|
|
71
|
+
)
|
|
72
|
+
rescue Aws::CloudWatchLogs::Errors::ResourceAlreadyExistsException
|
|
120
73
|
end
|
|
121
|
-
|
|
122
|
-
@cloud_id = resp.function_name
|
|
123
74
|
end
|
|
124
75
|
|
|
125
76
|
# Called automatically by {MU::Deploy#createResources}
|
|
126
77
|
def groom
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
78
|
+
old_props = MU.structToHash(cloud_desc)
|
|
79
|
+
|
|
80
|
+
new_props = get_properties
|
|
81
|
+
code_block = new_props[:code]
|
|
82
|
+
new_props.reject! { |k, _v| [:code, :publish, :tags].include?(k) }
|
|
83
|
+
changes = {}
|
|
84
|
+
new_props.each_pair { |k, v|
|
|
85
|
+
changes[k] = v if v != old_props[k]
|
|
86
|
+
}
|
|
87
|
+
if !changes.empty?
|
|
88
|
+
MU.log "Updating Lambda #{@mu_name}", MU::NOTICE, details: changes
|
|
89
|
+
MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).update_function_configuration(new_props)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if @code_sha256 and @code_sha256 != cloud_desc.code_sha_256.chomp
|
|
93
|
+
MU.log "Updating code in Lambda #{@mu_name}", MU::NOTICE, details: { "old" => @code_sha256, "new" => cloud_desc.code_sha_256 }
|
|
94
|
+
code_block[:publish] = true
|
|
95
|
+
code_block[:function_name] = @cloud_id
|
|
96
|
+
MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).update_function_code(code_block)
|
|
97
|
+
end
|
|
131
98
|
|
|
132
99
|
# tag_function = assign_tag(lambda_func.function_arn, @config['tags'])
|
|
133
100
|
|
|
@@ -141,7 +108,7 @@ module MU
|
|
|
141
108
|
### triggers must exist prior
|
|
142
109
|
if @config['triggers']
|
|
143
110
|
@config['triggers'].each { |tr|
|
|
144
|
-
trigger_arn =
|
|
111
|
+
trigger_arn = resolveARN(tr['service'], tr['name'])
|
|
145
112
|
|
|
146
113
|
trigger_properties = {
|
|
147
114
|
action: "lambda:InvokeFunction",
|
|
@@ -151,15 +118,33 @@ module MU
|
|
|
151
118
|
statement_id: "#{@mu_name}-ID-1",
|
|
152
119
|
}
|
|
153
120
|
|
|
154
|
-
MU.log
|
|
121
|
+
MU.log "Adding #{tr['service']} #{tr['name']} trigger to Lambda function #{@cloud_id}", details: trigger_properties
|
|
155
122
|
begin
|
|
156
|
-
MU::Cloud::AWS.lambda(region: @
|
|
123
|
+
MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).add_permission(trigger_properties)
|
|
157
124
|
rescue Aws::Lambda::Errors::ResourceConflictException
|
|
125
|
+
# just means the permission is already there
|
|
158
126
|
end
|
|
159
|
-
adjust_trigger(tr['service'], trigger_arn,
|
|
127
|
+
adjust_trigger(tr['service'], trigger_arn, arn, @mu_name)
|
|
160
128
|
}
|
|
161
129
|
|
|
162
130
|
end
|
|
131
|
+
|
|
132
|
+
if @config['invoke_on_completion']
|
|
133
|
+
invoke_params = {
|
|
134
|
+
function_name: @cloud_id,
|
|
135
|
+
invocation_type: @config['invoke_on_completion']['invocation_type'],
|
|
136
|
+
log_type: "Tail"
|
|
137
|
+
}
|
|
138
|
+
if @config['invoke_on_completion']['payload']
|
|
139
|
+
invoke_params[:payload] = JSON.generate(@config['invoke_on_completion']['payload'])
|
|
140
|
+
end
|
|
141
|
+
resp = MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).invoke(invoke_params)
|
|
142
|
+
if resp.status_code == 200
|
|
143
|
+
MU.log "Invoked #{@cloud_id}", MU::NOTICE, details: Base64.decode64(resp.log_result)
|
|
144
|
+
else
|
|
145
|
+
MU.log "Invoked #{@cloud_id} and got #{resp.status_code} (#{resp.function_error})", MU::WARN, details: Base64.decode64(resp.log_result)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
163
148
|
end
|
|
164
149
|
|
|
165
150
|
# Intended to be called by other Mu resources, such as Endpoints (API
|
|
@@ -170,16 +155,19 @@ module MU
|
|
|
170
155
|
function_name: @mu_name,
|
|
171
156
|
principal: "#{calling_service}.amazonaws.com",
|
|
172
157
|
source_arn: calling_arn,
|
|
173
|
-
statement_id: "#{calling_service}-#{calling_name}",
|
|
158
|
+
statement_id: "#{calling_service}-#{calling_name.gsub(/[^a-z0-9\-_]/i, '_')}",
|
|
174
159
|
}
|
|
175
160
|
|
|
176
161
|
begin
|
|
177
162
|
# XXX There doesn't seem to be an API call to list or view existing
|
|
178
163
|
# permissions, wtaf. This means we can't intelligently guard this.
|
|
179
|
-
MU::Cloud::AWS.lambda(region: @
|
|
164
|
+
MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).add_permission(trigger)
|
|
165
|
+
rescue Aws::Lambda::Errors::ValidationException => e
|
|
166
|
+
MU.log e.message+" (calling_arn: #{calling_arn}, calling_service: #{calling_service}, calling_name: #{calling_name})", MU::ERR, details: trigger
|
|
167
|
+
raise e
|
|
180
168
|
rescue Aws::Lambda::Errors::ResourceConflictException => e
|
|
181
169
|
if e.message.match(/already exists/)
|
|
182
|
-
MU::Cloud::AWS.lambda(region: @
|
|
170
|
+
MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).remove_permission(
|
|
183
171
|
function_name: @mu_name,
|
|
184
172
|
statement_id: "#{calling_service}-#{calling_name}"
|
|
185
173
|
)
|
|
@@ -192,17 +180,23 @@ module MU
|
|
|
192
180
|
end
|
|
193
181
|
|
|
194
182
|
# Look up an ARN for a given trigger type and resource name
|
|
195
|
-
def
|
|
196
|
-
supported_triggers = %w(apigateway sns events event cloudwatch_event)
|
|
183
|
+
def resolveARN(svc, name)
|
|
184
|
+
supported_triggers = %w(apigateway sns events event cloudwatch_event dynamodb)
|
|
197
185
|
if supported_triggers.include?(svc.downcase)
|
|
198
186
|
arn = nil
|
|
199
187
|
case svc.downcase
|
|
200
188
|
when 'sns'
|
|
201
|
-
|
|
189
|
+
sib_sns = @deploy.findLitterMate(name: name, type: "notifiers")
|
|
190
|
+
arn = sib_sns ? sib_sns.arn : "arn:aws:sns:#{@region}:#{MU::Cloud::AWS.credToAcct(@credentials)}:#{name}"
|
|
202
191
|
when 'alarm','events', 'event', 'cloudwatch_event'
|
|
203
|
-
|
|
192
|
+
sib_event = @deploy.findLitterMate(name: name, type: "job")
|
|
193
|
+
arn = sib_event ? sib_event.arn : "arn:aws:events:#{@region}:#{MU::Cloud::AWS.credToAcct(@credentials)}:rule/#{name}"
|
|
194
|
+
when 'dynamodb'
|
|
195
|
+
sib_dynamo = @deploy.findLitterMate(name: name, type: "nosqldb")
|
|
196
|
+
arn = sib_dynamo ? sib_dynamo.arn : "arn:aws:dynamodb:#{@region}:#{MU::Cloud::AWS.credToAcct(@credentials)}:table/#{name}"
|
|
204
197
|
when 'apigateway'
|
|
205
|
-
|
|
198
|
+
sib_apig = @deploy.findLitterMate(name: name, type: "endpoints")
|
|
199
|
+
arn = sib_apig ? sib_apig.arn : "arn:aws:apigateway:#{@region}:#{MU::Cloud::AWS.credToAcct(@credentials)}:#{name}"
|
|
206
200
|
when 's3'
|
|
207
201
|
arn = ''
|
|
208
202
|
end
|
|
@@ -214,21 +208,29 @@ module MU
|
|
|
214
208
|
end
|
|
215
209
|
|
|
216
210
|
# XXX placeholder, really; this is going end up being done from Endpoint, Log and Notification resources, I think
|
|
217
|
-
def adjust_trigger(trig_type, trig_arn, func_arn, func_id=nil, protocol='lambda',region=@
|
|
211
|
+
def adjust_trigger(trig_type, trig_arn, func_arn, func_id=nil, protocol='lambda',region=@region)
|
|
218
212
|
|
|
219
213
|
case trig_type
|
|
220
214
|
|
|
221
215
|
when 'sns'
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
216
|
+
MU::Cloud.resourceClass("AWS", "Notifier").subscribe(trig_arn, arn, "lambda", region: @region, credentials: @credentials)
|
|
217
|
+
when 'dynamodb'
|
|
218
|
+
stream = MU::Cloud::AWS.dynamostream(region: @region, credentials: @credentials).list_streams(table_name: trig_arn.sub(/.*?:table\//, '')).streams.first
|
|
219
|
+
# XXX guard this
|
|
220
|
+
MU.log "Adding DynamoDB Stream from #{stream.stream_arn} as trigger for #{@cloud_id}"
|
|
221
|
+
begin
|
|
222
|
+
MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).create_event_source_mapping(
|
|
223
|
+
event_source_arn: stream.stream_arn,
|
|
224
|
+
function_name: @cloud_id,
|
|
225
|
+
starting_position: "TRIM_HORIZON" # ...whatever that is
|
|
226
|
+
)
|
|
227
|
+
rescue ::Aws::Lambda::Errors::ResourceConflictException
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# MU::Cloud.resourceClass("AWS", "NoSQLDB").subscribe(trig_arn, arn, "lambda", region: @region, credentials: @credentials)
|
|
229
231
|
when 'event','cloudwatch_event', 'events'
|
|
230
232
|
# XXX don't do this, use MU::Cloud::AWS::Log
|
|
231
|
-
MU::Cloud::AWS.cloudwatch_events(region: region, credentials: @
|
|
233
|
+
MU::Cloud::AWS.cloudwatch_events(region: region, credentials: @credentials).put_targets({
|
|
232
234
|
rule: @config['trigger']['name'],
|
|
233
235
|
targets: [
|
|
234
236
|
{
|
|
@@ -237,9 +239,8 @@ module MU
|
|
|
237
239
|
}
|
|
238
240
|
]
|
|
239
241
|
})
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
# MU.log "Creation of API Gateway integrations not yet implemented, you'll have to do this manually", MU::WARN, details: "(because we'll basically have to implement all of APIG for this)"
|
|
242
|
+
when 'apigateway'
|
|
243
|
+
addTrigger(trig_arn, "lambda", trig_arn.sub(/.*?([a-z0-9\-_]+)$/i, '\1'))
|
|
243
244
|
end
|
|
244
245
|
end
|
|
245
246
|
|
|
@@ -247,9 +248,8 @@ module MU
|
|
|
247
248
|
# Return the metadata for this Function rule
|
|
248
249
|
# @return [Hash]
|
|
249
250
|
def notify
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
return deploy_struct
|
|
251
|
+
return nil if !cloud_desc
|
|
252
|
+
MU.structToHash(cloud_desc, stringify_keys: true)
|
|
253
253
|
end
|
|
254
254
|
|
|
255
255
|
# Does this resource type exist as a global (cloud-wide) artifact, or
|
|
@@ -270,14 +270,14 @@ module MU
|
|
|
270
270
|
# @param ignoremaster [Boolean]: If true, will remove resources not flagged as originating from this Mu server
|
|
271
271
|
# @param region [String]: The cloud provider region
|
|
272
272
|
# @return [void]
|
|
273
|
-
def self.cleanup(noop: false, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
|
273
|
+
def self.cleanup(noop: false, deploy_id: MU.deploy_id, ignoremaster: false, region: MU.curRegion, credentials: nil, flags: {})
|
|
274
274
|
MU.log "AWS::Function.cleanup: need to support flags['known']", MU::DEBUG, details: flags
|
|
275
275
|
|
|
276
276
|
MU::Cloud::AWS.lambda(credentials: credentials, region: region).list_functions.functions.each { |f|
|
|
277
277
|
desc = MU::Cloud::AWS.lambda(credentials: credentials, region: region).get_function(
|
|
278
278
|
function_name: f.function_name
|
|
279
279
|
)
|
|
280
|
-
if desc.tags and desc.tags["MU-ID"] ==
|
|
280
|
+
if desc.tags and desc.tags["MU-ID"] == deploy_id and (desc.tags["MU-MASTER-IP"] == MU.mu_public_ip or ignoremaster)
|
|
281
281
|
MU.log "Deleting Lambda function #{f.function_name}"
|
|
282
282
|
if !noop
|
|
283
283
|
MU::Cloud::AWS.lambda(credentials: credentials, region: region).delete_function(
|
|
@@ -292,7 +292,7 @@ module MU
|
|
|
292
292
|
# Canonical Amazon Resource Number for this resource
|
|
293
293
|
# @return [String]
|
|
294
294
|
def arn
|
|
295
|
-
cloud_desc.function_arn
|
|
295
|
+
cloud_desc ? cloud_desc.function_arn : nil
|
|
296
296
|
end
|
|
297
297
|
|
|
298
298
|
# Locate an existing function.
|
|
@@ -317,9 +317,9 @@ module MU
|
|
|
317
317
|
def toKitten(**_args)
|
|
318
318
|
bok = {
|
|
319
319
|
"cloud" => "AWS",
|
|
320
|
-
"credentials" => @
|
|
320
|
+
"credentials" => @credentials,
|
|
321
321
|
"cloud_id" => @cloud_id,
|
|
322
|
-
"region" => @
|
|
322
|
+
"region" => @region
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
if !cloud_desc
|
|
@@ -333,7 +333,21 @@ module MU
|
|
|
333
333
|
bok['runtime'] = cloud_desc.runtime
|
|
334
334
|
bok['timeout'] = cloud_desc.timeout
|
|
335
335
|
|
|
336
|
-
function = MU::Cloud::AWS.lambda(region: @
|
|
336
|
+
function = MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).get_function(function_name: bok['name'])
|
|
337
|
+
# event_srcs = MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).list_event_source_mappings(function_name: @cloud_id)
|
|
338
|
+
# if event_srcs and !event_srcs.event_source_mappings.empty?
|
|
339
|
+
# MU.log "dem mappings tho #{@cloud_id}", MU::WARN, details: event_srcs
|
|
340
|
+
# end
|
|
341
|
+
|
|
342
|
+
# begin
|
|
343
|
+
# invoke_cfg = MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).get_function_event_invoke_config(function_name: @cloud_id)
|
|
344
|
+
# MU.log "invoke config #{@cloud_id}", MU::WARN, details: invoke_cfg
|
|
345
|
+
# rescue ::Aws::Lambda::Errors::ResourceNotFoundException
|
|
346
|
+
# end
|
|
347
|
+
|
|
348
|
+
# MU.log @cloud_id, MU::WARN, details: cloud_desc if @cloud_id == "Espier-Scheduled-Scanner"
|
|
349
|
+
# MU.log "configuration #{@cloud_id}", MU::WARN, details: MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).get_function_configuration(function_name: @cloud_id) if @cloud_id == "Espier-Scheduled-Scanner"
|
|
350
|
+
|
|
337
351
|
|
|
338
352
|
if function.code.repository_type == "S3"
|
|
339
353
|
bok['code'] = {}
|
|
@@ -393,16 +407,29 @@ module MU
|
|
|
393
407
|
|
|
394
408
|
if function.configuration.role
|
|
395
409
|
shortname = function.configuration.role.sub(/.*?role\/([^\/]+)$/, '\1')
|
|
396
|
-
MU.log shortname, MU::NOTICE, details: function.configuration.role
|
|
397
410
|
bok['role'] = MU::Config::Ref.get(
|
|
398
411
|
id: shortname,
|
|
399
|
-
name: shortname,
|
|
400
412
|
cloud: "AWS",
|
|
401
413
|
type: "roles"
|
|
402
414
|
)
|
|
403
415
|
end
|
|
416
|
+
|
|
417
|
+
begin
|
|
418
|
+
pol = MU::Cloud::AWS.lambda(region: @region, credentials: @credentials).get_policy(function_name: @cloud_id).policy
|
|
419
|
+
MU.log @cloud_id, MU::WARN, details: JSON.parse(pol) if @cloud_id == "ESPIER-DEV-2020080900-LN-ON-DEMAND-SCANNER"
|
|
420
|
+
if pol
|
|
421
|
+
bok['triggers'] ||= []
|
|
422
|
+
JSON.parse(pol)["Statement"].each { |s|
|
|
423
|
+
bok['triggers'] << {
|
|
424
|
+
"service" => s["Principal"]["Service"].sub(/\..*/, ''),
|
|
425
|
+
"name" => s["Resource"].sub(/.*?[:\/]([^:\/]+)$/, '\1')
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
end
|
|
429
|
+
rescue ::Aws::Lambda::Errors::ResourceNotFoundException
|
|
430
|
+
end
|
|
404
431
|
#MU.log @cloud_id, MU::NOTICE, details: function
|
|
405
|
-
# XXX
|
|
432
|
+
# XXX permissions
|
|
406
433
|
|
|
407
434
|
bok
|
|
408
435
|
end
|
|
@@ -414,6 +441,22 @@ MU.log shortname, MU::NOTICE, details: function.configuration.role
|
|
|
414
441
|
def self.schema(_config)
|
|
415
442
|
toplevel_required = ["runtime"]
|
|
416
443
|
schema = {
|
|
444
|
+
"invoke_on_completion" => {
|
|
445
|
+
"type" => "object",
|
|
446
|
+
"description" => "Setting this will cause this Lambda function to be invoked when its groom phase is complete.",
|
|
447
|
+
"required" => ["invocation_type"],
|
|
448
|
+
"properties" => {
|
|
449
|
+
"invocation_type" => {
|
|
450
|
+
"type" => "string",
|
|
451
|
+
"enum" => ["RequestResponse", "Event", "Dryrun"],
|
|
452
|
+
"default" => "RequestReponse"
|
|
453
|
+
},
|
|
454
|
+
"payload" => {
|
|
455
|
+
"type" => "object",
|
|
456
|
+
"description" => "Optional input to the function, which will be formatted as JSON and sent for execution"
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
},
|
|
417
460
|
"triggers" => {
|
|
418
461
|
"type" => "array",
|
|
419
462
|
"items" => {
|
|
@@ -423,7 +466,7 @@ MU.log shortname, MU::NOTICE, details: function.configuration.role
|
|
|
423
466
|
"properties" => {
|
|
424
467
|
"service" => {
|
|
425
468
|
"type" => "string",
|
|
426
|
-
"enum" => %w{apigateway events s3 sns sqs dynamodb kinesis ses cognito alexa iot},
|
|
469
|
+
"enum" => %w{apigateway events s3 sns sqs dynamodb kinesis ses cognito alexa iot lex},
|
|
427
470
|
"description" => "The name of the AWS service that will trigger this function"
|
|
428
471
|
},
|
|
429
472
|
"name" => {
|
|
@@ -482,6 +525,28 @@ MU.log shortname, MU::NOTICE, details: function.configuration.role
|
|
|
482
525
|
def self.validateConfig(function, configurator)
|
|
483
526
|
ok = true
|
|
484
527
|
|
|
528
|
+
if function['triggers']
|
|
529
|
+
function['triggers'].each { |t|
|
|
530
|
+
mu_type = if t["service"] == "sns"
|
|
531
|
+
"notifiers"
|
|
532
|
+
elsif t["service"] == "apigateway"
|
|
533
|
+
"endpoints"
|
|
534
|
+
elsif t["service"] == "s3"
|
|
535
|
+
"buckets"
|
|
536
|
+
elsif t["service"] == "dynamodb"
|
|
537
|
+
"nosqldbs"
|
|
538
|
+
elsif t["service"] == "events"
|
|
539
|
+
"jobs"
|
|
540
|
+
elsif t["service"] == "sqs"
|
|
541
|
+
"msg_queues"
|
|
542
|
+
end
|
|
543
|
+
|
|
544
|
+
if mu_type
|
|
545
|
+
MU::Config.addDependency(function, t['name'], mu_type, my_phase: "groom")
|
|
546
|
+
end
|
|
547
|
+
}
|
|
548
|
+
end
|
|
549
|
+
|
|
485
550
|
if function['vpc']
|
|
486
551
|
fwname = "lambda-#{function['name']}"
|
|
487
552
|
# default to allowing pings, if no ingress_rules were specified
|
|
@@ -508,7 +573,10 @@ MU.log shortname, MU::NOTICE, details: function.configuration.role
|
|
|
508
573
|
MU::Config.addDependency(function, fwname, "firewall_rule")
|
|
509
574
|
end
|
|
510
575
|
|
|
511
|
-
|
|
576
|
+
function['role'] ||= function['iam_role']
|
|
577
|
+
function.delete("iam_role")
|
|
578
|
+
|
|
579
|
+
if !function['role']
|
|
512
580
|
policy_map = {
|
|
513
581
|
"basic" => "AWSLambdaBasicExecutionRole",
|
|
514
582
|
"kinesis" => "AWSLambdaKinesisExecutionRole",
|
|
@@ -537,9 +605,21 @@ MU.log shortname, MU::NOTICE, details: function.configuration.role
|
|
|
537
605
|
}
|
|
538
606
|
configurator.insertKitten(roledesc, "roles")
|
|
539
607
|
|
|
540
|
-
function['
|
|
608
|
+
function['role'] = function['name']+"execrole"
|
|
541
609
|
|
|
542
|
-
|
|
610
|
+
end
|
|
611
|
+
|
|
612
|
+
if function['role'].is_a?(String)
|
|
613
|
+
function['role'] = MU::Config::Ref.get(
|
|
614
|
+
name: function['role'],
|
|
615
|
+
type: "roles",
|
|
616
|
+
cloud: "AWS",
|
|
617
|
+
credentials: function['credentials']
|
|
618
|
+
)
|
|
619
|
+
end
|
|
620
|
+
|
|
621
|
+
if function['role']['name']
|
|
622
|
+
MU::Config.addDependency(function, function['role']['name'], "role")
|
|
543
623
|
end
|
|
544
624
|
|
|
545
625
|
ok
|
|
@@ -547,23 +627,109 @@ MU.log shortname, MU::NOTICE, details: function.configuration.role
|
|
|
547
627
|
|
|
548
628
|
private
|
|
549
629
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
# @param name [String]
|
|
554
|
-
def get_role_arn(name)
|
|
555
|
-
sib_role = @deploy.findLitterMate(name: name, type: "roles")
|
|
556
|
-
return sib_role.cloudobj.arn if sib_role
|
|
630
|
+
def get_properties
|
|
631
|
+
role_obj = MU::Config::Ref.get(@config['role']).kitten(@deploy, cloud: "AWS")
|
|
632
|
+
raise MuError.new "Failed to fetch object from role reference", details: @config['role'].to_h if !role_obj
|
|
557
633
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
634
|
+
lambda_properties = {
|
|
635
|
+
code: {},
|
|
636
|
+
function_name: @mu_name,
|
|
637
|
+
handler: @config['handler'],
|
|
638
|
+
publish: true,
|
|
639
|
+
role: role_obj.arn,
|
|
640
|
+
runtime: @config['runtime'],
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if @config['code']['zip_file'] or @config['code']['path']
|
|
644
|
+
tempfile = nil
|
|
645
|
+
if @config['code']['path']
|
|
646
|
+
tempfile = Tempfile.new
|
|
647
|
+
MU.log "#{@mu_name} using code at #{@config['code']['path']}"
|
|
648
|
+
MU::Master.zipDir(@config['code']['path'], tempfile.path)
|
|
649
|
+
@config['code']['zip_file'] = tempfile.path
|
|
650
|
+
else
|
|
651
|
+
MU.log "#{@mu_name} using code packaged at #{@config['code']['zip_file']}"
|
|
652
|
+
end
|
|
653
|
+
zip = File.read(@config['code']['zip_file'])
|
|
654
|
+
@code_sha256 = Base64.encode64(Digest::SHA256.digest(zip)).chomp
|
|
655
|
+
lambda_properties[:code][:zip_file] = zip
|
|
656
|
+
if tempfile
|
|
657
|
+
tempfile.close
|
|
658
|
+
tempfile.unlink
|
|
659
|
+
end
|
|
660
|
+
else
|
|
661
|
+
lambda_properties[:code][:s3_bucket] = @config['code']['s3_bucket']
|
|
662
|
+
lambda_properties[:code][:s3_key] = @config['code']['s3_key']
|
|
663
|
+
if @config['code']['s3_object_version']
|
|
664
|
+
lambda_properties[:code][:s3_object_version] = @config['code']['s3_object_version']
|
|
665
|
+
end
|
|
666
|
+
# XXX need to download to a temporarily file, read it in, and calculate the digest in order to trigger updates in groom
|
|
565
667
|
end
|
|
566
|
-
|
|
668
|
+
|
|
669
|
+
if @config.has_key?('timeout')
|
|
670
|
+
lambda_properties[:timeout] = @config['timeout'].to_i ## secs
|
|
671
|
+
end
|
|
672
|
+
|
|
673
|
+
if @config.has_key?('memory')
|
|
674
|
+
lambda_properties[:memory_size] = @config['memory'].to_i
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
SIBLING_VARS.each_key { |sib_type|
|
|
678
|
+
siblings = @deploy.findLitterMate(return_all: true, type: sib_type, cloud: "AWS")
|
|
679
|
+
if siblings
|
|
680
|
+
siblings.each_value { |sibling|
|
|
681
|
+
metadata = sibling.notify
|
|
682
|
+
if !metadata
|
|
683
|
+
MU.log "Failed to extract metadata from sibling #{sibling}", MU::WARN
|
|
684
|
+
next
|
|
685
|
+
end
|
|
686
|
+
SIBLING_VARS[sib_type].each { |var|
|
|
687
|
+
if metadata[var]
|
|
688
|
+
@config['environment_variables'] ||= []
|
|
689
|
+
@config['environment_variables'] << {
|
|
690
|
+
"key" => (sibling.config['name']+"_"+var).gsub(/[^a-z0-9_]/i, '_'),
|
|
691
|
+
"value" => metadata[var]
|
|
692
|
+
}
|
|
693
|
+
end
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
end
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
if @config.has_key?('environment_variables')
|
|
700
|
+
lambda_properties[:environment] = {
|
|
701
|
+
variables: Hash[@config['environment_variables'].map { |v| [v['key'], v['value']] }]
|
|
702
|
+
}
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
lambda_properties[:tags] = {}
|
|
706
|
+
MU::MommaCat.listStandardTags.each_pair { |k, v|
|
|
707
|
+
lambda_properties[:tags][k] = v
|
|
708
|
+
}
|
|
709
|
+
if @config['tags']
|
|
710
|
+
@config['tags'].each { |tag|
|
|
711
|
+
lambda_properties[:tags][tag['key']] = tag['value']
|
|
712
|
+
}
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
if @config.has_key?('vpc')
|
|
716
|
+
sgs = []
|
|
717
|
+
if @config['add_firewall_rules']
|
|
718
|
+
@config['add_firewall_rules'].each { |sg|
|
|
719
|
+
sg = @deploy.findLitterMate(type: "firewall_rule", name: sg['name'])
|
|
720
|
+
sgs << sg.cloud_id if sg and sg.cloud_id
|
|
721
|
+
}
|
|
722
|
+
end
|
|
723
|
+
if !@vpc
|
|
724
|
+
raise MuError, "Function #{@config['name']} had a VPC configured, but none was loaded"
|
|
725
|
+
end
|
|
726
|
+
lambda_properties[:vpc_config] = {
|
|
727
|
+
:subnet_ids => @vpc.subnets.map { |s| s.cloud_id },
|
|
728
|
+
:security_group_ids => sgs
|
|
729
|
+
}
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
lambda_properties
|
|
567
733
|
end
|
|
568
734
|
|
|
569
735
|
end
|