Skip to content

Commit

Permalink
Merge pull request #1 from erzz/initial-version
Browse files Browse the repository at this point in the history
Initial version
  • Loading branch information
erzz authored Sep 3, 2021
2 parents 6eab398 + c252ef1 commit 4dfc387
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Release
on: workflow_dispatch

jobs:
# <--------------- RUN SEMANTIC RELEASE ---------------->
release:
name: Semantic Release
runs-on: ubuntu-latest
steps:
- name: Checkout the code
uses: actions/checkout@v2
with:
fetch-depth: 0
persist-credentials: false

- name: Semantic Release
id: semantic-release
uses: cycjimmy/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
with:
dry_run: false
extra_plugins: |
@semantic-release/changelog
@semantic-release/git
40 changes: 40 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Tests
on: push

jobs:
# <---------------- TEST BASIC CONFIG ------------------>
basic:
name: Basic
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2

- name: Start
uses: ./
with:
google-cloud-project: ${{ secrets.TEST_PROJECT }}
service-account-keyfile: ${{ secrets.TEST_SA }}
team: google-dep-metrics
service: action-app
environment: test
status: started
result: pending
version: ${{ github.ref }}

- name: Fake deploy
id: deploy
run: echo "Deployed"

- name: Finish
uses: ./
with:
google-cloud-project: ${{ secrets.TEST_PROJECT }}
service-account-keyfile: ${{ secrets.TEST_SA }}
team: google-dep-metrics
service: action-app
environment: test
status: finished
result: ${{ steps.deploy.outcome }}
version: ${{ github.ref }}

