Skip to content

Commit d7e42d6

Browse files
author
Joshua Leaverton
committed
Adding shared library and github templates
1 parent 37b26a8 commit d7e42d6

File tree

5 files changed

+356
-0
lines changed

5 files changed

+356
-0
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: bug
6+
assignees: ''
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Steps to reproduce the behavior.
15+
16+
**Expected behavior**
17+
A clear and concise description of what you expected to happen.
18+
19+
**Please complete the following information about the solution:**
20+
- [ ] Version: [e.g. v1.0.0]
21+
22+
To get the version of the solution, you can look at the description of the created CloudFormation stack. For example, "_(SO0021) - Video On Demand workflow with AWS Step Functions, MediaConvert, MediaPackage, S3, CloudFront and DynamoDB. Version **v5.0.0**_". If the description does not contain the version information, you can look at the mappings section of the template:
23+
24+
```yaml
25+
Mappings:
26+
SourceCode:
27+
General:
28+
S3Bucket: "solutions"
29+
KeyPrefix: "video-on-demand-on-aws/v5.0.0"
30+
```
31+
32+
- [ ] Region: [e.g. us-east-1]
33+
- [ ] Was the solution modified from the version published on this repository?
34+
- [ ] If the answer to the previous question was yes, are the changes available on GitHub?
35+
- [ ] Have you checked your [service quotas](https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html) for the sevices this solution uses?
36+
- [ ] Were there any errors in the CloudWatch Logs?
37+
38+
**Screenshots**
39+
If applicable, add screenshots to help explain your problem (please **DO NOT include sensitive information**).
40+
41+
**Additional context**
42+
Add any other context about the problem here.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this solution
4+
title: ''
5+
labels: enhancement
6+
assignees: ''
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12+
13+
**Describe the feature you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Additional context**
17+
Add any other context or screenshots about the feature request here.

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*Issue #, if available:*
2+
3+
*Description of changes:*
4+
5+
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

source/lib/solution_metrics.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
###############################################################################
2+
# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. #
3+
# #
4+
# Licensed under the Apache License, Version 2.0 (the "License"). #
5+
# You may not use this file except in compliance with the License.
6+
# A copy of the License is located at #
7+
# #
8+
# http://www.apache.org/licenses/LICENSE-2.0 #
9+
# #
10+
# or in the "license" file accompanying this file. This file is distributed #
11+
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express #
12+
# or implied. See the License for the specific language governing permissions#
13+
# and limitations under the License. #
14+
###############################################################################
15+
16+
import os
17+
import requests
18+
from json import dumps
19+
from datetime import datetime
20+
21+
22+
def send_metrics(data,
23+
uuid=os.getenv('UUID'),
24+
solution_id=os.getenv('SOLUTION_ID'),
25+
url=os.getenv('METRICS_URL')):
26+
"""Sends anonymous customer metrics to s3 via API gateway owned and
27+
managed by the Solutions Builder team.
28+
29+
Args:
30+
data - anonymous customer metrics to be sent
31+
uuid - uuid of the solution
32+
solution_id: unique id of the solution
33+
url: url for API Gateway via which data is sent
34+
35+
Return: status code returned by https post request
36+
"""
37+
try:
38+
metrics_data = {
39+
"Solution": solution_id,
40+
"UUID": uuid,
41+
"TimeStamp": str(datetime.utcnow().isoformat()),
42+
"Data": data
43+
}
44+
json_data = dumps(metrics_data)
45+
headers = {'content-type': 'application/json'}
46+
response = requests.post(url, data=json_data, headers=headers)
47+
return response
48+
except:
49+
pass

