Skip to content

Commit 464483f

Browse files
Moved from gh action API to gh webhook API (#49)
* [add] Moved from gh action API to gh webhook API * [add] Further logging on API. Using PULL_REQUEST_TRIGGER_LABEL env var to decide uppon which PR label to use for trigger automation
1 parent 28b86a5 commit 464483f

File tree

13 files changed

+945
-87
lines changed

13 files changed

+945
-87
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "redis-benchmarks-specification"
3-
version = "0.1.11"
3+
version = "0.1.12"
44
description = "The Redis benchmarks specification describes the cross-language/tools requirements and expectations to foster performance and observability standards around redis related technologies. Members from both industry and academia, including organizations and individuals are encouraged to contribute."
55
authors = ["filipecosta90 <[email protected]>","Redis Performance Group <[email protected]>"]
66
readme = "Readme.md"

redis_benchmarks_specification/__api__/Readme.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,3 @@ Within root project folder
55
```
66
poetry run redis-benchmarks-spec-api
77
```
8-
9-
## Testing triggering a new commit spec via local api
10-
11-
```
12-
curl -u <USER>:<PASS> \
13-
-X POST -H "Content-Type: application/json" \
14-
--data '{"git_hash":"0cf2df84d4b27af4bffd2bf3543838f09e10f874"}' \
15-
http://localhost:5000/api/gh/redis/redis/commits
16-
```
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Apache License Version 2.0
2+
#
3+
# Copyright (c) 2021., Redis Labs
4+
# All rights reserved.
5+
#

redis_benchmarks_specification/__api__/api.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@
1515
GH_REDIS_SERVER_HOST,
1616
GH_REDIS_SERVER_PORT,
1717
GH_REDIS_SERVER_AUTH,
18-
REDIS_AUTH_SERVER_HOST,
19-
REDIS_AUTH_SERVER_PORT,
2018
LOG_FORMAT,
2119
LOG_DATEFMT,
2220
LOG_LEVEL,
2321
REDIS_HEALTH_CHECK_INTERVAL,
2422
REDIS_SOCKET_TIMEOUT,
23+
GH_REDIS_SERVER_USER,
2524
)
2625
from redis_benchmarks_specification.__common__.package import (
2726
populate_with_poetry_data,
@@ -47,11 +46,6 @@ def main():
4746
GH_REDIS_SERVER_HOST, GH_REDIS_SERVER_PORT
4847
)
4948
)
50-
print(
51-
"Using redis available at: {}:{} as auth server.".format(
52-
REDIS_AUTH_SERVER_HOST, REDIS_AUTH_SERVER_PORT
53-
)
54-
)
5549
conn = redis.StrictRedis(
5650
host=GH_REDIS_SERVER_HOST,
5751
port=GH_REDIS_SERVER_PORT,
@@ -61,7 +55,7 @@ def main():
6155
socket_connect_timeout=REDIS_SOCKET_TIMEOUT,
6256
socket_keepalive=True,
6357
)
64-
app = create_app(conn)
58+
app = create_app(conn, GH_REDIS_SERVER_USER)
6559
if args.logname is not None:
6660
print("Writting log to {}".format(args.logname))
6761
handler = logging.handlers.RotatingFileHandler(
Lines changed: 104 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,126 @@
1-
from flask import Flask, jsonify, request
2-
from marshmallow import ValidationError
3-
from json import dumps
1+
import json
2+
3+
from flask import jsonify
44
import redis
5-
from flask_httpauth import HTTPBasicAuth
5+
from flask import Flask, request
6+
from hmac import HMAC, compare_digest
7+
from hashlib import sha1
68

7-
from redis_benchmarks_specification.__api__.schema import (
8-
CommitSchema,
9-
)
109
from redis_benchmarks_specification.__common__.builder_schema import (
1110
commit_schema_to_stream,
1211
)
13-
from redis_benchmarks_specification.__common__.env import (
14-
REDIS_AUTH_SERVER_HOST,
15-
REDIS_AUTH_SERVER_PORT,
16-
)
12+
from redis_benchmarks_specification.__common__.env import PULL_REQUEST_TRIGGER_LABEL
1713

14+
SIG_HEADER = "X-Hub-Signature"
1815

19-
def create_app(conn, test_config=None):
16+
17+
def create_app(conn, user, test_config=None):
2018
app = Flask(__name__)
21-
auth = HTTPBasicAuth()
19+
2220
conn = conn
2321

24-
@auth.verify_password
25-
def verify_password(username, password):
22+
# GH Token Authentication
23+
def verify_signature(req):
2624
result = False
2725
try:
28-
auth_server_conn = redis.StrictRedis(
29-
host=REDIS_AUTH_SERVER_HOST,
30-
port=REDIS_AUTH_SERVER_PORT,
31-
decode_responses=True,
32-
username=username,
33-
password=password,
34-
)
35-
auth_server_conn.ping()
36-
result = True
26+
secret = conn.get("{}:auth_token".format(user))
27+
sig_header = req.headers.get(SIG_HEADER)
28+
if secret is not None and sig_header is not None:
29+
if type(secret) == str:
30+
secret = secret.encode()
31+
if "sha1=" in sig_header:
32+
received_sign = sig_header.split("sha1=")[-1].strip()
33+
expected_sign = HMAC(
34+
key=secret, msg=req.data, digestmod=sha1
35+
).hexdigest()
36+
result = compare_digest(received_sign, expected_sign)
3737
except redis.exceptions.ResponseError:
38-
result = False
38+
pass
3939
except redis.exceptions.AuthenticationError:
40-
result = False
40+
pass
4141
return result
4242

4343
@app.route("/api/gh/redis/redis/commits", methods=["POST"])
44-
@auth.login_required
4544
def base():
46-
# Get Request body from JSON
47-
request_data = request.json
48-
gh_org = "redis"
49-
gh_repo = "redis"
50-
schema = CommitSchema()
51-
response_data = {}
52-
err_message = ""
53-
try:
54-
# Validate request body against schema data types
55-
result = schema.load(request_data)
56-
except ValidationError as err:
57-
err_message = err.messages
58-
if result is True:
59-
# Convert request body back to JSON str
60-
data_now_json_str = dumps(result)
45+
if verify_signature(request):
46+
print(request)
47+
# Get Request body from JSON
48+
request_data = request.json
49+
if type(request_data) is str:
50+
request_data = json.loads(request_data)
51+
if type(request_data) is bytes:
52+
request_data = json.loads(request_data.decode())
53+
54+
gh_org = "redis"
55+
gh_repo = "redis"
56+
ref = None
57+
ref_label = None
58+
sha = None
59+
60+
event_type = "Ignored event from webhook"
61+
use_event = False
62+
# Pull request labeled
63+
trigger_label = PULL_REQUEST_TRIGGER_LABEL
64+
if "pull_request" in request_data:
65+
action = request_data["action"]
66+
if "labeled" == action:
67+
pull_request_dict = request_data["pull_request"]
68+
head_dict = pull_request_dict["head"]
69+
repo_dict = head_dict["repo"]
70+
labels = []
71+
if "labels" in pull_request_dict:
72+
labels = pull_request_dict["labels"]
73+
ref = head_dict["ref"]
74+
ref_label = head_dict["label"]
75+
sha = head_dict["sha"]
76+
html_url = repo_dict["html_url"].split("/")
77+
gh_repo = html_url[-1]
78+
gh_org = html_url[-2]
79+
for label in labels:
80+
label_name = label["name"]
81+
if trigger_label == label_name:
82+
use_event = True
83+
event_type = "Pull request labeled with '{}'".format(
84+
trigger_label
85+
)
86+
87+
# Git pushes to repo
88+
if "ref" in request_data:
89+
repo_dict = request_data["repository"]
90+
html_url = repo_dict["html_url"].split("/")
91+
gh_repo = html_url[-1]
92+
gh_org = html_url[-2]
93+
ref = request_data["ref"].split("/")[-1]
94+
ref_label = request_data["ref"]
95+
sha = request_data["after"]
96+
use_event = True
97+
event_type = "Git pushes to repo"
98+
99+
if use_event is True:
100+
fields = {"git_hash": sha, "ref_label": ref_label, "ref": ref}
101+
app.logger.info(
102+
"Using event {} to trigger benchmark. final fields: {}".format(
103+
event_type, fields
104+
)
105+
)
106+
result, response_data, err_message = commit_schema_to_stream(
107+
fields, conn, gh_org, gh_repo
108+
)
109+
app.logger.info(
110+
"Using event {} to trigger benchmark. final fields: {}".format(
111+
event_type, response_data
112+
)
113+
)
61114

62-
result, response_data, err_message = commit_schema_to_stream(
63-
data_now_json_str, conn, gh_org, gh_repo
64-
)
65-
if result is False:
66-
return jsonify(err_message), 400
115+
else:
116+
app.logger.info(
117+
"{}. input json was: {}".format(event_type, request_data)
118+
)
119+
response_data = {"message": event_type}
67120

68-
# Send data back as JSON
69-
return jsonify(response_data), 200
121+
# Send data back as JSON
122+
return jsonify(response_data), 200
123+
else:
124+
return "Forbidden", 403
70125

71126
return app

redis_benchmarks_specification/__api__/schema.py

Lines changed: 0 additions & 7 deletions
This file was deleted.

redis_benchmarks_specification/__common__/builder_schema.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# All rights reserved.
55
#
66
import logging
7-
from json import loads
87
from urllib.error import URLError
98
from urllib.request import urlopen
109
from github import Github
@@ -17,15 +16,15 @@
1716

1817

1918
def commit_schema_to_stream(
20-
json_str: str,
19+
fields: dict,
2120
conn: redis.StrictRedis,
22-
gh_org="redis",
23-
gh_repo="redis",
21+
gh_org,
22+
gh_repo,
2423
gh_token=None,
2524
):
2625
""" uses to the provided JSON dict of fields and pushes that info to the corresponding stream """
27-
fields = loads(json_str)
28-
reply_fields = loads(json_str)
26+
fields = fields
27+
reply_fields = dict(fields)
2928
result = False
3029
error_msg = None
3130
use_git_timestamp = False
@@ -72,8 +71,8 @@ def get_archive_zip_from_hash(gh_org, gh_repo, git_hash, fields):
7271

7372
def get_commit_dict_from_sha(
7473
git_hash,
75-
gh_org="redis",
76-
gh_repo="redis",
74+
gh_org,
75+
gh_repo,
7776
commit_dict={},
7877
use_git_timestamp=False,
7978
gh_token=None,
@@ -119,6 +118,13 @@ def request_build_from_commit_info(conn, fields, reply_fields):
119118
"""
120119
result = True
121120
error_msg = None
121+
for k, v in fields.items():
122+
if type(v) not in [str, int, float, bytes]:
123+
raise Exception(
124+
"Type of field {} is not bytes, string, int or float. Type ({}). Value={}".format(
125+
k, type(v), v
126+
)
127+
)
122128
id = conn.xadd(STREAM_KEYNAME_GH_EVENTS_COMMIT.encode(), fields)
123129
reply_fields["id"] = id
124130
return result, reply_fields, error_msg

redis_benchmarks_specification/__common__/env.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@
5050
REDIS_SOCKET_TIMEOUT = int(os.getenv("REDIS_SOCKET_TIMEOUT", "300"))
5151

5252
# environment variables
53+
PULL_REQUEST_TRIGGER_LABEL = os.getenv(
54+
"PULL_REQUEST_TRIGGER_LABEL", "trigger-benchmark"
55+
)
5356
DATASINK_RTS_PUSH = bool(os.getenv("DATASINK_PUSH_RTS", False))
5457
DATASINK_RTS_AUTH = os.getenv("DATASINK_RTS_AUTH", None)
5558
DATASINK_RTS_USER = os.getenv("DATASINK_RTS_USER", None)

utils/tests/test_api.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
# Copyright (c) 2021., Redis Labs
44
# All rights reserved.
55
#
6-
import redis_benchmarks_specification
7-
from redis_benchmarks_specification.__api__.app import create_app
86

97
from redis_benchmarks_specification.__common__.builder_schema import (
108
commit_schema_to_stream,
@@ -26,7 +24,7 @@
2624

2725
def test_commit_schema_to_stream():
2826
result, reply_fields, error_msg = commit_schema_to_stream(
29-
'{"git_hashss":"0cf2df84d4b27af4bffd2bf3543838f09e10f874"}',
27+
{"git_hashss": "0cf2df84d4b27af4bffd2bf3543838f09e10f874"},
3028
None,
3129
"redis",
3230
"redis",
@@ -38,7 +36,7 @@ def test_commit_schema_to_stream():
3836
conn.ping()
3937
conn.flushall()
4038
result, reply_fields, error_msg = commit_schema_to_stream(
41-
'{"git_hash":"0cf2df84d4b27af4bffd2bf3543838f09e10f874"}',
39+
{"git_hash": "0cf2df84d4b27af4bffd2bf3543838f09e10f874"},
4240
conn,
4341
"redis",
4442
"redis",

0 commit comments

Comments
 (0)