Skip to content

Commit f0cfb9b

Browse files
committed
Address comments.
1 parent 901ff3b commit f0cfb9b

File tree

9 files changed

+117
-76
lines changed

9 files changed

+117
-76
lines changed

test/cluster/keytar/Dockerfile

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
1-
# This Dockerfile should be built from within the accompanying build.sh script.
1+
# Dockerfile for generating the keytar image. See README.md for more information.
22
FROM debian:jessie
33

4+
ENV DEBIAN_FRONTEND noninteractive
5+
46
RUN apt-get update -y \
57
&& apt-get install --no-install-recommends -y -q \
8+
apt-utils \
9+
apt-transport-https \
610
build-essential \
11+
curl \
712
python2.7 \
813
python2.7-dev \
914
python-pip \
@@ -12,6 +17,10 @@ RUN apt-get update -y \
1217
&& pip install -U pip \
1318
&& pip install virtualenv
1419

20+
RUN echo "deb https://packages.cloud.google.com/apt cloud-sdk-jessie main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list
21+
RUN curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
22+
RUN apt-get update -y && apt-get install -y google-cloud-sdk && apt-get install -y kubectl
23+
1524
WORKDIR /app
1625
RUN virtualenv /env
1726
ADD requirements.txt /app/requirements.txt
@@ -20,19 +29,15 @@ ADD keytar.py test_runner.py /app/
2029
ADD static /app/static
2130

2231
ENV USER keytar
23-
ENV DEBIAN_FRONTEND noninteractive
2432

2533
ENV PYTHONPATH /env/lib/python2.7/site-packages
2634
ENV CLOUDSDK_PYTHON_SITEPACKAGES $PYTHONPATH
2735

28-
RUN wget https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-138.0.0-linux-x86_64.tar.gz
29-
RUN tar -xvf google-cloud-sdk-138.0.0-linux-x86_64.tar.gz
30-
RUN google-cloud-sdk/install.sh --usage-reporting false --path-update true --additional-components kubectl -q
3136
RUN /bin/bash -c "source ~/.bashrc"
3237

3338
EXPOSE 8080
3439
CMD []
3540
ENTRYPOINT ["/env/bin/python", "keytar.py"]
3641

37-
ENV PATH /env/bin:/app/google-cloud-sdk/bin:$PATH
42+
ENV PATH /env/bin:$PATH
3843

