diff --git a/Docker Image documentation.odt b/Docker Image documentation.odt new file mode 100644 index 00000000..3c42df6f Binary files /dev/null and b/Docker Image documentation.odt differ diff --git a/aks-terraform/aks-cluster-module/main.tf b/aks-terraform/aks-cluster-module/main.tf new file mode 100644 index 00000000..7acdf7d5 --- /dev/null +++ b/aks-terraform/aks-cluster-module/main.tf @@ -0,0 +1,21 @@ +resource "azurerm_kubernetes_cluster" "aks-cluster" { + name = var.aks_cluster_name + location = var.cluster_location + resource_group_name = var.resource_group_name + dns_prefix = var.dns_prefix + kubernetes_version = var.kubernetes_version +} + +default_node_pool { + name = "default" + node_count = 1 + vm_size = "standard_DS2_v2" + enable_auto_scaling = true + min_count = 1 + max_count = 3 +} + +service_principal { + client_id = var.service_principal_client_id + client_secret = var.service_principal_secret +} diff --git a/aks-terraform/aks-cluster-module/outputs.tf b/aks-terraform/aks-cluster-module/outputs.tf new file mode 100644 index 00000000..6bc89e78 --- /dev/null +++ b/aks-terraform/aks-cluster-module/outputs.tf @@ -0,0 +1,14 @@ +output "aks_cluster_name" { + description = "Name of the AKS cluster" + value = +} + +output "aks_cluster_id" { + description = "ID of the AKS cluster" + value = +} + +output "aks_kubeconfig" { + description = "Kubeconfig file for accessing the AKS cluster." + value = +} diff --git a/aks-terraform/aks-cluster-module/variables.tf b/aks-terraform/aks-cluster-module/variables.tf new file mode 100644 index 00000000..c7a7b896 --- /dev/null +++ b/aks-terraform/aks-cluster-module/variables.tf @@ -0,0 +1,64 @@ +# input variables + +variable "aks_cluster_name" { + description = "The name of the AKS cluster to be created." +  type        = string + default = "aks-cluster" + } + +variable "cluster_location" { + description = "Specfies the Azure region where the AKS cluster would be deployed to" + type = string + default = "UK South" + } + +variable "dns_prefix" { + description = "Defines the DNS prefix of cluster" + type = string + } + +variable "kubernetes_version" { + description = "Specifies which Kubernetes version the cluster would use" + type = string + default = "1.26.6" + } + +variable "service_principal_client_id" { + description = "Provides the Client ID for the service principal associated with cluster" + type = string + default = "549b492c-2de8-4e83-84fe-d55e63b066bf" + } + +varaible "service_principal_secret" { + description = "Supplies the Client secret for the service principal" + type = string + default = "KHL8Q~a954lzhfeG.Qqut942LABjem28J_cMwdgY" + } + +# Adding the following output variables from networking module as input +# varables. + +output "vnet_id" { + description = "For storing the id of the previously created vnet" + value = azure_resource_group.aks_vnet.name + } + + output "control_plane_subnet_id" { + description = "For storing the ID of the control plane subnet within the Vnet" + value = azure_resource_group.aks_vnet.control_plane_subnet.name + } + +output "worker_node_subnet_id" { + description = "For storing the ID of the worker node subnet within the Vnet" + value = azure_resource_group.aks_vnet.worker_node_subnet.name +} + +output "networking_resource_group_name" { + description = Azure Resource Group where the networking resources were provisioned in." + value = var.azure_resource_group.name + } + +output "aks_nsg_id" { + description = "store the ID of the Network Security Group (NSG)." + value = azure_resource_group.aks-nsg.name + } diff --git a/aks-terraform/application-manifest.yaml b/aks-terraform/application-manifest.yaml new file mode 100644 index 00000000..705dc862 --- /dev/null +++ b/aks-terraform/application-manifest.yaml @@ -0,0 +1,40 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: +  name: flask-app-deployment +spec: +  replicas: 2 +  selector: +    matchLabels: +      app: flask-app +  template: +    metadata: +      labels: +        app: flask-app +    spec: +      containers: +        - name: web-app-container +          image: /flask-app:v1 +          ports: +          - containerPort: 5000 +  strategy: +    type: RollingUpdate +    rollingUpdate: +      maxUnavailable: 1 +      maxSurge: 1 + +--- + +apiVersion: v1 +kind: service +metadata: +  name: flask-app-service +spec: +    selector: +    matchLabels: +      app: flask-app +  ports: + - protocol: TCP + port: 80 # port for iternal communication within the cluster location +  targetport: 5000 # port exposed by your computer + type: ClusterIP diff --git a/aks-terraform/main.tf b/aks-terraform/main.tf new file mode 100644 index 00000000..6c39dd30 --- /dev/null +++ b/aks-terraform/main.tf @@ -0,0 +1,16 @@ +terraform { +  required_providers { +    azurerm = { +      source  = "hashicorp/azure" +      version = "=3.0.0" +    } +  } +} + +provider "azurerm" { +  features {} +  client_id       = "549b492c-2de8-4e83-84fe-d55e63b066bf" +  client_secret   = "KHL8Q~a954lzhfeG.Qqut942LABjem28J_cMwdgY" +  subscription_id = "8ab233ac-c619-4888-bf7a-422ea867b8d8" +  tenant_id       = "47d4542c-f112-47f4-92c7-a838d8a5e8ef" +} diff --git a/aks-terraform/network-module/main.tf b/aks-terraform/network-module/main.tf new file mode 100644 index 00000000..8acf8c66 --- /dev/null +++ b/aks-terraform/network-module/main.tf @@ -0,0 +1,57 @@ +resource "azure_resource_group" "aks-resources" { + name = var.resource_group_name + location = "UK South" +} + +resource "virtual_network" "aks-vnet" { + name = "aks-vnet" + address_space = ["10.0.0.0/16"] +} + +resource "control_plane_subnet" "control-plane-subnet"{ + name = "control-plane-subnet" + virtual_network_name = virtual_network.aks_net.name + +} +resource "worker_node_subnet" "worker-node-subnet" { + name = "worker-node-subnet" + virtual_network_name = virtual_network.aks-vnet.name + address_prefixes = ["10.0.1.0/24"] + +} + +resource "network_security_group" "aks-nsg" { + name = "aks-nsg" + resource_group_name = var.resource_group_name + location = var.location +} + +resource "network_security_rule" "kube-apiserver-rule" { + name = "kube-apiserver-rule" + resource_group_name = "var.resource_group_name" + networking_security_group_name = network_security_group.aks_nsg.name + priority = 1001 + direction = "Inbound" + access = "Allow" + protocol = "TCP" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "*" + destination_address_prefix = "*" + +} + +resource "network_security_rule" "ssh-rule" { + name = "ssh-rule" + resource_group_name = "var.resource_group_name" + network_security_group_name = network_security_group.aks_nsg.name + priority = 1002 + direction = "Inbound" + access = Allow + protocol = "TCP" + source_port_range = "*" + destination_port_range = "80" + source_address_prefix = "*" + destination_address_prefix = "*" + +} \ No newline at end of file diff --git a/aks-terraform/network-module/outputs.tf b/aks-terraform/network-module/outputs.tf new file mode 100644 index 00000000..6ed62910 --- /dev/null +++ b/aks-terraform/network-module/outputs.tf @@ -0,0 +1,26 @@ +output "vnet_id" { + description = "For storing the ID of the previously created vnet" + value = azure_resource_group.aks-vnet.name +} + +output "control_plane_subnet_id" { + description = "For storing the Id of the control plane subnet within the vnet" + value = azure_resource_group.aks-vnet.control_plane_subnet_id.name + +} + +output "worker_node_subnet_id" { + description = "For storing the Id of the worker node subnet within the vnet" + value = azure_resource_group.aks-vnet.worker_node_subnet_id.name +} + +output "networking_resource_group_name" { + description = "Azure resource group for provisioning the network group" + value = var.resource_group_name.default +} + +output "aks_nsg_id" { + description = " To store the ID of the network security group (NSG)" + value = azure_resource_group.aks_nsg.name + +} \ No newline at end of file diff --git a/aks-terraform/network-module/variables.tf b/aks-terraform/network-module/variables.tf new file mode 100644 index 00000000..06543f6b --- /dev/null +++ b/aks-terraform/network-module/variables.tf @@ -0,0 +1,17 @@ +variable "resource_group_name" { + description = "The name of the Azure Resource group" + type = string + default = "aks-resource" +} + +variable "location" { + description = "Azure region where the networking resources will be deployed" + type = string + default = "UK South" +} + +variable "vnet_address_space" { + description = "Specifies the address space for the virtual network (Vnet)" + type = list(string) + default = ["10.0.0.0/16"] +} \ No newline at end of file diff --git a/app.py b/app.py index 50f4e29d..1a32d36d 100644 --- a/app.py +++ b/app.py @@ -9,7 +9,7 @@ # Initialise Flask App app = Flask(__name__) -# database connection +# database connection server = 'devops-project-server.database.windows.net' database = 'orders-db' username = 'maya' @@ -39,6 +39,7 @@ class Order(Base): __tablename__ = 'orders' date_uuid = Column('date_uuid', String, primary_key=True) + delivery_date = column('Delivery Date', DateTime) user_id = Column('User ID', String, primary_key=True) card_number = Column('Card Number', String) store_code = Column('Store Code', String) @@ -78,6 +79,7 @@ def display_orders(): @app.route('/add_order', methods=['POST']) def add_order(): date_uuid = request.form.get('date_uuid') + delivery_date = request.form['delivery_date'] user_id = request.form.get('user_id') card_number = request.form.get('card_number') store_code = request.form.get('store_code') @@ -85,7 +87,9 @@ def add_order(): product_quantity = request.form.get('product_quantity') order_date = request.form.get('order_date') shipping_date = request.form.get('shipping_date') - + + + # Create a session to interact with the database session = Session() @@ -98,7 +102,8 @@ def add_order(): product_code=product_code, product_quantity=product_quantity, order_date=order_date, - shipping_date=shipping_date + shipping_date=shipping_date, + delivery_date=delivery_date ) # Add the new order to the session and commit to the database @@ -109,4 +114,4 @@ def add_order(): # run the app if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000, debug=True) + app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/docker-image-documentation.txt b/docker-image-documentation.txt new file mode 100644 index 00000000..7a3fb1a0 --- /dev/null +++ b/docker-image-documentation.txt @@ -0,0 +1,18 @@ +Docker Image documentation + +Created a docker container image named dockerfile to include the following steps: +• Step 1 - Use an official Python runtime as a parent image. (used `python:3.8-slim`) +• Step 2 - Set the working directory in the container. Used WORKDIR /app. +• Step 3 - Copy the application files in the container. Used the command (COPY . .) +• Step 4 - Install system dependencies and ODBC driver. +• Step 5 - Install pip and setuptools. +• Step 6 - Install Python packages specified in requirements.txt. +• Step 7 - Expose port (EXPOSE 5000) +• Step 8 - Define Startup Command (CMD ["python", "app.py"]) +Next, build the docker container image with the command: + >docker build -t dockerfile . +Next, run the docker container using the command that includes the exposed port as in the docker image: + >docker run -p 5000:5000 dockerfile +Next, Open a web browser and go to http://127.0.0.1:5000 to interact with the application within the Docker container to confirm the application works. +Next, Tag and push the docker container image to docker hub. First login to docker using the command in the command line: docker tag dockerfile whule/dockerfile (note that dockerfile is the name of the docker container image). +Then push the container image to docker hub with this command: docker push whule/dockerfile (Note that whule is my docker hub userid and dockerfile is the docker container image name) diff --git a/dockerfile b/dockerfile new file mode 100644 index 00000000..4334ebd3 --- /dev/null +++ b/dockerfile @@ -0,0 +1,32 @@ +# TODO: Step 1 - Use an official Python runtime as a parent image. You can use `python:3.8-slim`. +FROM python:3.8-slim-buster + +# TODO: Step 2 - Set the working directory in the container +WORKDIR /app + +# TODO: Step 3 Copy the application files in the container +COPY . . + +# Install system dependencies and ODBC driver +RUN apt-get update && apt-get install -y \ + unixodbc unixodbc-dev odbcinst odbcinst1debian2 libpq-dev gcc && \ + apt-get install -y gnupg && \ + apt-get install -y wget && \ + wget -qO- https://packages.microsoft.com/keys/microsoft.asc | apt-key add - && \ + wget -qO- https://packages.microsoft.com/config/debian/10/prod.list > /etc/apt/sources.list.d/mssql-release.list && \ + apt-get update && \ + ACCEPT_EULA=Y apt-get install -y msodbcsql18 && \ + apt-get purge -y --auto-remove wget && \ + apt-get clean + +# Install pip and setuptools +RUN pip install --upgrade pip setuptools + +# TODO: Step 4 - Install Python packages specified in requirements.txt +RUN pip install -r requirements.txt + +# TODO: Step 5 - Expose port +EXPOSE 5000 + +# TODO: Step 6 - Define Startup Command +CMD ["python", "app.py"] diff --git a/templates/orders.html b/templates/orders.html index 9372e2d0..a43c48a1 100644 --- a/templates/orders.html +++ b/templates/orders.html @@ -1,19 +1,24 @@ - + Order Management - - - + + +
-

Fictional Company Name

+

Fictional Company Name

- - + +
- +
+

Order List

@@ -27,6 +32,7 @@

Order List

+ @@ -40,6 +46,7 @@

Order List

+ {% endfor %} @@ -73,10 +80,62 @@

Add New Order



+ +

+ + + - + diff --git a/~$cker Image documentation.odt b/~$cker Image documentation.odt new file mode 100644 index 00000000..69887b3e Binary files /dev/null and b/~$cker Image documentation.odt differ
Product Quantity Order Date Shipping DateDelivery Date
{{ order.product_quantity }} {{ order.order_date }} {{ order.shipping_date }}{{ order.delivery_date }}