Upload files to "z2"
This commit is contained in:
parent
e7da16d9c6
commit
997111a7ba
11
z2/Dockerfile
Normal file
11
z2/Dockerfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
FROM python:3.9-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY . /app/
|
||||||
|
|
||||||
|
RUN pip install flask mysql-connector-python
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
CMD ["python", "app.py"]
|
7
z2/Dockerfile.mysql
Normal file
7
z2/Dockerfile.mysql
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
FROM mysql:8.0
|
||||||
|
|
||||||
|
ENV MYSQL_ALLOW_EMPTY_PASSWORD=true
|
||||||
|
|
||||||
|
COPY sensors_db.sql /docker-entrypoint-initdb.d/
|
||||||
|
|
||||||
|
EXPOSE 3306
|
104
z2/README.md
Normal file
104
z2/README.md
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# Interactive Floor Plan Application with Kubernetes
|
||||||
|
|
||||||
|
## Application Description
|
||||||
|
|
||||||
|
This application is an interactive floor plan visualization tool that displays sensor data on different floors of a building. Users can navigate between floors using the buttons at the bottom of the page and click on sensors to view their current data.
|
||||||
|
|
||||||
|
## Container List
|
||||||
|
|
||||||
|
1. **floorplan-webapp**
|
||||||
|
- Web application container based on Python and Flask
|
||||||
|
- Serves the frontend HTML, CSS, and JavaScript files
|
||||||
|
- Provides an API endpoint for sensor data
|
||||||
|
|
||||||
|
2. **mysql-db**
|
||||||
|
- MySQL database container
|
||||||
|
- Stores sensor information including position, floor, location, and values
|
||||||
|
|
||||||
|
## Kubernetes Objects
|
||||||
|
|
||||||
|
1. **Namespace**
|
||||||
|
- `sensor-app`: Isolated environment for all application resources
|
||||||
|
|
||||||
|
2. **Deployment**
|
||||||
|
- `floorplan-webapp`: Manages the web application with 2 replicas for high availability
|
||||||
|
|
||||||
|
3. **StatefulSet**
|
||||||
|
- `mysql`: Manages the MySQL database instance with persistent storage
|
||||||
|
|
||||||
|
4. **Services**
|
||||||
|
- `floorplan-service`: NodePort service exposing the web application on port 30080
|
||||||
|
- `mysql-service`: Headless service for MySQL database access
|
||||||
|
|
||||||
|
5. **PersistentVolume**
|
||||||
|
- `mysql-pv`: 1GB volume for MySQL data storage
|
||||||
|
|
||||||
|
6. **PersistentVolumeClaim**
|
||||||
|
- `mysql-pvc`: Claims storage from the persistent volume for MySQL
|
||||||
|
|
||||||
|
## Network and Storage Configuration
|
||||||
|
|
||||||
|
### Networks
|
||||||
|
- The application uses Kubernetes' built-in networking
|
||||||
|
- Web application connects to MySQL using the `mysql-service` DNS name
|
||||||
|
- External access is provided through a NodePort service on port 30080
|
||||||
|
|
||||||
|
### Storage
|
||||||
|
- The MySQL database uses a persistent volume mounted at `/var/lib/mysql`
|
||||||
|
- The persistent volume is backed by a hostPath at `/mnt/data` on the host machine
|
||||||
|
|
||||||
|
## Container Configuration
|
||||||
|
|
||||||
|
### Web Application Container
|
||||||
|
- Based on Python 3.9 slim image
|
||||||
|
- Installed packages: Flask, mysql-connector-python
|
||||||
|
- Configured to connect to MySQL database using environment variables
|
||||||
|
- Exposes port 5000
|
||||||
|
|
||||||
|
### MySQL Container
|
||||||
|
- Based on MySQL 8.0 image
|
||||||
|
- Configured with empty root password for development purposes
|
||||||
|
- Initializes with the sensors_db database and sample data
|
||||||
|
- Exposes port 3306
|
||||||
|
|
||||||
|
## Application Management
|
||||||
|
|
||||||
|
### Preparation
|
||||||
|
1. Make all scripts executable:
|
||||||
|
```
|
||||||
|
chmod +x prepare-app.sh start-app.sh stop-app.sh
|
||||||
|
```
|
||||||
|
2. Run the preparation script:
|
||||||
|
```
|
||||||
|
./prepare-app.sh
|
||||||
|
```
|
||||||
|
This will:
|
||||||
|
- Create the required namespace
|
||||||
|
- Prepare the persistent volume directory
|
||||||
|
- Build the Docker images
|
||||||
|
|
||||||
|
### Starting the Application
|
||||||
|
1. Run the start script:
|
||||||
|
```
|
||||||
|
./start-app.sh
|
||||||
|
```
|
||||||
|
This will:
|
||||||
|
- Apply all Kubernetes configurations
|
||||||
|
- Wait for all components to be ready
|
||||||
|
- Display the URL to access the application
|
||||||
|
|
||||||
|
### Stopping the Application
|
||||||
|
1. Run the stop script:
|
||||||
|
```
|
||||||
|
./stop-app.sh
|
||||||
|
```
|
||||||
|
This will:
|
||||||
|
- Remove all Kubernetes objects created for the application
|
||||||
|
- The persistent volume data will remain intact
|
||||||
|
|
||||||
|
### Viewing the Application
|
||||||
|
1. Open your web browser
|
||||||
|
2. Navigate to the URL displayed after running the start script (typically http://[NODE-IP]:30080)
|
||||||
|
3. You should see the interactive floor plan with sensors
|
||||||
|
4. Use the buttons at the bottom to switch between floors
|
||||||
|
5. Click on sensors to view their data in the right panel
|
160
z2/app.js
Normal file
160
z2/app.js
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
// Global variable to store the current floor
|
||||||
|
let currentFloor = 1;
|
||||||
|
|
||||||
|
// Fallback data in case API fails
|
||||||
|
const fallbackSensors = {
|
||||||
|
1: [
|
||||||
|
{ id: 1, x: 100, y: 100, floor: 1, location: "Room A", value: "22°C" },
|
||||||
|
{ id: 2, x: 200, y: 200, floor: 1, location: "Room B", value: "24°C" },
|
||||||
|
],
|
||||||
|
2: [
|
||||||
|
{ id: 3, x: 150, y: 150, floor: 2, location: "Living Room", value: "23°C" },
|
||||||
|
{ id: 4, x: 250, y: 250, floor: 2, location: "Kitchen", value: "21°C" },
|
||||||
|
],
|
||||||
|
3: [
|
||||||
|
{ id: 5, x: 120, y: 120, floor: 3, location: "Hallway", value: "22°C" },
|
||||||
|
{ id: 6, x: 220, y: 220, floor: 3, location: "Bathroom", value: "23°C" },
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Function to fetch sensors from the API
|
||||||
|
async function fetchSensors() {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/sensors');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
console.log("Fetched sensors:", data);
|
||||||
|
|
||||||
|
if (data.length === 0) {
|
||||||
|
console.warn("No sensors returned from API, using fallback data");
|
||||||
|
return fallbackSensors[currentFloor];
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Could not fetch sensors:", error);
|
||||||
|
console.warn("Using fallback sensor data due to API error");
|
||||||
|
return fallbackSensors[currentFloor];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to display the map for the corresponding floor
|
||||||
|
function showFloor(floor) {
|
||||||
|
console.log(`Showing floor ${floor}`);
|
||||||
|
currentFloor = floor;
|
||||||
|
const map = document.getElementById('map');
|
||||||
|
map.src = `images/floor${floor}.png`;
|
||||||
|
|
||||||
|
// Fetch and display sensors for this floor
|
||||||
|
fetchSensors().then(sensors => {
|
||||||
|
// Filter sensors for the current floor
|
||||||
|
const floorSensors = sensors.filter(sensor => parseInt(sensor.floor) === parseInt(floor));
|
||||||
|
console.log(`Sensors for floor ${floor}:`, floorSensors);
|
||||||
|
|
||||||
|
if (floorSensors.length === 0) {
|
||||||
|
console.warn(`No sensors found for floor ${floor}, adding test sensors`);
|
||||||
|
// Add test sensors if none found
|
||||||
|
addTestSensors();
|
||||||
|
} else {
|
||||||
|
addSensorsToMap(floorSensors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the sensor data table
|
||||||
|
const table = document.getElementById('sensor-data');
|
||||||
|
table.innerHTML = `
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add sensor points to the map
|
||||||
|
function addSensorsToMap(floorSensors) {
|
||||||
|
// First clear all previous points
|
||||||
|
const mapContainer = document.getElementById('map-container');
|
||||||
|
const existingPoints = document.querySelectorAll('.sensor');
|
||||||
|
existingPoints.forEach(point => point.remove());
|
||||||
|
|
||||||
|
console.log("Map container:", mapContainer);
|
||||||
|
|
||||||
|
// Check if we have sensors to display
|
||||||
|
if (!floorSensors || floorSensors.length === 0) {
|
||||||
|
console.warn("No sensors found for this floor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new points
|
||||||
|
floorSensors.forEach(sensor => {
|
||||||
|
console.log(`Creating sensor point at x:${sensor.x}, y:${sensor.y}`);
|
||||||
|
const sensorPoint = document.createElement('div');
|
||||||
|
sensorPoint.classList.add('sensor');
|
||||||
|
sensorPoint.style.position = 'absolute';
|
||||||
|
sensorPoint.style.left = `${sensor.x}px`;
|
||||||
|
sensorPoint.style.top = `${sensor.y}px`;
|
||||||
|
sensorPoint.style.width = '15px';
|
||||||
|
sensorPoint.style.height = '15px';
|
||||||
|
sensorPoint.style.borderRadius = '50%';
|
||||||
|
sensorPoint.style.backgroundColor = 'red';
|
||||||
|
sensorPoint.style.border = '2px solid black';
|
||||||
|
sensorPoint.style.zIndex = '1000';
|
||||||
|
sensorPoint.setAttribute('data-id', sensor.id);
|
||||||
|
sensorPoint.addEventListener('click', () => showSensorData(sensor));
|
||||||
|
|
||||||
|
mapContainer.appendChild(sensorPoint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add test sensors if API sensors aren't working
|
||||||
|
function addTestSensors() {
|
||||||
|
const testSensors = fallbackSensors[currentFloor];
|
||||||
|
addSensorsToMap(testSensors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display sensor data in the dashboard
|
||||||
|
function showSensorData(sensor) {
|
||||||
|
const table = document.getElementById('sensor-data');
|
||||||
|
|
||||||
|
// Clear the table
|
||||||
|
table.innerHTML = `
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Add a new row with sensor data
|
||||||
|
const row = table.insertRow(1);
|
||||||
|
row.insertCell(0).textContent = sensor.id;
|
||||||
|
row.insertCell(1).textContent = sensor.location;
|
||||||
|
row.insertCell(2).textContent = sensor.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the app by showing floor 1 when the page loads
|
||||||
|
window.onload = function() {
|
||||||
|
console.log("Page loaded, initializing app...");
|
||||||
|
showFloor(1);
|
||||||
|
|
||||||
|
// Add additional test sensor directly to verify positioning
|
||||||
|
setTimeout(() => {
|
||||||
|
const mapContainer = document.getElementById('map-container');
|
||||||
|
const testPoint = document.createElement('div');
|
||||||
|
testPoint.style.position = 'absolute';
|
||||||
|
testPoint.style.left = '300px';
|
||||||
|
testPoint.style.top = '300px';
|
||||||
|
testPoint.style.width = '20px';
|
||||||
|
testPoint.style.height = '20px';
|
||||||
|
testPoint.style.borderRadius = '50%';
|
||||||
|
testPoint.style.backgroundColor = 'blue';
|
||||||
|
testPoint.style.border = '3px solid yellow';
|
||||||
|
testPoint.style.zIndex = '9999';
|
||||||
|
|
||||||
|
mapContainer.appendChild(testPoint);
|
||||||
|
console.log("Test point added to verify positioning");
|
||||||
|
}, 3000);
|
||||||
|
};
|
67
z2/app.py
Normal file
67
z2/app.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
from flask import Flask, jsonify, send_from_directory
|
||||||
|
import mysql.connector
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
|
||||||
|
app = Flask(__name__, static_folder='.', static_url_path='')
|
||||||
|
|
||||||
|
# Database connection with environment variables
|
||||||
|
def get_db_connection():
|
||||||
|
# Get environment variables or use defaults
|
||||||
|
host = os.environ.get('MYSQL_HOST', 'mysql-service.sensor-app')
|
||||||
|
user = os.environ.get('MYSQL_USER', 'root')
|
||||||
|
password = os.environ.get('MYSQL_PASSWORD', '')
|
||||||
|
database = os.environ.get('MYSQL_DB', 'sensors_db')
|
||||||
|
|
||||||
|
print(f"Connecting to MySQL: {host}, {user}, {database}")
|
||||||
|
|
||||||
|
# Try to connect with retries for Kubernetes startup sequence
|
||||||
|
max_retries = 50
|
||||||
|
retry_delay = 50
|
||||||
|
|
||||||
|
for attempt in range(max_retries):
|
||||||
|
try:
|
||||||
|
conn = mysql.connector.connect(
|
||||||
|
host=host,
|
||||||
|
user=user,
|
||||||
|
password=password,
|
||||||
|
database=database
|
||||||
|
)
|
||||||
|
print("Database connection successful!")
|
||||||
|
return conn
|
||||||
|
except mysql.connector.Error as err:
|
||||||
|
print(f"Database connection error: {err}")
|
||||||
|
if attempt < max_retries - 1:
|
||||||
|
print(f"Database connection failed, retrying in {retry_delay} seconds...")
|
||||||
|
time.sleep(retry_delay)
|
||||||
|
else:
|
||||||
|
print(f"Failed to connect to database after {max_retries} attempts")
|
||||||
|
raise
|
||||||
|
|
||||||
|
@app.route('/api/sensors', methods=['GET'])
|
||||||
|
def get_sensors():
|
||||||
|
try:
|
||||||
|
conn = get_db_connection()
|
||||||
|
cursor = conn.cursor(dictionary=True)
|
||||||
|
cursor.execute('SELECT * FROM sensors')
|
||||||
|
sensors = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
conn.close()
|
||||||
|
print(f"Sensors fetched from database: {sensors}")
|
||||||
|
return jsonify(sensors)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching sensors: {e}")
|
||||||
|
# Return empty array instead of error for better frontend handling
|
||||||
|
return jsonify([])
|
||||||
|
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return send_from_directory('.', 'index.html')
|
||||||
|
|
||||||
|
# Serve static files
|
||||||
|
@app.route('/<path:path>')
|
||||||
|
def static_files(path):
|
||||||
|
return send_from_directory('.', path)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(debug=True, host='0.0.0.0')
|
31
z2/deployment.yaml
Normal file
31
z2/deployment.yaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: floorplan-webapp
|
||||||
|
namespace: sensor-app
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: floorplan-webapp
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: floorplan-webapp
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: webapp
|
||||||
|
image: floorplan-webapp:latest
|
||||||
|
imagePullPolicy: Never
|
||||||
|
ports:
|
||||||
|
- containerPort: 5000
|
||||||
|
env:
|
||||||
|
- name: MYSQL_HOST
|
||||||
|
value: mysql-service.sensor-app
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
BIN
z2/floor1.png
Normal file
BIN
z2/floor1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 114 KiB |
BIN
z2/floor2.png
Normal file
BIN
z2/floor2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 136 KiB |
BIN
z2/floor3.png
Normal file
BIN
z2/floor3.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 790 KiB |
42
z2/index.html
Normal file
42
z2/index.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Building Map</title>
|
||||||
|
<link rel="stylesheet" href="styles.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<header>
|
||||||
|
<div class="header-content">
|
||||||
|
<h1>Interactive Floor Plan with Sensors</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="main-content">
|
||||||
|
<div id="map-container">
|
||||||
|
<img id="map" src="images/floor1.png" alt="Floor 1">
|
||||||
|
<!-- Sensor points will be added here dynamically -->
|
||||||
|
</div>
|
||||||
|
<div id="dashboard">
|
||||||
|
<h2>Sensor Data</h2>
|
||||||
|
<table id="sensor-data">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Value</th>
|
||||||
|
</tr>
|
||||||
|
<!-- Sensor data will be inserted here -->
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="buttons-container">
|
||||||
|
<button onclick="showFloor(1)">Floor 1</button>
|
||||||
|
<button onclick="showFloor(2)">Floor 2</button>
|
||||||
|
<button onclick="showFloor(3)">Floor 3</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
17
z2/prepare-app.sh
Normal file
17
z2/prepare-app.sh
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Create namespace
|
||||||
|
kubectl create namespace sensor-app
|
||||||
|
|
||||||
|
# Create directory for persistent volume if not exists
|
||||||
|
sudo mkdir -p /mnt/data
|
||||||
|
sudo chmod 777 /mnt/data
|
||||||
|
|
||||||
|
# Build Docker images
|
||||||
|
echo "Building web application image..."
|
||||||
|
docker build -t floorplan-webapp:latest -f Dockerfile .
|
||||||
|
|
||||||
|
echo "Building MySQL database image..."
|
||||||
|
docker build -t mysql-db:latest -f Dockerfile.mysql .
|
||||||
|
|
||||||
|
echo "Application prepared successfully!"
|
BIN
z2/sensors_db.sql
Normal file
BIN
z2/sensors_db.sql
Normal file
Binary file not shown.
26
z2/service.yaml
Normal file
26
z2/service.yaml
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: floorplan-service
|
||||||
|
namespace: sensor-app
|
||||||
|
spec:
|
||||||
|
type: NodePort
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 5000
|
||||||
|
nodePort: 30080
|
||||||
|
selector:
|
||||||
|
app: floorplan-webapp
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: mysql-service
|
||||||
|
namespace: sensor-app
|
||||||
|
spec:
|
||||||
|
ports:
|
||||||
|
- port: 3306
|
||||||
|
targetPort: 3306
|
||||||
|
selector:
|
||||||
|
app: mysql
|
||||||
|
clusterIP: None # Headless service for StatefulSet
|
34
z2/start-app.sh
Normal file
34
z2/start-app.sh
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Apply Kubernetes configurations
|
||||||
|
echo "Creating Kubernetes resources..."
|
||||||
|
|
||||||
|
# Create namespace if it doesn't exist
|
||||||
|
kubectl get namespace sensor-app || kubectl create namespace sensor-app
|
||||||
|
|
||||||
|
# Apply configurations
|
||||||
|
echo "Applying PersistentVolume, PersistentVolumeClaim, and StatefulSet..."
|
||||||
|
kubectl apply -f statefulset.yaml
|
||||||
|
|
||||||
|
echo "Waiting for MySQL StatefulSet to be ready..."
|
||||||
|
kubectl wait --for=condition=ready pod -l app=mysql --timeout=120s -n sensor-app
|
||||||
|
|
||||||
|
echo "Applying Deployment..."
|
||||||
|
kubectl apply -f deployment.yaml
|
||||||
|
|
||||||
|
echo "Applying Service..."
|
||||||
|
kubectl apply -f service.yaml
|
||||||
|
|
||||||
|
echo "Waiting for application to be ready..."
|
||||||
|
kubectl wait --for=condition=ready pod -l app=floorplan-webapp --timeout=60s -n sensor-app
|
||||||
|
|
||||||
|
LOCAL_PORT=8080
|
||||||
|
echo ""
|
||||||
|
echo "Application started successfully!"
|
||||||
|
echo "Setting up port forwarding from localhost:$LOCAL_PORT to the service..."
|
||||||
|
echo "You can access the application at: http://localhost:$LOCAL_PORT"
|
||||||
|
echo ""
|
||||||
|
echo "Press Ctrl+C to stop port forwarding when done"
|
||||||
|
|
||||||
|
# Start port forwarding
|
||||||
|
kubectl port-forward -n sensor-app service/floorplan-service $LOCAL_PORT:80
|
66
z2/statefulset.yaml
Normal file
66
z2/statefulset.yaml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolume
|
||||||
|
metadata:
|
||||||
|
name: mysql-pv
|
||||||
|
namespace: sensor-app
|
||||||
|
labels:
|
||||||
|
type: local
|
||||||
|
spec:
|
||||||
|
storageClassName: manual
|
||||||
|
capacity:
|
||||||
|
storage: 1Gi
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
hostPath:
|
||||||
|
path: "/mnt/data"
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: mysql-pvc
|
||||||
|
namespace: sensor-app
|
||||||
|
spec:
|
||||||
|
storageClassName: manual
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: mysql
|
||||||
|
namespace: sensor-app
|
||||||
|
spec:
|
||||||
|
serviceName: mysql-service
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: mysql
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: mysql
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: mysql
|
||||||
|
image: mysql-db:latest
|
||||||
|
imagePullPolicy: Never
|
||||||
|
ports:
|
||||||
|
- containerPort: 3306
|
||||||
|
name: mysql
|
||||||
|
env:
|
||||||
|
- name: MYSQL_ALLOW_EMPTY_PASSWORD
|
||||||
|
value: "true"
|
||||||
|
volumeMounts:
|
||||||
|
- name: mysql-persistent-storage
|
||||||
|
mountPath: /var/lib/mysql
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "500m"
|
||||||
|
volumes:
|
||||||
|
- name: mysql-persistent-storage
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: mysql-pvc
|
10
z2/stop-app.sh
Normal file
10
z2/stop-app.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Stopping and removing Kubernetes resources..."
|
||||||
|
|
||||||
|
# Delete all resources in the namespace
|
||||||
|
kubectl delete -f service.yaml
|
||||||
|
kubectl delete -f deployment.yaml
|
||||||
|
kubectl delete -f statefulset.yaml
|
||||||
|
|
||||||
|
echo "Application stopped successfully!"
|
96
z2/styles.css
Normal file
96
z2/styles.css
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/* General Styles */
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background-color: #333;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map-container {
|
||||||
|
position: relative;
|
||||||
|
width: 70%;
|
||||||
|
height: 500px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sensor point styling */
|
||||||
|
.sensor {
|
||||||
|
position: absolute;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: red;
|
||||||
|
border: 2px solid black;
|
||||||
|
cursor: pointer;
|
||||||
|
z-index: 100;
|
||||||
|
transition: transform 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sensor:hover {
|
||||||
|
transform: scale(1.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
#dashboard {
|
||||||
|
width: 25%;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sensor-data {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sensor-data th, #sensor-data td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button Styles */
|
||||||
|
.buttons-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 10px 20px;
|
||||||
|
margin: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 5px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #45a049;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user