├── 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 |
174 |
175 | {first_operand !== null && `${first_operand} ${current_operation ? get_operation_symbol(current_operation) : ''}`} 176 |
177 |
{calculator_display}
178 | {is_calculation_complete && ( 179 |
180 | = {calculator_display} 181 |
182 | )} 183 |
184 | 185 | {/* Display all the calculator buttons with 4 buttons on each row*/} 186 |
187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 |
212 |
213 |
214 | ); 215 | } 216 | 217 | export default App; --------------------------------------------------------------------------------