MP 6: Building a Microservice from Existing Code
Overview
Welcome to beginning of Act II – we will begin to use the Python programming language to work towards creating cloud-based services for the remaining of the semester.
Many cloud services are wrappers around other tools with easy-to-use API interfaces for users and developers to easily interact with the tools. For this MP, you will create a web service that “wraps” your mp2
solution to create a web-based microservice that will extracts hidden GIFs from within PNGs.
For extra credit, you can place it all in a docker container!
Initial Files
In your CS 240 directory, merge the initial starting files with the following commands:
git fetch release
git merge release/mp6 -m "Merging initial files"
Implementation
We have split the implementation into two parts:
- Implementing a flask-based web service.
- Packaging the above flask-application in a docker container (extra credit).
Part 1: Flask Application
Machine Problem
Complete the app.py
program using the Python flask
library to create a web-based service that accepts a PNG file (as png
in the POST
data) via a HTTP POST
request to /extract
:
- If the PNG file has a hidden GIF image (as defined by mp2), the hidden GIF file is returned.
- If the PNG file does not have a hidden GIF image (or is an invalid PNG file), an
HTTP 500
response is returned with some useful status text.
Installing Python
This MP requires a modern version of Python (ex: 3.8+). If you are running on the VM, follow our guide to getting your VM setup with Python.
Once Python is installed, you will need to install the Python library. Using native Python, this can be done via:
pip install flask
Using flask
For this MP, the complete flask
code is provided for you in the provided app.py
:
from flask import Flask
app = Flask(__name__)
# Route for "/" for a web-based interface to this microservice:
@app.route('/')
def index():
return render_template("index.html")
# Extract a hidden "uiuc" GIF from a PNG image:
@app.route('/extract', methods=["POST"])
def extract_hidden_gif():
# ...your code here...
To run this program, run:
python3.9 -m flask run
(orpython3 -m flask run
on some systems, orpython -m flask run
or the shorthandflask run
) to launch yourapp.py
flask server.- Follow the instructions on the console to view your microservice in your web browser.
Now you need to complete the extract_hidden_gif
to make your microservice work! :)
Using Your MP2
As part of the extract_hidden_gif
, you will need to use your mp2 png-extractGIF
program. You may want to verify that your png-extractGIF
program is complete and functional and that you can run the following commands:
- We have provided a
Makefile
so you can usemake
inmp6
to compilepng-extractGIF
. This uses your code from yourmp2
directory. - Testing using a PNG with a hidden GIF:
./png-extractGIF sample/waf.png taylor.gif
. (This should successfully savetaylor.gif
.) - Testing using a PNG without a
uiuc
chunk:./png-extractGIF sample/no-uiuc-chunk.png nothing.gif
. (This should run, not crash, and probably return a non-zero value frommain
.)
You may need to modify your MP2 program slightly to fix any bugs to ensure your program can work with your new microservice.
Useful Python Functions
There will be a few tasks you will need to complete in Python:
- You will need to save the contents of the
POST
request (the.png
file). For this purpose, your application should create atemp
directory if it doesn’t exist, so you can save the contents in this directory with a unique filename.- You can use the python
os.makedirs
function. - The contents of the data sent via
POST
is stored by flask in the variablerequest.files['png']
. - You can find many examples of reading and writing files in Python via a search.
- You can use the python
-
You will need to programmatically run your
./png-extractGIF
program. To do this, you will likely use the pythonos.system
function. This function will return the exit value frompng-extractGIF
. If you followed our code style, the exit value should be0
on success and non-zero on failure. -
Once you have the GIF file saved, you will likely want to use flask’s
send_file
function to send the GIF file. - If anything goes wrong, you can
return "Error Message", 500
to return an error (but change “Error Message” to something useful).
Testing Your Microservice
You can test your program in two different ways:
-
By using your web browser and visiting your flask server (ex:
http://127.0.0.1:5000/
). -
By the command line, using
curl
to make a request to your web server:curl -f -o output.gif http://localhost:5000/extract -F "png=@sample/waf.png"
- You can replace
@sample/waf.png
with another file. Ensure that you keep the@
symbol to tellcurl
to send the contents of the file. - You should inspect
output.gif
to ensure the extraction was successful. - Make sure that you get an error when sending it an invalid PNG file.
- Make sure you also get an error when sending it a PNG file without a hidden
uiuc
chunk.
- You can replace
Extra Credit: Packaging as a Docker Container
For +5 extra credit points, you will wrap your above flask application in a docker container.
Machine Problem
You need to complete the Dockerfile
that will run your flask application in a container. Specifically, it must:
- Launch the
png_microservice
- Be accessible on the host computer at
http://127.0.0.1:5000/
just like you weren’t running in docker.
Installing Docker
You will need to have docker
to complete this extra credit. The easiest way to install docker
is to download the free Docker Desktop.
Building and Running the Docker
You need to make sure you specify the correct DOCKER_BUILD_COMMAND
and DOCKER_RUN_COMMAND
in the .env
file. We will use the command specified in the .env
file to launch your docker container.
Running Tests
Run pytest test_docker.py
to run tests corresponding to the docker container.
Note: Running these tests locally will require you to install other python dependencies included in the requirements.txt
. You can install these python libraries using pip install -r requirements.txt
.
Note: The test script doesn’t automatically kill the docker container it launches. Once you run the tests for the docker container, run docker container ls
to identify the container name and then run docker kill <container-name>
to kill the corresponding container, otherwise you might get an error saying the port is already occupied.
Submit
When you have completed your program, double-check that your server runs as expected with a GIF image that has hidden data and a GIF image without hidden data. When you are ready, submit the code via the following git commands:
Note: Please run make clean
before submitting your code.
git add -u
git commit -m "MP6 submission"
git push origin master
You can verify your code was successfully submitted by viewing your git repo on https://github.com.