diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 000000000..26d33521a
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/devops-programme.iml b/.idea/devops-programme.iml
new file mode 100644
index 000000000..d6ebd4805
--- /dev/null
+++ b/.idea/devops-programme.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 000000000..639900d13
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 000000000..02f085c8d
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 000000000..35eb1ddfb
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.python-version b/.python-version
new file mode 100644
index 000000000..9919bf8c9
--- /dev/null
+++ b/.python-version
@@ -0,0 +1 @@
+3.10.13
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 000000000..2dd51b10a
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,9 @@
+FROM ubuntu:22.04
+
+RUN apt-get update && apt-get install -y python3 python3-pip && mkdir /app
+COPY requirements.txt /app/
+RUN pip3 install -r /app/requirements.txt
+WORKDIR /app
+COPY ./app /app
+
+CMD ["python3", "app.py"]
\ No newline at end of file
diff --git a/M1-3-Ansible/README.md b/M1-3-Ansible/README.md
new file mode 100644
index 000000000..26353f0b2
--- /dev/null
+++ b/M1-3-Ansible/README.md
@@ -0,0 +1,30 @@
+# M1-3-1 Configuration Management
+
+## Ansible Task
+Create an Ansible playbook that build, push and then run the Docker image for the Python application. Let your playbook has the following variables:
+
+- `image_name` - contains the name of your image without the tag, i.e. `vutoff/python-app`
+- `image_tag` - contains the tag you tagged your image with, i.e. `v0.2`
+- `listen_port` - contains the listening port you're binding your app to.
+
+Make sure that you set environment variable `PORT` when you define your container in the Ansible playbook that takes its value from `listen_port` variable.
+
+Use Ansible modules. Do not shell out.
+
+### Requirements
+- Make sure you have Python installed. Any version above 3.8 would suffice.
+- The `requirements.txt` file in this directory contains the required Ansible version. Run
+
+```sh
+pip install -r requirements.txt
+```
+
+- Make sure that Docker is running on your local machine.
+
+### Mind the following
+
+- If you're running Docker Desktop or Rancher Desktop, mind the location of the `docker.sock` file. The location of the socket file is
+ - Docker Desktop - `${HOME}/.docker/run/docker.sock`
+ - Rancher DEsktop - ${HOME}/.rd/run/docker.sock
+
+- If you're using one of the above, when you write your Ansible playbook you must specify the path to the docker socket with the parameter `docker_host`, i.e. `docker_host: "unix://{{ ansible_env.HOME }}/.rd/docker.sock"`.
\ No newline at end of file
diff --git a/M1-3-Ansible/requirements.txt b/M1-3-Ansible/requirements.txt
new file mode 100644
index 000000000..03a81f309
--- /dev/null
+++ b/M1-3-Ansible/requirements.txt
@@ -0,0 +1,2 @@
+ansible==8.5.0
+ansible-core==2.15.5
diff --git a/app/app.py b/app/app.py
new file mode 100644
index 000000000..1c2c83d55
--- /dev/null
+++ b/app/app.py
@@ -0,0 +1,14 @@
+import os
+
+from flask import Flask
+
+app = Flask(__name__)
+
+
+@app.route("/")
+def hello_world():
+ return "Hello, World!"
+
+
+if __name__ == "__main__":
+ app.run(port=os.environ.get("PORT", 5000), host="0.0.0.0")
diff --git a/app/app_test.py b/app/app_test.py
new file mode 100644
index 000000000..a1b1bacb2
--- /dev/null
+++ b/app/app_test.py
@@ -0,0 +1,17 @@
+import unittest
+
+from app import app
+
+
+class TestApp(unittest.TestCase):
+ def setUp(self):
+ self.client = app.test_client()
+
+ def test_hello_world(self):
+ response = self.client.get("/")
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.data, b"Hello, World!")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 000000000..75cb9a31a
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,8 @@
+blinker==1.6.3 ; python_version >= "3.10" and python_version < "4.0"
+click==8.1.7 ; python_version >= "3.10" and python_version < "4.0"
+colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
+flask==3.0.0 ; python_version >= "3.10" and python_version < "4.0"
+itsdangerous==2.1.2 ; python_version >= "3.10" and python_version < "4.0"
+jinja2==3.1.2 ; python_version >= "3.10" and python_version < "4.0"
+markupsafe==2.1.3 ; python_version >= "3.10" and python_version < "4.0"
+werkzeug==3.0.0 ; python_version >= "3.10" and python_version < "4.0"