cloud-mu 3.2.0 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|