gitops
This commit is contained in:
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
kubectl cnpg psql pg-devops -n devops
|
||||||
|
|
||||||
|
CREATE DATABASE giteadbtest;
|
||||||
|
CREATE USER giteatest WITH PASSWORD 'KAYQE1QA7uwUZ8uI';
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE giteadbtest TO giteatest;
|
||||||
|
ALTER DATABASE giteadbtest OWNER TO giteatest;
|
||||||
|
|
||||||
|
helm repo add gitea https://dl.gitea.io/charts/
|
||||||
|
helm repo update
|
||||||
|
|
||||||
|
|
||||||
|
kubectl create namespace gitea
|
||||||
|
|
||||||
|
cat <<EOF |cat >valuestest.yaml -
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: gitea/gitea
|
||||||
|
tag: 1.25.4-rootless
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
|
||||||
|
service:
|
||||||
|
http:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 3000
|
||||||
|
ssh:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 22
|
||||||
|
|
||||||
|
redis-cluster:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
redis:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
storageClass: csi-rbdfs-sc
|
||||||
|
size: 10Gi
|
||||||
|
|
||||||
|
postgresql:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
postgresql-ha:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
gitea:
|
||||||
|
admin:
|
||||||
|
username: gitadmin
|
||||||
|
password: KAYQE1QA7uwUZ8uI
|
||||||
|
email: gitadmin@italiadatacenter.com
|
||||||
|
|
||||||
|
config:
|
||||||
|
database:
|
||||||
|
DB_TYPE: postgres
|
||||||
|
HOST: pg-devops-rw.devops.svc:5432
|
||||||
|
NAME: giteadbtest
|
||||||
|
USER: giteatest
|
||||||
|
PASSWD: KAYQE1QA7uwUZ8uI
|
||||||
|
SSL_MODE: disable
|
||||||
|
|
||||||
|
server:
|
||||||
|
ROOT_URL: https://git2.pigreco66.it/
|
||||||
|
SSH_DOMAIN: git2.pigreco66.it
|
||||||
|
SSH_PORT: 22
|
||||||
|
|
||||||
|
security:
|
||||||
|
INSTALL_LOCK: true
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
helm upgrade --install gitea gitea-charts/gitea --namespace gitea -f values.yaml
|
||||||
|
|
||||||
|
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: gitea
|
||||||
|
namespace: gitea
|
||||||
|
spec:
|
||||||
|
hostnames:
|
||||||
|
- git.italiadatacenter.com
|
||||||
|
parentRefs:
|
||||||
|
- name: main-gateway
|
||||||
|
namespace: nginx-gateway
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: gitea-http
|
||||||
|
port: 3000
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: namespace-b
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc/namespace-B/manifests
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: namespace-B
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -1,7 +1,32 @@
|
|||||||
helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
|
helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
|
||||||
kubectl create namespace cattle-system
|
kubectl create namespace cattle-system
|
||||||
|
|
||||||
helm install rancher rancher-stable/rancher \
|
helm install rancher rancher-stable/rancher --namespace cattle-system --set hostname=idc.internal --set bootstrapPassword=.... --set ingress.tls.source=rancher
|
||||||
|
|
||||||
|
|
||||||
|
helm upgrade rancher rancher-stable/rancher \
|
||||||
--namespace cattle-system \
|
--namespace cattle-system \
|
||||||
--set hostname=k8s.italiadatacenter.com \
|
--reuse-values \
|
||||||
--set bootstrapPassword=admin
|
--set hostname=idc.internal \
|
||||||
|
--set bootstrapPassword=KAYQE1QA7uwUZ8uI \
|
||||||
|
--set ingress.enabled=false \
|
||||||
|
--set ingress.tls.source=rancher
|
||||||
|
|
||||||
|
Poc-25_sts
|
||||||
|
|
||||||
|
POC-25_sts
|
||||||
|
|
||||||
|
vi sistemarancher.sh
|
||||||
|
# 1. recupera il ClusterIP del service "rancher" già creato dal chart
|
||||||
|
CLUSTERIP=$(kubectl get svc -n cattle-system rancher -o jsonpath='{.spec.clusterIP}')
|
||||||
|
|
||||||
|
# 2. patch del deployment per aggiungere hostAliases
|
||||||
|
kubectl patch deployment rancher -n cattle-system --type='json' \
|
||||||
|
-p="[{\"op\":\"add\",\"path\":\"/spec/template/spec/hostAliases\",\"value\":[{\"ip\":\"$CLUSTERIP\",\"hostnames\":[\"idc.internal\"]}]}]"
|
||||||
|
|
||||||
|
# 3. crea il service NodePort per l'accesso dal browser
|
||||||
|
kubectl expose deployment rancher -n cattle-system --type=NodePort --port=443 --target-port=443 --name=rancher-nodeport
|
||||||
|
|
||||||
|
# 4. riavvia e segui i log
|
||||||
|
kubectl rollout restart deployment rancher -n cattle-system
|
||||||
|
kubectl -n cattle-system logs -l app=rancher -f
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: opens3-console-secrets
|
||||||
|
namespace: minio
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
# Endpoint S3 del server MinIO a cui la console si collega.
|
||||||
|
# Cambialo con l'URL reale del tuo MinIO (Service interno o esterno).
|
||||||
|
CONSOLE_MINIO_SERVER: "http://minio.minio.svc.cluster.local:9000"
|
||||||
|
|
||||||
|
# Passphrase e salt usati da opens3/console per cifrare le sessioni
|
||||||
|
# (PBKDF2). Generane di robusti, es.:
|
||||||
|
# openssl rand -base64 32
|
||||||
|
CONSOLE_PBKDF_PASSPHRASE: "OHB576kn9SS4JdD7qG4+hyjRpa353HQqxPQ22z2Do0w="
|
||||||
|
CONSOLE_PBKDF_SALT: "OBHOWF2INklmrtmyI+qNEb3dbV0yz9ZAxiJJCcC6GYw="
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: opens3-console
|
||||||
|
namespace: minio
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: console
|
||||||
|
image: opens3/console:latest
|
||||||
|
imagePullPolicy: IfNotPresent
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 9090
|
||||||
|
protocol: TCP
|
||||||
|
envFrom:
|
||||||
|
- secretRef:
|
||||||
|
name: opens3-console-secrets
|
||||||
|
# Se il MinIO target usa certificati self-signed, decommenta:
|
||||||
|
# env:
|
||||||
|
# - name: CONSOLE_MINIO_TLS_SKIP_VERIFICATION
|
||||||
|
# value: "on"
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 3
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 15
|
||||||
|
periodSeconds: 20
|
||||||
|
timeoutSeconds: 3
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop: ["ALL"]
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: opens3-console
|
||||||
|
namespace: minio
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
app.kubernetes.io/name: opens3-console
|
||||||
|
app.kubernetes.io/instance: opens3-console
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: httproute-minio-direct
|
||||||
|
spec:
|
||||||
|
hostnames:
|
||||||
|
- idcidp.pigreco66.it
|
||||||
|
parentRefs:
|
||||||
|
- group: gateway.networking.k8s.io
|
||||||
|
kind: Gateway
|
||||||
|
name: main-gateway
|
||||||
|
namespace: nginx-gateway
|
||||||
|
rules:
|
||||||
|
- backendRefs:
|
||||||
|
- group: ""
|
||||||
|
kind: Service
|
||||||
|
name: opens3-console
|
||||||
|
port: 80
|
||||||
|
weight: 1
|
||||||
|
filters:
|
||||||
|
- responseHeaderModifier:
|
||||||
|
remove:
|
||||||
|
- X-Frame-Options
|
||||||
|
- Content-Security-Policy
|
||||||
|
set:
|
||||||
|
- name: X-Frame-Options
|
||||||
|
value: SAMEORIGIN
|
||||||
|
- name: Content-Security-Policy
|
||||||
|
value: frame-ancestors 'self'
|
||||||
|
type: ResponseHeaderModifier
|
||||||
|
matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /minio-console
|
||||||
@@ -2,6 +2,13 @@
|
|||||||
helm repo add sonarqube https://SonarSource.github.io/helm-chart-sonarqube
|
helm repo add sonarqube https://SonarSource.github.io/helm-chart-sonarqube
|
||||||
helm repo update
|
helm repo update
|
||||||
|
|
||||||
|
helm pull sonarqube/sonarqube --version 2026.1.0
|
||||||
|
|
||||||
|
helm registry login harbor.italiadatacenter.com -u admin
|
||||||
|
(pwd: KAYQE1QA7uwUZ8uI)
|
||||||
|
|
||||||
|
helm push sonarqube-2026.1.0.tgz oci://harbor.italiadatacenter.com/italiadatacenter
|
||||||
|
|
||||||
########### creazione ns e secret db ################
|
########### creazione ns e secret db ################
|
||||||
kubectl create namespace sonarqube
|
kubectl create namespace sonarqube
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
# gitops-repo - esempio completo (3 namespace, Fleet su RKE2)
|
||||||
|
|
||||||
|
Repo di esempio pronto da usare come base: GitOps limitato a
|
||||||
|
namespace-A, namespace-B, namespace-C, con Fleet come motore di sync.
|
||||||
|
|
||||||
|
## Struttura
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── bootstrap/ <- file legacy Argo CD (non usati con Fleet)
|
||||||
|
│ ├── 00-namespace.yaml
|
||||||
|
│ ├── 01-appproject.yaml
|
||||||
|
│ └── 02-root.yaml
|
||||||
|
│
|
||||||
|
└── clusters/
|
||||||
|
└── idc/ <- nome cluster/repository scope attuale
|
||||||
|
├── namespace-A/
|
||||||
|
│ ├── application.yaml <- da migrare a Fleet GitRepo
|
||||||
|
│ └── manifests/
|
||||||
|
│ └── deployment.yaml
|
||||||
|
├── namespace-B/
|
||||||
|
│ ├── application.yaml <- da migrare a Fleet GitRepo
|
||||||
|
│ └── manifests/
|
||||||
|
│ └── deployment.yaml
|
||||||
|
└── namespace-C/
|
||||||
|
├── application.yaml <- gia convertito a Fleet GitRepo
|
||||||
|
└── manifests/
|
||||||
|
└── deployment.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cosa applichi a mano con Fleet
|
||||||
|
|
||||||
|
- Applichi a mano i manifest Fleet di tipo GitRepo (uno per namespace o uno aggregato).
|
||||||
|
- I file in clusters/idc/namespace-*/manifests vengono sincronizzati automaticamente da Fleet.
|
||||||
|
- I file in bootstrap sono legacy Argo CD: con Fleet installato, non sono necessari.
|
||||||
|
|
||||||
|
## Bootstrap Fleet - passo per passo
|
||||||
|
|
||||||
|
### 1. Verifica Fleet
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n cattle-fleet-system get pods
|
||||||
|
kubectl get crd gitrepos.fleet.cattle.io
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Applica il GitRepo
|
||||||
|
|
||||||
|
Esempio con namespace-C:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -f clusters/idc/namespace-C/application.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Verifica stato Fleet
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fleet-local get gitrepo
|
||||||
|
kubectl -n cattle-fleet-system get bundles
|
||||||
|
kubectl -n cattle-fleet-system get bundledeployments
|
||||||
|
```
|
||||||
|
|
||||||
|
## Repo privato GitHub
|
||||||
|
|
||||||
|
Se il repo e privato, configura le credenziali per Fleet (Secret nel namespace Fleet usato, tipicamente fleet-local o fleet-default).
|
||||||
|
|
||||||
|
## Prima di usare questo repo
|
||||||
|
|
||||||
|
Sostituisci ovunque compare:
|
||||||
|
- <tua-org> -> org/utente reale del tuo repo Git
|
||||||
|
- i deployment di esempio -> i tuoi manifest reali
|
||||||
|
|
||||||
|
## Migrazione consigliata (A e B)
|
||||||
|
|
||||||
|
Attualmente solo namespace-C e gia in formato Fleet.
|
||||||
|
Per allineare tutto:
|
||||||
|
|
||||||
|
1. Converti clusters/idc/namespace-A/application.yaml in GitRepo Fleet.
|
||||||
|
2. Converti clusters/idc/namespace-B/application.yaml in GitRepo Fleet.
|
||||||
|
3. Applica i due manifest e verifica bundle/bundledeployments.
|
||||||
|
|
||||||
|
## Estendere a un quarto namespace in futuro
|
||||||
|
|
||||||
|
1. Crea clusters/idc/namespace-D/manifests con i tuoi YAML.
|
||||||
|
2. Crea clusters/idc/namespace-D/application.yaml in formato Fleet GitRepo.
|
||||||
|
3. Applica il manifest e verifica la generazione dei bundle.
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: argocd
|
||||||
|
labels:
|
||||||
|
app.kubernetes.io/name: argocd
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# =====================================================================
|
||||||
|
# AppProject con perimetro ristretto a namespace-A, namespace-B,
|
||||||
|
# namespace-C. Qualunque Application che referenzi questo project e
|
||||||
|
# provi a scrivere in un namespace diverso da questi (+ argocd, per le
|
||||||
|
# risorse interne) viene rifiutata da Argo CD stesso.
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: AppProject
|
||||||
|
metadata:
|
||||||
|
name: gitops-3ns
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
description: "GitOps limitato a namespace-A, namespace-B, namespace-C"
|
||||||
|
|
||||||
|
sourceRepos:
|
||||||
|
- "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
|
||||||
|
destinations:
|
||||||
|
- namespace: argocd
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
- namespace: namespace-A
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
- namespace: namespace-B
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
- namespace: namespace-C
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
|
||||||
|
clusterResourceWhitelist:
|
||||||
|
- group: ""
|
||||||
|
kind: Namespace
|
||||||
|
|
||||||
|
namespaceResourceWhitelist:
|
||||||
|
- group: "*"
|
||||||
|
kind: "*"
|
||||||
|
|
||||||
|
orphanedResources:
|
||||||
|
warn: true
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# =====================================================================
|
||||||
|
# Root "app of apps": punta a gitops/clusters/idc/ nel repo. Grazie a
|
||||||
|
# directory.recurse=true, scopre automaticamente ogni application.yaml
|
||||||
|
# trovato dentro namespace-A/, namespace-B/, namespace-C/ e li applica
|
||||||
|
# come proprie Application figlie.
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: root-3ns
|
||||||
|
namespace: argocd
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc
|
||||||
|
directory:
|
||||||
|
recurse: true
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: argocd
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
|
retry:
|
||||||
|
limit: 5
|
||||||
|
backoff:
|
||||||
|
duration: 10s
|
||||||
|
factor: 2
|
||||||
|
maxDuration: 3m
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: namespace-a
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc/namespace-A/manifests
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: namespace-A
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# =====================================================================
|
||||||
|
# Esempio di manifest reale — sostituiscilo con le tue risorse
|
||||||
|
# effettive. Ogni file .yaml in questa cartella viene applicato
|
||||||
|
# automaticamente da Argo CD (Application "namespace-a").
|
||||||
|
# =====================================================================
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-a
|
||||||
|
namespace: namespace-A
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: esempio-app-a
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: esempio-app-a
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: esempio-app-a
|
||||||
|
image: nginx:1.27
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-a
|
||||||
|
namespace: namespace-A
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: esempio-app-a
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: namespace-b
|
||||||
|
namespace: argocd
|
||||||
|
spec:
|
||||||
|
project: gitops-3ns
|
||||||
|
|
||||||
|
source:
|
||||||
|
repoURL: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
targetRevision: main
|
||||||
|
path: gitops/clusters/idc/namespace-B/manifests
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: "https://kubernetes.default.svc"
|
||||||
|
namespace: namespace-B
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-b
|
||||||
|
namespace: namespace-B
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: esempio-app-b
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: esempio-app-b
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: esempio-app-b
|
||||||
|
image: nginx:1.27
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-b
|
||||||
|
namespace: namespace-B
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: esempio-app-b
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: fleet.cattle.io/v1alpha1
|
||||||
|
kind: GitRepo
|
||||||
|
metadata:
|
||||||
|
name: namespace-c
|
||||||
|
namespace: fleet-local
|
||||||
|
spec:
|
||||||
|
repo: "https://github.com/<tua-org>/gitops-repo.git"
|
||||||
|
branch: main
|
||||||
|
paths:
|
||||||
|
- gitops/clusters/idc/namespace-C/manifests
|
||||||
|
targets:
|
||||||
|
- clusterName: local
|
||||||
|
namespace: namespace-C
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-c
|
||||||
|
namespace: namespace-C
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: esempio-app-c
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: esempio-app-c
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: esempio-app-c
|
||||||
|
image: nginx:1.27
|
||||||
|
ports:
|
||||||
|
- containerPort: 80
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: esempio-app-c
|
||||||
|
namespace: namespace-C
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: esempio-app-c
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 80
|
||||||
@@ -0,0 +1,256 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# =====================================================================
|
||||||
|
# extract-manifests.sh
|
||||||
|
#
|
||||||
|
# Estrae tutte le risorse namespaced dai namespace indicati, le ripulisce
|
||||||
|
# con kubectl-neat (rimuove resourceVersion, uid, status, managedFields,
|
||||||
|
# creationTimestamp, ecc.) e le salva organizzate per namespace/kind,
|
||||||
|
# pronte per essere committate in un repo GitOps.
|
||||||
|
#
|
||||||
|
# Uso:
|
||||||
|
# ./extract-manifests.sh [opzioni] <namespace1> <namespace2> ...
|
||||||
|
# ./extract-manifests.sh [opzioni] --namespaces-file namespaces.txt
|
||||||
|
#
|
||||||
|
# Opzioni:
|
||||||
|
# -o, --output <dir> Directory di output (default: ./export)
|
||||||
|
# -s, --include-secrets Include anche i Secret (in CHIARO, base64 non
|
||||||
|
# cifrato — vedi warning qui sotto). Di default
|
||||||
|
# i Secret vengono SALTATI per sicurezza.
|
||||||
|
# -f, --namespaces-file File con un namespace per riga. Righe vuote e
|
||||||
|
# righe che iniziano con # vengono ignorate.
|
||||||
|
# -k, --kinds <lista> Lista custom di kind separati da virgola,
|
||||||
|
# al posto della discovery automatica
|
||||||
|
# (es. "deployment,service,httproute")
|
||||||
|
# -h, --help Mostra questo help
|
||||||
|
#
|
||||||
|
# Esempi:
|
||||||
|
# ./extract-manifests.sh monitoring minio idcidp-dev
|
||||||
|
# ./extract-manifests.sh -o ./gitops-repo/imported -s monitoring
|
||||||
|
# ./extract-manifests.sh -k "httproute,gateway" nginx-gateway
|
||||||
|
# ./extract-manifests.sh -f ./namespaces.txt -o ./gitops-repo/imported
|
||||||
|
#
|
||||||
|
# Prerequisiti:
|
||||||
|
# - kubectl configurato e puntato al cluster corretto
|
||||||
|
# - kubectl-neat installato (kubectl krew install neat)
|
||||||
|
# https://github.com/itaysk/kubectl-neat
|
||||||
|
# =====================================================================
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Default
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
OUTPUT_DIR="./export"
|
||||||
|
INCLUDE_SECRETS="false"
|
||||||
|
CUSTOM_KINDS=""
|
||||||
|
NAMESPACES_FILE=""
|
||||||
|
|
||||||
|
# Kind che non ha senso portare in un repo GitOps: generati/gestiti
|
||||||
|
# automaticamente da controller, non sono mai "desired state" da
|
||||||
|
# dichiarare a mano.
|
||||||
|
EXCLUDED_KINDS="events pods replicasets endpoints endpointslices controllerrevisions"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
grep '^#' "$0" | sed -e 's/^#//' -e 's/^ //'
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
load_namespaces_from_file() {
|
||||||
|
local file_path="$1"
|
||||||
|
|
||||||
|
if [[ ! -f "$file_path" ]]; then
|
||||||
|
echo "Errore: file namespace non trovato: $file_path" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
line="${line%$'\r'}"
|
||||||
|
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
|
||||||
|
line="${line#"${line%%[![:space:]]*}"}"
|
||||||
|
line="${line%"${line##*[![:space:]]}"}"
|
||||||
|
|
||||||
|
[[ -z "$line" ]] && continue
|
||||||
|
|
||||||
|
NAMESPACES+=("$line")
|
||||||
|
done < "$file_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Parsing argomenti
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
NAMESPACES=()
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-o|--output)
|
||||||
|
OUTPUT_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-s|--include-secrets)
|
||||||
|
INCLUDE_SECRETS="true"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-f|--namespaces-file)
|
||||||
|
NAMESPACES_FILE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-k|--kinds)
|
||||||
|
CUSTOM_KINDS="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Opzione sconosciuta: $1" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
NAMESPACES+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -n "$NAMESPACES_FILE" ]]; then
|
||||||
|
load_namespaces_from_file "$NAMESPACES_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#NAMESPACES[@]} -eq 0 ]]; then
|
||||||
|
echo "Errore: specifica almeno un namespace o usa --namespaces-file." >&2
|
||||||
|
echo "Uso: $0 [opzioni] <namespace1> <namespace2> ..." >&2
|
||||||
|
echo " o: $0 [opzioni] --namespaces-file namespaces.txt" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Prerequisiti
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
if ! command -v kubectl >/dev/null 2>&1; then
|
||||||
|
echo "Errore: kubectl non trovato nel PATH." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! kubectl neat --help >/dev/null 2>&1; then
|
||||||
|
echo "Errore: plugin kubectl-neat non trovato." >&2
|
||||||
|
echo "Installa con: kubectl krew install neat" >&2
|
||||||
|
echo "(krew: https://krew.sigs.k8s.io/docs/user-guide/setup/install/)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
echo "==> Output directory: $OUTPUT_DIR"
|
||||||
|
echo "==> Namespace da processare: ${NAMESPACES[*]}"
|
||||||
|
echo "==> Include Secret: $INCLUDE_SECRETS"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [[ "$INCLUDE_SECRETS" == "true" ]]; then
|
||||||
|
echo "########################################################"
|
||||||
|
echo "# ATTENZIONE: i Secret verranno esportati in CHIARO #"
|
||||||
|
echo "# (base64, NON cifrato). Non committarli in Git così #"
|
||||||
|
echo "# come sono. Usa Sealed Secrets, SOPS o External Secrets #"
|
||||||
|
echo "# Operator prima di aggiungerli al repo. #"
|
||||||
|
echo "########################################################"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Determina i kind namespaced da processare
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
get_kinds() {
|
||||||
|
if [[ -n "$CUSTOM_KINDS" ]]; then
|
||||||
|
echo "$CUSTOM_KINDS" | tr ',' '\n'
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Discovery automatica: tutti i kind namespaced supportati dal cluster
|
||||||
|
# (copre anche le CRD installate, es. httproute, podmonitor, cluster
|
||||||
|
# CNPG, ecc.), escludendo quelli in EXCLUDED_KINDS.
|
||||||
|
kubectl api-resources --namespaced=true --verbs=list -o name 2>/dev/null \
|
||||||
|
| cut -d. -f1 \
|
||||||
|
| sort -u \
|
||||||
|
| while read -r kind; do
|
||||||
|
skip="false"
|
||||||
|
for excl in $EXCLUDED_KINDS; do
|
||||||
|
[[ "$kind" == "$excl" ]] && skip="true" && break
|
||||||
|
done
|
||||||
|
[[ "$skip" == "false" ]] && echo "$kind"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
KINDS=$(get_kinds)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
# Estrazione
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
TOTAL_EXPORTED=0
|
||||||
|
TOTAL_EMPTY=0
|
||||||
|
TOTAL_ERRORS=0
|
||||||
|
|
||||||
|
for ns in "${NAMESPACES[@]}"; do
|
||||||
|
echo "=== Namespace: $ns ==="
|
||||||
|
|
||||||
|
if ! kubectl get namespace "$ns" >/dev/null 2>&1; then
|
||||||
|
echo " ! Namespace '$ns' non trovato, salto." >&2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
ns_dir="${OUTPUT_DIR}/${ns}"
|
||||||
|
mkdir -p "$ns_dir"
|
||||||
|
|
||||||
|
while IFS= read -r kind; do
|
||||||
|
[[ -z "$kind" ]] && continue
|
||||||
|
|
||||||
|
# Salta i secret a meno che non richiesti esplicitamente
|
||||||
|
if [[ "$kind" == "secrets" || "$kind" == "secret" ]] && [[ "$INCLUDE_SECRETS" != "true" ]]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Conta quante risorse di questo kind esistono nel namespace, per
|
||||||
|
# evitare di scrivere file vuoti/inutili
|
||||||
|
count=$(kubectl get "$kind" -n "$ns" --no-headers 2>/dev/null | wc -l | tr -d ' ')
|
||||||
|
|
||||||
|
if [[ "$count" -eq 0 ]]; then
|
||||||
|
TOTAL_EMPTY=$((TOTAL_EMPTY + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
out_file="${ns_dir}/${kind}.yaml"
|
||||||
|
|
||||||
|
if kubectl get "$kind" -n "$ns" -o yaml 2>/dev/null | kubectl neat > "$out_file" 2>/dev/null; then
|
||||||
|
# kubectl neat su una List vuota/malformata può comunque produrre
|
||||||
|
# un file quasi-vuoto: verifichiamo che contenga davvero "kind:"
|
||||||
|
if grep -q "^kind:" "$out_file" 2>/dev/null || grep -q "^items:" "$out_file" 2>/dev/null; then
|
||||||
|
echo " + ${kind} (${count})"
|
||||||
|
TOTAL_EXPORTED=$((TOTAL_EXPORTED + 1))
|
||||||
|
else
|
||||||
|
rm -f "$out_file"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo " ! Errore esportando ${kind}" >&2
|
||||||
|
rm -f "$out_file"
|
||||||
|
TOTAL_ERRORS=$((TOTAL_ERRORS + 1))
|
||||||
|
fi
|
||||||
|
done <<< "$KINDS"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "=== Riepilogo ==="
|
||||||
|
echo "Risorse esportate: $TOTAL_EXPORTED"
|
||||||
|
echo "Kind vuoti/saltati: $TOTAL_EMPTY"
|
||||||
|
echo "Errori: $TOTAL_ERRORS"
|
||||||
|
echo ""
|
||||||
|
echo "Output in: $OUTPUT_DIR"
|
||||||
|
echo ""
|
||||||
|
echo "Prossimi passi consigliati:"
|
||||||
|
echo " 1. Rivedi manualmente ogni file: alcuni campi (es. clusterIP,"
|
||||||
|
echo " nodePort, annotazioni iniettate da controller/webhook) vanno"
|
||||||
|
echo " rimossi a mano perché non fanno parte del 'desired state'."
|
||||||
|
echo " 2. Se hai esportato Secret, cifrali (Sealed Secrets / SOPS) prima"
|
||||||
|
echo " di committarli."
|
||||||
|
echo " 3. Riorganizza i file nella struttura del repo GitOps"
|
||||||
|
echo " (infrastructure/ vs apps/, vedi README del repo)."
|
||||||
@@ -0,0 +1,305 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
OUTPUT_DIR="./generated-helmops"
|
||||||
|
API_VERSION="fleet.cattle.io/v1alpha1"
|
||||||
|
RESOURCE_KIND="HelmOp"
|
||||||
|
VALUES_ARGS=()
|
||||||
|
WORKSPACE_NAMESPACE="fleet-local"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage:
|
||||||
|
./generate-fleet-helmops-from-helm.sh [options]
|
||||||
|
|
||||||
|
Description:
|
||||||
|
Legge le release presenti con `helm list -A`, recupera metadata e values
|
||||||
|
per ogni release e genera un file YAML per release in formato HelmOp-style.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-o, --output-dir <dir> Directory di output (default: ./generated-helmops)
|
||||||
|
-w, --workspace-namespace <ns>
|
||||||
|
Namespace dove creare la risorsa HelmOp
|
||||||
|
(default: fleet-local)
|
||||||
|
--api-version <value> apiVersion del manifest generato
|
||||||
|
(default: fleet.cattle.io/v1alpha1)
|
||||||
|
--kind <value> kind del manifest generato (default: HelmOp)
|
||||||
|
-a, --all-values Usa `helm get values -a -o yaml`
|
||||||
|
-h, --help Mostra questo help
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
./generate-fleet-helmops-from-helm.sh
|
||||||
|
./generate-fleet-helmops-from-helm.sh -o ./clusters/idc/imported
|
||||||
|
./generate-fleet-helmops-from-helm.sh -w fleet-default
|
||||||
|
./generate-fleet-helmops-from-helm.sh --kind HelmChart --api-version helm.cattle.io/v1
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
require_cmd() {
|
||||||
|
local cmd="$1"
|
||||||
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
echo "Errore: comando richiesto non trovato: $cmd" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
trim() {
|
||||||
|
local value="$1"
|
||||||
|
value="${value#"${value%%[![:space:]]*}"}"
|
||||||
|
value="${value%"${value##*[![:space:]]}"}"
|
||||||
|
printf '%s' "$value"
|
||||||
|
}
|
||||||
|
|
||||||
|
safe_file_name() {
|
||||||
|
printf '%s' "$1" | tr '/\\:' '---'
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_yaml_scalar() {
|
||||||
|
local key="$1"
|
||||||
|
local content="$2"
|
||||||
|
|
||||||
|
printf '%s\n' "$content" \
|
||||||
|
| sed -n "s/^[[:space:]]*${key}:[[:space:]]*//p" \
|
||||||
|
| head -n 1 \
|
||||||
|
| sed 's/^"//; s/"$//; s/^\x27//; s/\x27$//'
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_first_source() {
|
||||||
|
local content="$1"
|
||||||
|
|
||||||
|
awk '
|
||||||
|
/^sources:/ { in_sources=1; next }
|
||||||
|
in_sources && /^[^[:space:]-]/ { exit }
|
||||||
|
in_sources && /^[[:space:]]*-[[:space:]]*/ {
|
||||||
|
sub(/^[[:space:]]*-[[:space:]]*/, "")
|
||||||
|
print
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
' <<< "$content"
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_chart_name_from_ref() {
|
||||||
|
local chart_ref="$1"
|
||||||
|
|
||||||
|
if [[ "$chart_ref" =~ ^(.+)-([0-9][A-Za-z0-9.+_-]*)$ ]]; then
|
||||||
|
printf '%s' "${BASH_REMATCH[1]}"
|
||||||
|
else
|
||||||
|
printf '%s' "$chart_ref"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_chart_version_from_ref() {
|
||||||
|
local chart_ref="$1"
|
||||||
|
|
||||||
|
if [[ "$chart_ref" =~ ^(.+)-([0-9][A-Za-z0-9.+_-]*)$ ]]; then
|
||||||
|
printf '%s' "${BASH_REMATCH[2]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
find_repo_url_from_local_cache() {
|
||||||
|
local chart_name="$1"
|
||||||
|
local chart_version="$2"
|
||||||
|
local search_json=""
|
||||||
|
local repo_alias=""
|
||||||
|
|
||||||
|
[[ -z "$chart_name" ]] && return 0
|
||||||
|
|
||||||
|
search_json="$(helm search repo "$chart_name" --versions -o json 2>/dev/null || true)"
|
||||||
|
[[ -z "$search_json" || "$search_json" == "[]" ]] && return 0
|
||||||
|
|
||||||
|
if [[ -n "$chart_version" ]]; then
|
||||||
|
repo_alias="$(jq -r --arg chart "$chart_name" --arg version "$chart_version" '
|
||||||
|
map(select((.name | split("/") | last) == $chart and .version == $version))
|
||||||
|
| .[0].name // empty
|
||||||
|
' <<< "$search_json")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$repo_alias" ]]; then
|
||||||
|
repo_alias="$(jq -r --arg chart "$chart_name" '
|
||||||
|
map(select((.name | split("/") | last) == $chart))
|
||||||
|
| .[0].name // empty
|
||||||
|
' <<< "$search_json")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -z "$repo_alias" ]] && return 0
|
||||||
|
|
||||||
|
repo_alias="${repo_alias%%/*}"
|
||||||
|
|
||||||
|
helm repo list -o json 2>/dev/null \
|
||||||
|
| jq -r --arg alias "$repo_alias" 'map(select(.name == $alias)) | .[0].url // empty'
|
||||||
|
}
|
||||||
|
|
||||||
|
indent_file() {
|
||||||
|
local file_path="$1"
|
||||||
|
sed 's/^/ /' "$file_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-o|--output-dir)
|
||||||
|
OUTPUT_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-w|--workspace-namespace)
|
||||||
|
WORKSPACE_NAMESPACE="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--api-version)
|
||||||
|
API_VERSION="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--kind)
|
||||||
|
RESOURCE_KIND="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-a|--all-values)
|
||||||
|
VALUES_ARGS=(-a)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Opzione sconosciuta: $1" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
require_cmd helm
|
||||||
|
require_cmd jq
|
||||||
|
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
releases_json="$(helm list -A -o json)"
|
||||||
|
release_count="$(jq 'length' <<< "$releases_json")"
|
||||||
|
|
||||||
|
if [[ "$release_count" -eq 0 ]]; then
|
||||||
|
echo "Nessuna release Helm trovata." >&2
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==> Release trovate: $release_count"
|
||||||
|
echo "==> Directory output: $OUTPUT_DIR"
|
||||||
|
|
||||||
|
generated_count=0
|
||||||
|
warning_count=0
|
||||||
|
|
||||||
|
while IFS= read -r release; do
|
||||||
|
name="$(jq -r '.name' <<< "$release")"
|
||||||
|
namespace="$(jq -r '.namespace' <<< "$release")"
|
||||||
|
chart_ref="$(jq -r '.chart // ""' <<< "$release")"
|
||||||
|
|
||||||
|
metadata_yaml="$(helm get metadata "$name" -n "$namespace" -o yaml 2>/dev/null || true)"
|
||||||
|
if [[ -z "$metadata_yaml" ]]; then
|
||||||
|
echo "! Impossibile leggere metadata per ${namespace}/${name}, salto." >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
repo_url="$(trim "$(extract_yaml_scalar repo "$metadata_yaml")")"
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(extract_yaml_scalar repository "$metadata_yaml")")"
|
||||||
|
fi
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(extract_yaml_scalar repoURL "$metadata_yaml")")"
|
||||||
|
fi
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(extract_first_source "$metadata_yaml")")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
chart_name="$(trim "$(extract_yaml_scalar chart "$metadata_yaml")")"
|
||||||
|
chart_version="$(trim "$(extract_yaml_scalar version "$metadata_yaml")")"
|
||||||
|
|
||||||
|
if [[ -z "$chart_name" ]]; then
|
||||||
|
chart_name="$(extract_chart_name_from_ref "$chart_ref")"
|
||||||
|
fi
|
||||||
|
if [[ -z "$chart_version" ]]; then
|
||||||
|
chart_version="$(extract_chart_version_from_ref "$chart_ref")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="$(trim "$(find_repo_url_from_local_cache "$chart_name" "$chart_version")")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$repo_url" ]]; then
|
||||||
|
repo_url="REPO_URL_NOT_FOUND"
|
||||||
|
echo "! Repo URL non trovato in metadata o cache locale per ${namespace}/${name}" >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$chart_name" ]]; then
|
||||||
|
chart_name="CHART_NAME_NOT_FOUND"
|
||||||
|
echo "! Chart name non trovato per ${namespace}/${name}" >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
values_file="$(mktemp)"
|
||||||
|
if ! helm get values "$name" -n "$namespace" "${VALUES_ARGS[@]}" -o yaml > "$values_file" 2>/dev/null; then
|
||||||
|
printf '{}\n' > "$values_file"
|
||||||
|
echo "! Values non disponibili per ${namespace}/${name}, uso {}" >&2
|
||||||
|
warning_count=$((warning_count + 1))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -s "$values_file" ]]; then
|
||||||
|
printf '{}\n' > "$values_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
values_compact="$(tr -d '[:space:]' < "$values_file")"
|
||||||
|
|
||||||
|
ns_dir="${OUTPUT_DIR}/${namespace}"
|
||||||
|
mkdir -p "$ns_dir"
|
||||||
|
|
||||||
|
safe_name="$(safe_file_name "$name")"
|
||||||
|
out_file="${ns_dir}/${safe_name}-helmop.yaml"
|
||||||
|
|
||||||
|
cat > "$out_file" <<EOF
|
||||||
|
apiVersion: ${API_VERSION}
|
||||||
|
kind: ${RESOURCE_KIND}
|
||||||
|
metadata:
|
||||||
|
name: ${safe_name}
|
||||||
|
namespace: ${WORKSPACE_NAMESPACE}
|
||||||
|
spec:
|
||||||
|
namespace: ${namespace}
|
||||||
|
helm:
|
||||||
|
releaseName: ${name}
|
||||||
|
repo: ${repo_url}
|
||||||
|
chart: ${chart_name}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [[ -n "$chart_version" ]]; then
|
||||||
|
cat >> "$out_file" <<EOF
|
||||||
|
version: ${chart_version}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$values_compact" == "{}" ]]; then
|
||||||
|
cat >> "$out_file" <<EOF
|
||||||
|
values: {}
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat >> "$out_file" <<EOF
|
||||||
|
values:
|
||||||
|
$(indent_file "$values_file")
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f "$values_file"
|
||||||
|
|
||||||
|
echo "+ Generato ${out_file} da ${namespace}/${name}"
|
||||||
|
generated_count=$((generated_count + 1))
|
||||||
|
done < <(jq -c '.[]' <<< "$releases_json")
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Riepilogo ==="
|
||||||
|
echo "File generati: $generated_count"
|
||||||
|
echo "Warning: $warning_count"
|
||||||
|
echo "Output: $OUTPUT_DIR"
|
||||||
|
echo "Workspace namespace: $WORKSPACE_NAMESPACE"
|
||||||
|
echo ""
|
||||||
|
echo "Nota: il repo URL viene letto da 'helm get metadata' e, se assente,"
|
||||||
|
echo " viene cercato nella cache locale di 'helm repo list/search repo'."
|
||||||
|
echo "Se vedi REPO_URL_NOT_FOUND, completa il campo repo manualmente."
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Aggiunge un hostname a spec.template.spec.hostAliases del Deployment cert-manager.
|
||||||
|
#
|
||||||
|
# Uso:
|
||||||
|
# ./add-cert-manager-hostalias.sh <hostname>
|
||||||
|
#
|
||||||
|
# Esempio:
|
||||||
|
# ./add-cert-manager-hostalias.sh main-gateway-nginx.nginx-gateway.svc.cluster.local
|
||||||
|
# ./add-cert-manager-hostalias.sh api.internal
|
||||||
|
|
||||||
|
DEPLOYMENT_NAME="cert-manager"
|
||||||
|
DEPLOYMENT_NS="cert-manager"
|
||||||
|
TARGET_IP="10.43.37.118"
|
||||||
|
HOSTNAME_VAL="${1:-}"
|
||||||
|
|
||||||
|
if [[ -z "$HOSTNAME_VAL" ]]; then
|
||||||
|
echo "Uso: $0 <hostname>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v kubectl >/dev/null 2>&1; then
|
||||||
|
echo "Errore: kubectl non trovato nel PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v jq >/dev/null 2>&1; then
|
||||||
|
echo "Errore: jq non trovato nel PATH" >&2
|
||||||
|
echo "Installa jq e riprova." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Idempotenza: controlla solo il blocco hostAliases associato a TARGET_IP.
|
||||||
|
EXISTING_HOSTNAMES="$(kubectl get deployment "$DEPLOYMENT_NAME" -n "$DEPLOYMENT_NS" -o jsonpath="{.spec.template.spec.hostAliases[?(@.ip=='${TARGET_IP}')].hostnames[*]}" 2>/dev/null || true)"
|
||||||
|
if echo " $EXISTING_HOSTNAMES " | grep -Fq " $HOSTNAME_VAL "; then
|
||||||
|
echo "Hostname '$HOSTNAME_VAL' gia presente per IP ${TARGET_IP} in ${DEPLOYMENT_NS}/${DEPLOYMENT_NAME}. Nessuna modifica."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPLOY_JSON="$(kubectl get deployment "$DEPLOYMENT_NAME" -n "$DEPLOYMENT_NS" -o json)"
|
||||||
|
|
||||||
|
UPDATED_HOST_ALIASES="$({
|
||||||
|
echo "$DEPLOY_JSON" | jq -c --arg ip "$TARGET_IP" --arg hostname "$HOSTNAME_VAL" '
|
||||||
|
(.spec.template.spec.hostAliases //= [])
|
||||||
|
| if any(.spec.template.spec.hostAliases[]?; .ip == $ip) then
|
||||||
|
.spec.template.spec.hostAliases |= map(
|
||||||
|
if .ip == $ip then
|
||||||
|
if ((.hostnames // []) | index($hostname)) then
|
||||||
|
.
|
||||||
|
else
|
||||||
|
.hostnames = ((.hostnames // []) + [$hostname])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
.
|
||||||
|
end
|
||||||
|
)
|
||||||
|
else
|
||||||
|
.spec.template.spec.hostAliases += [{"ip": $ip, "hostnames": [$hostname]}]
|
||||||
|
end
|
||||||
|
| .spec.template.spec.hostAliases
|
||||||
|
'
|
||||||
|
} )"
|
||||||
|
|
||||||
|
PATCH_PAYLOAD="$(jq -cn --argjson hostAliases "$UPDATED_HOST_ALIASES" '{spec:{template:{spec:{hostAliases:$hostAliases}}}}')"
|
||||||
|
|
||||||
|
kubectl patch deployment "$DEPLOYMENT_NAME" \
|
||||||
|
-n "$DEPLOYMENT_NS" \
|
||||||
|
--type=merge \
|
||||||
|
-p "$PATCH_PAYLOAD" >/dev/null
|
||||||
|
|
||||||
|
echo "Hostname aggiunto con successo."
|
||||||
|
echo " Deployment: ${DEPLOYMENT_NS}/${DEPLOYMENT_NAME}"
|
||||||
|
echo " IP : ${TARGET_IP}"
|
||||||
|
echo " Hostname : ${HOSTNAME_VAL}"
|
||||||
@@ -35,6 +35,7 @@ fi
|
|||||||
# Per calcolare il token usa host pulito (senza schema e path)
|
# Per calcolare il token usa host pulito (senza schema e path)
|
||||||
host_for_token="${endpoint#*://}"
|
host_for_token="${endpoint#*://}"
|
||||||
host_for_token="${host_for_token%%/*}"
|
host_for_token="${host_for_token%%/*}"
|
||||||
|
host_no_port="${host_for_token%%:*}"
|
||||||
token="${host_for_token%%.*}"
|
token="${host_for_token%%.*}"
|
||||||
|
|
||||||
if [[ -z "$token" ]]; then
|
if [[ -z "$token" ]]; then
|
||||||
@@ -42,5 +43,18 @@ if [[ -z "$token" ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Se l'hostname non e nel dominio *.italiadatacenter.com, aggiungilo anche a cert-manager hostAliases.
|
||||||
|
if [[ "$host_no_port" != *.italiadatacenter.com ]]; then
|
||||||
|
HOSTALIAS_SCRIPT="/root/work/pipeline/add-cert-manager-hostalias.sh"
|
||||||
|
if [[ -x "$HOSTALIAS_SCRIPT" ]]; then
|
||||||
|
"$HOSTALIAS_SCRIPT" "$host_no_port"
|
||||||
|
elif [[ -f "$HOSTALIAS_SCRIPT" ]]; then
|
||||||
|
bash "$HOSTALIAS_SCRIPT" "$host_no_port"
|
||||||
|
else
|
||||||
|
echo "Errore: script non trovato: $HOSTALIAS_SCRIPT" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Output richiesto: <endpoint> https-<token> <token>-secret
|
# Output richiesto: <endpoint> https-<token> <token>-secret
|
||||||
/root/work/pipeline/add-listener.sh $endpoint https-$token $token-secret
|
/root/work/pipeline/add-listener.sh $endpoint https-$token $token-secret
|
||||||
|
|||||||
Reference in New Issue
Block a user