-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
ZO-4519: Deploy nightwatch to k8s
- Loading branch information
Showing
13 changed files
with
871 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
version: 2 | ||
updates: | ||
- package-ecosystem: "github-actions" | ||
directory: "/" | ||
schedule: | ||
interval: "weekly" | ||
commit-message: | ||
prefix: "MAINT:" | ||
|
||
- package-ecosystem: "docker" | ||
directory: "/smoketest" | ||
schedule: | ||
interval: "weekly" | ||
commit-message: | ||
prefix: "MAINT:" | ||
- package-ecosystem: "pip" | ||
directory: "/smoketest" | ||
schedule: | ||
interval: "weekly" | ||
commit-message: | ||
prefix: "MAINT:" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: Build and deploy nightwatch tests | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- '.github/workflows/nightwatch.yaml' | ||
- 'smoketest/**' | ||
pull_request: | ||
paths: | ||
- '.github/workflows/nightwatch.yaml' | ||
- 'smoketest/**' | ||
|
||
jobs: | ||
build: | ||
uses: zeitonline/gh-action-workflows/.github/workflows/[email protected] | ||
secrets: inherit | ||
with: | ||
versions: smoketest/k8s/base/versions | ||
# copy&paste from k8s/base and k8s/staging manifest; | ||
# the json/shell quoting is atrocious. | ||
args: | | ||
--override-type=strategic --overrides="{\"spec\": { | ||
\"serviceAccount\": \"baseproject\", | ||
\"containers\": [{ | ||
\"name\": \"nightwatch-test-$TAG\", | ||
\"env\": [ | ||
{\"name\": \"HTTPS_PROXY\", \"value\": \"http://static-ip-proxy.ops.zeit.de:3128\"}, | ||
{\"name\": \"VIVI_XMLRPC_PASSWORD\", \"valueFrom\": {\"secretKeyRef\": { | ||
\"name\": \"principals\", | ||
\"key\": \"vivi_zeit.cms.principals_system.nightwatch\" | ||
}}} | ||
] | ||
}] }}" | ||
# deploy happens via flux (on `main` branch) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#!/bin/bash | ||
|
||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
|
||
function vault_read() { | ||
local path=$1 | ||
local field=$2 | ||
|
||
if [[ -z "$VAULT_TOKEN" ]]; then | ||
VAULT_TOKEN=$(<"$HOME/.vault-token") | ||
fi | ||
curl --silent -H "X-Vault-Token: $VAULT_TOKEN" \ | ||
"${VAULT_ADDR%/}/v1/zon/v1/${path}" | \ | ||
sed -e "s+^.*\"${field}\":\"\([^\"]*\).*$+\1+" | ||
} | ||
|
||
|
||
COMMAND=$1 | ||
case $COMMAND in | ||
smoke) | ||
set -e | ||
shift | ||
if [[ "$1" != -* ]]; then | ||
environment=$1 | ||
shift | ||
else | ||
environment="staging" | ||
fi | ||
|
||
cd "$DIR/../smoketest" | ||
|
||
image=$(awk -F': ' '/^ newName:/ { print $2 }' \ | ||
< k8s/base/kustomization.yaml) | ||
docker buildx build --output type=docker --quiet --tag $image . | ||
docker run --rm -it \ | ||
-e VIVI_XMLRPC_PASSWORD=$(vault_read vivi/$environment/nightwatch password) \ | ||
$image \ | ||
--nightwatch-environment=$environment "$@" | ||
;; | ||
*) | ||
echo "Unrecognized command: $COMMAND" | ||
exit 1 | ||
;; | ||
esac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
k8s/**/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# See https://github.com/ZeitOnline/gh-action-workflows/blob/main/.github/workflows/nightwatch-build.yaml | ||
FROM python:3.12.1-slim as nightwatch | ||
WORKDIR /app | ||
RUN pip --no-cache-dir install pipenv | ||
COPY Pipfile Pipfile.lock ./ | ||
RUN pipenv sync | ||
COPY *.py ./ | ||
# See https://github.com/ZeitOnline/kustomize/blob/main/components/nightwatch/deployment.yaml | ||
ENTRYPOINT ["pipenv", "run", "pytest", "--tb=native"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[[source]] | ||
url = "https://pypi.org/simple" | ||
verify_ssl = true | ||
name = "pypi" | ||
|
||
[packages] | ||
"webdavclient3" = "*" | ||
"zeit.nightwatch" = ">=1.3.2" | ||
|
||
[requires] | ||
python_version = "3" |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
from io import BytesIO | ||
from urllib.parse import urlparse | ||
import os | ||
import xmlrpc.client | ||
|
||
import pytest | ||
import webdav3.client | ||
|
||
|
||
XMLRPC_AUTH = 'nightwatch:' + os.environ['VIVI_XMLRPC_PASSWORD'] | ||
CONFIG_STAGING = { | ||
'browser': {'baseurl': 'https://www.staging.zeit.de'}, | ||
'vivi': { | ||
'dav_url': 'http://cms-backend.staging.zeit.de:9000', | ||
'xmlrpc_url': f'https://{XMLRPC_AUTH}@vivi-frontend.staging.zeit.de:9090/', | ||
}, | ||
'elasticsearch': 'https://tms-es.staging.zon.zeit.de/zeit_content/_search', | ||
} | ||
|
||
|
||
CONFIG_PRODUCTION = { | ||
'browser': {'baseurl': 'https://www.zeit.de'}, | ||
'vivi': { | ||
'dav_url': 'http://cms-backend.zeit.de:9000', | ||
'xmlrpc_url': f'https://{XMLRPC_AUTH}@vivi-frontend.zeit.de:9090/', | ||
}, | ||
'elasticsearch': 'https://tms-es.zon.zeit.de/zeit_content/_search', | ||
} | ||
|
||
|
||
@pytest.fixture(scope='session') | ||
def nightwatch_config(nightwatch_environment): | ||
config = globals()['CONFIG_%s' % nightwatch_environment.upper()] | ||
return dict(config, environment=nightwatch_environment) | ||
|
||
|
||
@pytest.fixture(scope='session') | ||
def config(nightwatch_config): # shorter spelling for our tests | ||
return nightwatch_config | ||
|
||
|
||
def pytest_configure(config): | ||
config.option.prometheus_job_name = 'vivi-deployment-%s' % config.option.nightwatch_environment | ||
if config.option.prometheus_extra_labels is None: | ||
config.option.prometheus_extra_labels = [] | ||
config.option.prometheus_extra_labels.append('project=vivi-deployment') | ||
|
||
|
||
class ViviClient: | ||
def __init__(self, dav_url, xmlrpc_url): | ||
self.dav = webdav3.client.Client({'webdav_hostname': dav_url}) | ||
self.xmlrpc = xmlrpc.client.ServerProxy(xmlrpc_url) | ||
|
||
def set_property(self, unique_id, ns, name, value): | ||
path = '/cms/work' + urlparse(unique_id).path | ||
if not ns.startswith('http'): | ||
ns = 'http://namespaces.zeit.de/CMS/%s' % ns | ||
self.dav.set_property(path, {'namespace': ns, 'name': name, 'value': value}) | ||
|
||
def put(self, unique_id, body): | ||
path = '/cms/work' + urlparse(unique_id).path | ||
self.dav.upload_to(BytesIO(body.encode('utf-8')), path) | ||
|
||
def refresh_dav_cache(self, unique_id): | ||
if unique_id.startswith('/'): | ||
unique_id = 'http://xml.zeit.de' + unique_id | ||
self.xmlrpc.invalidate(unique_id) | ||
|
||
def publish(self, unique_id): | ||
if unique_id.startswith('/'): | ||
unique_id = 'http://xml.zeit.de' + unique_id | ||
self.xmlrpc.publish(unique_id) | ||
|
||
|
||
@pytest.fixture(scope='session') | ||
def vivi(config): | ||
return ViviClient(**config['vivi']) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
apiVersion: kustomize.config.k8s.io/v1beta1 | ||
kind: Kustomization | ||
|
||
components: | ||
- github.com/ZeitOnline/kustomize/components/nightwatch?ref=1.3 | ||
- versions | ||
|
||
patches: | ||
- target: | ||
kind: Deployment | ||
name: nightwatch | ||
patch: | | ||
- op: add | ||
path: /spec/template/spec/containers/0/env | ||
value: | ||
- name: VIVI_XMLRPC_PASSWORD | ||
valueFrom: | ||
secretKeyRef: | ||
name: principals | ||
key: vivi_zeit.cms.principals_system.nightwatch | ||
# See https://github.com/ZeitOnline/gh-action-workflows/blob/main/.github/workflows/nightwatch-build.yaml | ||
images: | ||
- name: nightwatch | ||
newName: europe-west3-docker.pkg.dev/zeitonline-engineering/docker-zon/vivi-nightwatch |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
apiVersion: kustomize.config.k8s.io/v1alpha1 | ||
kind: Component | ||
|
||
images: | ||
- name: nightwatch | ||
newTag: "nothing" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
apiVersion: kustomize.config.k8s.io/v1beta1 | ||
kind: Kustomization | ||
|
||
resources: | ||
- ../base | ||
|
||
patches: | ||
- target: | ||
kind: Deployment | ||
name: nightwatch | ||
patch: |- | ||
- op: replace | ||
path: /spec/template/spec/containers/0/args | ||
value: | ||
- "--nightwatch-environment=production" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
apiVersion: kustomize.config.k8s.io/v1beta1 | ||
kind: Kustomization | ||
|
||
resources: | ||
- ../base | ||
|
||
patches: | ||
- target: | ||
kind: Deployment | ||
name: nightwatch | ||
patch: |- | ||
- op: add | ||
path: /spec/template/spec/containers/0/env/- | ||
value: | ||
name: HTTPS_PROXY | ||
value: http://static-ip-proxy.ops.zeit.de:3128 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
from datetime import datetime, timezone | ||
from time import sleep | ||
|
||
import pytest | ||
|
||
|
||
def test_publisher_invalidates_fastly(vivi, http): | ||
article = '/data/nightwatch-publish.txt' | ||
|
||
expected = datetime.now().isoformat() | ||
|
||
vivi.put(article, expected) | ||
vivi.publish(article) | ||
|
||
# vivi runs the publisher asynchronously from the API call. | ||
timeout = 60 | ||
for i in range(timeout): | ||
sleep(1) | ||
r = http(article) | ||
current = r.text.strip() | ||
if current == expected: | ||
break | ||
else: | ||
pytest.fail('Expected %s, got %s after %s seconds' % (expected, current, timeout)) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'content', | ||
[ | ||
'/wirtschaft/2010-01/automarkt-usa-deutschland-smart', | ||
'/2010/01/index', | ||
], | ||
) | ||
def test_publisher_updates_metadata(vivi, http, config, content): | ||
before = datetime.now(timezone.utc) | ||
sleep(1) | ||
|
||
vivi.publish(content) | ||
|
||
# vivi runs the publisher asynchronously from the API call. | ||
timeout = 60 | ||
for i in range(timeout): | ||
sleep(1) | ||
r = http( | ||
config['elasticsearch'], | ||
json={ | ||
'query': {'bool': {'filter': [{'term': {'url': content}}]}}, | ||
'_source': ['payload.workflow.date_last_published'], | ||
}, | ||
) | ||
try: | ||
hit = r.json()['hits']['hits'][0]['_source'] | ||
current = hit['payload']['workflow']['date_last_published'] | ||
current = datetime.fromisoformat(current) | ||
except Exception: | ||
current = datetime.min | ||
if current > before: | ||
break | ||
else: | ||
pytest.fail('%s did not increase after %s seconds' % (current, timeout)) |