source/lib/waflibv2.py

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
######################################################################################################################
2+
# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. #
3+
# #
4+
# Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance #
5+
# with the License. A copy of the License is located at #
6+
# #
7+
# http://www.apache.org/licenses/LICENSE-2.0 #
8+
# #
9+
# or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES #
10+
# OR CONDITIONS OF ANY KIND, express or implied. See the License for the specific language governing permissions #
11+
# and limitations under the License. #
12+
######################################################################################################################
13+
import os
14+
import boto3
15+
import logging
16+
from botocore.config import Config
17+
from ipaddress import ip_address
18+
import sys
19+
from backoff import on_exception, expo
20+
21+
API_CALL_NUM_RETRIES = 5
22+
MAX_TIME = 10
23+
client = boto3.client('wafv2', config=Config(retries={'max_attempts': API_CALL_NUM_RETRIES}))
24+
25+
class WAFLIBv2(object):
26+
27+
def __init__(self):
28+
return
29+
30+
# Parse arn into ip_set_id
31+
def arn_to_id(self, arn):
32+
if arn == None:
33+
return None
34+
tmp = arn.split('/')
35+
return tmp.pop()
36+
37+
# Determine network version for source_ip
38+
def which_ip_version(self, log, source_ip):
39+
if source_ip == None:
40+
return None
41+
try:
42+
source_ip = source_ip.strip()
43+
ip_type = "IPV%s"%ip_address(source_ip).version
44+
return ip_type
45+
except Exception as e:
46+
log.error("Source ip %s is not IPV4 or IPV6.", str(source_ip))
47+
log.error(str(e))
48+
return None
49+
50+
# Append correct cidr to source_ip
51+
def set_ip_cidr(self, log, source_ip):
52+
if source_ip == None:
53+
return None
54+
try:
55+
source_ip = source_ip.strip()
56+
ip_type = "IPV%s"%ip_address(source_ip).version
57+
except Exception as e:
58+
log.error("Source ip %s is not IPV4 or IPV6.", str(source_ip))
59+
log.error(str(e))
60+
return None
61+
62+
ip_class = "32" if ip_type == "IPV4" else "128"
63+
return str(source_ip)+"/"+str(ip_class)
64+
65+
# Retrieve IPSet based on ip_set_id
66+
@on_exception(expo, client.exceptions.WAFInternalErrorException, max_time=MAX_TIME)
67+
def get_ip_set(self, log, scope, name, arn):
68+
try:
69+
log.info("[waflib:get_ip_set] Start")
70+
ip_set_id = self.arn_to_id(arn)
71+
response = client.get_ip_set(
72+
Scope=scope,
73+
Name=name,
74+
Id=ip_set_id
75+
)
76+
log.info("[waflib:get_ip_set] End")
77+
return response
78+
except Exception as e:
79+
log.error("Failed to get IPSet %s", str(ip_set_id))
80+
log.error(str(e))
81+
return None
82+
83+
# Retrieve addresses based on ip_set_id
84+
@on_exception(expo, client.exceptions.WAFInternalErrorException, max_time=MAX_TIME)
85+
def get_addresses(self, log, scope, name, arn):
86+
try:
87+
response = self.get_ip_set(log, scope, name, arn)
88+
addresses = response["IPSet"]["Addresses"]
89+
return addresses
90+
except Exception as e:
91+
log.error("Failed to get addresses for ARN %s", str(arn))
92+
log.error(str(e))
93+
return None
94+
95+
# Update addresses in an IPSet
96+
@on_exception(expo,
97+
(client.exceptions.WAFInternalErrorException,
98+
client.exceptions.WAFOptimisticLockException,
99+
client.exceptions.WAFLimitsExceededException),
100+
max_time=MAX_TIME)
101+
def update_ip_set(self, log, scope, name, ip_set_arn, addresses):
102+
log.info("[waflib:update_ip_set] Start")
103+
if (ip_set_arn is None or name is None):
104+
log.error("No IPSet found for: %s ", str(ip_set_arn))
105+
return None
106+
107+
try:
108+
# convert from arn to ip_set_id
109+
ip_set_id = self.arn_to_id(ip_set_arn)
110+
111+
# retrieve the ipset to get a locktoken
112+
ip_set = self.get_ip_set(log, scope, name, ip_set_arn)
113+
lock_token = ip_set['LockToken']
114+
description = ip_set['IPSet']['Description']
115+
log.info("Updating IPSet with description: %s", str(description))
116+
117+
response = client.update_ip_set(
118+
Scope=scope,
119+
Name=name,
120+
Description=description,
121+
Id=ip_set_id,
122+
Addresses=addresses,
123+
LockToken=lock_token
124+
)
125+
126+
new_ip_set = self.get_ip_set(log, scope, name, ip_set_id)
127+
log.info("[waflib:update_ip_set] End")
128+
return new_ip_set
129+
except Exception as e:
130+
log.error(e)
131+
log.error("Failed to update IPSet: %s", str(ip_set_id))
132+
return None
133+
134+
135+
# Put Log Configuration for webacl
136+
@on_exception(expo, client.exceptions.WAFInternalErrorException, max_time=MAX_TIME)
137+
def put_logging_configuration(self, log, web_acl_arn, delivery_stream_arn):
138+
try:
139+
response = client.put_logging_configuration(
140+
LoggingConfiguration={
141+
'ResourceArn': web_acl_arn,
142+
'LogDestinationConfigs': [delivery_stream_arn]
143+
}
144+
)
145+
return response
146+
except Exception as e:
147+
log.error("Failed to configure log for WebAcl: %s", str(web_acl_arn))
148+
log.error(str(e))
149+
return None
150+
151+
# Delete Log Configuration for webacl
152+
@on_exception(expo, client.exceptions.WAFInternalErrorException, max_time=MAX_TIME)
153+
def delete_logging_configuration(self, log, web_acl_arn):
154+
try:
155+
response = client.delete_logging_configuration(
156+
ResourceArn=web_acl_arn
157+
)
158+
return response
159+
except Exception as e:
160+
log.error("Failed to delete log for WebAcl: %s", str(web_acl_arn))
161+
log.error(str(e))
162+
return None
163+
164+
# List webacls
165+
@on_exception(expo, client.exceptions.WAFInternalErrorException, max_time=MAX_TIME)
166+
def list_web_acls(self, log, scope):
167+
try:
168+
response = client.list_web_acls(
169+
Scope=scope
170+
)
171+
return response
172+
except Exception as e:
173+
log.error("Failed to list WebAcld in scope: %s", str(scope))
174+
log.error(str(e))
175+
return None
176+
177+
178+
#################################################################
179+
# Following functions only used for testing, not in WAF Solution
180+
#################################################################
181+
182+
@on_exception(expo,
183+
(client.exceptions.WAFInternalErrorException,
184+
client.exceptions.WAFOptimisticLockException,
185+
client.exceptions.WAFLimitsExceededException),
186+
max_time=MAX_TIME)
187+
def create_ip_set(self, log, scope, name, description, version, addresses):
188+
try:
189+
response = client.create_ip_set(
190+
Scope=scope,
191+
Name=name,
192+
Description=description,
193+
IPAddressVersion=version,
194+
Addresses=addresses
195+
)
196+
return response
197+
except Exception as e:
198+
log.error("Failed to create IPSet: %s", str(name))
199+
log.error(str(e))
200+
return None
201+
202+
@on_exception(expo,
203+
(client.exceptions.WAFInternalErrorException,
204+
client.exceptions.WAFOptimisticLockException,
205+
client.exceptions.WAFAssociatedItemException),
206+
max_time=MAX_TIME)
207+
def delete_ip_set(self, log, scope, name, ip_set_id):
208+
try:
209+
response = self.get_ip_set(log, scope, name, ip_set_id)
210+
if response is not None:
211+
lock_token = response['LockToken']
212+
response = client.delete_ip_set(
213+
Scope=scope,
214+
Name=name,
215+
LockToken=lock_token,
216+
Id=ip_set_id
217+
)
218+
return response
219+
except Exception as e:
220+
log.error("Failed to delete IPSet: %s", str(name))
221+
log.error(str(e))
222+
return None
223+
224+
@on_exception(expo, client.exceptions.WAFInternalErrorException, max_time=MAX_TIME)
225+
def list_ip_sets(self, log, scope, marker=None):
226+
try:
227+
response = None
228+
if marker == None:
229+
response = client.list_ip_sets(
230+
Scope=scope,
231+
Limit=50
232+
)
233+
else:
234+
response = client.list_ip_sets(
235+
Scope=scope,
236+
NextMarker=marker,
237+
Limit=50
238+
)
239+
return response
240+
except Exception as e:
241+
log.error("Failed to list IPSets in scope: %s", str(scope))
242+
log.error(str(e))
243+
return None

0 commit comments

Comments
 (0)