├── Week 2
├── Docker Practice
│ ├── requirements.txt
│ ├── Answer
│ │ └── Dockerfile
│ ├── Dockerfile
│ ├── app.py
│ ├── test_app.py
│ └── README.md
├── DevOps Foundations-Session 2 Slides.pdf
└── README.md
├── Week 1
├── GitHub Actions Practice
│ ├── requirements.txt
│ ├── app.py
│ ├── Answer
│ │ ├── app.py
│ │ ├── test_app.py
│ │ └── github-ci.yml
│ ├── .github
│ │ └── workflows
│ │ │ └── github-ci.yml
│ ├── test_app.py
│ └── README.md
├── GitLab CI CD Practice
│ ├── requirements.txt
│ ├── .gitlab-ci.yml
│ ├── app.py
│ ├── Answer
│ │ ├── app.py
│ │ ├── test_app.py
│ │ └── .gitlab-ci.yml
│ ├── test_app.py
│ └── README.md
├── DevOps Foundations-Session 1 Slides.pdf
└── README.md
├── Project
├── frontend
│ ├── public
│ │ ├── robots.txt
│ │ ├── favicon.ico
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── calculator.jpg
│ │ ├── manifest.json
│ │ └── index.html
│ ├── src
│ │ ├── setupTests.js
│ │ ├── App.test.js
│ │ ├── index.css
│ │ ├── reportWebVitals.js
│ │ ├── index.js
│ │ ├── App.css
│ │ ├── logo.svg
│ │ └── App.js
│ ├── .gitignore
│ ├── Dockerfile
│ ├── Hint
│ │ └── Dockerfile
│ ├── package.json
│ └── README.md
├── backend
│ ├── Dockerfile
│ ├── Hint
│ │ └── Dockerfile
│ ├── README.md
│ └── app.py
├── .gitlab-ci.yml
├── github-actions.yml
├── docker-compose.yaml
├── SUBMISSION_README.md
└── README.md
├── Week 3
├── DevOps Foundations-Session 3 Slides.pdf
└── README.md
├── README.md
└── Practice Quizes
└── README.md
/Week 2/Docker Practice/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask
2 | pytest
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask
2 | pytest
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/requirements.txt:
--------------------------------------------------------------------------------
1 | Flask
2 | pytest
--------------------------------------------------------------------------------
/Project/frontend/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/Project/frontend/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiftkey-labs/DevOps-Foundations-Course/HEAD/Project/frontend/public/favicon.ico
--------------------------------------------------------------------------------
/Project/frontend/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiftkey-labs/DevOps-Foundations-Course/HEAD/Project/frontend/public/logo192.png
--------------------------------------------------------------------------------
/Project/frontend/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiftkey-labs/DevOps-Foundations-Course/HEAD/Project/frontend/public/logo512.png
--------------------------------------------------------------------------------
/Project/frontend/public/calculator.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiftkey-labs/DevOps-Foundations-Course/HEAD/Project/frontend/public/calculator.jpg
--------------------------------------------------------------------------------
/Week 1/DevOps Foundations-Session 1 Slides.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiftkey-labs/DevOps-Foundations-Course/HEAD/Week 1/DevOps Foundations-Session 1 Slides.pdf
--------------------------------------------------------------------------------
/Week 2/DevOps Foundations-Session 2 Slides.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiftkey-labs/DevOps-Foundations-Course/HEAD/Week 2/DevOps Foundations-Session 2 Slides.pdf
--------------------------------------------------------------------------------
/Week 3/DevOps Foundations-Session 3 Slides.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shiftkey-labs/DevOps-Foundations-Course/HEAD/Week 3/DevOps Foundations-Session 3 Slides.pdf
--------------------------------------------------------------------------------
/Project/frontend/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/Project/frontend/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/Project/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/Project/frontend/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/Project/frontend/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/Project/backend/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use an official Python runtime as a parent image
2 |
3 | # Set the working directory in the container
4 |
5 | # Copy the current directory contents into the container at /app
6 |
7 | # Install any needed packages specified in requirements.txt
8 |
9 | # Make port 5000 available to the world outside this container
10 |
11 | # Define environment variable
12 |
13 | # Run app.py when the container launches
14 |
15 | # End of File
--------------------------------------------------------------------------------
/Project/frontend/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use an official Node runtime as a parent image
2 |
3 | # Set the working directory in the container
4 |
5 | # Copy package.json and package-lock.json
6 |
7 | # Install app dependencies
8 |
9 | # Copy the current directory contents into the container
10 |
11 | # Build the app
12 |
13 | # Make port 3000 available to the world outside this container
14 |
15 | # Define environment variable
16 |
17 | # Run the app when the container launches
18 |
--------------------------------------------------------------------------------
/Week 2/Docker Practice/Answer/Dockerfile:
--------------------------------------------------------------------------------
1 | # TODO-STEP 1: Choose a base image
2 | FROM python:3.9-slim
3 |
4 | # TODO-STEP 2: Set the working directory
5 | WORKDIR /app
6 |
7 | # TODO-STEP 3: Copy the requirements file
8 | COPY requirements.txt .
9 |
10 | # TODO-STEP 4: Install the Python dependencies
11 | RUN pip install -r requirements.txt
12 |
13 | # TODO-STEP 5: Copy the application code
14 | COPY app.py .
15 |
16 | # TODO-STEP 6: Specify the command to run the application
17 | CMD ["python", "app.py"]
--------------------------------------------------------------------------------
/Project/backend/Hint/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use an official Python runtime as a parent image
2 | FROM
3 |
4 | # Set the working directory in the container
5 | WORKDIR
6 |
7 | # Copy the current directory contents into the container at /app
8 | COPY
9 |
10 | # Install any needed packages specified in requirements.txt
11 | RUN
12 |
13 | # Make port 5000 available to the world outside this container
14 | EXPOSE
15 |
16 | # Define environment variable
17 | ENV
18 |
19 | # Run app.py when the container launches
20 | CMD
--------------------------------------------------------------------------------
/Week 2/Docker Practice/Dockerfile:
--------------------------------------------------------------------------------
1 | # TODO-STEP 1: Choose a base image
2 | FROM
3 |
4 | # TODO-STEP 2: Set the working directory
5 | WORKDIR
6 |
7 | # TODO-STEP 3: Copy the requirements file
8 | COPY
9 |
10 | # TODO-STEP 4: Install the Python dependencies
11 | RUN
12 |
13 | # TODO-STEP 5: Copy the application code
14 | COPY
15 |
16 | # TODO-STEP 6: Specify the command to run the application
17 | CMD
--------------------------------------------------------------------------------
/Project/frontend/Hint/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use an official Node runtime as a parent image
2 | FROM
3 |
4 | # Set the working directory in the container
5 | WORKDIR
6 |
7 | # Copy package.json and package-lock.json
8 | COPY
9 |
10 | # Install app dependencies
11 | RUN
12 |
13 | # Copy the current directory contents into the container
14 | COPY
15 |
16 | # Build the app
17 | RUN
18 |
19 | # Make port 3000 available to the world outside this container
20 | EXPOSE
21 |
22 | # Define environment variable
23 | ENV
24 |
25 | # Run the app when the container launches
26 | CMD
--------------------------------------------------------------------------------
/Project/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | const root = ReactDOM.createRoot(document.getElementById('root'));
8 | root.render(
9 |
10 |
11 |
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/Project/frontend/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "Calculator App",
3 | "name": "DevOps Foundaitons Course- Calculator App",
4 | "icons": [
5 | {
6 | "src": "calculator.jpg",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "calculator.jpg",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "calculator.jpg",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/Project/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "calculator-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^5.17.0",
7 | "@testing-library/react": "^13.4.0",
8 | "@testing-library/user-event": "^13.5.0",
9 | "axios": "^1.7.7",
10 | "react": "^18.3.1",
11 | "react-dom": "^18.3.1",
12 | "react-scripts": "5.0.1",
13 | "web-vitals": "^2.1.4"
14 | },
15 | "scripts": {
16 | "start": "react-scripts start",
17 | "build": "react-scripts build",
18 | "test": "react-scripts test",
19 | "eject": "react-scripts eject"
20 | },
21 | "eslintConfig": {
22 | "extends": [
23 | "react-app",
24 | "react-app/jest"
25 | ]
26 | },
27 | "browserslist": {
28 | "production": [
29 | ">0.2%",
30 | "not dead",
31 | "not op_mini all"
32 | ],
33 | "development": [
34 | "last 1 chrome version",
35 | "last 1 firefox version",
36 | "last 1 safari version"
37 | ]
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Project/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | # TODO: Define stages for your pipeline
2 | stages:
3 |
4 | # TODO: Define variables (if needed)
5 | variables:
6 |
7 | # TODO: Define a job for building the frontend
8 | frontend-job:
9 | stage: # TODO: Specify stage
10 | image: # TODO: Specify Node.js image
11 | script:
12 | # TODO: Install dependencies
13 | # TODO: Build the React app
14 |
15 | # TODO: Define a job for building and testing the backend
16 | backend-job:
17 | stage: # TODO: Specify stage
18 | image: # TODO: Specify Python image
19 | script:
20 | # TODO: Install dependencies
21 | # TODO: Run tests
22 |
23 | # TODO: Define a job for building Docker images
24 | docker-build:
25 | stage: # TODO: Specify stage
26 | image: docker:latest
27 | services:
28 | - docker:dind
29 | script:
30 | # TODO: Build frontend Docker image
31 | # TODO: Build backend Docker image
32 | # TODO: Push images to Docker Hub (if on main branch)
33 |
34 | # OPTIONAL: Define a deployment job (if applicable)
35 | deploy:
36 | stage: # TODO: Specify stage
37 | script:
38 | # TODO: Add deployment steps
39 |
--------------------------------------------------------------------------------
/Project/github-actions.yml:
--------------------------------------------------------------------------------
1 | # TODO: Define the Workflow Name
2 | name:
3 |
4 | # TODO: Define triggers for the workflow
5 | on:
6 | # push:
7 | # branches:
8 | # pull_request:
9 | # branches:
10 |
11 | jobs:
12 | # TODO: Define a job for building and testing the frontend
13 | frontend:
14 | runs-on: ubuntu-latest
15 | steps:
16 | # TODO: Checkout code
17 | # TODO: Setup Node.js
18 | # TODO: Install dependencies
19 | # TODO: Run tests
20 | # TODO: Build the React app
21 |
22 | # TODO: Define a job for building and testing the backend
23 | backend:
24 | runs-on: ubuntu-latest
25 | steps:
26 | # TODO: Checkout code
27 | # TODO: Setup Python
28 | # TODO: Install dependencies
29 | # TODO: Run tests
30 |
31 | # TODO: Define a job for building and pushing Docker images
32 | docker:
33 | # Run this job only when 'frontend' & 'backend' stages are sucessfully completed
34 | needs:
35 | runs-on: ubuntu-latest
36 | steps:
37 | # TODO: Checkout code
38 | # TODO: Setup Docker
39 | # TODO: Build frontend Docker image
40 | # TODO: Build backend Docker image
41 | # TODO: Push images to Docker Hub (if on main branch)
42 |
43 | # OPTIONAL: Define a deployment job (if applicable)
44 | deploy:
45 | needs: docker
46 | runs-on: ubuntu-latest
47 | steps:
48 | # TODO: Add deployment steps
49 |
--------------------------------------------------------------------------------
/Project/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | # This is just a template placeholder docker-compose file. Use relevant sections which are applicable,
2 | # and feel free to customize.
3 | version: '3'
4 |
5 | services:
6 | frontend:
7 | # Specify the build context for the frontend
8 | build:
9 | # Map the host port to the container port
10 | ports:
11 | # Specify dependencies (if applicable)
12 | depends_on:
13 |
14 | # Additional options (uncomment and configure as needed):
15 |
16 | # Specify environment variables if needed
17 | # environment:
18 |
19 | # Specify volume for live code reloading (optional)
20 | # volumes:
21 |
22 | # Specify the command to run the development server (if different from Dockerfile)
23 | # command:
24 |
25 | backend:
26 | # Specify the build context for the backend
27 | build:
28 | # Map the host port to the container port
29 | ports:
30 |
31 | # Additional options (uncomment and configure as needed):
32 |
33 | # Specify environment variables if needed
34 | # environment:
35 |
36 | # Specify volume for live code reloading (optional)
37 | # volumes:
38 |
39 | # Specify the command to run the development server (if different from Dockerfile)
40 | # command:
41 |
42 | # Additional components (uncomment and configure as needed):
43 | # Define a custom network (if applicable)
44 | # networks:
45 |
46 | # Define volumes (if applicable)
47 | # volumes:
48 |
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | # TODO-STEP 1: Define the stages of the CI/CD pipeline
2 | # Uncomment the following lines and replace with appropriate stage names
3 | # For this exercise, we will use 'build' and 'test' stages
4 | stages:
5 | #-
6 | #-
7 |
8 | # Build stage
9 | # TODO-STEP 2: Create your "Build" stage
10 | # Uncomment the following line and give your job a descriptive name
11 | #:
12 | # TODO-STEP 2a: Specify the stage for this job
13 | #stage:
14 | image: python:3.9 # Do not change this. Keep this as is.
15 | script:
16 | - echo "Installing dependencies..."
17 | # TODO-STEP 2b: Add command to install dependencies
18 | # Hint: Use pip to install packages from requirements.txt
19 | #- pip install -r .txt
20 |
21 | # Test stage
22 | # TODO-STEP 3: Create your "Test" stage
23 | # Uncomment the following line and give your job a descriptive name
24 | #:
25 | # TODO-STEP 3a: Specify the stage for this job
26 | #stage:
27 | image: python:3.9 # Do not change this. Keep this as is.
28 | script:
29 | - echo "Running tests..."
30 | - pip install -r requirements.txt
31 | # TODO-STEP 3b: Add command to run tests
32 | # Hint: Write 'pytest' to automatically execute your test cases in the 'test_app.py' file.
33 | #-
34 |
35 | # Remember to remove the '#' symbol to uncomment lines when filling in the placeholders
--------------------------------------------------------------------------------
/Week 2/Docker Practice/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 |
3 |
4 | app = Flask(__name__)
5 |
6 |
7 | @app.route('/api/test')
8 | def hello():
9 | return {'message': 'Hello World!'}
10 |
11 |
12 | # Addition operation
13 | @app.route('/api/add', methods=['POST'])
14 | def add():
15 | data_request = request.get_json()
16 | if (not data_request or 'number_1' not in data_request or
17 | 'number_2' not in data_request):
18 | return jsonify({'error': 'Invalid input'}), 400
19 |
20 | number_1 = float(data_request['number_1'])
21 | number_2 = float(data_request['number_2'])
22 | result = number_1 + number_2
23 | return jsonify({'result': result})
24 |
25 |
26 | # Optional: Completing the following TODOs is optional for more practice
27 |
28 | # TODO: Implement the 'multiplication operation'
29 | # @app.route('/api/multiply', methods=['POST'])
30 | # def multiply():
31 | # data_request = request.get_json()
32 | # # Check if the input is valid
33 | # # Perform multiplication
34 | # # Return the result
35 |
36 | # TODO: Implement the 'subtraction operation'
37 | # @app.route('/api/subtract', methods=['POST'])
38 | # def subtract():
39 | # # Write code here
40 |
41 | # TODO: Implement the 'division operation'
42 | # @app.route('/api/divide', methods=['POST'])
43 | # def divide():
44 | # # Write code here
45 |
46 | # TODO: Add more routes and operations! Create your own calculator!
47 | # For example:
48 | # - Square root
49 | # - Exponentiation
50 | # - Trigonometric functions (sin, cos, tan)
51 | # - Logarithms
52 |
53 | if __name__ == '__main__':
54 | app.run(host='0.0.0.0', port=5000)
55 |
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 |
3 |
4 | app = Flask(__name__)
5 |
6 |
7 | @app.route('/api/test')
8 | def hello():
9 | return {'message': 'Hello World!'}
10 |
11 |
12 | # Addition operation
13 | @app.route('/api/add', methods=['POST'])
14 | def add():
15 | data_request = request.get_json()
16 | if (not data_request or 'number_1' not in data_request or
17 | 'number_2' not in data_request):
18 | return jsonify({'error': 'Invalid input'}), 400
19 |
20 | number_1 = float(data_request['number_1'])
21 | number_2 = float(data_request['number_2'])
22 | result = number_1 + number_2
23 | return jsonify({'result': result})
24 |
25 |
26 | # Optional: Completing the following TODOs is optional for more practice
27 |
28 | # TODO: Implement the 'multiplication operation'
29 | # @app.route('/api/multiply', methods=['POST'])
30 | # def multiply():
31 | # data_request = request.get_json()
32 | # # Check if the input is valid
33 | # # Perform multiplication
34 | # # Return the result
35 |
36 | # TODO: Implement the 'subtraction operation'
37 | # @app.route('/api/subtract', methods=['POST'])
38 | # def subtract():
39 | # # Write code here
40 |
41 | # TODO: Implement the 'division operation'
42 | # @app.route('/api/divide', methods=['POST'])
43 | # def divide():
44 | # # Write code here
45 |
46 | # TODO: Add more routes and operations! Create your own calculator!
47 | # For example:
48 | # - Square root
49 | # - Exponentiation
50 | # - Trigonometric functions (sin, cos, tan)
51 | # - Logarithms
52 |
53 | if __name__ == '__main__':
54 | app.run(host='0.0.0.0', port=5000)
55 |
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 |
3 |
4 | app = Flask(__name__)
5 |
6 |
7 | @app.route('/api/test')
8 | def hello():
9 | return {'message': 'Hello World!'}
10 |
11 |
12 | # Addition operation
13 | @app.route('/api/add', methods=['POST'])
14 | def add():
15 | data_request = request.get_json()
16 | if (not data_request or 'number_1' not in data_request or
17 | 'number_2' not in data_request):
18 | return jsonify({'error': 'Invalid input'}), 400
19 |
20 | number_1 = float(data_request['number_1'])
21 | number_2 = float(data_request['number_2'])
22 | result = number_1 + number_2
23 | return jsonify({'result': result})
24 |
25 |
26 | # Optional: Completing the following TODOs is optional for more practice
27 |
28 | # TODO: Implement the 'multiplication operation'
29 | # @app.route('/api/multiply', methods=['POST'])
30 | # def multiply():
31 | # data_request = request.get_json()
32 | # # Check if the input is valid
33 | # # Perform multiplication
34 | # # Return the result
35 |
36 | # TODO: Implement the 'subtraction operation'
37 | # @app.route('/api/subtract', methods=['POST'])
38 | # def subtract():
39 | # # Write code here
40 |
41 | # TODO: Implement the 'division operation'
42 | # @app.route('/api/divide', methods=['POST'])
43 | # def divide():
44 | # # Write code here
45 |
46 | # TODO: Add more routes and operations! Create your own calculator!
47 | # For example:
48 | # - Square root
49 | # - Exponentiation
50 | # - Trigonometric functions (sin, cos, tan)
51 | # - Logarithms
52 |
53 | if __name__ == '__main__':
54 | app.run(host='0.0.0.0', port=5000)
55 |
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/Answer/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 |
3 |
4 | app = Flask(__name__)
5 |
6 |
7 | @app.route('/api/test')
8 | def hello():
9 | return {'message': 'Hello World!'}
10 |
11 |
12 | # Addition operation
13 | @app.route('/api/add', methods=['POST'])
14 | def add():
15 | data_request = request.get_json()
16 | if (not data_request or 'number_1' not in data_request or
17 | 'number_2' not in data_request):
18 | return jsonify({'error': 'Invalid input'}), 400
19 |
20 | number_1 = float(data_request['number_1'])
21 | number_2 = float(data_request['number_2'])
22 | result = number_1 + number_2
23 | return jsonify({'result': result})
24 |
25 |
26 | # Optional: Completing the following TODOs is optional for more practice
27 |
28 | # TODO: Implement the 'multiplication operation'
29 | # @app.route('/api/multiply', methods=['POST'])
30 | # def multiply():
31 | # data_request = request.get_json()
32 | # # Check if the input is valid
33 | # # Perform multiplication
34 | # # Return the result
35 |
36 | # TODO: Implement the 'subtraction operation'
37 | # @app.route('/api/subtract', methods=['POST'])
38 | # def subtract():
39 | # # Write code here
40 |
41 | # TODO: Implement the 'division operation'
42 | # @app.route('/api/divide', methods=['POST'])
43 | # def divide():
44 | # # Write code here
45 |
46 | # TODO: Add more routes and operations! Create your own calculator!
47 | # For example:
48 | # - Square root
49 | # - Exponentiation
50 | # - Trigonometric functions (sin, cos, tan)
51 | # - Logarithms
52 |
53 | if __name__ == '__main__':
54 | app.run(host='0.0.0.0', port=5000)
55 |
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/Answer/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 |
3 |
4 | app = Flask(__name__)
5 |
6 |
7 | @app.route('/api/test')
8 | def hello():
9 | return {'message': 'Hello World!'}
10 |
11 |
12 | # Addition operation
13 | @app.route('/api/add', methods=['POST'])
14 | def add():
15 | data_request = request.get_json()
16 | if (not data_request or 'number_1' not in data_request or
17 | 'number_2' not in data_request):
18 | return jsonify({'error': 'Invalid input'}), 400
19 |
20 | number_1 = float(data_request['number_1'])
21 | number_2 = float(data_request['number_2'])
22 | result = number_1 + number_2
23 | return jsonify({'result': result})
24 |
25 |
26 | # Optional: Completing the following TODOs is optional for more practice
27 |
28 | # TODO: Implement the 'multiplication operation'
29 | # @app.route('/api/multiply', methods=['POST'])
30 | # def multiply():
31 | # data_request = request.get_json()
32 | # # Check if the input is valid
33 | # # Perform multiplication
34 | # # Return the result
35 |
36 | # TODO: Implement the 'subtraction operation'
37 | # @app.route('/api/subtract', methods=['POST'])
38 | # def subtract():
39 | # # Write code here
40 |
41 | # TODO: Implement the 'division operation'
42 | # @app.route('/api/divide', methods=['POST'])
43 | # def divide():
44 | # # Write code here
45 |
46 | # TODO: Add more routes and operations! Create your own calculator!
47 | # For example:
48 | # - Square root
49 | # - Exponentiation
50 | # - Trigonometric functions (sin, cos, tan)
51 | # - Logarithms
52 |
53 | if __name__ == '__main__':
54 | app.run(host='0.0.0.0', port=5000)
55 |
--------------------------------------------------------------------------------
/Project/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Calculator-DevOps Foundations
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Project/frontend/README.md:
--------------------------------------------------------------------------------
1 | # Frontend - React Calculator Web App
2 |
3 | ## Overview
4 | This directory will contain the frontend code for the `Calculator Application` built using `React`. This frontend provides a user-friendly interface to interact with the backend calculator API.
5 |
6 | ## Features
7 | - **Basic arithmetic operations**: addition, subtraction, multiplication, division
8 | - **Advanced operations**: square root, logarithm
9 | - Clear function to reset the calculator
10 | - Toggle the negative sign (+/-) of input number
11 | - Formatting for large numbers using exponential notation to avoid spilling outside the display
12 |
13 | ### Prerequisites
14 | 1. **Node.js**: To test if it is installed, open the Command Line `Terminal`, and run:
15 | ```bash
16 | node --version
17 | ```
18 | - If not installed, the latest version of Node.js can be downloaded from:
19 | - Windows: https://nodejs.org/en/download/prebuilt-installer
20 | - macOS: https://nodejs.org/en/download/prebuilt-installer
21 | - Linux: https://nodejs.org/en/download/package-manager (Recommendation: Use `Brew`)
22 |
23 | ### Installation Instructions
24 | 1. Clone this repository.
25 | 2. Navigate to the `Project/frontend/` directory, and open a command line terminal.
26 | 3. Run `npm install` to install dependencies.
27 |
28 | ### Running the Application
29 | To run the application with the development server, execute the following command in the `frontend` project directory:
30 | ```bash
31 | npm start
32 | ```
33 | > **NOTE**: The application will be available at http://localhost:3000 on your web browser.
34 |
35 |
36 | #### Usage
37 |
38 | The web application functions similarly to calculator apps found on Windows, macOS, or mobile devices. It has number keys for entering input and buttons for performing arithmetic and advanced operations.
39 |
40 | > **NOTE**: The web application has significant potential for enhancement to include additional features and better handle certain conditions. A detailed list of current fixes and possible enhancement features is available in the `App.js` file located in the `src` folder.
41 |
42 | ---
43 |
--------------------------------------------------------------------------------
/Project/frontend/src/App.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #1e1e1e;
3 | color: #ffffff;
4 | font-family: Arial, sans-serif;
5 | display: flex;
6 | justify-content: center;
7 | align-items: center;
8 | height: 100vh;
9 | margin: 0;
10 | }
11 |
12 | .calculator-box {
13 | text-align: center;
14 | }
15 |
16 | .calculator-title {
17 | color: #ffffff;
18 | margin-bottom: 20px;
19 | font-size: 30px;
20 | font-weight: 500;
21 | letter-spacing: 5px;
22 | }
23 | .calculator {
24 | width: 350px;
25 | margin: 0 auto;
26 | padding: 10px;
27 | border-radius: 12px;
28 | background-color: #2a2a2a;
29 | box-shadow: 0 4px 10px rgba(0, 0, 0, 0.5);
30 | transition: box-shadow 0.4s ease;
31 | }
32 |
33 | .calculator:hover {
34 | box-shadow: 0 8px 20px rgba(0, 0, 0, 1);
35 | }
36 |
37 | .display {
38 | background-color: #333333;
39 | padding: 10px;
40 | margin-bottom: 10px;
41 | text-align: right;
42 | font-size: 24px;
43 | border: none;
44 | border-radius: 10px;
45 | }
46 |
47 | .operation {
48 | font-size: 16px;
49 | color: #aaaaaa;
50 | }
51 |
52 | .current-value {
53 | font-size: 28px;
54 | }
55 |
56 | .result {
57 | font-size: 20px;
58 | color: #00ffcc;
59 | }
60 |
61 | .buttons {
62 | display: grid;
63 | grid-template-columns: repeat(4, 1fr);
64 | gap: 3px;
65 | }
66 | button {
67 | padding: 15px;
68 | font-size: 18px;
69 | border: none;
70 | border-radius: 5px;
71 | background-color: #444444;
72 | color: #ffffff;
73 | cursor: pointer;
74 | }
75 |
76 | button:hover {
77 | background-color: #555555;
78 | }
79 |
80 | #clear-button {
81 | background-color: #7cbbff;
82 | color: white;
83 | }
84 | #clear-button:hover {
85 | background-color: #1b89ff;
86 | }
87 |
88 | #operation-button {
89 | background-color: #f0ad4e;
90 | color: black;
91 | }
92 | #operation-button:hover {
93 | background-color: #ec971f;
94 | }
95 |
96 | #equals-button {
97 | background-color: #4CAF50;
98 | color: black;
99 | }
100 | #equals-button:hover {
101 | background-color: #45a049;
102 | }
103 |
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/.github/workflows/github-ci.yml:
--------------------------------------------------------------------------------
1 | # TODO-STEP 1: Define the Workflow Name
2 | # Uncomment the following line and replace with a descriptive name. For example: Python CI/CD Pipeline
3 | #name:
4 |
5 | # TODO-STEP 2: Define the Trigger Events
6 | # Uncomment the following lines to trigger the workflow on push and pull request events
7 | #on:
8 | # push:
9 | # pull_request:
10 |
11 | jobs:
12 | # Build job
13 | # TODO-STEP 3: Create your "Build" job
14 | #:
15 | # TODO-STEP 3a: Specify the runner for this job
16 | #runs-on: ubuntu-latest
17 |
18 | steps:
19 | - name: Checkout repository
20 | uses: actions/checkout@v2
21 |
22 | - name: Set up Python
23 | uses: actions/setup-python@v2
24 | with:
25 | python-version: '3.9'
26 |
27 | # TODO-STEP 3b: Enter a name for your step to display on GitHub. For example: Install dependencies
28 | #- name:
29 | # TODO-STEP 3c: Add commands to install dependencies
30 | # Hint: Use pip to install packages from requirements.txt
31 | # run: |
32 | # python -m pip install --upgrade pip
33 | # pip install -r .txt
34 |
35 | # Test job
36 | # TODO-STEP 4: Create your "Test" job
37 | #:
38 | # TODO-STEP 4a: Ensure this job runs after the build job.
39 | # NOTE: Make sure to use the Job Name used above in Line 14.
40 | #needs:
41 | #runs-on: ubuntu-latest
42 |
43 | steps:
44 | - name: Checkout repository
45 | uses: actions/checkout@v2
46 |
47 | - name: Set up Python
48 | uses: actions/setup-python@v2
49 | with:
50 | python-version: '3.9'
51 |
52 | # TODO-STEP 4b: Add command to install dependencies
53 | #- name: Install dependencies
54 | # run: |
55 | # python -m pip install --upgrade pip
56 | # pip install -r requirements.txt
57 |
58 | # TODO-STEP 4c: Add command to run tests
59 | # Hint: Use pytest to run your test cases
60 | #- name: Run tests
61 | # run: pytest
62 |
63 | # Remember to remove the '#' to uncomment lines when filling in the placeholders
--------------------------------------------------------------------------------
/Week 2/Docker Practice/test_app.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import json
3 | from app import app
4 |
5 |
6 | class TestApp(unittest.TestCase):
7 | def setUp(self):
8 | self.client = app.test_client()
9 |
10 | def test_hello_endpoint(self):
11 | response = self.client.get('/api/test')
12 | self.assertEqual(response.status_code, 200)
13 | self.assertEqual(response.json, {"message": "Hello World!"})
14 |
15 | def test_add_endpoint(self):
16 | payload = json.dumps({
17 | "number_1": 5,
18 | "number_2": 3
19 | })
20 | response = self.client.post('/api/add',
21 | data=payload,
22 | content_type='application/json')
23 | self.assertEqual(response.status_code, 200)
24 | self.assertEqual(response.json, {"result": 8})
25 |
26 | def test_add_invalid_input(self):
27 | payload = json.dumps({
28 | "number_1": 5
29 | })
30 | response = self.client.post('/api/add',
31 | data=payload,
32 | content_type='application/json')
33 | self.assertEqual(response.status_code, 400)
34 | self.assertEqual(response.json, {"error": "Invalid input"})
35 |
36 | # Optional: Tests for additional operations
37 | # Uncomment and complete these tests if you implement
38 | # the below routes
39 |
40 | # def test_multiply_endpoint(self):
41 | # # Prepare test data
42 | # payload = json.dumps({
43 | # "number_1": 4,
44 | # "number_2": 5
45 | # })
46 | #
47 | # # TODO: Get Response from API endpoint '/api/multiply'
48 | # # response = self.client.post('/api/multiply', data=payload,
49 | # # content_type='application/json')
50 | #
51 | # # TODO: Assert equals if API response is OK (200)
52 | # # self.assertEqual(response.status_code, 200)
53 | #
54 | # # TODO: Assert equals if API response 'result' is 20 (4 * 5)
55 | # # self.assertEqual(response.json, {"result": 20})
56 |
57 | # def test_subtract_endpoint(self):
58 | # # Write test code here
59 |
60 | # def test_divide_endpoint(self):
61 | # # Write test code here
62 |
63 | # Add more tests for any additional routes created
64 |
65 |
66 | if __name__ == '__main__':
67 | unittest.main()
68 |
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/test_app.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import json
3 | from app import app
4 |
5 |
6 | class TestApp(unittest.TestCase):
7 | def setUp(self):
8 | self.client = app.test_client()
9 |
10 | def test_hello_endpoint(self):
11 | response = self.client.get('/api/test')
12 | self.assertEqual(response.status_code, 200)
13 | self.assertEqual(response.json, {"message": "Hello World!"})
14 |
15 | def test_add_endpoint(self):
16 | payload = json.dumps({
17 | "number_1": 5,
18 | "number_2": 3
19 | })
20 | response = self.client.post('/api/add',
21 | data=payload,
22 | content_type='application/json')
23 | self.assertEqual(response.status_code, 200)
24 | self.assertEqual(response.json, {"result": 8})
25 |
26 | def test_add_invalid_input(self):
27 | payload = json.dumps({
28 | "number_1": 5
29 | })
30 | response = self.client.post('/api/add',
31 | data=payload,
32 | content_type='application/json')
33 | self.assertEqual(response.status_code, 400)
34 | self.assertEqual(response.json, {"error": "Invalid input"})
35 |
36 | # Optional: Tests for additional operations
37 | # Uncomment and complete these tests if you implement
38 | # the below routes
39 |
40 | # def test_multiply_endpoint(self):
41 | # # Prepare test data
42 | # payload = json.dumps({
43 | # "number_1": 4,
44 | # "number_2": 5
45 | # })
46 | #
47 | # # TODO: Get Response from API endpoint '/api/multiply'
48 | # # response = self.client.post('/api/multiply', data=payload,
49 | # # content_type='application/json')
50 | #
51 | # # TODO: Assert equals if API response is OK (200)
52 | # # self.assertEqual(response.status_code, 200)
53 | #
54 | # # TODO: Assert equals if API response 'result' is 20 (4 * 5)
55 | # # self.assertEqual(response.json, {"result": 20})
56 |
57 | # def test_subtract_endpoint(self):
58 | # # Write test code here
59 |
60 | # def test_divide_endpoint(self):
61 | # # Write test code here
62 |
63 | # Add more tests for any additional routes created
64 |
65 |
66 | if __name__ == '__main__':
67 | unittest.main()
68 |
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/test_app.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import json
3 | from app import app
4 |
5 |
6 | class TestApp(unittest.TestCase):
7 | def setUp(self):
8 | self.client = app.test_client()
9 |
10 | def test_hello_endpoint(self):
11 | response = self.client.get('/api/test')
12 | self.assertEqual(response.status_code, 200)
13 | self.assertEqual(response.json, {"message": "Hello World!"})
14 |
15 | def test_add_endpoint(self):
16 | payload = json.dumps({
17 | "number_1": 5,
18 | "number_2": 3
19 | })
20 | response = self.client.post('/api/add',
21 | data=payload,
22 | content_type='application/json')
23 | self.assertEqual(response.status_code, 200)
24 | self.assertEqual(response.json, {"result": 8})
25 |
26 | def test_add_invalid_input(self):
27 | payload = json.dumps({
28 | "number_1": 5
29 | })
30 | response = self.client.post('/api/add',
31 | data=payload,
32 | content_type='application/json')
33 | self.assertEqual(response.status_code, 400)
34 | self.assertEqual(response.json, {"error": "Invalid input"})
35 |
36 | # Optional: Tests for additional operations
37 | # Uncomment and complete these tests if you implement
38 | # the below routes
39 |
40 | # def test_multiply_endpoint(self):
41 | # # Prepare test data
42 | # payload = json.dumps({
43 | # "number_1": 4,
44 | # "number_2": 5
45 | # })
46 | #
47 | # # TODO: Get Response from API endpoint '/api/multiply'
48 | # # response = self.client.post('/api/multiply', data=payload,
49 | # # content_type='application/json')
50 | #
51 | # # TODO: Assert equals if API response is OK (200)
52 | # # self.assertEqual(response.status_code, 200)
53 | #
54 | # # TODO: Assert equals if API response 'result' is 20 (4 * 5)
55 | # # self.assertEqual(response.json, {"result": 20})
56 |
57 | # def test_subtract_endpoint(self):
58 | # # Write test code here
59 |
60 | # def test_divide_endpoint(self):
61 | # # Write test code here
62 |
63 | # Add more tests for any additional routes created
64 |
65 |
66 | if __name__ == '__main__':
67 | unittest.main()
68 |
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/Answer/test_app.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import json
3 | from app import app
4 |
5 |
6 | class TestApp(unittest.TestCase):
7 | def setUp(self):
8 | self.client = app.test_client()
9 |
10 | def test_hello_endpoint(self):
11 | response = self.client.get('/api/test')
12 | self.assertEqual(response.status_code, 200)
13 | self.assertEqual(response.json, {"message": "Hello World!"})
14 |
15 | def test_add_endpoint(self):
16 | payload = json.dumps({
17 | "number_1": 5,
18 | "number_2": 3
19 | })
20 | response = self.client.post('/api/add',
21 | data=payload,
22 | content_type='application/json')
23 | self.assertEqual(response.status_code, 200)
24 | self.assertEqual(response.json, {"result": 8})
25 |
26 | def test_add_invalid_input(self):
27 | payload = json.dumps({
28 | "number_1": 5
29 | })
30 | response = self.client.post('/api/add',
31 | data=payload,
32 | content_type='application/json')
33 | self.assertEqual(response.status_code, 400)
34 | self.assertEqual(response.json, {"error": "Invalid input"})
35 |
36 | # Optional: Tests for additional operations
37 | # Uncomment and complete these tests if you implement
38 | # the below routes
39 |
40 | # def test_multiply_endpoint(self):
41 | # # Prepare test data
42 | # payload = json.dumps({
43 | # "number_1": 4,
44 | # "number_2": 5
45 | # })
46 | #
47 | # # TODO: Get Response from API endpoint '/api/multiply'
48 | # # response = self.client.post('/api/multiply', data=payload,
49 | # # content_type='application/json')
50 | #
51 | # # TODO: Assert equals if API response is OK (200)
52 | # # self.assertEqual(response.status_code, 200)
53 | #
54 | # # TODO: Assert equals if API response 'result' is 20 (4 * 5)
55 | # # self.assertEqual(response.json, {"result": 20})
56 |
57 | # def test_subtract_endpoint(self):
58 | # # Write test code here
59 |
60 | # def test_divide_endpoint(self):
61 | # # Write test code here
62 |
63 | # Add more tests for any additional routes created
64 |
65 |
66 | if __name__ == '__main__':
67 | unittest.main()
68 |
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/Answer/test_app.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | import json
3 | from app import app
4 |
5 |
6 | class TestApp(unittest.TestCase):
7 | def setUp(self):
8 | self.client = app.test_client()
9 |
10 | def test_hello_endpoint(self):
11 | response = self.client.get('/api/test')
12 | self.assertEqual(response.status_code, 200)
13 | self.assertEqual(response.json, {"message": "Hello World!"})
14 |
15 | def test_add_endpoint(self):
16 | payload = json.dumps({
17 | "number_1": 5,
18 | "number_2": 3
19 | })
20 | response = self.client.post('/api/add',
21 | data=payload,
22 | content_type='application/json')
23 | self.assertEqual(response.status_code, 200)
24 | self.assertEqual(response.json, {"result": 8})
25 |
26 | def test_add_invalid_input(self):
27 | payload = json.dumps({
28 | "number_1": 5
29 | })
30 | response = self.client.post('/api/add',
31 | data=payload,
32 | content_type='application/json')
33 | self.assertEqual(response.status_code, 400)
34 | self.assertEqual(response.json, {"error": "Invalid input"})
35 |
36 | # Optional: Tests for additional operations
37 | # Uncomment and complete these tests if you implement
38 | # the below routes
39 |
40 | # def test_multiply_endpoint(self):
41 | # # Prepare test data
42 | # payload = json.dumps({
43 | # "number_1": 4,
44 | # "number_2": 5
45 | # })
46 | #
47 | # # TODO: Get Response from API endpoint '/api/multiply'
48 | # # response = self.client.post('/api/multiply', data=payload,
49 | # # content_type='application/json')
50 | #
51 | # # TODO: Assert equals if API response is OK (200)
52 | # # self.assertEqual(response.status_code, 200)
53 | #
54 | # # TODO: Assert equals if API response 'result' is 20 (4 * 5)
55 | # # self.assertEqual(response.json, {"result": 20})
56 |
57 | # def test_subtract_endpoint(self):
58 | # # Write test code here
59 |
60 | # def test_divide_endpoint(self):
61 | # # Write test code here
62 |
63 | # Add more tests for any additional routes created
64 |
65 |
66 | if __name__ == '__main__':
67 | unittest.main()
68 |
--------------------------------------------------------------------------------
/Project/frontend/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/Project/backend/README.md:
--------------------------------------------------------------------------------
1 | # Backend - Python Flask Calculator API
2 |
3 | ## Overview
4 | This directory will contain the backend code in Python programming language for performing the Calculator operations. This backend is a Flask-based REST API that provides various mathematical operations for a calculator application.
5 |
6 | ## Features
7 | - **Basic arithmetic operations**: addition, subtraction, multiplication, division
8 | - **Advanced operations**: square root, exponentiation, trigonometric functions, logarithms
9 | - **Error handling** for invalid inputs and edge cases
10 |
11 | ## API Endpoints
12 |
13 | ### Test Endpoint
14 | - `GET /api/test`: Returns a simple "Hello World" message
15 |
16 | ### Arithmetic Operations
17 | - `POST /api/add`: Addition
18 | - `POST /api/subtract`: Subtraction
19 | - `POST /api/multiply`: Multiplication
20 | - `POST /api/divide`: Division
21 |
22 | ### Advanced Operations
23 | - `POST /api/sqrt`: Square root
24 | - `POST /api/power`: Exponentiation
25 | - `POST /api/trig`: Trigonometric functions (sin, cos, tan)
26 | - `POST /api/log`: Logarithm
27 |
28 | ## Setup and Installation
29 |
30 | ### Prerequisites
31 | `Python` installed on your local machine _(Python 3.7 or higher recommended)_
32 | - To test if it is installed, open your Command Line Terminal, and run:
33 | ```bash
34 | python --version
35 | ```
36 | or
37 | ```bash
38 | python3 --version
39 | ```
40 | - If not installed, you can download Python here:
41 | - Windows OS: https://www.python.org/downloads/
42 | - macOS: https://www.python.org/downloads/macos/
43 |
44 | ### Installation Steps
45 |
46 | 1. Clone this repository.
47 | 2. Navigate to the `Project/backend/` directory, and open a command line terminal.
48 | 3. Run `pip install -r requirements.txt` to install dependencies.
49 |
50 | ### Running the Application
51 | To run the application, execute the following command in the project directory:
52 | ```bash
53 | python app.py
54 | ```
55 |
56 | The API will be available at http://localhost:5000.
57 |
58 | #### Usage Examples:
59 |
60 | - Addition:
61 |
62 | `POST /api/add`
63 |
64 | Content-Type: application/json
65 | ```json
66 | {
67 | "number_1": 5,
68 | "number_2": 3
69 | }
70 | ```
71 |
72 | Response:
73 | ```json
74 | {
75 | "result": 8
76 | }
77 | ```
78 |
79 | - Square Root:
80 |
81 | `POST /api/sqrt`
82 |
83 | Content-Type: application/json
84 | ```json
85 | {
86 | "number": 16
87 | }
88 | ```
89 |
90 | Response:
91 | ```json
92 | {
93 | "result": 4
94 | }
95 | ```
96 |
97 | ---
98 |
--------------------------------------------------------------------------------
/Week 1/README.md:
--------------------------------------------------------------------------------
1 | # Session 1: Introduction to DevOps & CI/CD
2 |
3 | This week will be focussed on learning theoretical concepts of DevOps, with in-depth focus on Continious Integration (CI) and Continious Delivery/Deployment (CD).
4 |
5 | ## Learning Objectives
6 | - Understand the fundamentals of DevOps, and comparison with Traditional SDLC.
7 | - Learn about CI/CD concepts and practices.
8 | - Implement a CI/CD pipeline using GitLab CI/CD and GitHub Actions.
9 |
10 | ## Contact Information
11 | For questions or assistance, please reach out to [Zainuddin Saiyed](https://www.linkedin.com/in/zain-saiyed/).
12 |
13 | ## Contents
14 |
15 | - **`README.md`**: Overview and instructions for `Week 1` materials.
16 | - **`DevOps Foundations-Session 1 Slides.pdf`**: In-person session presentation slides.
17 | - **`GitLab CI CD Practice/`**: Demo exercise for implementing a CI/CD pipeline on **GitLab**.
18 | - **`GitHub Action Practice/`**: This folder includes the demo practice exercise for implementing a CI/CD pipeline on **GitHub**.
19 |
20 | ## Helpful Guides and Essential Resources
21 |
22 | ### Gitlab CI/CD
23 | - **(Must Read)** [CI/CD Fundamentals by GitLab](https://about.gitlab.com/topics/ci-cd/)
24 | - **(Must Read)** [Understanding GitLab CI/CD](https://docs.gitlab.com/ee/ci/)
25 | - [CI/CD YAML syntax reference guide]( https://docs.gitlab.com/ee/ci/yaml/)
26 | - [Tutorial: Create and run your first GitLab CI/CD pipeline]( https://docs.gitlab.com/ee/ci/quick_start/)
27 | - [Examples of GitLab CI/CD for multiple languages](https://docs.gitlab.com/ee/ci/examples/)
28 |
29 | #### Video Tutorial
30 | - [GitLab CI CD Tutorial for Beginners [Crash Course]](https://www.youtube.com/watch?v=qP8kir2GUgo)
31 |
32 | ---
33 |
34 | ### GitHub Actions
35 |
36 | - **(Must Read)** [Understanding GitHub Actions](https://docs.github.com/en/actions/about-github-actions/understanding-github-actions)
37 | - [GitHub Actions syntax reference guide](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions)
38 | - [Quickstart for GitHub Actions](https://docs.github.com/en/actions/writing-workflows/quickstart)
39 | - [Tutorial: Create a GitHub Actions workflow](https://docs.github.com/en/actions/quickstart)
40 | - [An Example Workflow](https://docs.github.com/en/actions/use-cases-and-examples/creating-an-example-workflow)
41 | - [More Information about GitHub-hosted runners](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners)
42 | - Public Repositories: ([Click Here](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories))
43 | - Private Repositories ([Click Here](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for--private-repositories))
44 |
45 | - [How to use the checkout action in GitHub Actions?](https://graphite.dev/guides/github-actions-checkout)
46 |
47 |
48 | #### Video Tutorials:
49 | - [GitHub Actions Tutorial - Basic Concepts and CI/CD Pipeline with Docker](https://youtube.com/watch?v=R8_veQiYBjI&ab_channel=TechWorldwithNana )
50 |
51 | - [GitHub Actions Step by Step DEMO for Beginners](https://www.youtube.com/watch?v=ylEy4eLdhFs&ab_channel=AutomationStepbyStep)
52 |
53 | ---
--------------------------------------------------------------------------------
/Week 2/README.md:
--------------------------------------------------------------------------------
1 | # Week 2: Containerization and Orchestration with Docker and VMs
2 |
3 | ## Overview
4 |
5 | This week we dive into containerization technologies, primarily focusing on Docker, and comparing them with traditional virtualization using Virtual Machines (VMs.) We will explore the fundamentals of containerization, its benefits, and how to effectively use Docker for application deployment and management.
6 |
7 | ## Learning Objectives
8 |
9 | - Understand the concept of containerization and its advantages over traditional Virtual Machines (VMs).
10 | - Create, run, and manage Docker containers.
11 | - Write and optimize Dockerfiles for application containerization.
12 | - Understand basic container orchestration concepts.
13 |
14 | ## Contents
15 |
16 | - **`README.md`**: Overview and instructions for `Week 2` materials.
17 | - **`DevOps Foundations-Session 2 Slides.pdf`**: In-person session presentation slides.
18 | - **`Docker Practice/`**: A practice exercise (with Answer) for containerising a Python Flask API using **Docker**.
19 |
20 | ## Hands-on Practice Exercise
21 |
22 | Complete the Docker Containerization Exercise in the `Docker Practice/` folder. This exercise will guide you through:
23 |
24 | - Writing a Dockerfile
25 | - Building a Docker image
26 | - Running a containerized application
27 | - and, Testing our running container
28 |
29 | ## Helpful Guides and Essential Resources
30 |
31 | > **Docker command line cheat sheet**: https://docs.docker.com/get-started/docker_cheatsheet.pdf
32 |
33 | #### Helpful Reads:
34 |
35 | - [What is a virtual machine?](https://cloud.google.com/learn/what-is-a-virtual-machine) - By Google Cloud
36 | - [Introduction to Containerization: A Beginner's Walkthrough](https://medium.com/@stefan.paladuta17/)
37 | - [What is Docker?](https://aws.amazon.com/docker/) - By AWS
38 | - [What’s the Difference Between Docker and a VM?](https://aws.amazon.com/compare/the-difference-between-docker-vm/) - By AWS
39 | - [Docker vs. Virtual Machines: Differences](https://www.qa.com/resources/blog/docker-vs-virtual-machines-differences-you-should-know/)
40 | - [Docker Architecture: The components and processes - Part 1](https://www.blacksmith.sh/blog/docker-architecture-the-components-and-processes-part-1) - By Aditya Jayaprakash
41 | - [What is Microservices Architecture?](https://cloud.google.com/learn/what-is-microservices-architecture) - By Google Cloud
42 | - [Play with Docker Classroom](https://training.play-with-docker.com/)
43 | - [Docker Curriculum Guide](https://docker-curriculum.com/) - By Prakhar Srivastav
44 |
45 | #### Resources for writing Dockerfile:
46 |
47 | - [Writing a Dockerfile](https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/) - From Docker docs
48 | - [What is a Dockerfile & its best Practices](https://spacelift.io/blog/dockerfile)
49 | - [Dockerfile on Windows](https://learn.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/manage-windows-dockerfile) - By Microsoft
50 |
51 | #### Video Tutorials:
52 |
53 | - [Docker for DevOps](https://www.youtube.com/watch?v=fqMOX6JJhGo&ab_channel=freeCodeCamp.org) - By FreeCodeCamp.org
54 | - [Docker Tutorial for Beginners](https://www.youtube.com/watch?v=pTFZFxd4hOI) - By Programming with Mosh
55 | - [Docker Crash Course](https://www.youtube.com/watch?v=pg19Z8LL06w&ab_channel=TechWorldwithNana) - By TechWorld with Nana
56 | - [Docker Compose Tutorial](https://www.youtube.com/watch?v=HG6yIjZapSA&ab_channel=ProgrammingwithMosh) - By Programming with Mosh
57 |
58 |
59 | ## Contact Information
60 | For questions or assistance, please reach out to [Zainuddin Saiyed](https://www.linkedin.com/in/zain-saiyed/).
61 |
62 |
63 |
64 | ---
--------------------------------------------------------------------------------
/Week 3/README.md:
--------------------------------------------------------------------------------
1 | # Week 3: Advanced Docker Concepts and Cloud Computing Fundamentals
2 |
3 | ## Overview
4 |
5 | This week we dive deeper into Docker's advanced functionalities, focusing on:
6 | - Docker Compose
7 | - Docker Networks
8 | - and, Docker Volumes.
9 |
10 | Additionally, We will explore _microservices architecture_ and _fundamentals of cloud computing_. By learning these concepts you will gain a comprehensive understanding of how to leverage advanced techniques to interconnect and enhance application deployment and scalability.
11 |
12 |
13 | ## Learning Objectives
14 |
15 | - Understand and implement multi-container applications using Docker Compose.
16 | - Configure and manage Docker Networks for container communication.
17 | - Understand usage of Docker Volumes for persistent data storage.
18 | - Understand the principles of Microservices Architecture.
19 | - Grasp the basics of Cloud Computing and its impact on modern IT infrastructure.
20 |
21 |
22 | ## Contents
23 |
24 | - **`README.md`**: Overview and instructions for `Week 3` materials.
25 | - **`DevOps Foundations-Session 3 Slides.pdf`**: In-person session presentation slides.
26 |
27 |
28 | > **Note**: This week does not include a dedicated practice exercise, because the [`Project/`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Project) serves as an integrated exercise covering concepts from both Week 1 to Week 3. It is highly recommended to complete the Project to effectively understand and apply the Docker and CI/CD concepts learned.
29 |
30 |
31 | ## Helpful Guides and Essential Resources
32 |
33 | > **Docker command line cheat sheet**: https://docs.docker.com/get-started/docker_cheatsheet.pdf
34 |
35 | ### Docker Compose
36 | - [Learn to use Docker Compose](https://docs.docker.com/get-started/workshop/08_using_compose/) - Docker Docs
37 | - [Compose File Reference](https://docs.docker.com/compose/compose-file/) - Docker Docs
38 | - [Docker Compose Quickstart](https://docs.docker.com/compose/gettingstarted/) - Docker Docs
39 | - [Docker Compose Tutorial](https://www.youtube.com/watch?v=HG6yIjZapSA) - Programming with Mosh (Video)
40 |
41 | ### Docker Networking
42 | - [Understanding Docker Networking](https://docs.docker.com/network/) - Docker Docs
43 | - [Docker Networking – Basics, Network Types & Examples](https://spacelift.io/blog/docker-networking) - James Walker
44 | - [Docker Networking Crashcourse](https://www.youtube.com/watch?v=OU6xOM0SE4o) - Hussein Nasser (Video)
45 | - [Docker Networking Tutorial](https://www.youtube.com/watch?v=5grbXvV_DSk) - Christian Lempa (Video)
46 |
47 | ### Docker Volumes
48 | - [Introduction to Docker Volumes](https://docs.docker.com/storage/volumes/) - Docker Docs
49 | - [Docker Volumes: Efficient Data Management in Containerized Environments](https://semaphoreci.com/blog/docker-volumes) - Princewill Inyang
50 | - [Docker Volumes Explained in 6 minutes](https://www.youtube.com/watch?v=p2PH_YPCsis) - TechWorld with Nana (Video)
51 |
52 |
53 | ## Cloud Computing
54 | - [What is Cloud Computing?](https://aws.amazon.com/what-is-cloud-computing/) - AWS
55 | - [What is Cloud Computing?](https://azure.microsoft.com/en-us/resources/cloud-computing-dictionary/what-is-cloud-computing) - Microsoft Azure
56 | - [Cloud Computing in 2 minutes](https://www.youtube.com/watch?v=N0SYCyS2xZA) - Codebagel (Video)
57 | - [What Is Cloud Computing? | Cloud Computing Explained](https://www.youtube.com/watch?v=M988_fsOSWo) - Simplilearn (Video)
58 |
59 | ## Microservices Architecture
60 | - [What is Microservices Architecture?](https://cloud.google.com/learn/what-is-microservices-architecture) - Google Cloud
61 | - [Microservices vs Monolithic Architecture](https://atlassian.com/microservices/microservices-architecture/microservices-vs-monolith) - Atlassian
62 | - [Difference between Monolithic and Microservices architecture](https://aws.amazon.com/compare/the-difference-between-monolithic-and-microservices-architecture/) - AWS
63 | - [Mastering Chaos - A Netflix Guide to Microservices](https://www.youtube.com/watch?v=CZ3wIuvmHeM) - infoQ (Video)
64 |
65 | ## Advanced Material
66 | - [Docker Containers and Kubernetes Fundamentals - Course](https://www.youtube.com/watch?v=kTp5xUtcalw) - Free Code Camp (Video)
67 |
68 | ---
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DevOps Foundations Certification Course
2 |
3 | Welcome to the **DevOps Foundations Certification** course! This comprehensive program is designed to provide you with a solid understanding of DevOps principles and practices. This repository contains all materials organized by weekly sessions, each consisting its own set of additional resources, guides, helpful links, instructions, and hands-on practice exercises to guide your learning experience.
4 |
5 | The course is designed and taught by [**Zainuddin Saiyed**](https://linkedin.com/in/zain-saiyed).
6 |
7 |
8 | ## Course Structure
9 | The course consists of in-person sessions held every Tuesdays for four weeks, starting November 5. Each in-person session would include:
10 | - **Theoretical explanations** and discussions on foundation concepts
11 | - **Hands-on pratcical understanding** on the topics learnt
12 | - and, a fun and interactive **Kahoot Quiz** at the end of the session to test understanding of the topics learnt in class.
13 |
14 | ## In-Person Session Details:
15 | Every Tuesdays starting November 5 to November 26
16 | (6pm to 8pm)
17 |
18 | Room 134 (Lab)
19 |
20 | Goldberg CS Building 6050 University Ave.
21 |
22 |
23 | ## Course Timeline
24 |
25 | 1. **Session 1**: Introduction to DevOps & CI/CD **(November 5)**
26 | - _Core Topics_:
27 | - Traditional Software Development Lifecycle
28 | - DevOps: Concepts, Benefits, and Lifecycle Phases
29 | - Seven Major DevOps Practices
30 | - In-depth focus on Continious Integration (CI) and Continious Delivery/Deployment (CD)
31 | - _Understanding GitLab CI/CD_ (YAML configuration)
32 | - _Exploring GitHub Actions_ (YAML configuration)
33 | - _Materials available at_: [Go to: Week 1 - Material](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Week%201)
34 |
35 | 2. **Session 2**: Containerisation and Orchestration using Docker **(November 12)**
36 | - _Core Topics_:
37 | - Understanding Virtual Machines (VMs)
38 | - Introduction to Containerization
39 | - Containers vs Virtual Machines
40 | - Docker Fundamentals
41 | - Docker architecture
42 | - Docker images and containers
43 | - Basic Docker commands
44 | - _Materials available at_: [Go to: Week 2 - Material](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Week%202)
45 |
46 | 3. **Session 3**: Advanced Docker Concepts and Cloud Computing Fundamentals **(November 19)**
47 | - _Core Topics_:
48 | - Understanding Docker Compose
49 | - Understanding Docker Networks
50 | - Understanding Docker Volumes
51 | - Microservice Architectures
52 | - Basics of Cloud Computing
53 | - _Materials available at_: [Go to: Week 3 - Material](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Week%203)
54 |
55 | 4. **Session 4**: Final Exam & Project QnA session **(November 26)**
56 |
57 | > **Note:**
58 | > For each session, detailed materials including slides, practice exercises, and Kahoot quizzes are available in the corresponding week's folder. Participants are encouraged to review these resources for a comprehensive understanding of the topics covered.
59 |
60 |
61 | ## Certificate Eligibility
62 | To receive a certificate of completion, participants must meet the following criteria:
63 | 1. Attend a minimum of 2 out of the first 3 sessions (75% attendance).
64 | 2. Assessments and Deliverables:
65 | 1. Complete a **in-person examination** during Session 4 (November 26).
66 | 2. Submit a **takeaway course project**, which will be released on Session 2 (November 12) and due on December 4.
67 |
68 |
69 | ## Assessment and Rubric
70 |
71 | 1. **In-Person Examination:**
72 | - **Exam Day:** **`November 26th`**
73 | - **Duration:** 1 Hour
74 | - **Format:** 45 Scenario-Based Multiple-Choice Questions
75 | - **Topics Covered:** All topics from **Session 1** through **Session 3**
76 | - **Study Resources:**
77 | - Session Materials: [Week 1](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Week%201), [Week 2](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Week%202), [Week 3](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Week%203)
78 | - Practice Quizzes and Kahoot Question-Answers: [Click Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Practice%20Quizes)
79 |
80 | 2. **Takeaway Course Project:**
81 | - Release Date: November 12th
82 | - **Submission Deadline:** **`December 4th`**
83 | - Project Specification & Submission Guidelines: [Click Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Project)
84 | - Project Evaluation Criteria: [Click Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Project#evaluation-criteria)
85 |
86 |
87 | ---
88 |
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/Answer/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 | # TODO-STEP 1: Define the Stages
2 | stages:
3 | - build
4 | - test
5 | # Required for Step- Basic Task 2: Manual Job Execution
6 | - deploy
7 |
8 | # TODO-STEP 2: Create the "Build" Stage
9 | build_job:
10 | stage: build
11 | image: python:3.9
12 | script:
13 | - echo "Installing dependencies..."
14 | - pip install -r requirements.txt
15 |
16 | # TODO-STEP 3: Create the "Test" Stage
17 | test_job:
18 | stage: test
19 | image: python:3.9
20 | script:
21 | - echo "Running tests..."
22 | - pip install -r requirements.txt
23 | - pytest
24 |
25 | # Additional Practice Tasks and Challenges
26 |
27 | # Basic Task 1: Conditional Job Execution
28 | ## Example 1: This job runs only when python files are changed.
29 | count_python_files:
30 | stage: test
31 | image: python:3.9
32 | script:
33 | - echo "Counting the number of Python files changed..."
34 | - git diff --name-only $CI_COMMIT_BEFORE_SHA $CI_COMMIT_SHA | grep '\.py$' | wc -l
35 | rules:
36 | - changes:
37 | - "*.py"
38 |
39 | # Helper Explanation:
40 | # "Conditional jobs" are tasks that run only when specific conditions are met.
41 | # Such jobs help make the workflow (CI/CD pipeline) more efficient by executing
42 | # task-specific commands, which saves time and resources in CI/CD processes.
43 |
44 | ## Example 2: This job runs only when Python files are changed.
45 | lint_job:
46 | stage: test
47 | image: python:3.9
48 | script:
49 | - pip install flake8
50 | - flake8 .
51 | rules:
52 | - changes:
53 | - "*.py"
54 |
55 | # Job Explanation:
56 | # Linting jobs ensure code quality, consistency, and maintainability.
57 | # Running conditional jobs helps keep code standards high without
58 | # slowing down the CI/CD pipeline when there are no code changes.
59 | #
60 | # Helpful Reference: https://perforce.com/blog/qac/what-is-linting
61 |
62 | # Basic Task 2: Manual Job Execution
63 | ## Example: This job requires a person (manual intervention) to start it.
64 | deploy_job:
65 | stage: deploy
66 | script:
67 | - echo "Deploying application..."
68 | when: manual
69 |
70 | # Job Explanation:
71 | # Manual jobs are important for making sure deployments are done carefully
72 | # and involve human approval. Such manual jobs are crucial for controlled
73 | # deployments and human-in-the-loop processes. These jobs can be considered
74 | # like a safety switch which requires a human to flip before initiating an
75 | # important process. Such jobs are commonly used for production deployments
76 | # or any task requiring explicit approval.
77 |
78 | # Basic Task 3: Use Variables
79 | ## Example: This job shows how to use variables and conditional logic in a
80 | ## CI/CD pipeline. These are important for providing visibility into
81 | ## the build process and ensuring correct versions and environments
82 | ## are being used.
83 | version_info_job:
84 | stage: test
85 | script:
86 | # Using predefined GitLab CI variables
87 | - echo "Running tests for $CI_PROJECT_NAME"
88 | - echo "Current branch- $CI_COMMIT_BRANCH"
89 |
90 | # Using a command to get system information
91 | - echo "Python version- $(python --version)" # Quiz: When you inspect the logs, you will find this command fails. Why do you think this command fails? What can be added in this job to fix this?
92 |
93 | # Using custom variables
94 | - echo "App version- $APP_VERSION"
95 | - echo "Environment- $DEPLOY_ENVIRONMENT"
96 |
97 | # Example of conditional execution based on a variable
98 | - |
99 | if [ "$DEPLOY_ENVIRONMENT" = "production" ]; then
100 | echo "Performing production checks & operations..."
101 | # In a real scenario, you will run more comprehensive tests
102 | # or perform environment-specific configurations here ...
103 | else
104 | echo "Skipping production-specific checks & operations..."
105 | fi
106 |
107 | # Defining custom variables
108 | variables:
109 | APP_VERSION: "1.2.3"
110 | DEPLOY_ENVIRONMENT: "staging"
111 |
112 | # Job Explanation:
113 | # This job uses both:
114 | # - predefined GitLab CI variables (like $CI_PROJECT_NAME)
115 | # - and, custom variables (like $APP_VERSION).
116 | # This also demonstrates how to run conditional tasks based on the environment,
117 | # which is important for managing different configurations between staging and
118 | # production deployments.
119 | #
120 | # Such jobs are often used at the start of a pipeline to provide context for
121 | # subsequent jobs and give an overview of the build environment. It is
122 | # particularly valuable in complex projects having multiple environments and
123 | # frequent releases.
--------------------------------------------------------------------------------
/Project/backend/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, jsonify
2 | from flask_cors import CORS
3 | import math
4 |
5 | # Initialize Flask application
6 | app = Flask(__name__)
7 | CORS(app, resources={r"/api/*": {"origins": "*"}})
8 |
9 | # Function to validate input fields recieved in the request payload
10 | def validate_input_request_fields(data_request, required_fields):
11 | # Check if (data_request is empty) or (if any required field is missing)
12 | return ((not data_request) or (not all(field in data_request for field in required_fields)))
13 |
14 | # Test route for healthchecks
15 | @app.route('/api/test')
16 | def hello():
17 | return {'message': 'Hello World!'}
18 |
19 | # CALCUlATOR MATHEMATICAL OPERATIONS
20 | # Addition operation
21 | @app.route('/api/add', methods=['POST'])
22 | def add():
23 | data_request = request.get_json() # Get 'JSON' data from request payload
24 | if validate_input_request_fields(data_request, ['number_1', 'number_2']):
25 | return jsonify({'error': 'Invalid input'}), 400 # Return error if input is invalid
26 |
27 | # Convert request 'input' to 'float' and perform 'addition'
28 | number_1 = float(data_request['number_1'])
29 | number_2 = float(data_request['number_2'])
30 | result = number_1 + number_2
31 | return jsonify({'result': result}) # Return result to frontend as a 'JSON'
32 |
33 |
34 | # Multiplication operation
35 | @app.route('/api/multiply', methods=['POST'])
36 | def multiply():
37 | data_request = request.get_json()
38 | if validate_input_request_fields(data_request, ['number_1', 'number_2']):
39 | return jsonify({'error': 'Invalid input'}), 400
40 |
41 | # Convert request 'input' to 'float' and perform 'multiplication'
42 | number_1 = float(data_request['number_1'])
43 | number_2 = float(data_request['number_2'])
44 | result = number_1 * number_2
45 | return jsonify({'result': result})
46 |
47 |
48 | # Subtraction operation
49 | @app.route('/api/subtract', methods=['POST'])
50 | def subtract():
51 | data_request = request.get_json()
52 | if validate_input_request_fields(data_request, ['number_1', 'number_2']):
53 | return jsonify({'error': 'Invalid input'}), 400
54 |
55 | # Convert request 'input' to 'float' and perform 'subtraction'
56 | number_1 = float(data_request['number_1'])
57 | number_2 = float(data_request['number_2'])
58 | result = number_1 - number_2
59 | return jsonify({'result': result})
60 |
61 |
62 | # Division operation
63 | @app.route('/api/divide', methods=['POST'])
64 | def divide():
65 | data_request = request.get_json()
66 | if validate_input_request_fields(data_request, ['number_1', 'number_2']):
67 | return jsonify({'error': 'Invalid input'}), 400
68 |
69 | # Convert request 'input' to 'float' and perform 'division'
70 | number_1 = float(data_request['number_1'])
71 | number_2 = float(data_request['number_2'])
72 | if number_2 == 0:
73 | return jsonify({'error': 'Division by zero'}), 400 # Return 'error' if division is by 'zero'
74 | result = number_1 / number_2
75 | return jsonify({'result': result})
76 |
77 |
78 | # Square root operation
79 | @app.route('/api/sqrt', methods=['POST'])
80 | def square_root():
81 | data_request = request.get_json()
82 | if validate_input_request_fields(data_request, ['number']):
83 | return jsonify({'error': 'Invalid input'}), 400
84 |
85 | number = float(data_request['number'])
86 | if number < 0:
87 | return jsonify({'error': 'Cannot calculate square root of a negative number'}), 400 # Return 'error' if calculating square root of a negative number
88 | result = math.sqrt(number)
89 | return jsonify({'result': result})
90 |
91 | # Exponentiation operation
92 | @app.route('/api/power', methods=['POST'])
93 | def power():
94 | data_request = request.get_json()
95 | if validate_input_request_fields(data_request, ['base', 'exponent']):
96 | return jsonify({'error': 'Invalid input'}), 400
97 |
98 | base = float(data_request['base'])
99 | exponent = float(data_request['exponent'])
100 | result = math.pow(base, exponent) # Calculate Power
101 | return jsonify({'result': result})
102 |
103 | # Trigonometric functions
104 | @app.route('/api/trig', methods=['POST'])
105 | def trigonometric():
106 | data_request = request.get_json()
107 | if validate_input_request_fields(data_request, ['function', 'angle']):
108 | return jsonify({'error': 'Invalid input'}), 400
109 |
110 | function = data_request['function'].lower()
111 | angle = float(data_request['angle'])
112 |
113 | # Perform the appropriate trigonometric function
114 | if function == 'sin':
115 | result = math.sin(math.radians(angle))
116 | elif function == 'cos':
117 | result = math.cos(math.radians(angle))
118 | elif function == 'tan':
119 | result = math.tan(math.radians(angle))
120 | else:
121 | return jsonify({'error': 'Invalid trigonometric function'}), 400
122 |
123 | return jsonify({'result': result})
124 |
125 | # Logarithm operation
126 | @app.route('/api/log', methods=['POST'])
127 | def logarithm():
128 | data_request = request.get_json()
129 | if validate_input_request_fields(data_request, ['number']):
130 | return jsonify({'error': 'Invalid input'}), 400
131 |
132 | number = float(data_request['number'])
133 | if number <= 0:
134 | return jsonify({'error': 'Cannot calculate logarithm of a non-positive number'}), 400
135 |
136 | # Use natural log (base e) if no base is provided
137 | base = float(data_request.get('base', math.e))
138 | result = math.log(number, base)
139 | return jsonify({'result': result})
140 |
141 | if __name__ == '__main__':
142 | # Run the Flask application on port
143 | app.run(host='0.0.0.0', port=5000)
144 |
--------------------------------------------------------------------------------
/Practice Quizes/README.md:
--------------------------------------------------------------------------------
1 | # Final Exam Practice: DevOps, CI/CD, & Docker Concepts
2 |
3 | > **NOTE:**
4 | > To practice questions for your Final Exam in a learning environment, please [click here](https://forms.office.com/r/zyF1jJVYMG) or visit the following link:
5 | > [https://forms.office.com/r/zyF1jJVYMG](https://forms.office.com/r/zyF1jJVYMG)
6 |
7 | ---
8 | ### Instructions:
9 | Please read each question carefully and select the most appropriate answer based on the concepts covered during the sessions.
10 |
11 | ---
12 |
13 | # Practice Quizzes
14 |
15 | - Session 1 Kahoot: **To practice the quiz** in a learning environment, please [click here](https://forms.office.com/r/eJw6sR19ak) or visit the following link: https://forms.office.com/r/eJw6sR19ak.
16 |
17 | - Session 2 Kahoot: **To practice the quiz** in a learning environment, please [click here](https://forms.office.com/r/pHhuVd0caV) or visit the following link: https://forms.office.com/r/pHhuVd0caV.
18 |
19 |
20 |
21 |
Quiz on Session 1 - Introduction to DevOps and CI/CD Pipeline
22 |
23 | **To practice the quiz** in a learning environment, please [click here](https://forms.office.com/r/eJw6sR19ak) or visit the following link: https://forms.office.com/r/eJw6sR19ak.
24 |
25 | ---
26 |
27 | ## Questions
28 |
29 | 1. **What does CI/CD stand for?**
30 | - [ ] a) Continuous Integration/Continuous Deployment
31 | - [ ] b) Continuous Improvement/Continuous Development
32 | - [ ] c) Code Integration/Code Delivery
33 | - [ ] d) Computer Integration/Computer Delivery
34 |
35 | 2. **What is the main purpose of a CI/CD pipeline?**
36 | - [ ] a) Increase server capacity
37 | - [ ] b) Manage customer relationships
38 | - [ ] c) Improve network security
39 | - [ ] d) Automate software delivery process
40 |
41 | 3. **Which of these is NOT typically a stage in a CI/CD pipeline?**
42 | - [ ] a) Build
43 | - [ ] b) Deploy
44 | - [ ] c) Test
45 | - [ ] d) Marketing
46 |
47 | 4. **Which of these is NOT a key principle of DevOps?**
48 | - [ ] a) Collaboration
49 | - [ ] b) Automation
50 | - [ ] c) Secrecy between Teams (independent teams)
51 | - [ ] d) Continuous Improvement
52 |
53 | 5. **What is the purpose of automated testing in a CI/CD pipeline?**
54 | - [ ] a) To slow down the development process
55 | - [ ] b) To catch bugs early and ensure code quality
56 | - [ ] c) To replace manual testing entirely
57 | - [ ] d) To increase the cost of development
58 |
59 | 6. **DevOps practices are only applicable to software development and not to operations.**
60 | - [ ] a) True
61 | - [ ] b) False
62 |
63 | 7. **DevOps eliminates the need for separate development and operations teams.**
64 | - [ ] a) True
65 | - [ ] b) False
66 |
67 | > **NOTE**: Expand the below section after attempting all the above questions to reveal the answers.
68 | ---
69 |
70 |
71 | Reveal quiz answers:
72 |
73 | # Answers
74 |
75 | 1. a) Continuous Integration/Continuous Deployment
76 | 2. d) Automate software delivery process
77 | 3. d) Marketing
78 | 4. c) Secrecy between Teams (independent teams)
79 | 5. b) To catch bugs early and ensure code quality
80 | 6. b) False
81 | 7. b) False
82 |
83 |
84 |
85 |
86 | ---
87 |
88 |
89 |
Quiz on Session 2 - Containerization and Orchestration using Docker
90 |
91 |
92 | **To practice the quiz** in a learning environment, please [click here](https://forms.office.com/r/pHhuVd0caV) or visit the following link: https://forms.office.com/r/pHhuVd0caV.
93 |
94 | ---
95 |
96 | ## Questions
97 |
98 | 1. **What is Docker?**
99 | - [ ] a) A programming language
100 | - [ ] b) A Virtual Machine
101 | - [ ] c) A containerization platform
102 | - [ ] d) An operating system
103 |
104 | 2. **What is a Docker container?**
105 | - [ ] a) A Virtual Machine
106 | - [ ] b) A physical server
107 | - [ ] c) A storage device
108 | - [ ] d) A running instance of a Docker image
109 |
110 | 3. **Which file is used to define a Docker container?**
111 | - [ ] a) Containerfile
112 | - [ ] b) Imagefile
113 | - [ ] c) Dockerfile
114 | - [ ] d) requirements.txt
115 |
116 | 4. **Docker Hub is a registry for Docker images.**
117 | - [ ] a) True
118 | - [ ] b) False
119 |
120 | 5. **Which of these is NOT a benefit of using containers?**
121 | - [ ] a) Portability
122 | - [ ] b) Efficiency
123 | - [ ] c) Isolation
124 | - [ ] d) Monolithic
125 |
126 | 6. **What is the main difference between a container and a virtual machine?**
127 | - [ ] a) Containers are faster to start
128 | - [ ] b) Containers share the host OS kernel
129 | - [ ] c) Virtual machines provide better isolation
130 | - [ ] d) Virtual machines use less disk space
131 |
132 | 7. **What does the `docker ps` command do?**
133 | - [ ] a) List all images
134 | - [ ] b) List running containers
135 | - [ ] c) Stop all containers
136 | - [ ] d) Remove all containers
137 |
138 | 8. **What is the purpose of the Docker Daemon?**
139 | - [ ] a) To build Docker images
140 | - [ ] b) To store Docker images
141 | - [ ] c) To manage Docker objects and containers
142 | - [ ] d) To create Docker networks
143 |
144 | > **NOTE**: Expand the below section after attempting all the above questions to reveal the answers.
145 |
146 | ---
147 |
148 |
149 | Reveal quiz answers:
150 |
151 | # Answers
152 |
153 | 1. c) A containerization platform
154 | 2. d) A running instance of a Docker image
155 | 3. c) Dockerfile
156 | 4. a) True
157 | 5. d) Monolithic
158 | 6. b) Containers share the host OS kernel
159 | 7. b) List running containers
160 | 8. c) To manage Docker objects and containers
161 |
162 |
163 |
164 | ---
165 |
--------------------------------------------------------------------------------
/Project/SUBMISSION_README.md:
--------------------------------------------------------------------------------
1 | ## Multi-Container Docker Application with CI/CD: Calculator App Project
2 |
3 | #### Complete Project Instructions: [DevOps Foundations Course/Project](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master/Project)
4 |
5 | #### Submission by - ****
6 |
7 | ### Project Overview
8 |
9 | - **Brief project description:** What is the purpose of your application?
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | - **Which files are you implmenting? and why?:**
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | - _**Any other explanations for personal note taking.**_
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | ### Docker Implementation
34 |
35 | **Explain your Dockerfiles:**
36 |
37 | - **Backend Dockerfile** (Python API):
38 | - Here please explain the `Dockerfile` created for the Python Backend API.
39 | - This can be a simple explanation which serves as a reference guide, or revision to you when read back the readme in future.
40 |
41 |
42 |
43 |
44 |
45 |
46 | - **Frontend Dockerfile** (React App):
47 | - Similar to the above section, please explain the Dockerfile created for the React Frontend Web Application.
48 |
49 |
50 |
51 |
52 |
53 |
54 | **Use this section to document your choices and steps for building the Docker images.**
55 |
56 |
57 | ### Docker Compose YAML Configuration
58 |
59 | **Break down your `docker-compose.yml` file:**
60 |
61 | - **Services:** List the services defined. What do they represent?
62 | - **Networking:** How do the services communicate with each other?
63 | - **Volumes:** Did you use any volume mounts for persistent data?
64 | - **Environment Variables:** Did you define any environment variables for configuration?
65 |
66 | **Use this section to explain how your services interact and are configured within `docker-compose.yml`.**
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | ### CI/CD Pipeline (YAML Configuration)
76 |
77 | **Explain your CI/CD pipeline:**
78 |
79 | - What triggers the pipeline (e.g., push to main branch)?
80 | - What are the different stages (build, test, deploy)?
81 | - How are Docker images built and pushed to a registry (if applicable)?
82 |
83 | **Use this section to document your automated build and deployment process.**
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | ### CI/CD Pipeline (YAML Configuration)
93 |
94 | **Simply explain your CI/CD pipeline:**
95 |
96 | - What triggers the pipeline (e.g., push to main branch)?
97 | - What are the different stages (build, test, deploy)?
98 | - How are Docker images built and pushed to a registry?
99 |
100 | **Use this section to document your automated build, and docker process.**
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | ### Assumptions
110 |
111 | - List any assumptions you made while creating the Dockerfiles, `docker-compose.yml`, or CI/CD pipeline.
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 | ### Lessons Learned
121 |
122 | - What challenges did you encounter while working with Docker and CI/CD?
123 | - What did you learn about containerization and automation?
124 |
125 | **Use this section to reflect on your experience and learnings when implementing this project.**
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | ### Future Improvements
135 |
136 | - How could you improve your Dockerfiles, `docker-compose.yml`, or CI/CD pipeline?
137 | - (Optional-Just for personal reflection) Are there any additional functionalities you would like to consider for the calculator application to crate more stages in the CI/CD pipeline or add additional configuration in the Dockerfiles?
138 |
139 | **Use this section to brainstorm ways to enhance your project.**
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/Answer/github-ci.yml:
--------------------------------------------------------------------------------
1 | # TODO-STEP 1: Define the Workflow Name
2 | name: Python CI/CD Pipeline
3 |
4 | # TODO-STEP 2: Define the Trigger Events
5 | on:
6 | push:
7 | # Example of how to trigger on push to 'main' or 'develop' branches
8 | # branches: [ main, develop ]
9 | pull_request:
10 | # Example of how to trigger on push to 'main' or 'develop' branches
11 | # branches: [ main, develop ]
12 | workflow_dispatch: # Allow manual job trigger of the workflow from GitHub Actions UI
13 |
14 | # Additional Practice Task: Conditional Job Execution
15 | # Basic Task 3: Define environment variables
16 | env:
17 | APP_VERSION: "1.2.3"
18 | DEPLOY_ENVIRONMENT: "staging"
19 |
20 | jobs:
21 | # TODO-STEP 3: Create the "Build" Job
22 | build:
23 | runs-on: ubuntu-latest
24 | steps:
25 | - uses: actions/checkout@v2
26 | - name: Set up Python
27 | uses: actions/setup-python@v2
28 | with:
29 | python-version: 3.9
30 | - name: Install dependencies
31 | # Add command to install dependencies
32 | run: |
33 | echo "Installing dependencies..."
34 | pip install -r requirements.txt # Install project dependencies
35 |
36 | # TODO-STEP 4: Create the "Test" Job
37 | test:
38 | # Ensure this job runs after the build job
39 | needs: build # This job depends on the build job
40 | runs-on: ubuntu-latest
41 | steps:
42 | - uses: actions/checkout@v2
43 | - name: Set up Python
44 | uses: actions/setup-python@v2
45 | with:
46 | python-version: 3.9
47 | - name: Install dependencies
48 | # Add command to install dependencies
49 | run: pip install -r requirements.txt
50 | - name: Run tests
51 | # Add command to run tests
52 | run: pytest
53 |
54 | # Additional Practice Task: Conditional Job Execution
55 |
56 | # Basic Task 1: Conditional Job Execution
57 | ## Example 1: This job runs only on a pull requests.
58 | check_pr_title_and_info:
59 | runs-on: ubuntu-latest
60 | if: github.event_name == 'pull_request'
61 |
62 | steps:
63 | - uses: actions/checkout@v2
64 |
65 | - name: Check Pull Request Title
66 | run: |
67 | PR_TITLE="${{ github.event.pull_request.title }}"
68 | echo "Checking PR title: $PR_TITLE"
69 | if [[ $PR_TITLE == *"WIP"* ]]; then
70 | echo "This is a 'Work in Progress' Pull Request!"
71 | elif [[ $PR_TITLE == *"URGENT"* ]]; then
72 | echo "This Pull Request is marked as URGENT!"
73 | else
74 | echo "This is a regular Pull Request..."
75 | fi
76 |
77 | - name: Display information about Pull Request
78 | run: |
79 | echo "PR Event Number: ${{ github.event.number }}"
80 | echo "Author of PR: ${{ github.event.pull_request.user.login }}"
81 | echo "Branch: ${{ github.head_ref }}"
82 |
83 |
84 | # Helper Explanation:
85 | # "Conditional jobs" are tasks that run only when specific conditions are met.
86 | # Such jobs help make the workflow (CI/CD pipeline) more efficient by executing
87 | # task-specific commands, which saves time and resources in CI/CD processes.
88 |
89 | # Job Explanation:
90 | # The job performs two main tasks:
91 | # 1. "Check Pull Request Title": This checks the title of the pull request for
92 | # specific keywords (like, "WIP" or "URGENT") and prints a output based
93 | # on the title content. This can be useful for quickly identifying the status
94 | # or priority of a pull request.
95 | #
96 | # 2. "Display information about Pull Request": This displays/prints information
97 | # about the pull request, like: its number, the author, and the branch name.
98 | # This information can be valuable for tracking and managing various pull requests.
99 | #
100 | # Overall, by conditionally running jobs on pull requests and analyzing their metadata,
101 | # such job helps in automating parts of the code review process, by providing quick
102 | # insights about the incoming changes without requiring manual intervention.
103 |
104 |
105 | # Basic Task 2: Manual Job Execution
106 | manual_job:
107 | needs: [build, test] # This job depends on both build and test jobs
108 | runs-on: ubuntu-latest
109 | if: github.event_name == 'workflow_dispatch' # This job is triggered manually from GitHub UI
110 |
111 | steps:
112 | - name: Manual step to triger deployment
113 | run: echo "This job is triggered manually. Deploying application..."
114 |
115 | # Job Explanation:
116 | # Manual jobs are important for making sure deployments are done carefully
117 | # and involve human approval. Such manual jobs are crucial for controlled
118 | # deployments and human-in-the-loop processes. These jobs can be considered
119 | # like a safety switch which requires a human to flip before initiating an
120 | # important process. Such jobs are commonly used for production deployments
121 | # or any task requiring explicit approval.
122 |
123 |
124 | # Basic Task 3: Use Variables
125 | version_info_job:
126 | runs-on: ubuntu-latest
127 |
128 | steps:
129 | - uses: actions/checkout@v2
130 |
131 | - name: Set up Python
132 | uses: actions/setup-python@v2
133 | with:
134 | python-version: 3.9
135 |
136 | - name: Display version info
137 | run: |
138 | # Using predefined GitHub Actions variables
139 | echo "Running tests for ${{ github.repository }}"
140 | echo "Current branch- ${{ github.ref_name }}"
141 |
142 | # Using a command to get system information
143 | echo "Python version- $(python --version)"
144 |
145 | # Using custom variables
146 | echo "App version- ${{ env.APP_VERSION }}"
147 | echo "Environment- ${{ env.DEPLOY_ENVIRONMENT }}"
148 |
149 | # Example of conditional execution based on a variable
150 | if [ "${{ env.DEPLOY_ENVIRONMENT }}" = "production" ]; then
151 | echo "Performing production checks & operations..."
152 | # In a real scenario, you would run more comprehensive tests
153 | # or perform environment-specific configurations here ...
154 | else
155 | echo "Skipping production-specific checks & operations..."
156 | fi
157 |
158 | # Job Explanation:
159 | # This job uses both:
160 | # - predefined GitLab CI variables (like $CI_PROJECT_NAME)
161 | # - and, custom variables (like $APP_VERSION).
162 | # This also demonstrates how to run conditional tasks based on the environment,
163 | # which is important for managing different configurations between staging and
164 | # production deployments.
165 | #
166 | # Such jobs are often used at the start of a pipeline to provide context for
167 | # subsequent jobs and give an overview of the build environment. It is
168 | # particularly valuable in complex projects having multiple environments and
169 | # frequent releases.
170 |
--------------------------------------------------------------------------------
/Week 1/GitLab CI CD Practice/README.md:
--------------------------------------------------------------------------------
1 | # GitLab CI/CD Exercise: Python Backend Project
2 |
3 | In this exercise you will create and run your first CI/CD pipeline on GitLab. You will learn how to configure a simple pipeline and how to run it, and also explore some advanced features of GitLab CI/CD.
4 |
5 | ## Some Helpful Links:
6 |
7 | - **(Must Read)** CI/CD Fundamentals by GitLab: https://about.gitlab.com/topics/ci-cd/
8 | - **(Must Read)** Understanding GitLab CI/CD: https://docs.gitlab.com/ee/ci/
9 | - CI/CD YAML syntax reference guide: https://docs.gitlab.com/ee/ci/yaml/
10 | - Tutorial: Create and run your first GitLab CI/CD pipeline: https://docs.gitlab.com/ee/ci/quick_start/
11 | - Examples of GitLab CI/CD for multiple languages: https://docs.gitlab.com/ee/ci/examples/
12 |
13 | ## Prerequisites
14 |
15 | Before starting this exercise, ensure you have:
16 |
17 | 1. A GitLab account
18 | - If you do not have one, you can sign up at [GitLab.com](https://gitlab.com/users/sign_up)
19 |
20 | 2. `Git` installed on your local machine
21 | - To test if it is installed, open your Command Line Terminal and run:
22 | ```
23 | git --version
24 | ```
25 | - If not installed, download it from [git-scm.com]( )
26 |
27 | 3. `Python` installed on your local machine _(Python 3.7 or higher recommended)_
28 | - To test if it is installed, open your Command Line Terminal and run:
29 | ```
30 | python --version
31 | ```
32 | or
33 | ```
34 | python3 --version
35 | ```
36 | - If not installed, you can download Python here:
37 | - Windows OS: https://www.python.org/downloads/
38 | - macOS: https://www.python.org/downloads/macos/
39 |
40 | _Ensure all prerequisites are met before proceeding with the exercise._
41 |
42 |
43 | ## Objective
44 |
45 | Your task is to complete the `.gitlab-ci.yml` file to create a working CI/CD pipeline with two stages: `build` and `test`.
46 |
47 | ## Brief Instructions Overview
48 |
49 | 1. Clone this repository on your local machine.
50 | 2. Create a empty repository on your **GitLab account**.
51 | 3. Copy the content of this repository into the new empty repository created in GitLab.
52 | 4. Open the `.gitlab-ci.yml` file preset in `Week 1/` folder in your preferred text editor.
53 | 5. Follow the **TODO** steps in the `.gitlab-ci.yml` file to complete the configuration.
54 |
55 | ## [1/2] Step-by-Step Guide to complete the `.gitlab-ci.yml` file
56 |
57 | Follow this steps to complete the gitlab-ci yaml file:
58 |
59 | ### TODO-STEP 1: Define the Stages
60 | - Uncomment the `stages:` section.
61 | - Replace `` with `build` for the first stage and `test` for the second stage.
62 |
63 | ### TODO-STEP 2: Create the "Build" Stage
64 | - Uncomment the `:` line and replace `` with a descriptive name (e.g., `build_job`).
65 | - For TODO-STEP 2a, uncomment the `stage:` line and replace `` with `build`.
66 | - For TODO-STEP 2b, uncomment the `pip install` line and replace `` with `requirements`.
67 |
68 | ### TODO-STEP 3: Create the "Test" Stage
69 | - Uncomment the `:` line and replace `` with a descriptive name (e.g., `test_job`).
70 | - For TODO-STEP 3a, uncomment the `stage:` line and replace `` with `test`.
71 | - For TODO-STEP 3b, uncomment the command line and replace `` with `pytest`.
72 |
73 | > ## Important Notes
74 | > - Do not change the `image: python:3.9` line in either job.
75 | > - Remember to remove the `#` symbol to uncomment lines when replacing content in the placeholders.
76 | > - Make sure your indentation is correct. YAML is sensitive to indentation.
77 |
78 | ## [2/2] Executing the CI/CD Pipeline on GitLab
79 |
80 | After completing the `.gitlab-ci.yml` file:
81 | 1. Commit your changes in your local machine.
82 | 2. Push the changes to your GitLab repository.
83 | 3. Go to your project on GitLab and navigate to `"Build"` > `"Pipelines"` to see your pipeline running.
84 | - If you visit `"Build"` > `"Pipeline Editor"`, here you will find the `.gitlab-ci.yml` file.
85 | You can edit and make changes to this file and click `"Commit changes"` to see effects of your changes.
86 | 4. Debug any issues that arise and make necessary adjustments to your `.gitlab-ci.yml` file.
87 | 5. Once your pipeline run is successful, try making changes to the backend code and pushing the changes to see any changes in pipeline execution or logs.
88 | 6. Explore more options of the `.gitlab-ci.yml` configuration, the GitLab CI/CD interface, including job logs and pipeline graphs.
89 |
90 | > _Wohoo! You have successfully run your first CI/CD pipeline on GitLab._
91 |
92 | ## Additional Practice Tasks and Challenges
93 |
94 | ### Basic Tasks:
95 |
96 | 1. **Conditional Job Execution:** Implement a job that only runs when changes are made to specific files or directories:
97 | - **HINT:** Use the `changes` keyword in the `rules` section to run a job only when changes are made to Python files (`*.py`).
98 |
99 | 2. **Manual Job Execution:** Create a job that requires manual intervention to start the execution of the CI/CD pipeline.
100 | - **HINT:** Use the `when: manual` keyword.
101 |
102 | 3. **Use Variables:** Create a job that uses a custom environment variable, and set its value using the GitLab CI/CD variables feature in the project settings.
103 | - **HINT:** Refer to `variables` to define CI/CD variables for jobs ([Click Here](https://docs.gitlab.com/ee/ci/yaml/#variables)).
104 |
105 |
106 | > **SOLUTION:** The answers and examples of above task can be found in the file [`Answer/.gitlab-ci.yml`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Week%201/GitLab%20CI%20CD%20Practice/Answer/.gitlab-ci.yml).
107 |
108 | ## (OPTIONAL) Explore Intermediate-level challenges:
109 |
110 | - **Execute pipeline only in specific branches:** Set up a job that **runs only on specific branches**:
111 | - Create a job that runs only on the `development` branch using the `$CI_COMMIT_BRANCH` variable.
112 |
113 | - **Using Includes:** Create a separate YAML file for test jobs and include it in your main `.gitlab-ci.yml` file.
114 | - **HINT:** Refer to `include` to split your CI/CD configuration in mutliple files. For more details ([Click Here](https://docs.gitlab.com/ee/ci/yaml/#include)).
115 |
116 | - **Create Job Dependencies using needs:** Create a job that depends on the successful completion of another job.
117 | - **HINT:** Refer to `needs` by visiting ([Click Here](https://docs.gitlab.com/ee/ci/yaml/#needs)).
118 |
119 | - **Parallel Jobs:** Create multiple test jobs that run in parallel to speed up your pipeline.
120 | - **HINT:** Refer to `parallel` by visiting ([Click Here](https://docs.gitlab.com/ee/ci/yaml/#parallel)).
121 |
122 | - **Caching Dependencies:** Implement caching for pip dependencies to speed up subsequent pipeline runs.
123 | - **HINT:** Refer to `cache` by visiting ([Click Here](https://docs.gitlab.com/ee/ci/yaml/#cache)).
124 |
125 | - **Create a Docker Image Job:** Create a job in the `.gitlab-ci.yml` file which builds a Docker image of your Python application and pushes it to DockerHub.
126 |
127 | - **Jobs with Artifacts:** Create a job with artifacts by generating a test coverage report and save it as an artifact that can be downloaded after the pipeline completes.
128 |
129 | ## Conclusion
130 |
131 | Congratulations! You have finished this exercise of GitLab CI/CD. With this you have learned how to create a basic pipeline, execute the pipeline, and also learn about many more advanced features of the yaml configuration. Continue to explore and read further in the GitLab's documentation to learn more about the best practices and advanced CI/CD configurations.
132 |
133 | All the best, and happy learning!
134 |
135 |
--------------------------------------------------------------------------------
/Week 1/GitHub Actions Practice/README.md:
--------------------------------------------------------------------------------
1 | # GitHub Actions CI/CD Exercise: Python Backend Project
2 |
3 | In this exercise, you will create and run your first CI/CD pipeline on GitHub Actions. You will learn how to configure a simple pipeline and how to run it, and also explore some advanced features of GitHub Actions.
4 |
5 | ## Some Helpful Links:
6 |
7 | - **(Must Read)** Understanding GitHub Actions: https://docs.github.com/en/actions/about-github-actions/understanding-github-actions
8 | - GitHub Actions syntax reference guide: https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions
9 | - Tutorial: Create a GitHub Actions workflow: https://docs.github.com/en/actions/quickstart
10 | - More Information about GitHub-hosted runners:
11 | - Public Repositories: ([Click Here](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories))
12 | - Private Repositories ([Click Here](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for--private-repositories))
13 |
14 | - How to use the checkout action in GitHub Actions: ([Click Here](https://graphite.dev/guides/github-actions-checkout))
15 |
16 | ## Prerequisites
17 |
18 | Before starting this exercise, ensure you have:
19 |
20 | 1. A GitHub account
21 | - If you do not have one, you can sign up at [GitHub.com](https://github.com/join)
22 |
23 | 2. `Git` installed on your local machine
24 | - To test if it's installed, open your Command Line Terminal and run:
25 | ```
26 | git --version
27 | ```
28 | - If not installed, download it from [git-scm.com](https://git-scm.com/downloads)
29 |
30 | 3. `Python` installed on your local machine _(Python 3.7 or higher recommended)_
31 | - To test if it's installed, open your Command Line Terminal and run:
32 | ```
33 | python --version
34 | ```
35 | or
36 | ```
37 | python3 --version
38 | ```
39 | - If not installed, you can download Python here:
40 | - Windows OS: https://www.python.org/downloads/
41 | - macOS: https://www.python.org/downloads/macos/
42 |
43 | _Ensure all prerequisites are met before proceeding with the exercise._
44 |
45 | ## Objective
46 |
47 | Your task is to complete the `.github/workflows/github-ci.yml` file to create a working CI/CD pipeline with two jobs: `build` and `test`.
48 |
49 | ## Brief Instructions Overview
50 |
51 | 1. Fork this repository on your GitHub account.
52 | 2. Clone this forked repository on your **GitHub account** to local,
53 | **OR**
54 | You can edit the `.github/workflows/github-ci.yml` file on the browser version of GitHub.
55 | 3. Open the `.github/workflows/github-ci.yml` file in your preferred text editor.
56 | 4. Follow the **TODO** steps in the `github-ci.yml` file to complete the configuration.
57 |
58 | ## [1/2] Step-by-Step Guide to complete the `github-ci.yml` file
59 |
60 | Follow these steps to complete the GitHub Actions workflow file:
61 |
62 | ### TODO-STEP 1: Define the Workflow Name
63 | - Uncomment the `name:` line and replace `` with a descriptive name for your workflow (e.g., Python CI/CD Pipeline).
64 |
65 | ### TODO-STEP 2: Define the Trigger Events
66 | - Uncomment the `on:` section and the `push:` and `pull_request:` lines to trigger the workflow on push and pull request events.
67 |
68 | ### TODO-STEP 3: Create the "Build" Job
69 | - Uncomment the `:` line and replace it with a suitable job name (e.g., build).
70 | - For TODO-STEP 3a, uncomment the `runs-on:` line.
71 | - For TODO-STEP 3b, enter a name for your step to display on GitHub (e.g., Install dependencies).
72 | - For TODO-STEP 3c, add commands to install dependencies, replacing `` with `requirements`.
73 |
74 | ### TODO-STEP 4: Create the "Test" Job
75 | - Uncomment the `:` line and replace it with a suitable job name (e.g., test).
76 | - For TODO-STEP 4a, uncomment the `needs:` line and replace `` with the name you used for the first job.
77 | - For TODO-STEP 4b, uncomment the `Install dependencies` step.
78 | - For TODO-STEP 4c, uncomment the `Run tests` step.
79 |
80 | > ## Important Notes
81 | > - Make sure to keep the `uses: actions/setup-python@v2` and `uses: actions/checkout@v2` steps as is.
82 | > - Remember to remove the `#` symbol to uncomment lines when replacing content in the placeholders.
83 | > - Make sure your indentation is correct. YAML is sensitive to indentation.
84 |
85 | ## [2/2] Executing the CI/CD Pipeline on GitHub Actions
86 |
87 | After completing the `github-ci.yml` file:
88 | 1. Commit your changes in your local machine.
89 | 2. Push the changes to your GitHub repository.
90 | 3. Go to your project on GitHub and navigate to the `"Actions"` tab to see your workflow running.
91 | 4. Debug any issues that arise and make necessary adjustments to your `github-ci.yml` file.
92 | 5. Once your workflow run is successful, try making changes to the backend code and pushing the changes to see any changes in workflow execution or logs.
93 | 6. Explore more options of the GitHub Actions configuration, including job logs and workflow visualizations.
94 |
95 | > _Wohoo! You have successfully run your first CI/CD pipeline on GitHub Actions._
96 |
97 | ## Additional Practice Tasks and Challenges
98 |
99 | ### Basic Tasks:
100 |
101 | 1. **Conditional Job Execution:** Implement a job that only runs when changes are made to specific files or directories:
102 | - **HINT:** Use the `paths` keyword in the `on` section to run a job only when changes are made to Python files (`'**.py'`). For more details ([Click Here](paths)).
103 |
104 | 2. **Manual Workflow Dispatch:** Create a workflow that can be triggered manually from the GitHub Actions UI.
105 | - **HINT:** Use the `workflow_dispatch` event trigger. For more details ([Click Here](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onworkflow_dispatch)).
106 |
107 | 3. **Use Environment Variables:** Create a job that uses a custom environment variable, and set its value using GitHub Secrets.
108 | - **HINT:** Use `env` to define environment variables and `${{ secrets.SECRET_NAME }}` to access GitHub Secrets.
109 | - [env](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#env)
110 | - [jobs..steps[*].env](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsenv)
111 | - [jobs..container.env](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idcontainerenv)
112 |
113 | > **SOLUTION:** The answers and examples of above task can be found in the file [`Answer/github-ci.yml`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Week%201/GitHub%20Actions%20Practice/Answer/github-ci.yml).
114 |
115 | ## (OPTIONAL) Explore Intermediate-level challenges:
116 |
117 | - **Execute workflow only on specific branches:** Set up a job that runs only on specific branches: i.e. Create a job that runs only on the `development` branch using the `branches` keyword under the `on` section.
118 | - **HINT:** Refer `on` for more details ([Click Here](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#onpull_requestpull_request_targetbranchesbranches-ignore))
119 |
120 | - **Create Job Dependencies:** Create a job that depends on the successful completion of another job.
121 | - **HINT:** Use the `needs` keyword to specify job dependencies. For more details ([Click Here](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idneeds))
122 |
123 | - **Matrix Strategy:** Create a test job that runs on multiple Python versions using a matrix strategy.
124 | - **HINT:** Use the `strategy` and `matrix` keywords to define multiple Python versions. For more details ([Click Here](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#jobsjob_idstrategy))
125 |
126 | - **Caching Dependencies:** Implement caching for pip dependencies to speed up subsequent workflow runs.
127 | - **HINT:** Use the `actions/cache` action to cache pip dependencies. For more details:
128 | - ([Click Here - github.com/actions/cache](https://github.com/actions/cache))
129 | - ([Click Here - documentation](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/caching-dependencies-to-speed-up-workflows#using-the-cache-action))
130 |
131 | - **Create a Docker Image Job:** Create a job in the workflow file which builds a Docker image of your Python application and pushes it to DockerHub.
132 |
133 | - **Jobs with Artifacts:** Create a job that generates a test coverage report and saves it as an artifact that can be downloaded after the workflow completes.
134 |
135 | ## Conclusion
136 |
137 | Congratulations! You have completed this exercise in GitHub Actions. You have learned how to create a basic workflow, run the workflow, and also about many other advanced features of the YAML configuration. Continue to explore and read further in GitHub's documentation to learn more about the best practices and advanced CI/CD configurations.
138 |
139 | All the best, and happy learning!
140 |
141 |
--------------------------------------------------------------------------------
/Week 2/Docker Practice/README.md:
--------------------------------------------------------------------------------
1 | # Docker Containerization Exercise: Python Flask API
2 |
3 | This exercise guides you through the process of containerizing a Python Flask API using Docker. After sucessfully completing this exercise you will have learnt how to create a Dockerfile, build a Docker image, and run a container.
4 |
5 | ## Prerequisites
6 |
7 | Before starting this exercise, ensure you have:
8 |
9 | 1. **Docker** installed on your local machine:
10 | - To test if it is installed, open your Command Line Terminal and run:
11 | ```bash
12 | docker --version
13 | ```
14 | - If not installed, download it from here:
15 | - Windows: [Docker Desktop for Windows](https://docs.docker.com/desktop/setup/install/windows-install/)
16 | - macOS: [Docker Desktop for Mac](https://docs.docker.com/desktop/setup/install/mac-install/)
17 | - Linux: [Docker Engine for Linux](https://docs.docker.com/desktop/setup/install/linux/)
18 |
19 | For convenience, please find the video tutorials to guide through the installation process:
20 |
21 | - [Windows Tutorial](https://www.youtube.com/watch?v=ZyBBv1JmnWQ)
22 | - [macOS Tutorial](https://www.youtube.com/watch?v=uDkf1fSPlYQ)
23 | - Linux Tutorials: [Option 1](https://www.youtube.com/watch?v=cqbh-RneBlk) or [Option 2](https://www.youtube.com/watch?v=PtwHLvfiyks)
24 |
25 | 2. A [**DockerHub account**](https://hub.docker.com/), if you do not have one, you can sign up [here](https://hub.docker.com/signup)
26 |
27 | 3. **Python** installed on your local machine _(Python 3.7 or higher recommended)_
28 | - To test if it is installed, open your Command Line Terminal and run:
29 | ```bash
30 | python --version
31 | ```
32 | or
33 | ```bash
34 | python3 --version
35 | ```
36 | - If not installed, you can download Python here:
37 | - [Windows OS](https://www.python.org/downloads/)
38 | - [macOS](https://www.python.org/downloads/macos/)
39 |
40 | _Ensure all prerequisites are met before proceeding with the exercise._
41 |
42 |
43 | ## Objective
44 |
45 | The objective of this practice task is to complete the `Dockerfile` file to containerize the provided Python Flask Calculator API.
46 |
47 | Provided Code Structure:
48 | - `app.py`: This is the Python Flask Calculator API.
49 | - `requirements.txt`: File containing list of libraries or packages which need to be installed for running the `app.py`.
50 | - `Dockerfile`: Template file which is to be completed.
51 |
52 | ## [1/2] Step-by-Step Guide to Complete the `Dockerfile`
53 |
54 | Open the `Dockerfile` and follow these steps to complete it:
55 |
56 | ### TODO-STEP 1: Choose a base image
57 | - Replace `` with an appropriate Python base image (e.g., `python:3.9-slim`).
58 |
59 | _Official Python images available on [DockerHub Here](https://hub.docker.com/_/python)._
60 |
61 | ### TODO-STEP 2: Create a dedicated working directory for our application
62 | - Replace `` with a appropriate folder name (e.g., `/app`)
63 |
64 | ### TODO-STEP 3: Copy the dependencies (requirements) file into the container
65 | - Replace `` with `requirements.txt`
66 | - Replace `` based on the folder name set in STEP-2 (e.g.,`requirements.txt`)
67 |
68 | ### TODO-STEP 4: Install the Python dependencies
69 | - Replace `` with `pip install -r requirements.txt`
70 |
71 | ### TODO-STEP 5: Copy the application code `app.py`
72 | - Apply the same principle as STEP-3 for `app.py` in this step.
73 |
74 | ### TODO-STEP 6: Specify the command to run the application
75 | - Replace `` with `["python", "app.py"]`
76 |
77 | > **TIP**: If there is any confusion between `RUN`, `CMD`, and `ENTRYPOINT` commands then refer to these helpful resources:
78 | > - [Docker best practices in choosing between RUN, CMD, ENTRYPOINT ](https://www.docker.com/blog/docker-best-practices-choosing-between-run-cmd-and-entrypoint/)
79 | > - [Stack Overflow: Difference Between RUN, CMD, ENTRYPOINT](https://stackoverflow.com/questions/37461868/difference-between-run-and-cmd-in-a-dockerfile)
80 |
81 | > ## Important Notes
82 | > - Make sure to remove the `<` and `>` symbols when replacing the placeholders.
83 | > - Double-check your indentation and syntax.
84 |
85 |
86 | ## [2/2] Building and Running the Docker Container
87 |
88 | After completing the above `Dockerfile` steps:
89 |
90 | 1. **Open a terminal** in the directory containing your `Dockerfile` and application files (in our case `app.py`).
91 |
92 | 2. To **build a Docker image**, use the following syntax:
93 | ```bash
94 | docker build -t .
95 | ```
96 | - ``: Replace this with a valid name for the image.
97 | - `.` at the end of the command specifies the "build context" to be the "current directory". _(i.e. build our Dockerfile present in the current directory)_
98 |
99 | _For example_, to build an image named "calculator-api":
100 | ```bash
101 | docker build -t calculator-api .
102 | ```
103 |
104 | 3. To **run a Docker container**, use the following syntax:
105 | ```
106 | docker run -p :
107 | ```
108 | - The above command starts running the container, and maps port on which the application which runs inside the container to the port on the local host machine.
109 | - ``: The port on the local host machine.
110 | - ``: The port inside the Docker container.
111 | - ``: The name of the image you built.
112 |
113 | _For example_, execute the following command to run the "calculator-api" container image:
114 |
115 | ```bash
116 | docker run -p 5000:6000 calculator-api
117 | ```
118 | - This command:
119 | 1. Starts running a container from the "calculator-api" image
120 | 2. Maps port 6000 in the container (this is the port on which the calculator api `app.py` runs) **to** port 5000 of the host machine (this is the port on which we can call the API to reach our application).
121 |
122 | - For more information on these commands, refer to the Docker documentation:
123 | - [`docker run` documentation](https://docs.docker.com/engine/containers/run/)
124 | - [`-p` flag documentation](https://docs.docker.com/engine/containers/run/#exposed-ports)
125 |
126 | 4. **Testing the Application**: Use a tool like cURL or Postman to test the API endpoints:
127 | - Test endpoint: `GET http://localhost:5000/api/test`
128 |
129 | (_This endpoint can be tested on the browser visit: [http://localhost:5000/api/test](http://localhost:5000/api/test)_)
130 |
131 | - Addition endpoint: `POST http://localhost:5000/api/add`
132 | ```json
133 | {
134 | "number_1": 5,
135 | "number_2": 3
136 | }
137 | ```
138 |
139 | 5. **Stopping the Container**: Press `Ctrl+C` in the terminal where the container is running to stop it.
140 |
141 | > Congratulations! You've successfully containerized your Python Calculator API using Docker.
142 |
143 | > **SOLUTION:** The solution for the above tasks can be found in the file [`Answer/Dockerfile`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Week%202/Docker%20Practice/Answer/Dockerfile).
144 | It is highly recommended that you attempt to complete the exercise independently before reviewing the solution, as this will enhance your learning experience. If you encounter any difficulties, feel free to consult the solution for guidance.
145 |
146 | ## Additional Topics and Further Practice
147 |
148 | 1. **Environment Variables**: Modify the Dockerfile to use an environment variable for configuring the port number on which the application runs. _For example_:
149 |
150 | - Use the `ENV` instruction in your Dockerfile to set a default port, and update the `CMD` instruction to use this environment variable.
151 | - In Dockerfile use `ENV PORT=5000` and then use `CMD ["python", "app.py", "--port", "$PORT"]`
152 | - Learn more: [Docker ENV instruction](https://docs.docker.com/reference/dockerfile/#env)
153 |
154 | 2. **Multi-stage Build**: Create a Dockerfile with separate stages for 'building' and 'testing' the application. To achieve this:
155 | - Use multiple `FROM` statements to define different stages.
156 | - Create a stage for installing dependencies and running tests.
157 | - Copy only necessary files to the final stage.
158 | - Learn more: [Multi-stage builds](https://docs.docker.com/build/building/multi-stage/)
159 |
160 | 3. **Docker Compose**: Create a `docker-compose.yml` file to run your application along with multiple other services (e.g., your backend application and a database).
161 | - Learn more: [Docker compose overview](https://docs.docker.com/compose/)
162 |
163 | 4. **Health Checks**: Implement a health check in the `Dockerfile` to ensure the application is running correctly. To achieve this:
164 | - Create a simple endpoint in the application for health checks.
165 | - Use the `HEALTHCHECK` instruction in the Dockerfile.
166 | - Configure the check interval, timeout, and retries.
167 | - _For example:_
168 | ```Dockerfile
169 | HEALTHCHECK --interval=5m --timeout=3s \
170 | CMD curl -f http://localhost:5000/health || exit 1
171 | ```
172 | - Learn more: [Docker HEALTHCHECK ](https://docs.docker.com/reference/dockerfile/#healthcheck)
173 |
174 | 5. **Custom Network**: Explore Docker networking (`docker network create`) to create a custom network.
175 | - Learn more: [Docker networking guide](https://docs.docker.com/engine/network/)
176 |
177 | Remember to explore the Docker documentation for more advanced features and best practices!
178 |
179 |
180 | ## Conclusion
181 |
182 | Congratulations! You have successfully containerized a Python Flask API using Docker. This exercise introduced you to key Docker concepts and practices. Continue exploring Docker's documentation and experiment with more complex configurations to deepen your understanding.
183 |
184 | All the best, and happy learning!
185 |
186 | ---
--------------------------------------------------------------------------------
/Project/README.md:
--------------------------------------------------------------------------------
1 | # Multi-Container Docker Application with CI/CD: Calculator App Project
2 |
3 | ## Project Overview
4 | The goal of this project is to assess your understanding of Docker containerization and Continuous Integration/Continuous Deployment (CI/CD) principles. You will be provided with a simple calculator web application consisting of a **React frontend** and a **Python backend**. Your task is to containerize these components, create a multi-container setup using Docker Compose, and implement an automated CI/CD pipeline.
5 |
6 | **NOTE**: [Please **submit** your project here](https://airtable.com/appkB4tLGaUIf7rIf/shr6YX4kY3rUhMTIu): https://airtable.com/appkB4tLGaUIf7rIf/shr6YX4kY3rUhMTIu
7 |
8 | ## Learning Objectives
9 | After successful completion of this project, you will:
10 | 1. Gain practical experience in containerizing existing applications using Docker.
11 | 2. Learn to orchestrate multi-container applications with Docker Compose.
12 | 3. Understand and implement CI/CD practices using GitHub Actions or GitLab CI/CD.
13 | 4. Develop skills in writing clear documentation and setup instructions.
14 |
15 | ## Provided Components
16 | The following code will be available:
17 | 1. **Frontend:** A React-based calculator web application.
18 | 2. **Backend:** A Python Flask API for performing calculation operations.
19 |
20 | > **NOTE:** The template `Dockerfile` and `YAML configurations` are available in this directory. It is **NOT** compulsory to use these files as they are. It may be that creating your own files from scratch and referring to the templates may be more beneficial and efficient. Feel free to adapt based on which feels best as needed.
21 |
22 | ## TODO Tasks
23 | ### STEP-1: Implement the Dockerfiles
24 | 1. Create Dockerfiles for both frontend and backend components.
25 | 2. Create a `docker-compose.yml` file for local development.
26 | 3. (Good to have) Use environment variables for configuration management.
27 |
28 | ### STEP-2: Implement the CI/CD Pipeline
29 | 1. Implement a workflow using GitHub Actions or GitLab CI/CD.
30 | 2. Automate the building and testing of Docker images.
31 | 3. Configure the pipeline to push images to Docker Hub.
32 |
33 | ### STEP-3: Write Clear Documentation
34 | - Create a comprehensive README.md with setup instructions and an explanation of the created Dockerfile and YAML configuration.
35 |
36 | > Please find the **TODO** template [`Project/SUBMISSION_README.md` Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/SUBMISSION_README.md)
37 |
38 |
39 | ## Technical Requirements
40 |
41 | ### 1. Docker Implementation
42 | #### i. Frontend Dockerfile:
43 | - Use an appropriate base image (e.g., `node:14-alpine`).
44 | - Copy the entire frontend code along with `package.json`.
45 | - Install dependencies in `package.json`.
46 | - Build the React app.
47 | - Start running the React app using `npm`.
48 | - (Optional) Use a lightweight web server (e.g., `nginx:alpine`) to serve the built files.
49 |
50 | > Please find the **TODO** template [`Project/frontend/Dockerfile` Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/frontend/Dockerfile)
51 |
52 | #### ii. Backend Dockerfile:
53 | - Use an appropriate base image (e.g., `python:3.9-slim`).
54 | - Copy `requirements.txt` and install dependencies.
55 | - Copy the rest of the backend code.
56 | - Expose the necessary port.
57 | - Specify the command to run the API server.
58 |
59 | > Please find the **TODO** template [`Project/backend/Dockerfile` Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/backend/Dockerfile)
60 |
61 |
62 | #### iii. docker-compose.yml:
63 | - Define services for both frontend and backend.
64 | - Map appropriate ports.
65 | - Set up environment variables.
66 | - Ensure proper networking between services.
67 |
68 | > Please find the **TODO** template [`Project/docker-compose.yaml` Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/docker-compose.yaml)
69 |
70 |
71 | #### iv. (Optional) Environment Variables:
72 | - Use `.env` files for local development.
73 | - Implement environment variables for sensitive information (e.g., API endpoints).
74 |
75 | ### 2. CI/CD Pipeline (GitHub Actions)
76 | Create a YAML configuration file with the following steps:
77 | 1. Trigger on push to the main branch and pull requests.
78 | 2. Set up the environment (Node.js, Python, Docker).
79 | 3. Build Docker images for frontend and backend.
80 | 4. Run any tests (Optional).
81 | 5. Push images to Docker Hub (on successful merge to main).
82 |
83 | > Please find the **TODO** template GitLab CI [`Project/.gitlab-ci.yml` Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/.gitlab-ci.yml)
84 |
85 | **OR**
86 |
87 | > Please find the **TODO** template GitHub Actions [`Project/github-actions.yml` Here](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/github-actions.yml)
88 |
89 |
90 | ## Testing Requirements
91 |
92 | ### Application Testing (Frontend + Backend)
93 | 1. **API Endpoint Validation**
94 | - Ensure all calculation endpoints are reachable & return correct results.
95 |
96 | 2. **Functional Testing**
97 | - Verify all calculator operations work correctly:
98 | - Addition (+)
99 | - Subtraction (-)
100 | - Multiplication (*)
101 | - Division (/)
102 |
103 | ### Docker and Containerization Testing
104 | 1. **Compose File Validation**
105 | - Verify containers start successfully on appropriate ports.
106 | - Check if the frontend-container is successfully communicating with the backend-container.
107 | - Validate port mappings.
108 |
109 | ## Project Timeline and Submission
110 |
111 | ### Important Dates
112 |
113 | - **Submission Deadline:** December 4, 2024, 11:59 PM
114 | - **Submission Method:** Online submission form [Here](https://airtable.com/appkB4tLGaUIf7rIf/shr6YX4kY3rUhMTIu) Or https://airtable.com/appkB4tLGaUIf7rIf/shr6YX4kY3rUhMTIu
115 |
116 | > **NOTE**: [FORM LINK](https://airtable.com/appkB4tLGaUIf7rIf/shr6YX4kY3rUhMTIu): https://airtable.com/appkB4tLGaUIf7rIf/shr6YX4kY3rUhMTIu
117 |
118 | ### Submission Checklist
119 | - [ ] Frontend Dockerfile -------------------- ([`Project/frontend/Dockerfile`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/frontend/Dockerfile))
120 | - [ ] Backend Dockerfile --------------------- ([`Project/backend/Dockerfile`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/backend/Dockerfile))
121 | - [ ] docker-compose.yml ------------------- ([`Project/docker-compose.yaml`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/docker-compose.yaml))
122 | - [ ] CI/CD YAML configuration file --------- ([`Project/.gitlab-ci.yml`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/.gitlab-ci.yml)) **OR** ([`Project/github-actions.yml`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/github-actions.yml))
123 | - [ ] Submission Explanation README.md -- ([`Project/SUBMISSION_README.md`](https://github.com/shiftkey-labs/DevOps-Foundations-Course/blob/master/Project/SUBMISSION_README.md))
124 | - [ ] Docker Hub image links
125 | - [ ] Successful functional testing
126 |
127 | ## Project Completion Questions
128 |
129 | **Please answer the following questions to ensure all the steps of the project are completed:**
130 |
131 | 1. [ ] Have you created the Backend Dockerfile?
132 | - [ ] Are you able to create the backend container and test the API?
133 | 2. [ ] Have you created the Frontend Dockerfile?
134 | - [ ] Are you able to create the frontend container and test the Web app?
135 | 3. [ ] Have you created the docker-compose YAML file?
136 | - [ ] Are you able to successfully run the compose file and test the application?
137 | 4. [ ] Have you written the CI/CD YAML file?
138 | - [ ] When you run your CI/CD pipeline, are all of your stages passing?
139 | 5. [ ] Have you written the SUBMISSION_README file?
140 |
141 | 6. [ ] Is the latest Frontend Dockerfile, Backend Dockerfile, CI/CD YAML file, and README pushed to the GitHub repository?
142 |
143 | > **Note:** If you have answered **'YES'**/✅ to all the Checklist Questions, then good work! You have completed all steps of the project and are all set to submit your work!
144 |
145 | ## Project Deliverables
146 | 1. `Dockerfile` for frontend.
147 | 2. `Dockerfile` for backend.
148 | 3. `docker-compose.yml` file.
149 | 4. CI/CD YAML configuration `.github/workflows/ci.yml` OR `.gitab-ci.yml` file.
150 | 5. `README.md` file containing:
151 | - Brief Project overview.
152 | - Instructions for setting up and running the application locally using Docker Compose.
153 | - Explanation of the CI/CD pipeline and its stages.
154 | - Any assumptions or design decisions made.
155 |
156 | ## Submission Guidelines
157 | 1. Fork the provided [GitHub repository](https://github.com/shiftkey-labs/DevOps-Foundations-Course/tree/master) containing the frontend and backend code (present in the Project folder).
158 | 2. Implement your solutions in the forked repository.
159 | 3. Ensure that your repository includes all required files:
160 | - Dockerfiles
161 | - docker-compose.yml
162 | - CI/CD YAML configuration file
163 | 4. Push your Docker images to Docker Hub.
164 | 5. The form to submit the following will be available soon:
165 | - URL or link of your GitHub repository.
166 | - URL or link of your Docker Hub repository.
167 |
168 |
169 | ## Evaluation Criteria
170 | Your project will be evaluated based on the following:
171 | 1. Correct implementation of Frontend, Backend `Dockerfiles` and `docker-compose.yml` files (**40%**-Divided equally).
172 | 2. Successful implementation of the CI/CD pipeline using GitHub Actions or GitLab CI/CD (**40%**).
173 | 3. Completeness and clarity of the README documentation (**20%**).
174 |
175 | ## Support
176 | If you encounter any issues or have questions about the project requirements, Docker concepts, or CI/CD implementation, please reach out to the instructor for clarification and assistance.
177 |
178 |
179 | ---
180 |
--------------------------------------------------------------------------------
/Project/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import axios from 'axios';
3 | import './App.css';
4 | /*
5 | App: Calculator application with basic arithmetic operations and few advanced operations like logarithms and square roots.
6 | NOTE: The code is not 100% complete and flawless. There is room for improvement. These could include:
7 | TODO: Fixes Required
8 | [1] After a invalid operation is performed either 'Error' or 'Error: ' is displayed
9 | on screen. After which if a user clicks on any number for calculation, this app considers the text for calculation. This
10 | needs to be fixed to reset the display and add the first clicked operand as the first number.
11 | [2] Need to add check if result is error string and when pressing a 'operation symbol' followed by pressing 'equals' button
12 | then do not call backend with the operands. As this generates error 500 code.
13 | [3] Implement robust handling of Error conditions ( example: 'division by zero', etc) by displaying a specific error message
14 | instead of relying on backend error.
15 | [5] Adding a limit to the number of decimal places that can be entered for avoiding precision issues.
16 | [6] Implement robust handling of extremely large numbers (refer to JavaScript's maximum and minimum number limit) to prevent
17 | unexpected behavior.
18 |
19 | TODO: Enhancements
20 | [1] Add Keyboard input support for ease of use.
21 | [2] Add explicit checks for invalid operations to send-in more accurate requests to backend to minimize error hits to backend
22 | and potential 500 server errors.
23 | [3] Add a 'backspace' or 'delete' function to allow users to correct mistakes while entering input number.
24 | [4] Add a dynamic font size adjustment for the display to accommodate very large numbers without overflow.
25 | [5] Add a feature for storing calculation histories to allow users to review past calculations and use these results for further
26 | calculations.
27 | [6] Add a feature to copy the result in to the clipboard directly from the calculator display.
28 | [7] Add unit tests for the frontend to ensure reliability.
29 | */
30 | function App() {
31 | // State variables for calculator functionality
32 | const [calculator_display, set_calculator_display] = useState('0'); // Current display value
33 | const [first_operand, set_first_operand] = useState(null);
34 | const [current_operation, set_current_operation] = useState(null);
35 | const [awaiting_second_operand, set_awaiting_second_operand] = useState(false);
36 | const [is_calculation_complete, set_is_calculation_complete] = useState(false); // Flag for calculation state
37 |
38 | // Helper Function to format large numbers for display after operations
39 | const format_large_number = (number) => {
40 | // If number is within printable limit return number as is.
41 | if (Math.abs(number) < 1e15 && Math.abs(number) > 1e-6) {
42 | return number.toString();
43 | }
44 | // For very large or very small numbers convert to exponential notation with 10 digits maximum
45 | return number.toExponential(10);
46 | };
47 |
48 | // Helper Function to get the symbol for each operation
49 | const get_operation_symbol = (operation) => {
50 | switch (operation) {
51 | case 'add': return '+';
52 | case 'subtract': return '-';
53 | case 'multiply': return '×';
54 | case 'divide': return '÷';
55 | default: return '';
56 | }
57 | };
58 |
59 | // Handle number [0 to 9] button clicks
60 | const handle_number_input = (input_number) => {
61 | // When handling the inputs if second number is not yet received or if 'equals' sign is not clicked
62 | if (awaiting_second_operand || is_calculation_complete) {
63 | set_calculator_display(input_number);
64 | set_awaiting_second_operand(false);
65 | set_is_calculation_complete(false);
66 | } else {
67 | // If user entered only decimal then convert it to 0
68 | if (input_number === '.') {
69 | if (!calculator_display.includes('.')) {
70 | set_calculator_display(calculator_display === '0' ? '0.' : calculator_display + input_number);
71 | }
72 | } else {
73 | set_calculator_display(calculator_display === '0' ? input_number : calculator_display + input_number);
74 | }
75 | }
76 | };
77 |
78 | // Handle operation [Eg.: +,-,x, etc] button clicks by setting first_operand, operation type, second_operand, and operation_status
79 | // When a operation sign is clicked then await second number
80 | const handle_operation_click = (operation) => {
81 | set_first_operand(parseFloat(calculator_display));
82 | set_current_operation(operation);
83 | set_awaiting_second_operand(true);
84 | set_is_calculation_complete(false);
85 | };
86 |
87 | // Toggle the negative sign of the current number (+/-)
88 | const toggle_sign = () => {
89 | set_calculator_display(num_on_display => {
90 | if (num_on_display === '0') return num_on_display;
91 | return num_on_display.startsWith('-') ? num_on_display.slice(1) : '-' + num_on_display;
92 | });
93 | };
94 |
95 | // Perform calculation and display the result
96 | const calculate_result = async () => {
97 | // If first_operand and operation type not found then do nothing
98 | if (first_operand === null || current_operation === null) return;
99 |
100 | try {
101 | // Request backend API with operands and operation type to get results
102 | const api_response = await axios.post(`http://localhost:5000/api/${current_operation}`, {
103 | number_1: first_operand,
104 | number_2: parseFloat(calculator_display)
105 | });
106 | // Format the returned result from API in case if large number
107 | const formatted_result = format_large_number(api_response.data.result);
108 | set_calculator_display(formatted_result);
109 | set_is_calculation_complete(true);
110 | } catch (error) {
111 | // If invalid operation then display error
112 | if (error.response?.data?.error) {
113 | set_calculator_display('Error: ' + error.response.data.error);
114 | } else {
115 | set_calculator_display('Error');
116 | }
117 | set_is_calculation_complete(false);
118 | }
119 |
120 | set_first_operand(null);
121 | set_current_operation(null);
122 | };
123 |
124 | // Clear the calculator display by clearing the calculator variables. [Reset display]
125 | const clear_calculator = () => {
126 | set_calculator_display('0');
127 | set_first_operand(null);
128 | set_current_operation(null);
129 | set_awaiting_second_operand(false);
130 | };
131 |
132 | // Handle advanced operations (Eg.: sqrt, log)
133 | const perform_advanced_operation = async (operation) => {
134 | try {
135 | let api_endpoint = '';
136 | let request_payload = {};
137 |
138 | // Create the API request to send to backend API
139 | switch (operation) {
140 | case 'sqrt':
141 | api_endpoint = 'sqrt';
142 | request_payload = { number: parseFloat(calculator_display) };
143 | break;
144 | case 'log':
145 | api_endpoint = 'log';
146 | request_payload = { number: parseFloat(calculator_display) };
147 | break;
148 | default:
149 | return;
150 | }
151 |
152 | // Request backend API with operand and operation type to get results
153 | const api_response = await axios.post(`http://localhost:5000/api/${api_endpoint}`, request_payload);
154 | // Format the returned result from API in case if large number
155 | const formatted_result = format_large_number(api_response.data.result);
156 | // Display result on the calculator display
157 | set_calculator_display(formatted_result);
158 | set_is_calculation_complete(true);
159 | } catch (error) {
160 | if (error.response?.data?.error) {
161 | set_calculator_display('Error: ' + error.response.data.error);
162 | } else {
163 | set_calculator_display('Error');
164 | }
165 | }
166 | };
167 |
168 | return (
169 |
170 |
CALCULATOR
171 |
172 | {/* A display screen to display the operand, mathematical operation, and the calculated result */}
173 |