7 Commits

16 changed files with 4 additions and 557 deletions

View File

@ -1,18 +1,6 @@
FROM python:3.11.7-alpine FROM python:3.11.7-alpine
# Wersja i data builda jako build-arg
ARG APP_VERSION=unknown
ARG BUILD_DATE=unknown
# Ustawiamy zmienne w ENV, by były dostępne w kontenerze
ENV APP_VERSION=$APP_VERSION
ENV BUILD_DATE=$BUILD_DATE
WORKDIR /app WORKDIR /app
COPY api . COPY api .
RUN apk add --no-cache curl RUN apk add --no-cache curl
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
CMD python3 app.py CMD python3 app.py

View File

@ -3,7 +3,7 @@ from flask_jwt_extended import get_jwt_identity
from models import User, db from models import User, db
import os import os
from sqlalchemy import text from sqlalchemy import text
from sqlalchemy.exc import DatabaseError, InterfaceError from sqlalchemy.exc import DatabaseError
import time import time
from werkzeug.security import generate_password_hash from werkzeug.security import generate_password_hash
@ -41,7 +41,7 @@ def wait_for_db(max_retries):
connection.execute(text("SELECT 1")) connection.execute(text("SELECT 1"))
db_ready = True db_ready = True
return return
except DatabaseError | InterfaceError: except DatabaseError:
time.sleep(3) time.sleep(3)
raise Exception("Failed to connect to database.") raise Exception("Failed to connect to database.")

View File

@ -2,7 +2,6 @@ from flask import Blueprint, jsonify, request, abort
from flask_jwt_extended import create_access_token, set_access_cookies, jwt_required, \ from flask_jwt_extended import create_access_token, set_access_cookies, jwt_required, \
verify_jwt_in_request, get_jwt_identity, unset_jwt_cookies, get_jwt verify_jwt_in_request, get_jwt_identity, unset_jwt_cookies, get_jwt
from models import db, RevokedToken, User from models import db, RevokedToken, User
import os
from utils import admin_required, validate_access, get_user_or_404 from utils import admin_required, validate_access, get_user_or_404
from werkzeug.security import check_password_hash, generate_password_hash from werkzeug.security import check_password_hash, generate_password_hash
@ -111,10 +110,3 @@ def user_logout():
response = jsonify({"msg": "User logged out successfully."}) response = jsonify({"msg": "User logged out successfully."})
unset_jwt_cookies(response) unset_jwt_cookies(response)
return response return response
@user_bp.route('/version', methods=['GET'])
def version():
return jsonify({
"version": os.getenv("APP_VERSION", "unknown"),
"build_time": os.getenv("BUILD_DATE", "unknown")
})

View File

@ -1,20 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argo-ingress
namespace: argo
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: argo.marcin00.pl
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argo-server
port:
number: 2746

View File

