Skip to content

Commit 7015005

Browse files
🔨 adding helper release monitoring script (#4504)
1 parent 3e1deb5 commit 7015005

File tree

12 files changed

+434
-2
lines changed

12 files changed

+434
-2
lines changed

.codeclimate.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ exclude_patterns:
6464
- "dist/"
6565
- "features/"
6666
- "**/node_modules/"
67-
- "script/"
67+
- "script"
6868
- "**/spec/"
6969
- "**/test/"
7070
- "**/tests/"
@@ -83,4 +83,5 @@ exclude_patterns:
8383
- packages/models-library/src/models_library/utils/_original_fastapi_encoders.py
8484
- services/resource-usage-tracker/src/simcore_service_resource_usage_tracker/modules/db/repositories/resource_tracker.py
8585
- services/web/server/src/simcore_service_webserver/exporter/formatters/sds/xlsx/templates/code_description.py
86-
- services/web/server/src/simcore_service_webserver/projects/db.py # NOTE: refactor will be done in upcomming PRs
86+
- services/web/server/src/simcore_service_webserver/projects/db.py
87+
- "scripts/"

scripts/release/monitor/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.PHONY: install-dev
2+
install-dev:
3+
pip install .

scripts/release/monitor/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Helper for monitoring of release
2+
`pip install .`
3+
`monitor-release --help`
4+
5+
Check current status of containers
6+
`monitor-release master containers`
7+
Check running sidecars:
8+
`monitor-release master sidecars`
9+
10+
# Create .env file
11+
```
12+
MASTER_PORTAINER_URL=
13+
MASTER_PORTAINER_USERNAME=
14+
MASTER_PORTAINER_PASSWORD=
15+
16+
DALCO_STAGING_PORTAINER_URL=
17+
DALCO_STAGING_PORTAINER_USERNAME=
18+
DALCO_STAGING_PORTAINER_PASSWORD=
19+
20+
DALCO_PRODUCTION_PORTAINER_URL=
21+
DALCO_PRODUCTION_PORTAINER_USERNAME=
22+
DALCO_PRODUCTION_PORTAINER_PASSWORD=
23+
24+
TIP_PRODUCTION_PORTAINER_URL=
25+
TIP_PRODUCTION_PORTAINER_USERNAME=
26+
TIP_PRODUCTION_PORTAINER_PASSWORD=
27+
28+
AWS_STAGING_PORTAINER_URL=
29+
AWS_STAGING_PORTAINER_USERNAME=
30+
AWS_STAGING_PORTAINER_PASSWORD=
31+
32+
AWS_PRODUCTION_PORTAINER_URL=
33+
AWS_PRODUCTION_PORTAINER_USERNAME=
34+
AWS_PRODUCTION_PORTAINER_PASSWORD=
35+
```

scripts/release/monitor/monitor_release/__init__.py

Whitespace-only changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from enum import Enum
2+
3+
import typer
4+
from monitor_release.models import Deployment
5+
from monitor_release.portainer import check_containers_deploys, check_running_sidecars
6+
from monitor_release.settings import get_settings
7+
from rich.console import Console
8+
9+
app = typer.Typer()
10+
console = Console()
11+
12+
13+
class Action(str, Enum):
14+
containers = "containers"
15+
sidecars = "sidecars"
16+
17+
18+
@app.command()
19+
def main(deployment: Deployment, action: Action):
20+
settings = get_settings(deployment)
21+
console.print(f"Deployment: {deployment}")
22+
console.print(f"Action: {action}")
23+
24+
if action == Action.containers:
25+
check_containers_deploys(settings, deployment)
26+
if action == Action.sidecars:
27+
check_running_sidecars(settings, deployment)
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# GET https://git.speag.com/api/v4/projects/300/pipeline_schedules
2+
3+
# POST https://git.speag.com/api/v4/projects/300/pipeline_schedules/43/take_ownership
4+
5+
# PUT https://git.speag.com/api/v4/projects/300/pipeline_schedules/74
6+
# {
7+
# "active": true
8+
# }
9+
10+
# HEADERS: PRIVATE-TOKEN:
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from datetime import datetime
2+
from enum import Enum
3+
4+
from pydantic import BaseModel
5+
6+
7+
class Deployment(str, Enum):
8+
master = "master"
9+
aws_staging = "aws-staging"
10+
dalco_staging = "dalco-staging"
11+
aws_production = "aws-production"
12+
dalco_production = "dalco-production"
13+
tip_production = "tip-production"
14+
15+
16+
class RunningSidecar(BaseModel):
17+
name: str
18+
created_at: datetime
19+
user_id: str
20+
project_id: str
21+
service_key: str
22+
service_version: str
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
from monitor_release.models import RunningSidecar
2+
from monitor_release.portainer_utils import (
3+
check_simcore_deployed_services,
4+
check_simcore_running_sidecars,
5+
get_bearer_token,
6+
get_containers,
7+
get_services,
8+
get_tasks,
9+
)
10+
from rich.console import Console
11+
from rich.table import Table
12+
13+
console = Console()
14+
15+
16+
def check_containers_deploys(settings, deployment):
17+
token = get_bearer_token(settings)
18+
services = get_services(settings, token)
19+
tasks = get_tasks(settings, token)
20+
containers = get_containers(settings, token)
21+
22+
output = check_simcore_deployed_services(settings, services, tasks, containers)
23+
24+
table = Table(
25+
"Service",
26+
"Status",
27+
"Last Updated",
28+
"Git SHA",
29+
title=f"[bold yellow]{deployment.upper()}[/bold yellow]",
30+
)
31+
for item in output.values():
32+
service_name = item["service_name"]
33+
container_status = "[bold red]Not running[/bold red]"
34+
container_timestamp = None
35+
container_git_sha = None
36+
for task in item["tasks"]:
37+
oldest_running_task_timestamp = None
38+
if task["status"] == "running":
39+
if (
40+
oldest_running_task_timestamp is None
41+
or oldest_running_task_timestamp > task["timestamp"]
42+
):
43+
container_status = f"[green]{task['status']}[/green]"
44+
container_timestamp = f"{task['timestamp']}"
45+
container_git_sha = task["git_sha"]
46+
47+
oldest_running_task_timestamp = task["timestamp"]
48+
if task["status"] == "starting":
49+
container_status = f"[blue]{task['status']}[/blue]"
50+
container_timestamp = f"{task['timestamp']}"
51+
container_git_sha = task["git_sha"]
52+
break
53+
54+
table.add_row(
55+
service_name, container_status, container_timestamp, container_git_sha
56+
)
57+
58+
console.print(table)
59+
60+
61+
def check_running_sidecars(settings, deployment):
62+
token = get_bearer_token(settings)
63+
services = get_services(settings, token)
64+
65+
sidecars: list[RunningSidecar] = check_simcore_running_sidecars(settings, services)
66+
table = Table(
67+
"Sidecar name",
68+
"Created at",
69+
"User ID",
70+
"Project ID",
71+
"Service Key",
72+
"Service Version",
73+
title=f"[bold yellow]{deployment.upper()}[/bold yellow]",
74+
)
75+
for sidecar in sidecars:
76+
table.add_row(
77+
sidecar.name,
78+
f"{sidecar.created_at}",
79+
sidecar.user_id,
80+
sidecar.project_id,
81+
sidecar.service_key,
82+
sidecar.service_version,
83+
)
84+
85+
console.print(table)
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import json
2+
3+
import arrow
4+
import requests
5+
from monitor_release.models import RunningSidecar
6+
from monitor_release.settings import Settings
7+
8+
9+
def get_bearer_token(settings: Settings):
10+
headers = {"accept": "application/json", "Content-Type": "application/json"}
11+
payload = json.dumps(
12+
{
13+
"Username": settings.portainer_username,
14+
"Password": settings.portainer_password,
15+
}
16+
)
17+
response = requests.post(
18+
f"{settings.portainer_url}/portainer/api/auth",
19+
headers=headers,
20+
data=payload,
21+
)
22+
bearer_token = response.json()["jwt"]
23+
return bearer_token
24+
25+
26+
def get_services(settings: Settings, bearer_token):
27+
services_url = f"{settings.portainer_url}/portainer/api/endpoints/{settings.portainer_endpoint_version}/docker/services"
28+
response = requests.get(
29+
services_url,
30+
headers={
31+
"Authorization": "Bearer " + bearer_token,
32+
"Content-Type": "application/json",
33+
},
34+
)
35+
services = response.json()
36+
return services
37+
38+
39+
def get_tasks(settings: Settings, bearer_token):
40+
tasks_url = f"{settings.portainer_url}/portainer/api/endpoints/{settings.portainer_endpoint_version}/docker/tasks"
41+
response = requests.get(
42+
tasks_url,
43+
headers={
44+
"Authorization": "Bearer " + bearer_token,
45+
"Content-Type": "application/json",
46+
},
47+
)
48+
tasks = response.json()
49+
return tasks
50+
51+
52+
def get_containers(settings: Settings, bearer_token):
53+
bearer_token = get_bearer_token(settings)
54+
55+
containers_url = f"{settings.portainer_url}/portainer/api/endpoints/{settings.portainer_endpoint_version}/docker/containers/json?all=true"
56+
response = requests.get(
57+
containers_url,
58+
headers={
59+
"Authorization": "Bearer " + bearer_token,
60+
"Content-Type": "application/json",
61+
},
62+
)
63+
containers = response.json()
64+
return containers
65+
66+
67+
def check_simcore_running_sidecars(settings: Settings, services):
68+
running_sidecars: list[RunningSidecar] = []
69+
for service in services:
70+
if (
71+
service["Spec"]["Name"].startswith("dy-sidecar")
72+
and service["Spec"]["Labels"]["io.simcore.runtime.swarm-stack-name"]
73+
== settings.swarm_stack_name
74+
):
75+
running_sidecars.append(
76+
RunningSidecar(
77+
name=service["Spec"]["Name"],
78+
created_at=arrow.get(service["CreatedAt"]).datetime,
79+
user_id=service["Spec"]["Labels"]["io.simcore.runtime.user-id"],
80+
project_id=service["Spec"]["Labels"][
81+
"io.simcore.runtime.project-id"
82+
],
83+
service_key=service["Spec"]["Labels"][
84+
"io.simcore.runtime.service-key"
85+
],
86+
service_version=service["Spec"]["Labels"][
87+
"io.simcore.runtime.service-version"
88+
],
89+
)
90+
)
91+
return running_sidecars
92+
93+
94+
def _generate_containers_map(containers):
95+
container_map = {}
96+
for container in containers:
97+
git_sha = (
98+
container.get("Labels").get("org.opencontainers.image.revision")
99+
if container.get("Labels").get(
100+
"org.opencontainers.image.revision"
101+
) # container.get("Labels").get("org.label-schema.vcs-ref")
102+
else container.get("Labels").get("org.label-schema.vcs-ref")
103+
)
104+
105+
container_map[container["Id"]] = {"git_sha": git_sha}
106+
return container_map
107+
108+
109+
def check_simcore_deployed_services(settings: Settings, services, tasks, containers):
110+
container_map = _generate_containers_map(containers)
111+
service_task_map = {}
112+
for service in services:
113+
if service["Spec"]["Name"].startswith(settings.starts_with):
114+
service_task_map[service["ID"]] = {
115+
"service_name": service["Spec"]["Name"],
116+
"tasks": [],
117+
}
118+
119+
for task in tasks:
120+
if task["ServiceID"] in service_task_map:
121+
if task["Status"].get("ContainerStatus") is None:
122+
continue
123+
container_id = task["Status"]["ContainerStatus"]["ContainerID"]
124+
125+
service_task_map[task["ServiceID"]]["tasks"].append(
126+
{
127+
"created_at": arrow.get(task["CreatedAt"]).datetime,
128+
"status": task["Status"]["State"],
129+
"timestamp": arrow.get(task["Status"]["Timestamp"]).datetime,
130+
"git_sha": container_map.get(container_id, {}).get("git_sha"),
131+
}
132+
)
133+
134+
return service_task_map
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# placeholder

0 commit comments

Comments
 (0)