Add Linux App Store Web Portal with Kubernetes deployment
- React-style static web portal with Tailwind CSS - OS detection (Debian/Ubuntu, Fedora, Arch, Generic) - Dynamic install commands (apt://, appstream://, flatpak) - 9 pre-configured applications - Kubernetes: 2 replicas, LoadBalancer service, Nginx ingress - GitLab Container Registry (git.giaco.net/capitano/webapplinux) - Namespace: linuxwebapp - Added Dockerfile, nginx.conf, deploy.sh, docker-compose.yml - Updated README.md with deployment instructions
This commit is contained in:
9
Dockerfile
Normal file
9
Dockerfile
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
COPY frontend/ /usr/share/nginx/html/
|
||||||
|
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
9
Dockerfile.simple
Normal file
9
Dockerfile.simple
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
COPY frontend/ /usr/share/nginx/html/
|
||||||
|
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
62
README.md
62
README.md
@@ -4,58 +4,74 @@
|
|||||||
|
|
||||||
### Prerequisiti
|
### Prerequisiti
|
||||||
|
|
||||||
- Cluster Kubernetes attivo
|
- Cluster Kubernetes attivo (es. `10.66.200.x/24`)
|
||||||
- kubectl configurato
|
- kubectl configurato
|
||||||
- Container registry accessibile (Docker Hub o privato)
|
- Container registry privato (GitLab: `git.giaco.net`)
|
||||||
|
- Personal Access Token per il registry
|
||||||
|
|
||||||
### Build e Deploy
|
### Build e Deploy
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Build l'immagine
|
# Login al registry GitLab
|
||||||
docker build -t linux-app-store:latest .
|
echo "<GITLAB_TOKEN>" | docker login git.giaco.net -u capitano --password-stdin
|
||||||
|
|
||||||
# Tagga per il push
|
# Build l'immagine
|
||||||
docker tag linux-app-store:latest <username>/linux-app-store:latest
|
docker build -t git.giaco.net/capitano/webapplinux:latest .
|
||||||
|
|
||||||
# Push su registry
|
# Push su registry
|
||||||
docker push <username>/linux-app-store:latest
|
docker push git.giaco.net/capitano/webapplinux:latest
|
||||||
|
|
||||||
# Deploy su Kubernetes
|
# Deploy su Kubernetes
|
||||||
|
kubectl apply -f k8s/namespace.yaml
|
||||||
kubectl apply -f k8s/deployment.yaml
|
kubectl apply -f k8s/deployment.yaml
|
||||||
kubectl apply -f k8s/service.yaml
|
kubectl apply -f k8s/service.yaml
|
||||||
kubectl apply -f k8s/ingress.yaml
|
kubectl apply -f k8s/ingress.yaml
|
||||||
|
|
||||||
# Verifica
|
# Verifica
|
||||||
kubectl get pods
|
kubectl get pods -n linuxwebapp
|
||||||
kubectl get svc
|
kubectl get svc -n linuxwebapp
|
||||||
kubectl get ingress
|
kubectl get ingress -n linuxwebapp
|
||||||
|
|
||||||
# Log
|
# Log
|
||||||
kubectl logs -l app=linux-app-store -f
|
kubectl logs -l app=linux-app-store -n linuxwebapp -f
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Accesso al portale
|
||||||
|
|
||||||
|
Il portale è accessibile tramite ingress nginx all'indirizzo:
|
||||||
|
- **URL**: `http://apps.local/`
|
||||||
|
|
||||||
|
Per raggiungerlo localmente, aggiungi una entry nel file `/etc/hosts`:
|
||||||
|
```
|
||||||
|
10.66.200.211 apps.local
|
||||||
|
```
|
||||||
|
(sostituisci `10.66.200.211` con l'IP del tuo Ingress controller)
|
||||||
|
|
||||||
### File struttura
|
### File struttura
|
||||||
|
|
||||||
```
|
```
|
||||||
infrastructure/
|
webapplinux/
|
||||||
├── Dockerfile # Dockerfile multi-stage (Nginx)
|
├── Dockerfile # Dockerfile Nginx
|
||||||
├── Dockerfile.simple # Dockerfile semplificato
|
├── docker-compose.yml # Compose per sviluppo locale
|
||||||
├── nginx.conf # Configurazione Nginx
|
├── nginx.conf # Configurazione Nginx
|
||||||
|
├── README.md # Questo file
|
||||||
├── frontend/
|
├── frontend/
|
||||||
│ ├── index.html # Pagina principale
|
│ ├── index.html # Pagina principale
|
||||||
│ ├── script.js # Logica dell'app
|
│ ├── script.js # Logica OS detection & install
|
||||||
│ └── apps.json # Database applicazioni
|
│ └── apps.json # Database applicazioni
|
||||||
└── k8s/
|
└── k8s/
|
||||||
├── deployment.yaml # Kubernetes Deployment (2.repliche)
|
├── namespace.yaml # Namespace linuxwebapp
|
||||||
|
├── deployment.yaml # Deployment (2 repliche, git registry)
|
||||||
├── service.yaml # Service (ClusterIP)
|
├── service.yaml # Service (ClusterIP)
|
||||||
└── ingress.yaml # Ingress (dominio apps.local)
|
└── ingress.yaml # Ingress (dominio apps.local)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Customizzazione
|
### Customizzazione
|
||||||
|
|
||||||
1. Modificare `frontend/apps.json` per aggiungere rimuovere applicazioni
|
1. **Applicazioni**: Modifica `frontend/apps.json` per aggiungere/rimuovere app
|
||||||
2. Aggiornare `nginx.conf` per personalizzare le regole di routing
|
2. **Nginx**: Aggiorna `nginx.conf` per routing personalizzato
|
||||||
3. Modificare `k8s/deployment.yaml` per aggiornare le risorse o le immagini
|
3. **Risorse**: Modifica `k8s/deployment.yaml` per cpu/memory
|
||||||
|
4. **Immagine**: Cambia `image` nel deployment per usare un altro registry
|
||||||
|
|
||||||
### Rimozione
|
### Rimozione
|
||||||
|
|
||||||
@@ -63,4 +79,12 @@ infrastructure/
|
|||||||
kubectl delete -f k8s/ingress.yaml
|
kubectl delete -f k8s/ingress.yaml
|
||||||
kubectl delete -f k8s/service.yaml
|
kubectl delete -f k8s/service.yaml
|
||||||
kubectl delete -f k8s/deployment.yaml
|
kubectl delete -f k8s/deployment.yaml
|
||||||
|
kubectl delete -f k8s/namespace.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### CI/CD
|
||||||
|
|
||||||
|
Usa il file `.gitlab-ci.yml` (da creare) per automatizzare:
|
||||||
|
1. Build dell'immagine
|
||||||
|
2. Push su GitLab registry
|
||||||
|
3. Deploy automatico in Kubernetes
|
||||||
|
|||||||
18
deploy.sh
Executable file
18
deploy.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
REGISTRY="git.giaco.net"
|
||||||
|
IMAGE_NAME="capitano/webapplinux"
|
||||||
|
TAG="latest"
|
||||||
|
|
||||||
|
echo "Building image..."
|
||||||
|
docker build -t $REGISTRY/$IMAGE_NAME:$TAG /home/capitano/kubernetes/infrastructure/webapplinux/
|
||||||
|
|
||||||
|
echo "Pushing to registry..."
|
||||||
|
docker push $REGISTRY/$IMAGE_NAME:$TAG
|
||||||
|
|
||||||
|
echo "Deploying to Kubernetes..."
|
||||||
|
kubectl apply -f k8s/namespace.yaml 2>/dev/null || true
|
||||||
|
kubectl apply -f k8s/
|
||||||
|
|
||||||
|
echo "Check status with: kubectl get pods -n linuxwebapp"
|
||||||
11
docker-compose.yml
Normal file
11
docker-compose.yml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
services:
|
||||||
|
web:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
volumes:
|
||||||
|
- ./frontend:/usr/share/nginx/html
|
||||||
|
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
|
environment:
|
||||||
|
- NGINX_HOST=apps.local
|
||||||
|
- NGINX_PORT=80
|
||||||
112
frontend/apps.json
Normal file
112
frontend/apps.json
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
{
|
||||||
|
"apps": [
|
||||||
|
{
|
||||||
|
"id": "vlc",
|
||||||
|
"name": "VLC Media Player",
|
||||||
|
"description": "The most complete media player ever created. Play all your favorite media formats.",
|
||||||
|
"icon": "fa-film",
|
||||||
|
"colors": "from-purple-500 to-indigo-600",
|
||||||
|
"packages": {
|
||||||
|
"apt": "vlc",
|
||||||
|
"appstream": "org.videolan.VLC",
|
||||||
|
"flatpak": "https://flathub.org-repo/vlc.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "gimp",
|
||||||
|
"name": "GIMP",
|
||||||
|
"description": "GNU Image Manipulation Program - professional-grade photo editing tool.",
|
||||||
|
"icon": "fa-image",
|
||||||
|
"colors": "from-blue-500 to-cyan-600",
|
||||||
|
"packages": {
|
||||||
|
"apt": "gimp",
|
||||||
|
"appstream": "org.gimp.GIMP",
|
||||||
|
"flatpak": "https://flathub.org-repo/gimp.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "vscode",
|
||||||
|
"name": "VS Code",
|
||||||
|
"description": "Visual Studio Code - the code editor redefined for modern development.",
|
||||||
|
"icon": "fa-code",
|
||||||
|
"colors": "from-blue-600 to-blue-800",
|
||||||
|
"packages": {
|
||||||
|
"apt": "code",
|
||||||
|
"appstream": "com.visualstudio.code",
|
||||||
|
"flatpak": "https://flathub.org-repo/code.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "thunderbird",
|
||||||
|
"name": "Thunderbird",
|
||||||
|
"description": "Email client that puts control back in your hands with powerful features.",
|
||||||
|
"icon": "fa-envelope",
|
||||||
|
"colors": "from-orange-500 to-red-600",
|
||||||
|
"packages": {
|
||||||
|
"apt": "thunderbird",
|
||||||
|
"appstream": "org.mozilla.thunderbird",
|
||||||
|
"flatpak": "https://flathub.org-repo/thunderbird.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "libreoffice",
|
||||||
|
"name": "LibreOffice",
|
||||||
|
"description": "The-free-and-open-source productivity suite for documents, spreadsheets, and presentations.",
|
||||||
|
"icon": "fa-file-alt",
|
||||||
|
"colors": "from-teal-500 to-green-600",
|
||||||
|
"packages": {
|
||||||
|
"apt": "libreoffice",
|
||||||
|
"appstream": "org.libreoffice.LibreOffice",
|
||||||
|
"flatpak": "https://flathub.org-repo/libreoffice.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "firefox",
|
||||||
|
"name": "Firefox",
|
||||||
|
"description": "The web browser built for privacy, speed, and customization.",
|
||||||
|
"icon": "fa-globe",
|
||||||
|
"colors": "from-orange-600 to-red-700",
|
||||||
|
"packages": {
|
||||||
|
"apt": "firefox",
|
||||||
|
"appstream": "org.mozilla.firefox",
|
||||||
|
"flatpak": "https://flathub.org-repo/firefox.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "inkscape",
|
||||||
|
"name": "Inkscape",
|
||||||
|
"description": "Professional vector graphics editor for illustrations, diagrams, and logos.",
|
||||||
|
"icon": "fa-pen-nib",
|
||||||
|
"colors": "from-blue-400 to-indigo-500",
|
||||||
|
"packages": {
|
||||||
|
"apt": "inkscape",
|
||||||
|
"appstream": "org.inkscape.Inkscape",
|
||||||
|
"flatpak": "https://flathub.org-repo/inkscape.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "discord",
|
||||||
|
"name": "Discord",
|
||||||
|
"description": "All-in-one voice and text chat for gamers and communities.",
|
||||||
|
"icon": "fa-comments",
|
||||||
|
"colors": "from-indigo-500 to-purple-600",
|
||||||
|
"packages": {
|
||||||
|
"apt": "discord",
|
||||||
|
"appstream": "com.discordapp.Discord",
|
||||||
|
"flatpak": "https://flathub.org-repo/discord.flatpakref"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "github-desktop",
|
||||||
|
"name": "GitHub Desktop",
|
||||||
|
"description": "Simple collaboration from your desktop - git made easy.",
|
||||||
|
"icon": "fa-github",
|
||||||
|
"colors": "from-gray-600 to-gray-800",
|
||||||
|
"packages": {
|
||||||
|
"apt": "github-desktop",
|
||||||
|
"appstream": "com.githubDesktop.githubDesktop",
|
||||||
|
"flatpak": "https://flathub.org-repo/github-desktop.flatpakref"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
49
frontend/index.html
Normal file
49
frontend/index.html
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="it">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Linux App Store</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
theme: {
|
||||||
|
extend: {
|
||||||
|
colors: {
|
||||||
|
gray: {
|
||||||
|
850: '#1f2937',
|
||||||
|
900: '#111827',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-900 text-white">
|
||||||
|
<nav class="bg-gray-850 border-b border-gray-700">
|
||||||
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
|
<div class="flex items-center justify-between h-16">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<i class="fas fa-store text-blue-500 text-2xl mr-3"></i>
|
||||||
|
<span class="text-xl font-bold">Linux App Store</span>
|
||||||
|
</div>
|
||||||
|
<div id="os-display" class="hidden text-sm text-gray-400"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||||
|
<div class="mb-8">
|
||||||
|
<h1 class="text-3xl font-bold mb-2">Discovery</h1>
|
||||||
|
<p class="text-gray-400">Discover and install applications directly on your Linux system</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="apps-container" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<script src="script.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
192
frontend/script.js
Normal file
192
frontend/script.js
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
const OS_TYPE = {
|
||||||
|
DEB: 'deb',
|
||||||
|
RPM: 'rpm',
|
||||||
|
ARCH: 'arch',
|
||||||
|
GENERIC: 'generic'
|
||||||
|
};
|
||||||
|
|
||||||
|
function detectOS() {
|
||||||
|
const userAgent = navigator.userAgent.toLowerCase();
|
||||||
|
|
||||||
|
if (userAgent.includes('ubuntu') ||
|
||||||
|
userAgent.includes('debian') ||
|
||||||
|
userAgent.includes('linuxmint') ||
|
||||||
|
userAgent.includes('pop!_os')) {
|
||||||
|
return { type: OS_TYPE.DEB, name: 'Debian/Ubuntu-based' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userAgent.includes('fedora') ||
|
||||||
|
userAgent.includes('rhel') ||
|
||||||
|
userAgent.includes('redhat') ||
|
||||||
|
userAgent.includes('centos') ||
|
||||||
|
userAgent.includes('opensuse') ||
|
||||||
|
userAgent.includes('suse')) {
|
||||||
|
return { type: OS_TYPE.RPM, name: 'Fedora/RedHat-based' };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userAgent.includes('arch') ||
|
||||||
|
userAgent.includes('endeavouros') ||
|
||||||
|
userAgent.includes('manjaro')) {
|
||||||
|
return { type: OS_TYPE.ARCH, name: 'Arch Linux' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { type: OS_TYPE.GENERIC, name: 'Generic Linux' };
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderApps(apps) {
|
||||||
|
const container = document.getElementById('apps-container');
|
||||||
|
|
||||||
|
apps.forEach(app => {
|
||||||
|
const appCard = document.createElement('div');
|
||||||
|
appCard.className = 'bg-gray-850 rounded-xl overflow-hidden shadow-lg hover:shadow-2xl transition-shadow duration-300 border border-gray-700';
|
||||||
|
|
||||||
|
appCard.innerHTML = `
|
||||||
|
<div class="p-6">
|
||||||
|
<div class="flex items-start justify-between mb-4">
|
||||||
|
<div class="flex items-center">
|
||||||
|
<div class="w-12 h-12 rounded-lg bg-gradient-to-br ${app.colors} flex items-center justify-center mr-4">
|
||||||
|
<i class="${app.icon} fa-xl text-white"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-xl font-bold">${app.name}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="text-gray-400 text-sm mb-6 line-clamp-2">${app.description}</p>
|
||||||
|
|
||||||
|
<div class="bg-gray-900 rounded-lg p-3 mb-4 text-xs text-gray-500 font-mono">
|
||||||
|
<div class="mb-1"><i class="fas fa-terminal mr-2"></i>Installazione:</div>
|
||||||
|
<div id="install-${app.id}">Caricamento...</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button onclick="installApp('${app.id}', '${app.packages.apt}', '${app.packages.appstream}', '${app.packages.flatpak}')"
|
||||||
|
class="w-full bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white font-bold py-3 px-4 rounded-lg transition-all duration-200 transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2">
|
||||||
|
<i class="fas fa-download mr-2"></i>Installa
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
container.appendChild(appCard);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateInstallLink(appId, aptPackage, appstreamId, flatpakUrl) {
|
||||||
|
const osInfo = detectOS();
|
||||||
|
const installDiv = document.getElementById(`install-${appId}`);
|
||||||
|
|
||||||
|
let installCommand = '';
|
||||||
|
let protocol = '';
|
||||||
|
|
||||||
|
switch (osInfo.type) {
|
||||||
|
case OS_TYPE.DEB:
|
||||||
|
protocol = 'apt://';
|
||||||
|
installCommand = `${protocol}${aptPackage}`;
|
||||||
|
break;
|
||||||
|
case OS_TYPE.RPM:
|
||||||
|
protocol = 'appstream://';
|
||||||
|
installCommand = `${protocol}${appstreamId}`;
|
||||||
|
break;
|
||||||
|
case OS_TYPE.ARCH:
|
||||||
|
protocol = 'appstream://';
|
||||||
|
installCommand = `${protocol}${appstreamId} (pacman -S ${aptPackage})`;
|
||||||
|
break;
|
||||||
|
case OS_TYPE.GENERIC:
|
||||||
|
protocol = 'flatpak';
|
||||||
|
installCommand = `Download: ${flatpakUrl}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
installDiv.innerHTML = `<i class="fas fa-terminal mr-2"></i> ${installCommand}`;
|
||||||
|
|
||||||
|
const installBtn = document.querySelector(`button[onclick="installApp('${appId}', '${aptPackage}', '${appstreamId}', '${flatpakUrl}')"]`);
|
||||||
|
|
||||||
|
installBtn.onclick = function() {
|
||||||
|
handleInstall(appId, aptPackage, appstreamId, flatpakUrl);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleInstall(appId, aptPackage, appstreamId, flatpakUrl) {
|
||||||
|
const osInfo = detectOS();
|
||||||
|
let url = '';
|
||||||
|
|
||||||
|
switch (osInfo.type) {
|
||||||
|
case OS_TYPE.DEB:
|
||||||
|
url = `apt://${aptPackage}`;
|
||||||
|
break;
|
||||||
|
case OS_TYPE.RPM:
|
||||||
|
url = `appstream://${appstreamId}`;
|
||||||
|
break;
|
||||||
|
case OS_TYPE.ARCH:
|
||||||
|
url = `appstream://${appstreamId}`;
|
||||||
|
break;
|
||||||
|
case OS_TYPE.GENERIC:
|
||||||
|
url = flatpakUrl;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (url.startsWith('apt://') || url.startsWith('appstream://')) {
|
||||||
|
const protocol = url.split(':')[0];
|
||||||
|
let command = url.replace(`${protocol}://`, '');
|
||||||
|
|
||||||
|
if (protocol === 'apt') {
|
||||||
|
command = `<span class="text-green-400">sudo apt install ${command}</span>`;
|
||||||
|
} else {
|
||||||
|
command = `<span class="text-green-400">${protocol} install ${command}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const notification = createNotification(`Comando generato per ${osInfo.name}:<br>${command}`, 'success');
|
||||||
|
document.body.appendChild(notification);
|
||||||
|
|
||||||
|
setTimeout(() => notification.remove(), 5000);
|
||||||
|
} else if (url) {
|
||||||
|
window.open(url, '_blank');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createNotification(message, type) {
|
||||||
|
const notification = document.createElement('div');
|
||||||
|
notification.className = `fixed top-4 right-4 bg-gray-800 border-l-4 border-${type === 'success' ? 'green' : 'red'}-500 text-white px-6 py-4 rounded shadow-lg z-50 transition-all duration-500 transform translate-x-full`;
|
||||||
|
notification.innerHTML = `
|
||||||
|
<div class="flex items-center">
|
||||||
|
<i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-circle'} text-${type === 'success' ? 'green' : 'red'}-500 mr-3"></i>
|
||||||
|
<div>${message}</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.classList.remove('translate-x-full');
|
||||||
|
}, 100);
|
||||||
|
|
||||||
|
return notification;
|
||||||
|
}
|
||||||
|
|
||||||
|
function highlightOS(osInfo) {
|
||||||
|
const osDisplay = document.getElementById('os-display');
|
||||||
|
if (osDisplay) {
|
||||||
|
osDisplay.innerHTML = `<i class="fab fa-${osInfo.name.includes('Ubuntu') ? 'ubuntu' : osInfo.name.includes('Fedora') ? 'fedora' : osInfo.name.includes('Arch') ? 'linux' : 'linux'} mr-2"></i>${osInfo.name}`;
|
||||||
|
osDisplay.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
fetch('apps.json')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
const osInfo = detectOS();
|
||||||
|
highlightOS(osInfo);
|
||||||
|
renderApps(data.apps);
|
||||||
|
|
||||||
|
data.apps.forEach(app => {
|
||||||
|
updateInstallLink(app.id, app.packages.apt, app.packages.appstream, app.packages.flatpak);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error loading apps:', error);
|
||||||
|
const container = document.getElementById('apps-container');
|
||||||
|
container.innerHTML = `<div class="col-span-full text-center py-10 text-red-500">
|
||||||
|
<i class="fas fa-exclamation-triangle text-3xl mb-2"></i>
|
||||||
|
<p>Errore nel caricamento delle applicazioni</p>
|
||||||
|
</div>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', init);
|
||||||
47
k8s/deployment.yaml
Normal file
47
k8s/deployment.yaml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: linux-app-store
|
||||||
|
namespace: linuxwebapp
|
||||||
|
labels:
|
||||||
|
app: linux-app-store
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: linux-app-store
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: linux-app-store
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: linux-app-store
|
||||||
|
image: git.giaco.net/capitano/webapplinux:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: 80
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
env:
|
||||||
|
- name: NGINX_HOST
|
||||||
|
value: "apps.local"
|
||||||
|
- name: NGINX_PORT
|
||||||
|
value: "80"
|
||||||
22
k8s/ingress.yaml
Normal file
22
k8s/ingress.yaml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: linux-app-store-ingress
|
||||||
|
namespace: linuxwebapp
|
||||||
|
labels:
|
||||||
|
app: linux-app-store
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: apps.local
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: linux-app-store-service
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
6
k8s/namespace.yaml
Normal file
6
k8s/namespace.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: linuxwebapp
|
||||||
|
labels:
|
||||||
|
name: linuxwebapp
|
||||||
16
k8s/service.yaml
Normal file
16
k8s/service.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: linux-app-store-service
|
||||||
|
namespace: linuxwebapp
|
||||||
|
labels:
|
||||||
|
app: linux-app-store
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
selector:
|
||||||
|
app: linux-app-store
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
name: http
|
||||||
26
nginx.conf
Normal file
26
nginx.conf
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name apps.local;
|
||||||
|
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /apps.json {
|
||||||
|
add_header Content-Type application/json;
|
||||||
|
add_header Access-Control-Allow-Origin *;
|
||||||
|
}
|
||||||
|
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml application/json;
|
||||||
|
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user