@ -1,23 +0,0 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: argo-workflow-manager
namespace: argo-events
rules:
- apiGroups: ["argoproj.io"]
resources: ["workflows", "workflowtemplates", "cronworkflows"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: argo-ui-user-read-access
namespace: argo-events
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: argo-workflow-manager
subjects:
- kind: ServiceAccount
name: argo-ui-user
namespace: argo

View File

@ -1,109 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: webhook-deploy
namespace: argo-events
spec:
template:
serviceAccountName: operate-workflow-sa
dependencies:
- name: gitea-push
eventSourceName: webhook
eventName: user-microservice-deploy
triggers:
- template:
name: deploy-user-microservice
k8s:
operation: create
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: deploy-user-microservice-
spec:
entrypoint: main
serviceAccountName: operate-workflow-sa
volumeClaimTemplates:
- metadata:
name: workspace
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 128Mi
templates:
- name: main
steps:
- - name: checkout
template: checkout
- - name: deploy
template: deploy
- name: checkout
container:
image: alpine/git
command: [sh, -c]
workingDir: /workspace
env:
- name: REPO_URL
value: https://gitea.marcin00.pl/pikram/user-microservice-deploy.git
- name: REPO_BRANCH
value: argo-deploy
args:
- |
git clone --depth 1 --branch "${REPO_BRANCH}" --single-branch "${REPO_URL}" repo
volumeMounts:
- name: workspace
mountPath: /workspace
- name: deploy
container:
image: marcin00.azurecr.io/azure-cli-kubectl:latest
command: [sh, -c]
workingDir: /workspace/repo
env:
- name: CLIENT_ID
value: "c302726f-fafb-4143-94c1-67a70975574a"
- name: CLUSTER_NAME
value: "build"
- name: RESOURCE_GROUP
value: "tst-aks-rg"
- name: DEPLOY_FILES
value: "namespace.yaml secret-store.yaml deploy.yaml ingress.yaml"
- name: DEPLOYMENT
value: "api"
- name: NAMESPACE
value: "user-microservice"
- name: HEALTHCHECK_URL
value: "https://user-microservice.marcin00.pl/health"
args:
- |
echo "===> Logging in to Azure"
az login --identity --client-id $CLIENT_ID
az aks get-credentials --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --overwrite-existing
kubelogin convert-kubeconfig -l azurecli
echo "===> Applying Kubernetes manifests"
for file in $DEPLOY_FILES; do
kubectl apply -f "$file"
done
echo "===> Waiting for deployment to complete"
kubectl rollout status deployment/$DEPLOYMENT -n $NAMESPACE --timeout=60s
echo "===> Running health check"
for i in $(seq 1 120); do
if curl -sf $HEALTHCHECK_URL; then
echo "Health check OK"
exit 0
else
echo "Health check failed. Retry $i..."
sleep 5
fi
done
echo "Health check failed"
exit 1
volumeMounts:
- name: workspace
mountPath: /workspace

View File

@ -1,13 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: EventBus
metadata:
name: default
namespace: argo-events
spec:
nats:
native:
# Optional, defaults to 3.
# If it is < 3, set it to 3, that is the minimal requirement.
replicas: 3
# Optional, authen strategy, "none" or "token", defaults to "none"
auth: token

View File

@ -1,38 +0,0 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: operate-workflow-sa
namespace: argo-events
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: operate-workflow-role
namespace: argo-events
rules:
- apiGroups: [ "argoproj.io" ]
resources: [ "workflows" ]
verbs: [ "*" ]
- apiGroups: [ "argoproj.io" ]
resources: [ "workflowtaskresults" ]
verbs: [ "create", "patch" ]
- apiGroups: [ "" ]
resources: [ "pods" ]
verbs: [ "get", "patch" ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: operate-workflow-role-binding
namespace: argo-events
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: operate-workflow-role
subjects:
- kind: ServiceAccount
name: operate-workflow-sa
namespace: argo-events

View File

@ -1,30 +0,0 @@
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: azure-keyvault
namespace: argo-events
spec:
provider: azure
secretObjects:
- secretName: gitea-secrets
type: Opaque
data:
- objectName: gitea-known-host
key: GITEA_KNOWN_HOST
- objectName: gitea-deploy-key
key: GITEA_DEPLOY_KEY
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: "f91aef65-7d2a-4df8-a884-e33b05d54a31" # client_id of the user-assigned managed identity
clientID: "f91aef65-7d2a-4df8-a884-e33b05d54a31" # client_id of the user-assigned managed identity
keyvaultName: "dev-aks"
objects: |
array:
- |
objectName: gitea-known-host
objectType: secret
- |
objectName: gitea-deploy-key
objectType: secret
tenantID: "f4e3e6f7-d21c-460e-b201-2192174e7f41"

View File

@ -1,172 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: webhook-build
namespace: argo-events
spec:
template:
serviceAccountName: operate-workflow-sa
dependencies:
- name: gitea-push
eventSourceName: webhook
eventName: user-microservice
triggers:
- template:
name: trigger-build-workflow
k8s:
group: argoproj.io
version: v1alpha1
resource: workflows
operation: create
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: build-workflow-
namespace: argo-events
spec:
entrypoint: main
serviceAccountName: operate-workflow-sa
volumeClaimTemplates:
- metadata:
name: workspace
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 128Mi
volumes:
- name: secrets-store
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: azure-keyvault
templates:
- name: main
steps:
- - name: checkout
template: checkout
- - name: tests
template: tests
- - name: build-and-push-image
template: build-and-push-image
arguments:
parameters:
- name: git-sha
value: "{{steps.checkout.outputs.parameters.git-sha}}"
- - name: gitops-commit
template: gitops-commit
arguments:
parameters:
- name: git-sha
value: "{{steps.checkout.outputs.parameters.git-sha}}"
- name: checkout
container:
image: alpine/git
command: [sh, -c]
workingDir: /workspace
env:
- name: REPO_URL
value: https://gitea.marcin00.pl/pikram/user-microservice.git
- name: REPO_BRANCH
value: argo-workflows
args:
- |
git clone --depth 1 --branch "${REPO_BRANCH}" --single-branch "${REPO_URL}" repo
cd repo
git rev-parse HEAD > /tmp/gitsha.txt
volumeMounts:
- name: workspace
mountPath: /workspace
outputs:
parameters:
- name: git-sha
valueFrom:
path: /tmp/gitsha.txt
- name: tests
script:
image: python:3.11.7-alpine
command: [sh]
workingDir: /workspace/repo/api
source: |
python3 -m venv env
source env/bin/activate
pip install -r requirements.txt pytest
python3 -m pytest --junit-xml=pytest_junit.xml
volumeMounts:
- name: workspace
mountPath: /workspace
- name: build-and-push-image
inputs:
parameters:
- name: git-sha
podSpecPatch: |
runtimeClassName: sysbox-runc
metadata:
annotations:
io.kubernetes.cri-o.userns-mode: "auto:size=65536"
container:
image: marcin00.azurecr.io/azure-cli-docker:slim-bookworm
command: [sh, -c]
workingDir: /workspace/repo
env:
- name: DOCKER_IMAGE
value: marcin00.azurecr.io/user-microservice:{{inputs.parameters.git-sha}}
- name: CLIENT_ID
value: c302726f-fafb-4143-94c1-67a70975574a
- name: ACR_NAME
value: marcin00
args:
- |
dockerd &
docker build -t $DOCKER_IMAGE --build-arg APP_VERSION={{inputs.parameters.git-sha}} --build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") .
az login --identity --client-id ${CLIENT_ID}
az acr login --name ${ACR_NAME}
docker push ${DOCKER_IMAGE}
volumeMounts:
- name: workspace
mountPath: /workspace
- name: gitops-commit
inputs:
parameters:
- name: git-sha
container:
image: alpine/git
command: [sh, -c]
env:
- name: DEPLOY_REPO_URL
value: ssh://git@srv22.mikr.us:20343/pikram/user-microservice-deploy.git
- name: DEPLOY_REPO_BRANCH
value: argo-deploy
- name: CI_COMMIT_SHA
value: "{{inputs.parameters.git-sha}}"
args:
- |
mkdir -p ~/.ssh
cp /mnt/secrets/gitea-known-host ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
cp /mnt/secrets/gitea-deploy-key ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
git config --global user.name "argo[bot]"
git config --global user.email "argo@marcin00.pl"
git clone --depth 1 --branch $DEPLOY_REPO_BRANCH --single-branch $DEPLOY_REPO_URL repo
cd repo
awk -v commit="$CI_COMMIT_SHA" '
$0 ~ /name:[[:space:]]*api/ { in_api_container = 1; print; next }
in_api_container && $0 ~ /^[[:space:]]*image:[[:space:]]*/ {
sub(/:[^:[:space:]]+$/, ":" commit)
in_api_container = 0
print
next
}
{ print }
' deploy.yaml > deploy.tmp && mv deploy.tmp deploy.yaml
git add deploy.yaml
git diff-index --quiet HEAD || git commit -m "Argo: Changed deployed version to $CI_COMMIT_SHA"
git push origin $DEPLOY_REPO_BRANCH
volumeMounts:
- name: secrets-store
mountPath: "/mnt/secrets"
readOnly: true

View File

@ -1,19 +0,0 @@
apiVersion: argoproj.io/v1alpha1
kind: EventSource
metadata:
name: webhook
namespace: argo-events
spec:
service:
ports:
- port: 12000
targetPort: 12000
webhook:
user-microservice:
endpoint: /user-microservice
method: POST
port: "12000"
user-microservice-deploy:
endpoint: /user-microservice-deploy
method: POST
port: "12000"

View File

@ -1,27 +0,0 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argo-ingress
namespace: argo-events
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
ingressClassName: nginx
rules:
- host: argo-hook.marcin00.pl
http:
paths:
- path: /user-microservice
pathType: Prefix
backend:
service:
name: webhook-eventsource-svc
port:
number: 12000
- path: /user-microservice-deploy
pathType: Prefix
backend:
service:
name: webhook-eventsource-svc
port:
number: 12000

View File

@ -1,16 +0,0 @@
apiVersion: v1
kind: Service
metadata:
name: webhook-eventsource-svc
namespace: argo-events
spec:
type: ClusterIP
ports:
- name: default
port: 12000
protocol: TCP
targetPort: 12000
selector:
controller: eventsource-controller
eventsource-name: webhook
owner-name: webhook

View File

@ -1,65 +0,0 @@
#!/bin/bash
# === KONFIGURACJA ===
APP_URL="https://user-microservice.marcin00.pl/version"
MARKER_FILE="version_marker.txt"
OUTPUT_FILE="deployment_times.csv"
CHECK_INTERVAL=1 # sekundy
# === POBRANIE AKTUALNEJ WERSJI APLIKACJI ===
echo "[INFO] Pobieranie aktualnej wersji z /version..."
OLD_VERSION=$(curl -s "$APP_URL" | jq -r '.version')
if [[ -z "$OLD_VERSION" ]]; then
echo "[ERROR] Nie udało się pobrać aktualnej wersji aplikacji."
exit 1
fi
echo "[INFO] Aktualna wersja: $OLD_VERSION"
# === Modyfikacja pliku, commit i push ===
TIMESTAMP=$(date +%s)
echo "$TIMESTAMP" > "$MARKER_FILE"
git add "$MARKER_FILE"
git commit -m "Automatyczna zmiana: $TIMESTAMP"
START_TIME=$(date +%s)
echo "[INFO] Wykonuję git push..."
git push
if [[ $? -ne 0 ]]; then
echo "[ERROR] Push nie powiódł się."
exit 1
fi
echo "[INFO] Oczekiwanie na wdrożenie nowej wersji..."
# === Odpytywanie endpointa /version ===
WAITED=0
echo "[WAIT] Oczekiwanie na nową wersję..."
while true; do
sleep $CHECK_INTERVAL
WAITED=$((WAITED + CHECK_INTERVAL))
NEW_VERSION=$(curl -s "$APP_URL" | jq -r '.version')
if [[ "$NEW_VERSION" != "$OLD_VERSION" ]]; then
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
# Nadpisujemy linię z licznikiem
printf "\r[INFO] Nowa wersja wdrożona po %d healtcheck próbach: %s\n" "$WAITED" "$NEW_VERSION"
echo "[INFO] Czas wdrożenia: $DURATION sekund"
echo "$START_TIME,$END_TIME,$DURATION,$OLD_VERSION,$NEW_VERSION" >> "$OUTPUT_FILE"
break
else
# Nadpisujemy TYLKO linię z licznikiem
printf "\r[WAIT] Czekam... wykonano %d healtcheck prób" "$WAITED"
fi
done
# Żeby kursor przeszedł do nowej linii po zakończeniu
echo ""

View File

@ -1 +0,0 @@
1754157020