Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ ENV/

# Rope project settings
.ropeproject

.idea
28 changes: 28 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env groovy

pipeline {
agent {
label {
label 'docker'
}
}
options {
timestamps()
timeout(time: 30, unit: 'MINUTES')
}
environment {
AWS_ACCESS_KEY_ID = credentials('AAMDEV_AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = credentials('AAMDEV_AWS_SECRET_ACCESS_KEY')
AWS_PROFILE = "aamdevelopment"
AWS_DEFAULT_REGION="eu-west-1"
DOCKER_REGISTRY = "${env.KDMTS_REGISTRY}"
IMAGE_TAG = "${env.BRANCH_NAME}"
}
stages {
stage('Build docker image') {
steps {
sh 'make docker-build-mocky'
}
}
}
}
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export WORKSPACE_DIR:=$(shell pwd)
export IMAGE_TAG?=dev

PACKER?=packer.io

ifeq ($(IMAGE_TAG), master)
export IMAGE_TAG=latest
endif

ifdef AWS_PROFILE
export AWS_PROFILE_ARGS=--profile $(AWS_PROFILE)
endif

docker-login-aws-ecr:
@$(shell aws ecr get-login --no-include-email --region eu-west-1 $(AWS_PROFILE_ARGS))

docker-build-mocky: docker-login-aws-ecr
$(PACKER) build ops/mocky_packer.json
6 changes: 0 additions & 6 deletions endpoints.json

This file was deleted.

8 changes: 8 additions & 0 deletions examples/endpoints.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
"/hello",
"/hello/<name>",
"/hello/world/<__world_number__>"
]



5 changes: 5 additions & 0 deletions examples/responses/hello/alice/get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"body": "Hello Alice!",
"status": 201,
"headers": {"Content-Type": "application/json"}
}
5 changes: 5 additions & 0 deletions examples/responses/hello/bob/get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"body": "Hello Bob!",
"status": 201,
"headers": {"Content-Type": "application/json"}
}
File renamed without changes.
9 changes: 9 additions & 0 deletions examples/responses/hello/world/__world_number__/get.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"body": {
"World Number": 123
},
"status": 201,
"headers": {
"Content-Type": "application/json"
}
}
78 changes: 56 additions & 22 deletions mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@
METHOD_NOT_ALLOWED_RESPONSE = {
'body': {'message': 'Method not implemented'},
'headers': {'Content-Type': 'application/json'},
'status': 405
'status_code': 405
}

PREFLIGHT_RESPONSE = {
'headers': {'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': '*',
'Access-Control-Max-Age': '86400'},
'status_code': 200
}


Expand All @@ -19,7 +27,7 @@ def load_json(file_path):


def save_json(file_path, data):
with open(file_path, 'w') as f:
with open(file_path, 'w+') as f:
json.dump(data, f)


Expand All @@ -28,10 +36,12 @@ class MethodFile(Enum):
POST = 'post.json'
PUT = 'put.json'
DELETE = 'delete.json'
OPTIONS = 'options.json'


class Config:
def __init__(self):
print(os.getcwd())
mock_workdir = os.getenv('MOCK_WORKDIR')
mock_endpoints = os.getenv('MOCK_ENDPOINTS', 'endpoints.json')
responses_dir_name = os.getenv('MOCK_RESPONSES_DIR_NAME', 'responses')
Expand All @@ -43,44 +53,64 @@ def __init__(self):

class FileResource(Resource):
_response_file_path = None
_request_data = None
_response = None
_method = None
_method_file = None

def __init__(self, responses_path, endpoint_path):
self._responses_path = responses_path
self._endpoint_path = endpoint_path

def get(self, **kwargs):
self._update_file_paths(MethodFile.GET, **kwargs)
self._save_request_data()
response = self._get_response()
return response
self._process(**kwargs)
return self._response

def post(self, **kwargs):
self._update_file_paths(MethodFile.POST, **kwargs)
self._save_request_data()
response = self._get_response()
return response
self._process(**kwargs)
return self._response

def put(self, **kwargs):
self._update_file_paths(MethodFile.PUT, **kwargs)
response = self._get_response()
return response
self._process(**kwargs)
return self._response

def delete(self, **kwargs):
self._update_file_paths(MethodFile.DELETE, **kwargs)
response = self._get_response()
return response
self._process(**kwargs)
return self._response

