Add another flask exercise

This commit is contained in:
abregman 2020-01-16 23:50:49 +02:00
parent 24edb687e4
commit 85d8a566d1
10 changed files with 201 additions and 57 deletions

View File

@ -4,7 +4,7 @@
:bar_chart:  There are currently **834** questions :bar_chart:  There are currently **834** questions
:warning:  These are not interview questions and most of them shouldn't be used as interview questions. Please read [Q&A](common-qa.md) for more details :warning:  You can use these for preparing for an interview but most of the questions and exercises don't represent an actual interview. Please read [Q&A](common-qa.md) for more details
:thought_balloon:  If you wonder "How to prepare for a DevOps interview?", you might want to read some of my suggestions [here](prepare_for_interview.md) :thought_balloon:  If you wonder "How to prepare for a DevOps interview?", you might want to read some of my suggestions [here](prepare_for_interview.md)
@ -6125,11 +6125,12 @@ Below you can find several exercises
* [Jenkins: writing pipelines](exercises/jenkins_pipelines.md) * [Jenkins: writing pipelines](exercises/jenkins_pipelines.md)
* [CI for open source project](exercises/ci_for_open_source_project.md) * [CI for open source project](exercises/ci_for_open_source_project.md)
* [Flask, Containers and CI](exercises/flask_container_ci/README.md) * [Flask, Containers and CI](exercises/flask_container_ci/README.md)
* [Flask, Containers and CI 2](exercises/flask_container_ci2/README.md)
## Credits ## Credits
Thanks to all of our amazing [contributors](https://github.com/bregman-arie/devops-exercises/graphs/contributors) who make it easy for everyone to learn and prepare to their interviews. Thanks to all of our amazing [contributors](https://github.com/bregman-arie/devops-exercises/graphs/contributors) who make it easy for everyone to learn new things :)
Logos credits can be found [here](credits.md) Logos credits can be found [here](credits.md)

View File

@ -1,6 +1,8 @@
Your mission, should you choose to accept it, involves fixing the app in this directory, containerize it and set up a CI for it. Your mission, should you choose to accept it, involves fixing the app in this directory, containerize it and set up a CI for it.
Please read carefully all the instructions. Please read carefully all the instructions.
If any of the following steps is not working, it is expected from you to fix them
## Installation ## Installation
1. Create a virtual environment with `python3 -m venv challenge_venv` 1. Create a virtual environment with `python3 -m venv challenge_venv`
@ -9,8 +11,6 @@ Please read carefully all the instructions.
## Run the app ## Run the app
If any of the following steps is not working, it is expected from you to fix them
1. Move to `challenges/flask_container_ci` directory, if you are not already there 1. Move to `challenges/flask_container_ci` directory, if you are not already there
1. Run `export FLASK_APP=app/main.py` 1. Run `export FLASK_APP=app/main.py`
1. To run the app execute `flask run`. If it doesn't works, fix it 1. To run the app execute `flask run`. If it doesn't works, fix it

View File

@ -1,53 +0,0 @@
#!/usr/bin/env python
# coding=utf-8
from flask import Flask
from flask import make_response
import json
from werkzeug.exceptions import NotFound
app = Flask(__name__)
with open("./users.json", "r") as f:
users = json.load(f)
@app.routee("/", methods=['GET'])
def index():
return pretty_json({
"resources": {
"users": "/users",
"user": "/users/<username>",
},
"current_uri": "/"
})
@app.route("/users", methods=['GET'])
def all_users():
return pretty_json(users)
@app.route("/users/<username>", methods=['GET'])
def user_data(username):
if username not in users:
raise NotFound
return pretty_json(users[username])
@app.route("/users/<username>/something", methods=['GET'])
def user_something(username):
raise NotImplementedError()
def pretty_json(arg):
response = make_response(json.dumps(arg, sort_keys=True, indent=4))
response.headers['Content-type'] = "application/json"
return response
if __name__ == "__main__":
app.run(port=5000)

View File

@ -0,0 +1,79 @@
Your mission, should you choose to accept it, involves developing an app, containerize it and set up a CI for it.
Please read carefully all the instructions.
If any of the following steps is not working, it is expected from you to fix them
## Installation
1. Create a virtual environment with `python3 -m venv challenge_venv`
2. Activate it with `source challenge_venv/bin/activate`
3. Install the requirements in this directory `pip install -r requirements.txt`
## Run the app
1. Move to `challenges/flask_container_ci` directory, if you are not already there
1. Run `export FLASK_APP=app/main.py`
1. To run the app execute `flask run`. If it doesn't works, fix it
3. Access `http://127.0.0.1:5000`. You should see the following
```
{
"current_uri": "/",
"example": "/matrix/'123n456n789'",
"resources": {
"column": "/columns/<matrix>/<column_number>",
"matrix": "/matrix/<matrix>",
"row": "/rows/<matrix>/<row_number>"
}
}
```
4. You should be able to access any of the resources and get the following data:
* /matrix/\<matrix\>
for example, for /matrix/123n456n789 the user will get:
1 2 3
4 5 6
7 8 9
* /matrix/\<matrix\>/\<column_number\>
for example, for /matrix/123n456n789/2 the user will get:
2
5
8
* /matrix/\<matrix\>/\<row_number\>
for example, for /matrix/123n456n789/1 the user will get:
1 2 3
## Containers
Using Docker or Podman, containerize the flask app so users can run the following two commands:
```
docker build -t app:latest /path/to/Dockerfile
docker run -d -p 5000:5000 app
```
1. You can use any image base you would like
2. Containerize only what you need for running the application, nothing else.
## CI
Great, now that we have a working app and also can run it in a container, let's set up a CI for it so it won't break again in the future
In current directory you have a file called tests.py which includes the tests for the app. What is required from you, is:
1. Write a CI pipeline that will run the app tests. You are free to choose whatever CI system or service you prefer. Use `python tests.py` for running the tests.
2. There should be some kind of test for the Dockerfile you wrote
3. Add additional unit test (or any other level of tests) for testing the app
### Guidelines
* Except the app functionality, you can change whatever you want - structure, tooling, libraries, ... If possible, add `notes.md` file which explains reasons, logic, thoughts and anything else you would like to share
* The CI part should include the source code for the pipeline definition

View File

@ -0,0 +1,2 @@
#!/usr/bin/env python
# coding=utf-8

View File

@ -0,0 +1,11 @@
#!/usr/bin/env python
# coding=utf-8
import os
basedir = os.path.abspath(os.path.dirname(__file__))
SECRET_KEY = 'shhh'
CSRF_ENABLED = True
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db')

View File

@ -0,0 +1,50 @@
#!/usr/bin/env python
# coding=utf-8
from flask import Flask
from flask import make_response
import json
app = Flask(__name__)
@app.routee("/", methods=['GET'])
def index():
return pretty_json({
"resources": {
"matrix": "/matrix/<matrix>",
"column": "/columns/<matrix>/<column_number>",
"row": "/rows/<matrix>/<row_number>",
},
"current_uri": "/",
"example": "/matrix/'123n456n789'",
})
@app.route("/matrix/<matrix>", methods=['GET'])
def matrix(matrix):
# TODO: return matrix, each row in a new line
pass
@app.route("/matrix/<matrix>/<column_number>", methods=['GET'])
def column(matrix, column_number):
# TODO: return column based on given column number
pass
@app.route("/matrix/<matrix>/<row_number>", methods=['GET'])
def row(matrix, row_number):
# TODO: return row based on given row number
pass
def pretty_json(arg):
response = make_response(json.dumps(arg, sort_keys=True, indent=4))
response.headers['Content-type'] = "application/json"
return response
if __name__ == "__main__":
app.run(port=5000)

View File

@ -0,0 +1,28 @@
#!/usr/bin/env python
# coding=utf-8
import os
import unittest
from config import basedir
from app import app
from app import db
class TestCase(unittest.TestCase):
def setUp(self):
app.config['TESTING'] = True
app.config['WTF_CSRF_ENABLED'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(
basedir, 'test.db')
self.app = app.test_client()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
if __name__ == '__main__':
unittest.main()

View File

@ -0,0 +1 @@
flask

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python
# coding=utf-8
import unittest
from app import main
class TestCase(unittest.TestCase):
def setUp(self):
self.app = main.app.test_client()
def test_main_page(self):
response = self.app.get('/', follow_redirects=True)
self.assertEqual(response.status_code, 200)
def test_matrix(self):
response = self.app.get('/matrix/123n459,789', follow_redirects=True)
# Change when the matrix route is fixed and returning the actual matrix
self.assertEqual(response.status_code, 500)
if __name__ == '__main__':
unittest.main()