Skip to content

Commit

Permalink
Merge pull request #5 from dinuta/flask-playing-ground
Browse files Browse the repository at this point in the history
Flask server restful
  • Loading branch information
dinuta authored Jun 1, 2019
2 parents 5c38740 + ae58c1d commit ec55c0d
Show file tree
Hide file tree
Showing 22 changed files with 213 additions and 55 deletions.
11 changes: 6 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ services:
- docker

env:
SCRIPTS_DIR: /home/dev/bin/
SCRIPTS_DIR: /home/dev/scripts/
SERVER: "127.0.0.1:5000" #not used atm

before_install:
- docker build -t dinutac/jinja2docker:latest .
Expand All @@ -16,13 +17,13 @@ script:
- docker-compose down -v

- docker run -i
-v $TRAVIS_BUILD_DIR/templates:/data
-v $TRAVIS_BUILD_DIR/variables:/variables -e TEMPLATE=standalone.j2
-v $TRAVIS_BUILD_DIR/inputs/templates:/data
-v $TRAVIS_BUILD_DIR/inputs/variables:/variables -e TEMPLATE=standalone.j2
-e VARIABLES=variables.yml -e DATABASE=mysql56 -e IMAGE=latest dinutac/jinja2docker:latest

- docker run --entrypoint jinja2
-v $TRAVIS_BUILD_DIR/templates:/data
-v $TRAVIS_BUILD_DIR/variables:/variables
-v $TRAVIS_BUILD_DIR/inputs/templates:/data
-v $TRAVIS_BUILD_DIR/inputs/variables:/variables
dinutac/jinja2docker:latest
/data/json.j2 /variables/json.json --format=json

Expand Down
30 changes: 11 additions & 19 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
FROM alpine:latest

ENV PUID 1000
ENV PGID 1000


RUN apk add --update python3 && \
pip3 install --upgrade pip setuptools

Expand All @@ -18,7 +14,12 @@ RUN pip3 install \
urllib3 \
simplejson \
Jinja2 \
jinja2-cli
jinja2-cli \
flask \
flask_restplus\
jsonify \
requests \
parameterized