2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
venv/*
.python-version
15 changes: 15 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/github",
[
"@semantic-release/git",
{
"message": "chore(release): ${nextRelease.version}\n\n${nextRelease.notes}"
}
]
],
"branches": ["main"]
}
43 changes: 43 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Contributing

## Quick version of setting up your environment

### Python on MacOS

Assuming you use MacOS - otherwise the general commands likely work for all OS's but I won't make an promises

1. Install Homebrew if not installed already:

```shell
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```
2. Install pyenv
```shell
brew install pyenv
```
3. Install & activate python 3.9.7 or higher
```shell
pyenv install 3.9.7
pyenv local 3.9.7
```
4. Create and activate venv
```shell
python3 -m venv venv && source venv/bin/activate
```
5. Install requirements
```shell
pip install -r requirements.txt
```
### Manual Testing Requirements

```shell
export GOOGLE_CLOUD_PROJECT=<my-project-id>
# The following account will need cloud monitoring admin role
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa-key.json
```

### Manual Test Command Example

```shell
python push_deploy_metric.py --team test-team --service test-service --environment test-env --status started --result inactive --version v0.0.0 --metric-value 1
```
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# google-dep-metrics
Pings deployment metrics at Google Cloud Monitoring

## Required inputs
* google_cloud_project = the project_id of the project to which the metrics should be sent
* google_sa_keyfile = a secret holding a service account key with the role `monitoring-admin`
57 changes: 57 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: "Google Deployment Metrics"
author: "Sean Erswell-Liljefelt"
description: "Sends custom deployment metrics to Google Cloud Monitoring"
branding:
color: blue
icon: bar-chart
inputs:
google-cloud-project:
description: "The Google Cloud project_id to which the metrics should be sent"
required: true
service-account-keyfile:
description: "A secret holding the service account keyfile to use for authentication with your project"
required: true
team:
description: "The name of the team the deployed service belongs to."
required: true
service:
description: "The name of the service or application being deployed."
required: true
environment:
description: "The environment into which the service/application is being deployed (suggest 'production' or 'branch-name')"
required: true
status:
description: "What stage of the deployment process is occurring (suggest either 'started' or 'finished')"
required: true
result:
description: "The result so far. (suggest one of 'queued' 'pending' 'error' 'in_progress' 'failure' 'inactive' or 'success'"
required: true
version:
description: "The version or commit being deployed (e.g. v1.0.5 or git short SHA"
required: true
metric-value:
description: "By default we send the value 1 for any deployment update. If for some reason you want to change that you can specify any integer"
required: false
default: "1"
runs:
using: "composite"
steps:
- name: Send metric
shell: bash
env:
GOOGLE_CLOUD_PROJECT: ${{ inputs.google-cloud-project }}
SA_KEY: ${{ inputs.service-account-keyfile }}
TEAM: ${{ inputs.team}}
SERVICE: ${{ inputs.service }}
ENVIRONMENT: ${{ inputs.environment }}
STATUS: ${{ inputs.status }}
RESULT: ${{ inputs.result }}
VERSION: ${{ inputs.version }}
METRIC_VALUE: ${{ inputs.metric-value }}
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
echo "$SA_KEY" > $(pwd)/sa.json
export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/sa.json
python3 push_deploy_metric.py --team "$TEAM" --service "$SERVICE" --environment "$ENVIRONMENT" --status "$STATUS" --result "$RESULT" --version "$VERSION" --metric-value "$METRIC_VALUE"
62 changes: 62 additions & 0 deletions push_deploy_metric.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import os
import pprint
import time
import argparse
from google.oauth2 import service_account
from google.cloud import monitoring_v3

parser = argparse.ArgumentParser()

parser.add_argument("--team", action="store", dest="dep_team", help="The name of the team the deployed service belongs to", type=str)
parser.add_argument("--service", action="store", dest="dep_service", help="The name of the service or application being deployed", type=str)
parser.add_argument("--environment", action="store", dest="dep_environment", help="The environment into which the service/application is being deployed", type=str)
parser.add_argument("--status", action="store", dest="dep_status", help="Either 'started' or 'finished'", type=str)
parser.add_argument("--result", action="store", dest="dep_result", help="One of 'queued' 'pending' 'error' 'in_progress' 'failure' 'inactive' or 'success'", type=str)
parser.add_argument("--version", action="store", dest="dep_version", help="The version or commit being deployed", type=str)
parser.add_argument("--metric-value", action="store", dest="metric_value", help="The count to give for this deployment status - usually 1", type=int)
args = parser.parse_args()

project_id = os.environ["GOOGLE_CLOUD_PROJECT"]

credentials = service_account.Credentials.from_service_account_file(
os.environ["GOOGLE_APPLICATION_CREDENTIALS"])

print(f"Using service account {credentials.service_account_email} for {project_id}")

def write_time_series(project_id, metric_value):
client = monitoring_v3.MetricServiceClient()
project_name = client.common_project_path(project_id)

series = monitoring_v3.types.TimeSeries()
series.metric.type = 'custom.googleapis.com/deployment/status'
# Using global as seemingly no better options... perhaps generic_task but that leads to
# numerous resource labels that wouldn't serve much purpose or be very artificial
# https://cloud.google.com/monitoring/custom-metrics/creating-metrics#custom-metric-resources
series.resource.type = 'global'
series.metric.labels['team'] = args.dep_team
series.metric.labels['service'] = args.dep_service
series.metric.labels['environment'] = args.dep_environment
series.metric.labels['status'] = args.dep_status
series.metric.labels['result'] = args.dep_result
series.metric.labels['version'] = args.dep_version
now = time.time()
seconds = int(now)
nanos = int((now - seconds) * 10 ** 9)
interval = monitoring_v3.TimeInterval(
{"end_time": {"seconds": seconds, "nanos": nanos}}
)
point = monitoring_v3.Point({"interval": interval, "value": {"int64_value": metric_value}})
series.points = [point]
pprint.pprint(series)
client.create_time_series(name=project_name, time_series=[series])

class MissingProjectIdError(Exception):
pass

# Google rate limit is 1 metric per series every 10 seconds
try:
write_time_series(project_id, args.metric_value)
except:
print(f"Probably hit the rate limit so forcing a sleep for 10 seconds...")
time.sleep(11)
write_time_series(project_id, args.metric_value)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
google-cloud-monitoring

0 comments on commit 4dfc387

Please sign in to comment.