test/cluster/keytar/README.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
# Keytar
2-
Keytar is a system for monitoring docker images on [docker hub](https://hub.docker.com). When a new image is created, Keytar can start a cluster on Google Compute Engine (GKE) and run Kubernetes applications for the purpose of executing cluster tests. It exposes a simple web status page showing test results.
2+
3+
Keytar is an internally used Vitess system for continuous execution of cluster
4+
tests on Kubernetes/Google Cloud. It monitors docker images on [Docker Hub](https://hub.docker.com). When a new image is uploaded to Docker Hub, Keytar starts a cluster on Google Compute Engine (GKE) and runs Kubernetes applications for the purpose of executing cluster tests. It exposes a simple web status page showing test results.
5+
36
## Setup
4-
How to set up keytar for Vitess:
7+
8+
How to set up Keytar for Vitess:
9+
510
* Create service account keys with GKE credentials on the account to run the tests on. Follow [step 1 from the GKE developers page](https://developers.google.com/identity/protocols/application-default-credentials?hl=en_US#howtheywork).
6-
* Move the generated keyfile to $VTTOP/test/cluster/keytar/config.
7-
* Create or modify the test configuration file ($VTTOP/test/cluster/keytar/config/vitess_p0_config.yaml).
11+
* Move the generated keyfile to `$VTTOP/test/cluster/keytar/config`.
12+
* Create or modify the test configuration file (`$VTTOP/test/cluster/keytar/config/vitess_p0_config.yaml`).
813
* Ensure the configuration has the correct values for GKE project name and keyfile:
914
```
1015
cluster_setup:
@@ -15,19 +20,24 @@ How to set up keytar for Vitess:
1520
* Then run the following commands:
1621
```
1722
> cd $VTTOP/test/cluster/keytar
18-
> KEYTAR_KEY=<desired password> KEYTAR_PORT=<desired port, default 8080> KEYTAR_CONFIG=<desired configuration, default vitess_p0_config.yaml> ./keytar-up.sh
23+
> KEYTAR_PASSWORD=<desired password> KEYTAR_PORT=<desired port, default 8080> KEYTAR_CONFIG=<desired configuration, default vitess_p0_config.yaml> ./keytar-up.sh
1924
```
20-
* Add a Docker hub webhook pointing to the Keytar service. The webhook URL should be in the form:
25+
* Add a Docker Hub webhook pointing to the Keytar service. The webhook URL should be in the form:
2126
```
22-
http://<keytar-service-IP>:80/test_request?key=<KEYTAR_KEY>
27+
http://<keytar-service-IP>:80/test_request?password=<KEYTAR_PASSWORD>
2328
```
24-
## Viewing Status
29+
30+
## Dashboard
31+
2532
The script to start Keytar should output a web address to view the current status. If not, the following command can also be run:
2633
```shell
2734
> kubectl get service keytar -o template --template '{{if ge (len .status.loadBalancer) 1}}{{index (index .status.loadBalancer.ingress 0) "ip"}}{{end}}'
2835
```
36+
2937
## Limitations
38+
3039
Currently, Keytar has the following limitations:
40+
3141
* Only one configuration file allowed at a time.
3242
* Configuration cannot be updated dynamically.
3343
* Test results are saved in memory and are not durable.

test/cluster/keytar/config/vitess_p0_config.yaml renamed to test/cluster/keytar/config/vitess_config.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ install:
4646
- /app/linux-amd64/
4747
cluster_setup:
4848
- type: gke
49-
project_name: e-sunlight-726
5049
keyfile: /config/keyfile.json
5150
config:
5251
- docker_image: vitess/root

test/cluster/keytar/dummy_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python
2-
"""Dummy no-op test."""
2+
"""Dummy no-op test to be used in the webdriver test."""
33

44
import logging
55
import sys

test/cluster/keytar/keytar-controller-template.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ spec:
1212
spec:
1313
containers:
1414
- name: keytar
15-
image: thompsonja/keytar
15+
image: vitess/keytar
1616
ports:
1717
- name: http-server
1818
containerPort: {{port}}
1919
resources:
2020
limits:
2121
memory: "4Gi"
2222
cpu: "500m"
23-
args: ["--config_file", "{{config}}", "--port", "{{port}}", "--key", "{{key}}"]
23+
args: ["--config_file", "{{config}}", "--port", "{{port}}", "--password", "{{password}}"]
2424
volumeMounts:
2525
- name: config
2626
mountPath: /config

test/cluster/keytar/keytar-up.sh

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ set -e
44

55
KUBECTL=${KUBECTL:-kubectl}
66

7-
config_path=${KEYTAR_CONFIG_PATH:-"$VTTOP/test/cluster/keytar/config"}
7+
config_path=${KEYTAR_CONFIG_PATH:-"./config"}
88
port=${KEYTAR_PORT:-8080}
9-
key=${KEYTAR_KEY:-"defaultkey"}
10-
config=${KEYTAR_CONFIG:-"/config/vitess_p0_config.yaml"}
9+
password=${KEYTAR_PASSWORD:-"defaultkey"}
10+
config=${KEYTAR_CONFIG:-"/config/vitess_config.yaml"}
1111

1212
sed_script=""
13-
for var in config_path port config key; do
13+
for var in config_path port config password; do
1414
sed_script+="s,{{$var}},${!var},g;"
1515
done
1616

@@ -29,11 +29,11 @@ echo "Creating firewall-rule"
2929
gcloud compute firewall-rules create keytar --allow tcp:80
3030

3131
for i in `seq 1 20`; do
32-
addr=`$KUBECTL get service keytar -o template --template '{{if ge (len .status.loadBalancer) 1}}{{index (index .status.loadBalancer.ingress 0) "ip"}}{{end}}'`
33-
if [[ -n $addr ]]; then
34-
echo Keytar address: http://${addr}:80
32+
ip=`$KUBECTL get service keytar -o template --template '{{if ge (len .status.loadBalancer) 1}}{{index (index .status.loadBalancer.ingress 0) "ip"}}{{end}}'`
33+
if [[ -n "$ip" ]]; then
34+
echo "Keytar address: http://${ip}:80"
3535
break
3636
fi
37-
echo Waiting for keytar external IP
37+
echo "Waiting for keytar external IP"
3838
sleep 10
3939
done

test/cluster/keytar/keytar.py

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#!/usr/bin/env python
2-
"""Main python file."""
2+
"""Keytar flask app."""
33

44
import argparse
55
import datetime
@@ -20,36 +20,6 @@
2020
keytar_args = None
2121
keytar_config = None
2222
results = {}
23-
q = Queue.Queue()
24-
tasks = []
25-
26-
27-
def worker():
28-
while True:
29-
item = q.get()
30-
run_test_config(item)
31-
q.task_done()
32-
33-
worker_thread = threading.Thread(target=worker)
34-
worker_thread.daemon = True
35-
worker_thread.start()
36-
37-
38-
def _add_new_result(timestamp):
39-
result = {'time': timestamp, 'status': 'Start', 'tests': {}}
40-
results[timestamp] = result
41-
42-
43-
def _get_download_github_repo_args(tempdir, github_config):
44-
repo_prefix = 'github'
45-
if 'repo_prefix' in github_config:
46-
repo_prefix = github_config['repo_prefix']
47-
repo_dir = os.path.join(tempdir, repo_prefix)
48-
git_args = ['git', 'clone', 'https://github.com/%s' % github_config['repo'],
49-
repo_dir]
50-
if 'branch' in github_config:
51-
git_args += ['-b', github_config['branch']]
52-
return git_args, repo_dir
5323

5424

5525
def run_test_config(config):
@@ -110,7 +80,7 @@ def test_results():
11080

11181
@app.route('/test_log')
11282
def test_log():
113-
log = '%s.log' % flask.request.values['log_name']
83+
log = '%s.log' % os.path.basename(flask.request.values['log_name'])
11484
return (flask.send_from_directory('/tmp/testlogs', log), 200,
11585
{'Content-Type': 'text/css'})
11686

@@ -124,26 +94,27 @@ def update_results():
12494
return 'OK'
12595

12696

127-
def _validate_request(keytar_key, request_values):
128-
if keytar_key:
129-
if 'key' not in request_values:
130-
return 'Expected key not provided in test_request!'
131-
elif request_values['key'] != keytar_key:
132-
return 'Incorrect key passed to test_request!'
97+
def _validate_request(keytar_password, request_values):
98+
if keytar_password:
99+
if 'password' not in request_values:
100+
return 'Expected password not provided in test_request!'
101+
elif request_values['password'] != keytar_password:
102+
return 'Incorrect password passed to test_request!'
133103

134104

135105
@app.route('/test_request', methods=['POST'])
136106
def test_request():
137107
"""Respond to a post request to execute tests.
138108
139109
This expects a json payload containing the docker webhook information.
140-
If this app is configured to use a key, the key should be passed in as part
141-
of the POST request.
110+
If this app is configured to use a password, the password should be passed in
111+
as part of the POST request.
142112
143113
Returns:
144114
HTML response.
145115
"""
146-
validation_error = _validate_request(keytar_args.key, flask.request.values)
116+
validation_error = _validate_request(
117+
keytar_args.password, flask.request.values)
147118
if validation_error:
148119
flask.abort(400, validation_error)
149120
webhook_data = flask.request.get_json()
@@ -152,7 +123,7 @@ def test_request():
152123
if not configs:
153124
return 'No config found for repo_name: %s' % repo_name
154125
for config in configs:
155-
q.put(config)
126+
test_worker.add_test(config)
156127
return 'OK'
157128

158129

@@ -169,9 +140,10 @@ def process_config(config):
169140
logging.info('authenticating using keyfile: %s',
170141
cluster_setup['keyfile'])
171142
subprocess.call(gcloud_args)
172-
subprocess.call(
173-
['gcloud', 'config', 'set', 'project',
174-
cluster_setup['project_name']])
143+
if 'project_name' in cluster_setup:
144+
subprocess.call(
145+
['gcloud', 'config', 'set', 'project',
146+
cluster_setup['project_name']])
175147
os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = (
176148
cluster_setup['keyfile'])
177149
if 'dependencies' in install_config:
@@ -188,11 +160,52 @@ def process_config(config):
188160
os.environ['PATH'] = '%s:%s' % (path, os.environ['PATH'])
189161

190162

163+
def _add_new_result(timestamp):
164+
result = {'time': timestamp, 'status': 'Start', 'tests': {}}
165+
results[timestamp] = result
166+
167+
168+
def _get_download_github_repo_args(tempdir, github_config):
169+
repo_prefix = 'github'
170+
if 'repo_prefix' in github_config:
171+
repo_prefix = github_config['repo_prefix']
172+
repo_dir = os.path.join(tempdir, repo_prefix)
173+
git_args = ['git', 'clone', 'https://github.com/%s' % github_config['repo'],
174+
repo_dir]
175+
if 'branch' in github_config:
176+
git_args += ['-b', github_config['branch']]
177+
return git_args, repo_dir
178+
179+
180+
class TestWorker(object):
181+
182+
def __init__(self):
183+
# Create a simple test queue. HTTP requests simply append to the queue.
184+
self.test_queue = Queue.Queue()
185+
self.worker_thread = threading.Thread(target=self.worker_loop)
186+
self.worker_thread.daemon = True
187+
188+
def worker_loop(self):
189+
# Run forever, executing tests as they are added to the queue
190+
while True:
191+
item = self.test_queue.get()
192+
run_test_config(item)
193+
self.test_queue.task_done()
194+
195+
def start(self):
196+
self.worker_thread.start()
197+
198+
def add_test(self, config):
199+
self.test_queue.put(config)
200+
201+
test_worker = TestWorker()
202+
203+
191204
if __name__ == '__main__':
192205
logging.getLogger().setLevel(logging.INFO)
193206
parser = argparse.ArgumentParser(description='Run keytar')
194207
parser.add_argument('--config_file', help='Keytar config file', required=True)
195-
parser.add_argument('--key', help='Key', default=None)
208+
parser.add_argument('--password', help='Password', default=None)
196209
parser.add_argument('--port', help='Port', default=8080, type=int)
197210
keytar_args = parser.parse_args()
198211
with open(keytar_args.config_file, 'r') as yaml_file:
@@ -204,4 +217,6 @@ def process_config(config):
204217
if not os.path.isdir('/tmp/testlogs'):
205218
os.mkdir('/tmp/testlogs')
206219

220+
test_worker.start()
221+
207222
app.run(host='0.0.0.0', port=keytar_args.port, debug=True)

test/cluster/keytar/keytar_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ def setUpClass(cls):
1919
testlog.write('foo')
2020

2121
def test_validate_request(self):
22-
self.assertFalse(keytar._validate_request('foo', {'key': 'foo'}))
23-
self.assertFalse(keytar._validate_request(None, {'key': 'foo'}))
22+
self.assertFalse(keytar._validate_request('foo', {'password': 'foo'}))
23+
self.assertFalse(keytar._validate_request(None, {'password': 'foo'}))
2424
self.assertFalse(keytar._validate_request(None, {}))
25-
self.assertTrue(keytar._validate_request('foo', {'key': 'foo2'}))
25+
self.assertTrue(keytar._validate_request('foo', {'password': 'foo2'}))
2626
self.assertTrue(keytar._validate_request('foo', {}))
2727

2828
def test_get_download_github_repo_args(self):

test/cluster/keytar/static/script.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,19 @@ $(document).ready(function() {
33

44
var appendTestResults = function(data) {
55
resultsElement.empty();
6-
var html = "<table align='center' id='results' border='1'><thead><tr><th>Time</th><th>Docker Image</th><th>Sandbox Name</th><th>Status</th><th>Tests</th><th>Results</th></thead><tbody>";
6+
var html = " \
7+
<table align='center' id='results' border='1'> \
8+
<thead> \
9+
<tr> \
10+
<th>Time</th> \
11+
<th>Docker Image</th> \
12+
<th>Sandbox Name</th> \
13+
<th>Status</th> \
14+
<th>Tests</th> \
15+
<th>Results</th> \
16+
</tr> \
17+
</thead> \
18+
<tbody>";
719
$.each(data, function(key, value) {
820
html += "<tr><td>" + value.time + "</td><td><a href=https://hub.docker.com/r/" + value.docker_image + ">" + value.docker_image + "</a></td><td>" + value.name + "</td><td>" + value.status + "</td><td><table>";
921
$.each(value.tests, function(key, val) {

0 commit comments

Comments
 (0)