## Cleanup
Expand All @@ -27,34 +28,25 @@ RUN apk del \
make && \
rm -rf /var/cache/apk/*

# create dev user
RUN addgroup -g $PGID dev && \
adduser -h /config -u $PUID -H -D -G dev -s /bin/bash dev && \
mkdir -p /home/dev/bin && \
sed -ri 's/(wheel:x:10:root)/\1,dev/' /etc/group && \
sed -ri 's/# %wheel ALL=\(ALL\) NOPASSWD: ALL/%wheel ALL=\(ALL\) NOPASSWD: ALL/' /etc/sudoers

# Create a shared data volume
# create an empty file, otherwise the volume will
# belong to root.
RUN mkdir /data/ && \
touch /data/.extra && \
chown -R dev:dev /data
RUN mkdir /data/

## Expose some volumes
VOLUME ["/data"]
VOLUME ["/variables"]

ENV TEMPLATES_DIR /data
ENV VARS_DIR /variables
ENV SCRIPTS_DIR /home/dev/bin/
ENV SCRIPTS_DIR /home/dev/scripts
ENV OUT_DIR out
ENV TEMPLATE docker-compose.j2
ENV VARIABLES variables.yml

COPY *.py /home/dev/bin/
RUN chown -R dev:dev /home/dev && chmod 700 $SCRIPTS_DIR*.py
ADD . $SCRIPTS_DIR/
RUN chmod +x $SCRIPTS_DIR/*.py

WORKDIR /data

ENTRYPOINT ["/home/dev/bin/render.py"]
ENTRYPOINT ["python3", "/home/dev/scripts/main.py"]
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ docker run -i -v **your_jinja2_template_folder**:/data \

Example:
```
docker run -i -v C:\Users\cdinuta\IdeaProjects\jinja2docker\templates:/data \
-v C:\Users\cdinuta\IdeaProjects\jinja2docker\variables:/variables -e TEMPLATE=standalone.j2 \
docker run -i -v C:\Users\cdinuta\IdeaProjects\jinja2docker\inputs\templates:/data \
-v C:\Users\cdinuta\IdeaProjects\jinja2docker\inputs\variables:/variables -e TEMPLATE=standalone.j2 \
-e VARIABLES=variables.yml -e DATABASE=mysql56 -e IMAGE=latest dinutac/jinja2docker:latest > docker-compose.yml
```

Expand Down Expand Up @@ -74,7 +74,7 @@ The recommendation is either paste selectively smaller chunks of yaml or use jso

## Latest updates

### Integrated Jinja2 Cli
### 1. Integrated Jinja2 Cli

https://github.com/mattrobenolt/jinja2-cli

Expand All @@ -94,10 +94,14 @@ jinja2 /data/standalone.j2 /variables/variables.yml --format=yml > docker-compos
#### 2. Hybrid call
```
docker run --entrypoint jinja2 \
-v C:\Users\cdinuta\IdeaProjects\jinja2docker\templates:/data \
-v C:\Users\cdinuta\IdeaProjects\jinja2docker\variables:/variables \
-v C:\Users\cdinuta\IdeaProjects\jinja2docker\inputs\templates:/data \
-v C:\Users\cdinuta\IdeaProjects\jinja2docker\inputs\variables:/variables \
dinutac/jinja2docker:latest \
/data/json.j2 /variables/json.json --format=json
```

! observe that jinja2 is called before image name and the arguments after


### 2. Added flask restful server
Info in wiki: https://github.com/dinuta/jinja2docker/wiki
15 changes: 11 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
version: "3"

services:
jinja2docker:
container_name: jinja2docker
image: dinutac/jinja2docker:latest
hostname: jinja2docker
entrypoint: tail -f /etc/alpine-release #keep the container up to use exec command from docker
entrypoint: python3 /home/dev/scripts/main_flask.py
# entrypoint: tail -f /etc/alpine-release
environment:
limit: 'sky' #example env var inserted. you can read it with environ('limit')
volumes:
- ./templates:/data
- ./variables:/variables
- ./:/out
- ./inputs/templates:/data
- ./inputs/variables:/variables
- ./:/home/dev/scripts/
ports:
- "5000:5000"

expose:
- "5000"
Empty file added entitities/__init__.py
Empty file.
14 changes: 6 additions & 8 deletions render.py → entitities/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,10 @@ def rend_template(self, argv):
self.env.globals["environ"] = lambda key: os.environ.get(key)
self.env.globals["get_context"] = lambda: data

template = self.env.get_template(self.template)
sys.stdout.write(template.render(data))
try:
template = self.env.get_template(self.template).render(data)
except Exception as e:
raise e
sys.stdout.write(template)

return template.render(data);


if __name__ == '__main__':
render = Render(os.environ.get('TEMPLATE'), os.environ.get('VARIABLES'))
render.rend_template(sys.argv[1:])
return template
5 changes: 5 additions & 0 deletions inputs/templates/json.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"os": "{{os}}",
"version": {{version}},
"installed_apps": "{{installed_apps}}"
}
File renamed without changes.
3 changes: 3 additions & 0 deletions inputs/templates/yml.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"os": "{{os}}"
"version": {{version}}
"installed_apps": "{{installed_apps}}"
2 changes: 1 addition & 1 deletion variables/json.json → inputs/variables/json.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"os" : "windows",
"os": "windows",
"version": 10,
"installed_apps": "json"
}
File renamed without changes.
File renamed without changes.
10 changes: 10 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env python3

import os
import sys

from entitities.render import Render

if __name__ == '__main__':
render = Render(os.environ.get('TEMPLATE'), os.environ.get('VARIABLES'))
render.rend_template(sys.argv[1:])
7 changes: 7 additions & 0 deletions main_flask.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env python3

from rest.render_flask_app import init_app, app

if __name__ == "__main__":
init_app(app)
app.run(host='0.0.0.0')
14 changes: 14 additions & 0 deletions rest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from flask import Flask

print("Start init")


def create_app():
print("Start init flask!")
app = Flask(__name__, instance_relative_config=False)
app.config.from_object('rest.flask_config.Config')
with app.app_context():
return app


print("End init")
3 changes: 3 additions & 0 deletions rest/flask_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Config:
TESTING = True
FLASK_DEBUG = True
63 changes: 63 additions & 0 deletions rest/render_flask_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import os

from flask import Flask, jsonify, request, Blueprint
from flask_restplus import Api

from entitities.render import Render

env_vars = {
"TEMPLATES_DIR": os.environ.get('TEMPLATES_DIR'),
"VARS_DIR": os.environ.get('VARS_DIR'),
"TEMPLATE": os.environ.get('TEMPLATE'),
"VARIABLES": os.environ.get('VARIABLES'),
"TEMPLATES_DIR_FILES": os.listdir(os.environ.get('TEMPLATES_DIR')),
"VARS_DIR_FILES": os.listdir(os.environ.get('VARS_DIR')),
"PATH": os.environ.get('PATH')
}

app = Flask(__name__)
api = Api(app)


def init_app(flask_app):
blueprint = Blueprint('api', __name__, url_prefix='/api')
api.init_app(blueprint)
flask_app.register_blueprint(blueprint)


# TODO define swagger specs

@app.route('/env')
def get_vars():
return jsonify(env_vars), 200


@app.route('/rend/<template>/<variables>', methods=['GET'])
def get_content(template, variables):
os.environ['TEMPLATE'] = template
os.environ['VARIABLES'] = variables
r = Render(os.environ['TEMPLATE'], os.environ['VARIABLES'])
try:
result = r.rend_template("dummy")
except Exception as e:
result = "Exception({0})".format(e.__str__())

return result, 200


@app.route('/rendwithenv/<template>/<variables>', methods=['POST'])
def get_content_with_env(template, variables):
input_json = request.get_json(force=True)
os.environ['TEMPLATE'] = template
os.environ['VARIABLES'] = variables
for key, value in input_json.items():
if key not in env_vars:
os.environ[key] = value

r = Render(os.environ['TEMPLATE'], os.environ['VARIABLES'])
try:
result = r.rend_template("dummy")
except Exception as e:
result = "Exception({0})".format(e.__str__())

return result, 200
5 changes: 0 additions & 5 deletions templates/json.j2

This file was deleted.

3 changes: 0 additions & 3 deletions templates/yml.j2

This file was deleted.

Empty file added tests/__init__.py
Empty file.
56 changes: 56 additions & 0 deletions tests/flask_rest_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/usr/bin/env python3
import os
import unittest

import requests
import yaml
from flask import json
from parameterized import parameterized


class FlaskServerTestCase(unittest.TestCase):
server = "http://0.0.0.0:5000"

def test_env_endpoint(self):
response = json.loads(requests.get(self.server + "/env").text)
self.assertEqual(len(response), 7)
self.assertEqual(response.get('VARS_DIR'), os.environ['VARS_DIR'])
self.assertEqual(response.get('TEMPLATES_DIR'), os.environ['TEMPLATES_DIR'])

@parameterized.expand([
("json.j2", "json.json"),
("yml.j2", "yml.yml")
])
def test_rend_endpoint(self, template, variables):
response = yaml.load(requests.get(self.server + f"/rend/{template}/{variables}").text)
self.assertEqual(len(response), 3)

@parameterized.expand([
("json.j2", "doesnotexists.json"),
("yml.j2", "doesnotexists.yml")
])
def test_rend_endpoint(self, template, variables):
expected = f"Exception([Errno 2] No such file or directory: \'/variables/{variables}\')"
response = requests.get(self.server + f"/rend/{template}/{variables}").text
self.assertEqual(expected, response)

@parameterized.expand([
("doesnotexists.j2", "json.json"),
("doesnotexists.j2", "yml.yml")
])
def test_rend_endpoint(self, template, variables):
expected = f"Exception({template})"
response = requests.get(self.server + f"/rend/{template}/{variables}").text
self.assertEqual(expected, response)

# @parameterized.expand([
# ("standalone.j2", "variables.yml")
# ])
# def test_rendwithenv_endpoint(self, template, variables):
# payload = {'DATABASE': 'mysql56', 'IMAGE': 'latest'}
# response = yaml.load(requests.post(self.server + f"/rendwithenv/{template}/{variables}", data=payload).text)
# self.assertEqual(len(response), 3)


if __name__ == '__main__':
unittest.main()
13 changes: 8 additions & 5 deletions render_test.py → tests/render_test.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
#!/usr/bin/env python3
import os
import unittest

from render import *
import yaml

from entitities.render import Render


class RenderTestCase(unittest.TestCase):

def test_json(self):
os.environ['TEMPLATE'] = "json.j2";
os.environ['VARIABLES'] = "json.json";
os.environ['TEMPLATE'] = "json.j2"
os.environ['VARIABLES'] = "json.json"
r = Render(os.environ['TEMPLATE'], os.environ['VARIABLES'])

template = yaml.load(r.rend_template("dummy"), Loader=yaml.Loader)
Expand All @@ -19,8 +22,8 @@ def test_json(self):
self.assertEqual(template.get("installed_apps"), data.get("installed_apps"))

def test_yml(self):
os.environ['TEMPLATE'] = "yml.j2";
os.environ['VARIABLES'] = "yml.yml";
os.environ['TEMPLATE'] = "yml.j2"
os.environ['VARIABLES'] = "yml.yml"
r = Render(os.environ['TEMPLATE'], os.environ['VARIABLES'])

template = yaml.load(r.rend_template("dummy"), Loader=yaml.Loader)
Expand Down

0 comments on commit ec55c0d

Please sign in to comment.