add reverse predit endpoint

This commit is contained in:
Michaela 2021-10-09 15:56:26 +11:00
parent e75988050e
commit e33d46f1cb
4 changed files with 300 additions and 1 deletions

View File

@ -114,6 +114,14 @@ resource "aws_apigatewayv2_route" "predictions" {
target = "integrations/${aws_apigatewayv2_integration.predictions.id}"
}
resource "aws_apigatewayv2_route" "reverse_predictions" {
api_id = aws_apigatewayv2_api.main.id
api_key_required = false
authorization_type = "NONE"
route_key = "GET /predictions/reverse"
target = "integrations/${aws_apigatewayv2_integration.reverse_predictions.id}"
}
resource "aws_apigatewayv2_integration" "predictions" {
api_id = aws_apigatewayv2_api.main.id
connection_type = "INTERNET"
@ -124,12 +132,28 @@ resource "aws_apigatewayv2_integration" "predictions" {
payload_format_version = "2.0"
}
resource "aws_apigatewayv2_integration" "reverse_predictions" {
api_id = aws_apigatewayv2_api.main.id
connection_type = "INTERNET"
integration_method = "POST"
integration_type = "AWS_PROXY"
integration_uri = aws_lambda_function.reverse_predictions.arn
timeout_milliseconds = 30000
payload_format_version = "2.0"
}
data "archive_file" "predictions" {
type = "zip"
source_file = "predict/lambda_function.py"
output_path = "${path.module}/build/predictions.zip"
}
data "archive_file" "reverse_predictions" {
type = "zip"
source_file = "reverse-predict/lambda_function.py"
output_path = "${path.module}/build/reverse-predict.zip"
}
resource "aws_lambda_function" "predictions" {
function_name = "predictions"
handler = "lambda_function.predict"
@ -153,3 +177,29 @@ resource "aws_lambda_permission" "predictions" {
principal = "apigateway.amazonaws.com"
source_arn = "arn:aws:execute-api:us-east-1:${data.aws_caller_identity.current.account_id}:${aws_apigatewayv2_api.main.id}/*/*/predictions"
}
resource "aws_lambda_function" "reverse_predictions" {
function_name = "reverse-predictions"
handler = "lambda_function.predict"
filename = "${path.module}/build/reverse-predict.zip"
source_code_hash = data.archive_file.reverse_predictions.output_base64sha256
publish = true
memory_size = 128
role = aws_iam_role.basic_lambda_role.arn
runtime = "python3.9"
timeout = 30
architectures = ["arm64"]
environment {
variables = {
"ES" = "es.${local.domain_name}"
}
}
}
resource "aws_lambda_permission" "reverse_predictions" {
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.reverse_predictions.arn
principal = "apigateway.amazonaws.com"
source_arn = "arn:aws:execute-api:us-east-1:${data.aws_caller_identity.current.account_id}:${aws_apigatewayv2_api.main.id}/*/*/predictions/reverse"
}

View File

@ -0,0 +1,162 @@
import boto3
import botocore.credentials
from botocore.awsrequest import AWSRequest
from botocore.endpoint import URLLib3Session
from botocore.auth import SigV4Auth
import json
import os
from datetime import datetime, timedelta, timezone
import sys
import traceback
import http.client
import math
import logging
import gzip
from io import BytesIO
import base64
HOST = os.getenv("ES")
def predict(event, context):
path = "reverse-prediction-*/_search"
payload = {
"aggs": {
"2": {
"terms": {
"field": "serial.keyword",
"order": {
"_key": "desc"
},
"size": 1000
},
"aggs": {
"1": {
"top_hits": {
"_source": True,
"size": 1,
"sort": [
{
"datetime": {
"order": "desc"
}
}
]
}
}
}
}
},
"size": 0,
"stored_fields": [
"*"
],
"script_fields": {},
"docvalue_fields": [
{
"field": "datetime",
"format": "date_time"
}
],
"_source": {
"excludes": []
},
"query": {
"bool": {
"must": [],
"filter": [
{
"range": {
"datetime": {
"gte": "now-6h",
"lte": "now",
"format": "strict_date_optional_time"
}
}
}
],
"should": [
],
"must_not": []
}
}
}
if "queryStringParameters" in event:
if "vehicles" in event["queryStringParameters"] and event["queryStringParameters"]["vehicles"] != "RS_*;*chase" and event["queryStringParameters"]["vehicles"] != "":
for serial in event["queryStringParameters"]["vehicles"].split(","):
payload["query"]["bool"]["should"].append(
{
"match_phrase": {
"serial.keyword": serial
}
}
)
# for single sonde allow longer predictions
payload['query']['bool']['filter'].pop(0)
logging.debug("Start ES Request")
results = es_request(payload, path, "GET")
logging.debug("Finished ES Request")
output = {x['1']['hits']['hits'][0]['_source']['serial']: x['1']['hits']['hits'][0]['_source'] for x in results['aggregations']['2']['buckets']}
compressed = BytesIO()
with gzip.GzipFile(fileobj=compressed, mode='w') as f:
json_response = json.dumps(output)
f.write(json_response.encode('utf-8'))
gzippedResponse = compressed.getvalue()
return {
"body": base64.b64encode(gzippedResponse).decode(),
"isBase64Encoded": True,
"statusCode": 200,
"headers": {
"Content-Encoding": "gzip",
"content-type": "application/json"
}
}
def es_request(payload, path, method):
# get aws creds
session = boto3.Session()
params = json.dumps(payload)
compressed = BytesIO()
with gzip.GzipFile(fileobj=compressed, mode='w') as f:
f.write(params.encode('utf-8'))
params = compressed.getvalue()
headers = {"Host": HOST, "Content-Type": "application/json",
"Content-Encoding": "gzip"}
request = AWSRequest(
method=method, url=f"https://{HOST}/{path}", data=params, headers=headers
)
SigV4Auth(boto3.Session().get_credentials(),
"es", "us-east-1").add_auth(request)
session = URLLib3Session()
r = session.send(request.prepare())
return json.loads(r.text)
if __name__ == "__main__":
# print(get_sondes({"queryStringParameters":{"lat":"-28.22717","lon":"153.82996","distance":"50000"}}, {}))
# mode: 6hours
# type: positions
# format: json
# max_positions: 0
# position_id: 0
# vehicles: RS_*;*chase
print(predict(
{"queryStringParameters": {
"vehicles": ""
}}, {}
))
# get list of sondes, serial, lat,lon, alt
# and current rate
# for each one, request http://predict.cusf.co.uk/api/v1/?launch_latitude=-37.8136&launch_longitude=144.9631&launch_datetime=2021-02-22T00:15:18.513413Z&launch_altitude=30000&ascent_rate=5&burst_altitude=30000.1&descent_rate=5
# have to set the burst alt slightly higher than the launch

81
vpc.tf Normal file
View File

@ -0,0 +1,81 @@
resource "aws_vpc" "main" {
cidr_block = "172.31.0.0/16"
assign_generated_ipv6_cidr_block = true
}
resource "aws_egress_only_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
}
locals {
private_subnets = {
"us-east-1a"= "172.31.128.0/24",
"us-east-1b"= "172.31.131.0/24",
"us-east-1c"= "172.31.130.0/24",
"us-east-1d"= "172.31.133.0/24",
"us-east-1e"= "172.31.129.0/24",
"us-east-1f"= "172.31.132.0/24"
}
public_subnets = {
"us-east-1a"= "172.31.80.0/20",
"us-east-1b"= "172.31.16.0/20",
"us-east-1c"= "172.31.32.0/20",
"us-east-1d"= "172.31.0.0/20",
"us-east-1e"= "172.31.48.0/20",
"us-east-1f"= "172.31.64.0/20"
}
}
resource "aws_subnet" "private" {
for_each = local.private_subnets
map_public_ip_on_launch = false
vpc_id = aws_vpc.main.id
cidr_block = each.value
tags = {
Name = "${each.key} - private"
}
}
resource "aws_subnet" "public" {
for_each = local.public_subnets
map_public_ip_on_launch = false
vpc_id = aws_vpc.main.id
cidr_block = each.value
tags = {
Name = "${each.key} - public"
}
}
resource "aws_route_table" "main" {
vpc_id = aws_vpc.main.id
}
resource "aws_route_table_association" "public" {
for_each = local.public_subnets
subnet_id = aws_subnet.public[each.key].id
route_table_id = aws_route_table.main.id
}
resource "aws_route_table_association" "private" {
for_each = local.private_subnets
subnet_id = aws_subnet.private[each.key].id
route_table_id = aws_route_table.main.id
}
resource "aws_internet_gateway" "gw" {
vpc_id = aws_vpc.main.id
}
resource "aws_route" "main6" {
route_table_id = aws_route_table.main.id
destination_ipv6_cidr_block = "::/0"
egress_only_gateway_id = aws_egress_only_internet_gateway.main.id
}
resource "aws_route" "main" {
route_table_id = aws_route_table.main.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.gw.id
}

View File

@ -62,4 +62,10 @@ resource "aws_apigatewayv2_integration" "sign_socket" {
# TODO subnet for reader
# ecr
# padding interfaces
# service, reader, writer
# task definition
# s3 config bucket
# iam roles
# reader autoscaling