fluxcd-reconciler, env creator calling it every 30 sec to sync the cluster
diff --git a/charts/fluxcd-reconciler/.helmignore b/charts/fluxcd-reconciler/.helmignore
new file mode 100644
index 0000000..0e8a0eb
--- /dev/null
+++ b/charts/fluxcd-reconciler/.helmignore
@@ -0,0 +1,23 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*.orig
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/charts/fluxcd-reconciler/Chart.yaml b/charts/fluxcd-reconciler/Chart.yaml
new file mode 100644
index 0000000..c504ef5
--- /dev/null
+++ b/charts/fluxcd-reconciler/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: fluxcd-reconciler
+description: A Helm chart for a service triggering fluxcd reconcilations
+type: application
+version: 0.0.1
+appVersion: "0.0.1"
diff --git a/charts/fluxcd-reconciler/templates/install.yaml b/charts/fluxcd-reconciler/templates/install.yaml
new file mode 100644
index 0000000..68ce7e4
--- /dev/null
+++ b/charts/fluxcd-reconciler/templates/install.yaml
@@ -0,0 +1,91 @@
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: fluxcd-reconciler
+ namespace: {{ .Release.Namespace }}
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: fluxcd-reconciler
+rules: # TODO(gio): restrict to ns create and dnszone get
+- apiGroups:
+ - "source.toolkit.fluxcd.io/v1"
+ resources:
+ - "gitrepositories"
+ verbs:
+ - get
+ - update
+- apiGroups:
+ - "kustomize.toolkit.fluxcd.io"
+ resources:
+ - "kustomizations"
+ verbs:
+ - get
+ - update
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: fluxcd-reconciler
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: fluxcd-reconciler
+subjects:
+- kind: ServiceAccount
+ name: fluxcd-reconciler
+ namespace: {{ .Release.Namespace }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: fluxcd-reconciler
+ namespace: {{ .Release.Namespace }}
+spec:
+ type: ClusterIP
+ selector:
+ app: fluxcd-reconciler
+ ports:
+ - name: http
+ port: 80
+ targetPort: http
+ protocol: TCP
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: fluxcd-reconciler
+ namespace: {{ .Release.Namespace }}
+spec:
+ selector:
+ matchLabels:
+ app: fluxcd-reconciler
+ replicas: 1
+ serviceAccountName: fluxcd-reconciler
+ template:
+ metadata:
+ labels:
+ app: fluxcd-reconciler
+ spec:
+ containers:
+ - name: fluxcd-reconciler
+ image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ ports:
+ - name: http
+ containerPort: 8080
+ protocol: TCP
+ command: ["fluxcd-reconciler", "--port=8080"]
+ resources:
+ requests:
+ memory: "10Mi"
+ cpu: "10m"
+ limits:
+ memory: "20Mi"
+ cpu: "100m"
+ tolerations:
+ - key: "pcloud"
+ operator: "Equal"
+ value: "role"
+ effect: "NoSchedule"
diff --git a/charts/fluxcd-reconciler/values.yaml b/charts/fluxcd-reconciler/values.yaml
new file mode 100644
index 0000000..cbf0bca
--- /dev/null
+++ b/charts/fluxcd-reconciler/values.yaml
@@ -0,0 +1,4 @@
+image:
+ repository: giolekva/fluxcd-reconciler
+ tag: latest
+ pullPolicy: Always
diff --git a/core/fluxcd-reconciler/.gitignore b/core/fluxcd-reconciler/.gitignore
new file mode 100644
index 0000000..19350b1
--- /dev/null
+++ b/core/fluxcd-reconciler/.gitignore
@@ -0,0 +1,2 @@
+fluxcd_reconciler
+fluxcd_reconciler_*
diff --git a/core/fluxcd-reconciler/Dockerfile b/core/fluxcd-reconciler/Dockerfile
new file mode 100644
index 0000000..024afab
--- /dev/null
+++ b/core/fluxcd-reconciler/Dockerfile
@@ -0,0 +1,7 @@
+FROM gcr.io/distroless/static:nonroot
+
+ARG TARGETARCH
+
+COPY tmp/charts /charts
+
+COPY fluxcd_reconciler_${TARGETARCH} /fluxcd_reconciler
diff --git a/core/fluxcd-reconciler/Makefile b/core/fluxcd-reconciler/Makefile
new file mode 100644
index 0000000..70f5889
--- /dev/null
+++ b/core/fluxcd-reconciler/Makefile
@@ -0,0 +1,44 @@
+clean:
+ rm -rf tmp
+ rm -f fluxcd_reconciler fluxcd_reconciler_*
+
+build: export CGO_ENABLED=0
+build: clean
+ /usr/local/go/bin/go build -o fluxcd_reconciler main.go
+
+run: build
+ ./fluxcd_reconciler --port=8080 --kubeconfig=/Users/lekva/dev/src/pcloud/priv/kubeconfig-hetzner
+
+## installer image
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64:
+ /usr/local/go/bin/go build -o fluxcd_reconciler_arm64 main.go
+
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64:
+ /usr/local/go/bin/go build -o fluxcd_reconciler_amd64 main.go
+
+push_arm64: clean build_arm64
+ mkdir tmp
+ cp -r ../../charts tmp/
+ podman build --platform linux/arm64 --tag=giolekva/fluxcd-reconciler:arm64 .
+ rm -rf tmp
+ podman push giolekva/fluxcd-reconciler:arm64
+
+push_amd64: clean build_amd64
+ mkdir tmp
+ cp -r ../../charts tmp/
+ podman build --platform linux/amd64 --tag=giolekva/fluxcd-reconciler:amd64 .
+ rm -rf tmp
+ podman push giolekva/fluxcd-reconciler:amd64
+
+push: push_arm64 push_amd64
+ podman manifest create giolekva/fluxcd-reconciler:latest giolekva/fluxcd-reconciler:arm64 giolekva/fluxcd-reconciler:amd64
+ podman manifest push giolekva/fluxcd-reconciler:latest docker://docker.io/giolekva/fluxcd-reconciler:latest
+ podman manifest rm giolekva/fluxcd-reconciler:latest
diff --git a/core/fluxcd-reconciler/go.mod b/core/fluxcd-reconciler/go.mod
new file mode 100644
index 0000000..dc180cb
--- /dev/null
+++ b/core/fluxcd-reconciler/go.mod
@@ -0,0 +1,39 @@
+module github.com/giolekva/pcloud/core/fluxcd-reconciler
+
+go 1.21.5
+
+require (
+ github.com/gorilla/mux v1.8.1
+ k8s.io/client-go v0.28.4
+)
+
+require (
+ github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/go-logr/logr v1.2.4 // indirect
+ github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang/protobuf v1.5.3 // indirect
+ github.com/google/gofuzz v1.2.0 // indirect
+ github.com/imdario/mergo v0.3.6 // indirect
+ github.com/json-iterator/go v1.1.12 // indirect
+ github.com/kr/text v0.2.0 // indirect
+ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
+ github.com/modern-go/reflect2 v1.0.2 // indirect
+ github.com/spf13/pflag v1.0.5 // indirect
+ golang.org/x/net v0.17.0 // indirect
+ golang.org/x/oauth2 v0.8.0 // indirect
+ golang.org/x/sys v0.13.0 // indirect
+ golang.org/x/term v0.13.0 // indirect
+ golang.org/x/text v0.13.0 // indirect
+ golang.org/x/time v0.3.0 // indirect
+ google.golang.org/appengine v1.6.7 // indirect
+ google.golang.org/protobuf v1.31.0 // indirect
+ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
+ gopkg.in/inf.v0 v0.9.1 // indirect
+ gopkg.in/yaml.v2 v2.4.0 // indirect
+ k8s.io/apimachinery v0.28.4 // indirect
+ k8s.io/klog/v2 v2.100.1 // indirect
+ k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 // indirect
+ sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
+ sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
+ sigs.k8s.io/yaml v1.3.0 // indirect
+)
diff --git a/core/fluxcd-reconciler/go.sum b/core/fluxcd-reconciler/go.sum
new file mode 100644
index 0000000..b89fc6b
--- /dev/null
+++ b/core/fluxcd-reconciler/go.sum
@@ -0,0 +1,142 @@
+github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
+github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
+github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ=
+github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
+github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
+github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
+github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
+github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
+github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
+github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
+github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
+github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
+github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
+github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
+github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
+github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
+github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
+github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
+github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
+golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
+golang.org/x/oauth2 v0.8.0 h1:6dkIjl3j3LtZ/O3sTgZTMsLKSftL/B8Zgq4huOIIUu8=
+golang.org/x/oauth2 v0.8.0/go.mod h1:yr7u4HXZRm1R1kBWqr/xKNqewf0plRYoB7sla+BCIXE=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
+golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
+golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
+golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
+google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+k8s.io/api v0.28.4 h1:8ZBrLjwosLl/NYgv1P7EQLqoO8MGQApnbgH8tu3BMzY=
+k8s.io/api v0.28.4/go.mod h1:axWTGrY88s/5YE+JSt4uUi6NMM+gur1en2REMR7IRj0=
+k8s.io/apimachinery v0.28.4 h1:zOSJe1mc+GxuMnFzD4Z/U1wst50X28ZNsn5bhgIIao8=
+k8s.io/apimachinery v0.28.4/go.mod h1:wI37ncBvfAoswfq626yPTe6Bz1c22L7uaJ8dho83mgg=
+k8s.io/client-go v0.28.4 h1:Np5ocjlZcTrkyRJ3+T3PkXDpe4UpatQxj85+xjaD2wY=
+k8s.io/client-go v0.28.4/go.mod h1:0VDZFpgoZfelyP5Wqu0/r/TRYcLYuJ2U1KEeoaPa1N4=
+k8s.io/klog/v2 v2.100.1 h1:7WCHKK6K8fNhTqfBhISHQ97KrnJNFZMcQvKp7gP/tmg=
+k8s.io/klog/v2 v2.100.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
+k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 h1:LyMgNKD2P8Wn1iAwQU5OhxCKlKJy0sHc+PcDwFB24dQ=
+k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9/go.mod h1:wZK2AVp1uHCp4VamDVgBP2COHZjqD1T68Rf0CM3YjSM=
+k8s.io/utils v0.0.0-20230406110748-d93618cff8a2 h1:qY1Ad8PODbnymg2pRbkyMT/ylpTrCM8P2RJ0yroCyIk=
+k8s.io/utils v0.0.0-20230406110748-d93618cff8a2/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
+sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3 h1:PRbqxJClWWYMNV1dhaG4NsibJbArud9kFxnAMREiWFE=
+sigs.k8s.io/structured-merge-diff/v4 v4.2.3/go.mod h1:qjx8mGObPmV2aSZepjQjbmb2ihdVs8cGKBraizNC69E=
+sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
+sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
diff --git a/core/fluxcd-reconciler/main.go b/core/fluxcd-reconciler/main.go
new file mode 100644
index 0000000..9220fec
--- /dev/null
+++ b/core/fluxcd-reconciler/main.go
@@ -0,0 +1,170 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "log"
+ "net/http"
+ "time"
+
+ "github.com/gorilla/mux"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+ "k8s.io/apimachinery/pkg/runtime/schema"
+ "k8s.io/client-go/dynamic"
+ "k8s.io/client-go/rest"
+ "k8s.io/client-go/tools/clientcmd"
+)
+
+var port = flag.Int("port", 8080, "Port to listen on")
+var kubeconfig = flag.String("kubeconfig", "", "Path to kubeconfig file")
+
+const reconcileAnnotation = "reconcile.fluxcd.io/requestedAt"
+const reconcileAtLayout = time.RFC3339Nano
+
+type Server struct {
+ port int
+ client dynamic.Interface
+}
+
+func NewServer(port int, client dynamic.Interface) *Server {
+ return &Server{port, client}
+}
+
+func (s *Server) Start() {
+ r := mux.NewRouter()
+ r.Path("/source/git/{namespace}/{name}/reconcile").Methods("GET").HandlerFunc(s.sourceGitReconcile)
+ r.Path("/kustomization/{namespace}/{name}/reconcile").Methods("GET").HandlerFunc(s.kustomizationReconcile)
+ http.Handle("/", r)
+ log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", s.port), nil))
+}
+
+func getReconciledAt(obj *unstructured.Unstructured) (string, error) {
+ status, ok := obj.Object["status"]
+ if !ok {
+ return "", fmt.Errorf("status not found")
+ }
+ statusMap, ok := status.(map[string]interface{})
+ if !ok {
+ return "", fmt.Errorf("status not map")
+ }
+ val, ok := statusMap["lastHandledReconcileAt"]
+ if !ok {
+ return "", fmt.Errorf("lastHandledReconcileAt not found in status")
+ }
+ valStr, ok := val.(string)
+ if !ok {
+ return "", fmt.Errorf("lastHandledReconcileAt not string")
+ }
+ return valStr, nil
+}
+
+func reconcile(
+ client dynamic.Interface,
+ res schema.GroupVersionResource,
+ namespace string,
+ name string,
+) error {
+ unstr, err := client.Resource(res).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
+ if err != nil {
+ return err
+ }
+ timeNowTime := time.Now()
+ annotations := unstr.GetAnnotations()
+ annotations[reconcileAnnotation] = timeNowTime.Format(reconcileAtLayout)
+ unstr.SetAnnotations(annotations)
+ unstr, err = client.Resource(res).Namespace(namespace).Update(context.TODO(), unstr, metav1.UpdateOptions{})
+ if err != nil {
+ return err
+ }
+ for {
+ unstr, err := client.Resource(res).Namespace(namespace).Get(context.TODO(), name, metav1.GetOptions{})
+ if err != nil {
+ return err
+ }
+ reconciledAt, err := getReconciledAt(unstr)
+ if err != nil {
+ return err
+ }
+ reconciledAtTime, err := time.Parse(reconcileAtLayout, reconciledAt)
+ if err != nil {
+ return err
+ }
+ reconciledAtTime = reconciledAtTime.Add(3 * time.Hour)
+ if reconciledAtTime.After(timeNowTime) {
+ return nil
+ }
+ }
+}
+
+func (s *Server) sourceGitReconcile(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ namespace, ok := vars["namespace"]
+ if !ok {
+ http.Error(w, "namespace missing", http.StatusBadRequest)
+ return
+ }
+ name, ok := vars["name"]
+ if !ok {
+ http.Error(w, "name missing", http.StatusBadRequest)
+ return
+ }
+ res := schema.GroupVersionResource{
+ Group: "source.toolkit.fluxcd.io",
+ Version: "v1",
+ Resource: "gitrepositories",
+ }
+ if err := reconcile(s.client, res, namespace, name); err != nil {
+ http.Error(w, "error", http.StatusInternalServerError)
+ return
+ }
+}
+
+func (s *Server) kustomizationReconcile(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ namespace, ok := vars["namespace"]
+ if !ok {
+ http.Error(w, "namespace missing", http.StatusBadRequest)
+ return
+ }
+ name, ok := vars["name"]
+ if !ok {
+ http.Error(w, "name missing", http.StatusBadRequest)
+ return
+ }
+ res := schema.GroupVersionResource{
+ Group: "kustomize.toolkit.fluxcd.io",
+ Version: "v1",
+ Resource: "kustomizations",
+ }
+ if err := reconcile(s.client, res, namespace, name); err != nil {
+ http.Error(w, "error", http.StatusInternalServerError)
+ return
+ }
+}
+
+func NewKubeClient(kubeconfig string) (dynamic.Interface, error) {
+ if kubeconfig == "" {
+ config, err := rest.InClusterConfig()
+ if err != nil {
+ return nil, err
+ }
+ return dynamic.NewForConfig(config)
+ } else {
+ config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
+ if err != nil {
+ return nil, err
+ }
+ return dynamic.NewForConfig(config)
+ }
+}
+
+func main() {
+ flag.Parse()
+ client, err := NewKubeClient(*kubeconfig)
+ if err != nil {
+ log.Fatal(err)
+ }
+ NewServer(*port, client).Start()
+}
diff --git a/core/installer/app.go b/core/installer/app.go
index 511f1a4..85f1cba 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -114,6 +114,7 @@
CreateResourceRendererController(valuesTmpls, tmpls),
CreateHeadscaleController(valuesTmpls, tmpls),
CreateDNSZoneManager(valuesTmpls, tmpls),
+ CreateFluxcdReconciler(valuesTmpls, tmpls),
}
for _, a := range CreateStoreApps() {
ret = append(ret, a.App)
@@ -577,6 +578,22 @@
}
}
+func CreateFluxcdReconciler(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/fluxcd-reconciler.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "fluxcd-reconciler",
+ []string{"fluxcd-reconciler"},
+ []*template.Template{
+ tmpls.Lookup("fluxcd-reconciler.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("fluxcd-reconciler.md"),
+ }
+}
+
type httpAppRepository struct {
apps []StoreApp
}
diff --git a/core/installer/bootstrapper.go b/core/installer/bootstrapper.go
index 94c1e2d..e3331c4 100644
--- a/core/installer/bootstrapper.go
+++ b/core/installer/bootstrapper.go
@@ -88,6 +88,10 @@
if err := b.installDNSZoneManager(ss, repoIO, nsGen, b.ns, env); err != nil {
return err
}
+ fmt.Println("Installing Fluxcd Reconciler")
+ if err := b.installFluxcdReconciler(ss, repoIO, nsGen, b.ns, env); err != nil {
+ return err
+ }
fmt.Println("Installing env manager")
if err := b.installEnvManager(ss, repoIO, nsGen, b.ns, env); err != nil {
return err
@@ -555,6 +559,34 @@
return nil
}
+func (b Bootstrapper) installFluxcdReconciler(ss *soft.Client, repo RepoIO, nsGen NamespaceGenerator, nsCreator NamespaceCreator, env EnvConfig) error {
+ appRepo := NewInMemoryAppRepository(CreateAllApps())
+ app, err := appRepo.Find("fluxcd-reconciler")
+ if err != nil {
+ return err
+ }
+ ns, err := nsGen.Generate(app.Namespaces[0])
+ if err != nil {
+ return err
+ }
+ if err := nsCreator.Create(ns); err != nil {
+ return err
+ }
+ derived := Derived{
+ Global: Values{
+ PCloudEnvName: env.Name,
+ },
+ Values: map[string]any{},
+ Release: Release{
+ Namespace: ns,
+ },
+ }
+ if err := repo.InstallApp(*app, filepath.Join("/infrastructure", app.Name), derived.Values, derived); err != nil {
+ return err
+ }
+ return nil
+}
+
type HelmActionConfigFactory interface {
New(namespace string) (*action.Configuration, error)
}
diff --git a/core/installer/tasks/env.go b/core/installer/tasks/env.go
index 2dd8da5..f5cc0c7 100644
--- a/core/installer/tasks/env.go
+++ b/core/installer/tasks/env.go
@@ -1,7 +1,10 @@
package tasks
import (
+ "fmt"
"net"
+ "net/http"
+ "time"
"github.com/charmbracelet/keygen"
@@ -47,7 +50,7 @@
nsCreator: nsCreator,
repo: repo,
}
- return newSequentialParentTask(
+ t := newSequentialParentTask(
"Create env",
append(
[]Task{
@@ -57,5 +60,26 @@
},
SetupInfra(env, &st)...,
)...,
- ), DNSZoneRef{"dns-zone", env.Name}
+ )
+ done := make(chan struct{})
+ t.OnDone(func(_ error) {
+ close(done)
+ })
+ go reconcile(fmt.Sprintf("%s-flux", env.PCloudEnvName), done)
+ go reconcile(env.Name, done)
+ return t, DNSZoneRef{"dns-zone", env.Name}
+}
+
+func reconcile(name string, quit chan struct{}) {
+ git := fmt.Sprintf("http://fluxcd-reconciler.dodo-fluxcd-reconciler.svc.cluster.local/source/git/%s/%s/reconcile", name, name)
+ kust := fmt.Sprintf("http://fluxcd-reconciler.dodo-fluxcd-reconciler.svc.cluster.local/kustomization/%s/%s/reconcile", name, name)
+ for {
+ select {
+ case <-time.After(30 * time.Second):
+ http.Get(git)
+ http.Get(kust)
+ case <-quit:
+ return
+ }
+ }
}
diff --git a/core/installer/values-tmpl/fluxcd-reconciler.jsonschema b/core/installer/values-tmpl/fluxcd-reconciler.jsonschema
new file mode 100644
index 0000000..4a7c07d
--- /dev/null
+++ b/core/installer/values-tmpl/fluxcd-reconciler.jsonschema
@@ -0,0 +1,5 @@
+{
+ "type": "object",
+ "properties": {},
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/fluxcd-reconciler.md b/core/installer/values-tmpl/fluxcd-reconciler.md
new file mode 100644
index 0000000..f31c256
--- /dev/null
+++ b/core/installer/values-tmpl/fluxcd-reconciler.md
@@ -0,0 +1 @@
+Installs gateway to Fluxcd API
diff --git a/core/installer/values-tmpl/fluxcd-reconciler.yaml b/core/installer/values-tmpl/fluxcd-reconciler.yaml
new file mode 100644
index 0000000..d749a7d
--- /dev/null
+++ b/core/installer/values-tmpl/fluxcd-reconciler.yaml
@@ -0,0 +1,15 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: fluxcd-reconciler
+ namespace: {{ .Release.Namespace }}
+spec:
+ chart:
+ spec:
+ chart: charts/fluxcd-reconciler
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.Id }}
+ interval: 1m0s
+ values: