Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine status reports design #3088

Merged
merged 5 commits into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
* [Added] Create packages from Athena query results ([#3004](https://github.com/quiltdata/quilt/pull/3004))
* [Added] Add "Create text file" menu ([#3017](https://github.com/quiltdata/quilt/pull/3017))
* [Added] Redirect to last selected Athena workgroup ([#3067](https://github.com/quiltdata/quilt/pull/3067))
* [Added] `status_reports` lambda ([#2989](https://github.com/quiltdata/quilt/pull/2989))
* [Added] `status_reports` lambda ([#2989](https://github.com/quiltdata/quilt/pull/2989), [#3088](https://github.com/quiltdata/quilt/pull/3088))
* [Added] Stack Status Admin UI: reports ([#3068](https://github.com/quiltdata/quilt/pull/3068))
* [Added] Edit button for text files in packages ([#3070](https://github.com/quiltdata/quilt/pull/3070))
* [Fixed] Fix package creation in S3 buckets with SSE-KMS enabled ([#2754](https://github.com/quiltdata/quilt/pull/2754))
Expand Down
1 change: 1 addition & 0 deletions lambdas/status_reports/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include src/t4_lambda_status_reports/templates/*
1 change: 1 addition & 0 deletions lambdas/status_reports/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
version="0.0.1",
packages=find_packages(where="src"),
package_dir={"": "src"},
include_package_data=True,
install_requires=[
"Jinja2==3.1.2",
"aiobotocore==2.3.4",
Expand Down
151 changes: 22 additions & 129 deletions lambdas/status_reports/src/t4_lambda_status_reports/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ def create_syn():

async def list_stack_canaries(cfn, stack_name: str) -> T.List[str]:
result = []
async for page in cfn.get_paginator("list_stack_resources").paginate(StackName=stack_name):
async for page in cfn.get_paginator("list_stack_resources").paginate(
StackName=stack_name
):
for r in page["StackResourceSummaries"]:
if r["ResourceType"] == "AWS::Synthetics::Canary":
result.append(r["PhysicalResourceId"])
Expand All @@ -39,10 +41,9 @@ async def drain(syn, method: str, key: str, names: T.List[str]) -> T.List[dict]:
names[i:i + CANARIES_PER_REQUEST]
for i in range(0, len(names), CANARIES_PER_REQUEST)
]
pages = await asyncio.gather(*[
getattr(syn, method)(Names=chunk)
for chunk in chunks
])
pages = await asyncio.gather(
*[getattr(syn, method)(Names=chunk) for chunk in chunks]
)
return list(itertools.chain.from_iterable(p[key] for p in pages))


Expand Down Expand Up @@ -102,7 +103,9 @@ async def get_canaries(syn, cfn, stack_name: str) -> T.List[dict]:

async def get_resources(cfn, stack_name: str) -> T.List[dict]:
result = []
async for page in cfn.get_paginator("list_stack_resources").paginate(StackName=stack_name):
async for page in cfn.get_paginator("list_stack_resources").paginate(
StackName=stack_name
):
result.extend(page["StackResourceSummaries"])
return result

Expand All @@ -112,129 +115,12 @@ async def get_stack_data(cfn, stack_name: str) -> dict:
return resp["Stacks"][0]


jenv = jinja2.Environment(autoescape=jinja2.select_autoescape())
# TODO: styling
tmpl = jenv.from_string("""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Status Report</title>
</head>
<body>
<h1>Quilt Status Report</h1>
<dl>
<dt>CloudFormation Stack:</dt>
<dd>{{ stack_name }}</dd>
<dt>AWS Region:</dt>
<dd>{{ aws_region }}</dd>
<dt>Timestamp:</dt>
<dd>{{ now.isoformat() }}</dd>
</dl>

<h2>Operational Qualification</h2>
<table>
<thead>
<tr>
<th>Test</th>
<th>Schedule</th>
<th>State</th>
<th>Last Run</th>
</tr>
</thead>
<tbody>
{% for canary in canaries %}
<tr>
<td>{{ canary.group }} / {{ canary.title }}</td>
<td>{{ canary.schedule }}</td>
<td>
{% if canary.ok %}
Passed
{% elif canary.ok is false %}
Failed
{% else %}
Running
{% endif %}
</td>
<td>
{% if canary.lastRun %}
{{ canary.lastRun }}
{% else %}
N/A
{% endif %}
</td>

</tr>
{% endfor %}
</tbody>
</table>

<h2>Installation Qualification</h2>

<h3>Stack Resources</h3>
<table>
<thead>
<tr>
<th>Logical ID</th>
<th>Physical ID</th>
<th>Type</th>
<th>Status</th>
<th>Last Updated</th>
</tr>
</thead>
<tbody>
{% for r in resources %}
<tr>
<td>{{ r.LogicalResourceId }}</td>
<td>{{ r.PhysicalResourceId }}</td>
<td>{{ r.ResourceType }}</td>
<td>{{ r.ResourceStatus }}</td>
<td>{{ r.LastUpdatedTimestamp.isoformat() }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<h3>Stack Outputs</h3>
<table>
<thead>
<tr>
<th>Output Key</th>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for o in stack_data.Outputs %}
<tr>
<td>{{ o.OutputKey }}</td>
<td>{{ o.OutputValue }}</td>
<td>{{ o.Description }}</td>
</tr>
{% endfor %}
</tbody>
</table>

<h3>Stack Parameters</h3>
<table>
<thead>
<tr>
<th>Parameter Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{% for p in stack_data.Parameters %}
<tr>
<td>{{ p.ParameterKey }}</td>
<td>{{ p.ParameterValue }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
""")
jenv = jinja2.Environment(
loader=jinja2.PackageLoader("t4_lambda_status_reports"),
autoescape=jinja2.select_autoescape(),
)

tmpl = jenv.get_template("entry.html.jinja")


async def generate_status_report(stack_name: str):
Expand All @@ -245,13 +131,19 @@ async def generate_status_report(stack_name: str):
get_resources(cfn, stack_name),
get_stack_data(cfn, stack_name),
)
catalog_url = next(
o["OutputValue"]
for o in stack_data["Outputs"]
if o["OutputKey"] == "QuiltWebHost"
)
html = tmpl.render(
stack_name=stack_name,
aws_region=AWS_REGION,
now=now,
canaries=canaries,
resources=resources,
stack_data=stack_data,
catalog_url=catalog_url,
)
return now, html

Expand Down Expand Up @@ -284,6 +176,7 @@ async def lambda_handler(*_):

if __name__ == "__main__":
import sys

args = sys.argv[1:]
stack_name = args[0] if len(args) >= 1 else os.getenv("STACK_NAME")
assert stack_name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{% macro stylesheet(href) %}
<link href="{{ href }}" rel="stylesheet" crossorigin="anonymous" referrerpolicy="no-referrer" />
{% endmacro %}

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
{{ stylesheet("https://fonts.googleapis.com/css?family=Roboto+Mono:400,700|Roboto:300,400,500") }}
{{ stylesheet("https://unpkg.com/[email protected]/dist/material-components-web.min.css") }}
<link
href="https://quilt-web-public.s3.amazonaws.com/q-128-square.png"
rel="icon"
type="image/png"
sizes="128x128"
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>


<style>{% block style %}{% endblock %}</style>
<title>{% block title required %}{% endblock %}</title>
</head>
<body class="mdc-typography">
{% block body required %}{% endblock %}
</body>
</html>
Loading