def options(self, **kwargs):
self._process(**kwargs)
return self._response

def _process(self, **kwargs):
self._process_request(**kwargs)
self._response = self._get_response()

def _process_request(self, **kwargs):
self._method = request.method
self._method_file = MethodFile[self._method].value
self._extract_request_data()
self._update_file_paths(**kwargs)
self._log_request_data()
self._save_request_data()

def _save_request_data(self):
def _extract_request_data(self):
request_data = {
'headers': dict(request.headers),
'body': request.json if request.is_json else request.data.decode() or None,
'args': dict(request.args),
'endpoint': request.endpoint,
'method': request.method
'method': self._method
}
save_json(self._request_file_path, request_data)
self._request_data = request_data

def _update_file_paths(self, method, **kwargs):
def _save_request_data(self):
save_json(self._request_file_path, self._request_data)

def _log_request_data(self):
app.logger.info("REQUEST: %s" % (self._request_data,))

def _update_file_paths(self, **kwargs):
endpoint_path = self._endpoint_path

for key, value in kwargs.items():
Expand All @@ -90,17 +120,21 @@ def _update_file_paths(self, method, **kwargs):
else:
endpoint_path = endpoint_path.replace(path_key, value)

self._response_file_path = os.path.join(self._responses_path, endpoint_path, method.value)
self._response_file_path = os.path.join(self._responses_path, endpoint_path, self._method_file)
self._request_file_path = os.path.join(self._responses_path, 'last_request.json')

def _get_response(self):
try:
response_data = load_json(self._response_file_path)
except IOError:
response_data = METHOD_NOT_ALLOWED_RESPONSE
if self._method_file == MethodFile.OPTIONS.value:
response_data = PREFLIGHT_RESPONSE
else:
response_data = METHOD_NOT_ALLOWED_RESPONSE
body = response_data.get('body')
status_code = response_data.get('status_code')
headers = response_data.get('headers')
app.logger.info("RESPONSE: %s" % (response_data,))
response = Response(json.dumps(body), status_code, headers)
return response

Expand Down
28 changes: 28 additions & 0 deletions ops/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash

set -ex

export EXEC_USER_NAME=exec_user

function add_exec_user() {
if [ -z "${EXEC_USER_ID}" ]
then
EXEC_USER_ID=0
fi

if [ ${EXEC_USER_ID} == 0 ]
then
useradd -m -o -g 0 -u ${EXEC_USER_ID} ${EXEC_USER_NAME}
else
useradd -m -o -u ${EXEC_USER_ID} ${EXEC_USER_NAME}
fi
}

id -u exec_user &> /dev/null || add_exec_user

if [ "${1}" == "mock" ]
then
su ${EXEC_USER_NAME} -c "python3 /mock.py"
else
exec "$@"
fi
60 changes: 60 additions & 0 deletions ops/mocky_packer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"variables": {
"workspace_dir": "{{env `WORKSPACE_DIR`}}",
"aws_registry": "{{env `KDMTS_REGISTRY`}}",
"tag": "{{env `IMAGE_TAG`}}"
},
"builders": [
{
"type": "docker",
"image": "python:3.6",
"commit": true,
"changes": [
"LABEL maintainer=artsalliancemedia.com",
"ENV MOCK_WORKDIR=/mock",
"EXPOSE 8080",
"VOLUME /mock",
"WORKDIR /mock",
"ENTRYPOINT [\"/docker-entrypoint.sh\"]",
"CMD [\"mock\"]"
]
}
],
"provisioners": [
{
"type": "file",
"source": "{{user `workspace_dir`}}/mock.py",
"destination": "/"
},
{
"type": "file",
"source": "{{user `workspace_dir`}}/ops/docker-entrypoint.sh",
"destination": "/"
},
{
"type": "file",
"source": "{{user `workspace_dir`}}/requirements.txt",
"destination": "/tmp/"
},
{
"type": "shell",
"inline": [
"pip3 install --upgrade -r /tmp/requirements.txt"
]
}
],
"post-processors": [
[
{
"type": "docker-tag",
"repository": "{{user `aws_registry`}}/aam_mocky",
"tag": "{{user `tag`}}"
},
{
"type": "docker-push",
"ecr_login": false,
"login_server": "https://{{user `aws_registry`}}/aam_mocky"
}
]
]
}
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
flask
flask-restful