Compare commits
14 Commits
d85b409662
..
v1.9.6
| Author | SHA1 | Date | |
|---|---|---|---|
| 1fa28590b4 | |||
| 30a3ea66d5 | |||
| 6f2cfad65f | |||
| 2621d233f9 | |||
| af4997df5a | |||
| 1980fd04ba | |||
| d06d0c76c2 | |||
| 9244328da8 | |||
| 70489c3dac | |||
| 2a3ee1c8af | |||
| 8a01cb4755 | |||
| 9dfea6c795 | |||
| 29cb46963c | |||
| ca7c5f77a4 |
+2
-1
@@ -4,7 +4,8 @@ CHANGELOG.md
|
||||
*.md
|
||||
|
||||
# Deployment files
|
||||
deployment.yml
|
||||
deployment-dev.yml
|
||||
deployment-prod.yml
|
||||
run.sh
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
name: Dev
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: build-htz-01
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Build and push Docker image
|
||||
run: |
|
||||
docker build -t cr.jdbnet.co.uk/public/ipam:dev \
|
||||
--build-arg VERSION=dev \
|
||||
.
|
||||
docker push cr.jdbnet.co.uk/public/ipam:dev
|
||||
|
||||
deploy:
|
||||
name: Deploy to Kubernetes
|
||||
needs: release
|
||||
runs-on: k3s-internal-htz-01
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Deploy to Kubernetes
|
||||
run: |
|
||||
sudo kubectl replace -f deployment-dev.yml --grace-period=60 --force
|
||||
@@ -0,0 +1,60 @@
|
||||
name: Release
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
if: github.event.pull_request.merged == true && startsWith(github.head_ref, 'v')
|
||||
runs-on: build-htz-01
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Extract Version
|
||||
id: get_version
|
||||
run: echo "VERSION=${{ github.head_ref }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate Changelog
|
||||
id: changelog
|
||||
uses: https://github.com/metcalfc/changelog-generator@v4.6.2
|
||||
with:
|
||||
myToken: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
run: |
|
||||
VERSION=${{ steps.get_version.outputs.VERSION }}
|
||||
docker build -t cr.jdbnet.co.uk/public/ipam:$VERSION \
|
||||
-t cr.jdbnet.co.uk/public/ipam:latest \
|
||||
--build-arg VERSION=$VERSION \
|
||||
.
|
||||
docker push cr.jdbnet.co.uk/public/ipam:$VERSION
|
||||
docker push cr.jdbnet.co.uk/public/ipam:latest
|
||||
|
||||
- name: Create Gitea Release
|
||||
uses: https://gitea.com/actions/gitea-release-action@v1
|
||||
with:
|
||||
tag_name: ${{ steps.get_version.outputs.VERSION }}
|
||||
name: ${{ steps.get_version.outputs.VERSION }}
|
||||
body: ${{ steps.changelog.outputs.changelog }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
deploy:
|
||||
name: Deploy to Kubernetes
|
||||
needs: release
|
||||
runs-on: k3s-internal-htz-01
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Deploy to Kubernetes
|
||||
run: |
|
||||
sudo kubectl replace -f deployment-prod.yml --grace-period=60 --force
|
||||
@@ -1,59 +0,0 @@
|
||||
name: Release Please
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
packages: write
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
release_created: ${{ steps.release.outputs.release_created }}
|
||||
steps:
|
||||
- uses: googleapis/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
manifest-file: .release-please-manifest.json
|
||||
config-file: .release-please-config.json
|
||||
|
||||
- name: Checkout
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Read version
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
id: version
|
||||
run: |
|
||||
VERSION=$(cat VERSION)
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "VERSION=$VERSION" >> $GITHUB_ENV
|
||||
|
||||
- name: Build and push Docker image
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
ghcr.io/jdb-net/ipam:${{ env.VERSION }}
|
||||
ghcr.io/jdb-net/ipam:latest
|
||||
build-args: |
|
||||
VERSION=${{ env.VERSION }}
|
||||
@@ -1,46 +0,0 @@
|
||||
name: Staging
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: Build and Push
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
ghcr.io/jdb-net/ipam:staging
|
||||
|
||||
deploy:
|
||||
name: Deploy to Kubernetes
|
||||
needs: build-and-push
|
||||
runs-on: [ k3s-internal-htz-01 ]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Apply manifests
|
||||
run: |
|
||||
sudo kubectl replace -f deployment.yml --grace-period=60 --force
|
||||
@@ -1,6 +1,9 @@
|
||||
FROM python:3.13-slim
|
||||
LABEL org.opencontainers.image.vendor="JDB-NET"
|
||||
WORKDIR /app
|
||||
COPY . /app
|
||||
ARG VERSION=unknown
|
||||
ENV VERSION=${VERSION}
|
||||
RUN pip install -r requirements.txt
|
||||
RUN apt-get update && apt-get install -y curl mariadb-client-compat
|
||||
RUN rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -40,7 +40,7 @@ docker run -d \
|
||||
-e SECRET_KEY=your_secret_key \
|
||||
-e NAME="Your Organisation" \
|
||||
-e LOGO_PNG="https://example.com/logo.png" \
|
||||
ghcr.io/jdb-net/ipam:latest
|
||||
cr.jdbnet.co.uk/public/ipam:latest
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
@@ -48,7 +48,7 @@ docker run -d \
|
||||
```yaml
|
||||
services:
|
||||
ipam:
|
||||
image: ghcr.io/jdb-net/ipam:latest
|
||||
image: cr.jdbnet.co.uk/public/ipam:latest
|
||||
container_name: ipam
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
@@ -247,7 +247,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: ipam
|
||||
image: ghcr.io/jdb-net/ipam:latest
|
||||
image: cr.jdbnet.co.uk/public/ipam:latest
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
env:
|
||||
|
||||
@@ -27,14 +27,7 @@ limiter = Limiter(
|
||||
|
||||
@app.context_processor
|
||||
def inject_env_vars():
|
||||
version = 'unknown'
|
||||
try:
|
||||
version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'VERSION')
|
||||
if os.path.exists(version_file):
|
||||
with open(version_file, 'r') as f:
|
||||
version = f.read().strip()
|
||||
except Exception:
|
||||
pass
|
||||
version = os.environ.get('VERSION', 'unknown')
|
||||
|
||||
# Import has_permission and is_feature_enabled from routes after routes are registered
|
||||
from routes import has_permission, is_feature_enabled
|
||||
|
||||
@@ -15,7 +15,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: ipam
|
||||
image: ghcr.io/jdb-net/ipam:staging
|
||||
image: cr.jdbnet.co.uk/public/ipam:dev
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
@@ -0,0 +1,64 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ipam
|
||||
namespace: ipam
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ipam
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ipam
|
||||
spec:
|
||||
containers:
|
||||
- name: ipam
|
||||
image: cr.jdbnet.co.uk/public/ipam:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 5000
|
||||
name: "ipam"
|
||||
env:
|
||||
- name: SECRET_KEY
|
||||
value: "41TbN7v5peFLZPrdwSCc64J3mjmiUk5fkVWsmb2m"
|
||||
- name: MYSQL_HOST
|
||||
value: "10.10.25.4"
|
||||
- name: MYSQL_USER
|
||||
value: "ipam"
|
||||
- name: MYSQL_PASSWORD
|
||||
value: "WXPmo05sGCfjGe"
|
||||
- name: MYSQL_DATABASE
|
||||
value: "ipam"
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ipam-ingress-service
|
||||
namespace: ipam
|
||||
spec:
|
||||
selector:
|
||||
app: ipam
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 5000
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: ipam-ingress
|
||||
namespace: ipam
|
||||
spec:
|
||||
rules:
|
||||
- host: ipam.jdb143.uk
|
||||
http:
|
||||
paths:
|
||||
- pathType: Prefix
|
||||
path: "/"
|
||||
backend:
|
||||
service:
|
||||
name: ipam-ingress-service
|
||||
port:
|
||||
number: 80
|
||||
@@ -2605,7 +2605,7 @@ def register_routes(app, limiter=None):
|
||||
@app.route('/check_update')
|
||||
@login_required
|
||||
def check_update():
|
||||
"""Check for available updates from GitHub (cached for 3 hours)"""
|
||||
"""Check for available updates from Gitea (cached for 3 hours)"""
|
||||
cache_key = 'check_update'
|
||||
|
||||
# Check cache first
|
||||
@@ -2614,15 +2614,11 @@ def register_routes(app, limiter=None):
|
||||
return jsonify(cached_result)
|
||||
|
||||
try:
|
||||
# Get current version
|
||||
version_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'VERSION')
|
||||
current_version = 'unknown'
|
||||
if os.path.exists(version_file):
|
||||
with open(version_file, 'r') as f:
|
||||
current_version = f.read().strip()
|
||||
# Get current version from environment
|
||||
current_version = os.environ.get('VERSION', 'unknown').lstrip('v')
|
||||
|
||||
# Fetch latest release from GitHub
|
||||
response = requests.get('https://api.github.com/repos/JDB-NET/ipam/releases/latest', timeout=5)
|
||||
# Fetch latest release from Gitea
|
||||
response = requests.get('https://git.jdbnet.co.uk/api/v1/repos/jamie/ipam/releases/latest', timeout=5)
|
||||
if response.status_code != 200:
|
||||
return jsonify({'error': 'Failed to fetch release information'}), 500
|
||||
|
||||
|
||||
@@ -16,12 +16,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
const compareLink = document.getElementById('toast-compare-link');
|
||||
const closeBtn = document.getElementById('toast-close');
|
||||
|
||||
// Set versions
|
||||
currentVersionEl.textContent = 'v' + data.current_version;
|
||||
latestVersionEl.textContent = 'v' + data.latest_version;
|
||||
// Set versions (don't add 'v' prefix for dev versions)
|
||||
currentVersionEl.textContent = (data.current_version === 'dev' ? '' : 'v') + data.current_version;
|
||||
latestVersionEl.textContent = (data.latest_version === 'dev' ? '' : 'v') + data.latest_version;
|
||||
|
||||
// Set compare link (current version to latest version)
|
||||
compareLink.href = `https://github.com/JDB-NET/ipam/compare/v${data.current_version}...v${data.latest_version}`;
|
||||
compareLink.href = `https://git.jdbnet.co.uk/jamie/ipam/compare/v${data.current_version}...v${data.latest_version}`;
|
||||
|
||||
// Show toast
|
||||
toast.classList.remove('hidden');
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
document.addEventListener("DOMContentLoaded",function(){let t=sessionStorage.getItem("update-toast-dismissed");!t&&fetch("/check_update").then(t=>t.json()).then(t=>{if(t.update_available){let e=document.getElementById("update-toast"),n=document.getElementById("toast-current-version"),s=document.getElementById("toast-latest-version"),a=document.getElementById("toast-compare-link"),o=document.getElementById("toast-close");n.textContent="v"+t.current_version,s.textContent="v"+t.latest_version,a.href=`https://github.com/JDB-NET/ipam/compare/v${t.current_version}...v${t.latest_version}`,e.classList.remove("hidden"),o.addEventListener("click",function(){e.classList.add("hidden"),sessionStorage.setItem("update-toast-dismissed","true")})}}).catch(t=>{console.error("Error checking for updates:",t)})});
|
||||
document.addEventListener("DOMContentLoaded",function(){let e=sessionStorage.getItem("update-toast-dismissed");!e&&fetch("/check_update").then(e=>e.json()).then(e=>{if(e.update_available){let t=document.getElementById("update-toast"),n=document.getElementById("toast-current-version"),s=document.getElementById("toast-latest-version"),a=document.getElementById("toast-compare-link"),d=document.getElementById("toast-close");n.textContent=("dev"===e.current_version?"":"v")+e.current_version,s.textContent=("dev"===e.latest_version?"":"v")+e.latest_version,a.href=`https://git.jdbnet.co.uk/jamie/ipam/compare/v${e.current_version}...v${e.latest_version}`,t.classList.remove("hidden"),d.addEventListener("click",function(){t.classList.add("hidden"),sessionStorage.setItem("update-toast-dismissed","true")})}}).catch(e=>{console.error("Error checking for updates:",e)})});
|
||||
@@ -1,22 +1,24 @@
|
||||
<header class="bg-zinc-800 shadow-md py-3 px-6 flex items-center justify-between relative">
|
||||
<header class="bg-zinc-800 shadow-md py-3 px-6 relative flex items-center justify-between lg:grid lg:grid-cols-[auto_minmax(18rem,1fr)_auto] lg:gap-6">
|
||||
<div class="flex items-center space-x-3 flex-shrink-0">
|
||||
<a href="/" class="flex items-center space-x-3">
|
||||
<img src="{{ LOGO_PNG }}" alt="Logo" class="h-8 rounded">
|
||||
<span class="text-2xl font-bold text-white whitespace-nowrap">{{ NAME }} IPAM</span>
|
||||
</a>
|
||||
<a href="https://github.com/JDB-NET/ipam/releases" target="_blank" rel="noopener noreferrer" class="text-sm font-normal text-gray-300 hover:text-gray-100 -ml-1 mt-3">v{{ VERSION }}</a>
|
||||
<a href="https://git.jdbnet.co.uk/jamie/ipam/releases" target="_blank" rel="noopener noreferrer" class="text-sm font-normal text-gray-300 hover:text-gray-100 -ml-1 mt-3">{{ VERSION }}</a>
|
||||
</div>
|
||||
<div class="hidden lg:flex items-center justify-center absolute left-1/2" style="transform: translateX(calc(-50% + 1.5rem));">
|
||||
<form action="/search" method="GET" class="flex items-center space-x-2">
|
||||
<input type="text" name="q" id="search-input" placeholder="Search..."
|
||||
class="bg-zinc-700 text-white placeholder-gray-400 px-4 py-2 rounded-md text-base focus:outline-none focus:ring-2 focus:ring-gray-500 w-100"
|
||||
|
||||
<div class="hidden lg:flex items-center min-w-0">
|
||||
<form action="/search" method="GET" class="flex items-center space-x-2 w-full max-w-2xl mx-auto">
|
||||
<input type="text" name="q" id="search-input" placeholder="Search..."
|
||||
class="bg-zinc-700 text-white placeholder-gray-400 px-4 py-2 rounded-md text-base focus:outline-none focus:ring-2 focus:ring-gray-500 w-full min-w-0"
|
||||
value="{{ request.args.get('q', '') }}">
|
||||
<button type="submit" class="text-gray-200 hover:text-gray-400 hover:cursor-pointer flex-shrink-0">
|
||||
<i class="fas fa-search"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<nav class="hidden lg:flex items-center space-x-6 flex-shrink-0" id="main-nav">
|
||||
|
||||
<nav class="hidden lg:flex items-center space-x-6 flex-shrink-0 whitespace-nowrap justify-self-end" id="main-nav">
|
||||
{% if has_permission('view_index') %}
|
||||
<a href="/" class="text-gray-200 hover:text-gray-400 font-medium flex items-center gap-2">
|
||||
<i class="fas fa-home"></i>
|
||||
|
||||
Reference in New Issue
Block a user