diff --git a/.github/kind.yml b/.github/kind.yml index 9438061..f9ef53a 100644 --- a/.github/kind.yml +++ b/.github/kind.yml @@ -31,6 +31,9 @@ nodes: - containerPort: 443 hostPort: 443 protocol: TCP + extraMounts: + - hostPath: /home/tmp + containerPath: /data - role: worker - role: worker - role: worker diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 6365f9a..cfaff7d 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -27,7 +27,7 @@ jobs: with: fetch-depth: 0 - name: Run Trivy vulnerability scanner in repo mode - uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef # v0.17.0 + uses: aquasecurity/trivy-action@6e7b7d1fd3e4fef0c5fa8cce1229c54b2c9bd0d8 # v0.24.0 with: scan-type: fs ignore-unfixed: false @@ -37,8 +37,12 @@ jobs: scanners: vuln,secret exit-code: '0' vuln-type: os,library + env: + # Trivy is returning TOOMANYREQUESTS + # See: https://github.com/aquasecurity/trivy-action/issues/389#issuecomment-2385416577 + TRIVY_DB_REPOSITORY: 'public.ecr.aws/aquasecurity/trivy-db:2' - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@cdcdbb579706841c47f7063dda365e292e5cad7a # v2.13.4 with: sarif_file: trivy-results.sarif - category: code \ No newline at end of file + category: code diff --git a/.github/workflows/conformance-tests.yaml b/.github/workflows/conformance-tests.yaml index 98cbab7..f108eb9 100644 --- a/.github/workflows/conformance-tests.yaml +++ b/.github/workflows/conformance-tests.yaml @@ -86,7 +86,11 @@ jobs: - name: Install latest kyverno run: | set -e - kubectl create -f https://github.com/kyverno/kyverno/raw/main/config/install-latest-testing.yaml + set -e + export HELM=${{ steps.helm.outputs.helm-path }} + helm repo add kyverno https://kyverno.github.io/kyverno/ + kubectl create namespace kyverno + helm install kyverno --namespace kyverno kyverno/kyverno --set features.policyExceptions.enabled=true --set features.policyExceptions.namespace='*' - name: Wait for kyverno ready run: | set -e @@ -96,7 +100,7 @@ jobs: set -e kubectl get apiservices v1alpha2.wgpolicyk8s.io v1.reports.kyverno.io - name: Install Chainsaw - uses: kyverno/action-install-chainsaw@d1a61148c0437a66760d11d8575332305c2234cb # v0.2.10 + uses: kyverno/action-install-chainsaw@d311eacde764f806c9658574ff64c9c3b21f8397 # v0.2.11 - name: Test with Chainsaw env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/migration-tests.yaml b/.github/workflows/migration-tests.yaml index 18c08fe..b767f28 100644 --- a/.github/workflows/migration-tests.yaml +++ b/.github/workflows/migration-tests.yaml @@ -74,10 +74,13 @@ jobs: run: | set -e kind create cluster --image kindest/node:${{ matrix.k8s-version.version }} --config ./.github/kind.yml - - name: Install kyverno v1.12.4 + - name: Install kyverno run: | set -e - kubectl create -f https://github.com/kyverno/kyverno/raw/main/config/install-latest-testing.yaml + export HELM=${{ steps.helm.outputs.helm-path }} + helm repo add kyverno https://kyverno.github.io/kyverno/ + kubectl create namespace kyverno + helm install kyverno --namespace kyverno kyverno/kyverno --set features.policyExceptions.enabled=true --set features.policyExceptions.namespace='*' - name: Wait for kyverno ready run: | set -e @@ -111,7 +114,7 @@ jobs: set -e kubectl get apiservices v1alpha2.wgpolicyk8s.io v1.reports.kyverno.io - name: Install Chainsaw - uses: kyverno/action-install-chainsaw@d1a61148c0437a66760d11d8575332305c2234cb # v0.2.10 + uses: kyverno/action-install-chainsaw@d311eacde764f806c9658574ff64c9c3b21f8397 # v0.2.11 - name: Test with Chainsaw env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Makefile b/Makefile index e818021..4cbee4b 100644 --- a/Makefile +++ b/Makefile @@ -164,23 +164,23 @@ codegen-install-manifest: $(HELM) ## Create install manifest | $(SED) -e '/^#.*/d' \ > ./config/install.yaml -codegen-install-manifest-inmemory: $(HELM) ## Create install manifest without postgres +codegen-install-manifest-etcd: $(HELM) ## Create install manifest without postgres @echo Generate latest install manifest... >&2 @$(HELM) template reports-server --namespace reports-server ./charts/reports-server/ \ --set apiServicesManagement.installApiServices.enabled=true \ --set image.tag=latest \ - --set config.debug=true \ + --set config.etcd.enabled=true \ --set postgresql.enabled=false \ --set templating.enabled=true \ | $(SED) -e '/^#.*/d' \ - > ./config/install-inmemory.yaml + > ./config/install-etcd.yaml .PHONY: codegen codegen: ## Rebuild all generated code and docs codegen: codegen-helm-docs codegen: codegen-openapi codegen: codegen-install-manifest -codegen: codegen-install-manifest-inmemory +codegen: codegen-install-manifest-etcd .PHONY: verify-codegen verify-codegen: codegen ## Verify all generated code and docs are up to date @@ -220,12 +220,12 @@ kind-install: $(HELM) kind-load ## Build image, load it in kind cluster and depl --set image.repository=$(PACKAGE) \ --set image.tag=$(GIT_SHA) -.PHONY: kind-install-inmemory -kind-install-inmemory: $(HELM) kind-load ## Build image, load it in kind cluster and deploy helm chart +.PHONY: kind-install-etcd +kind-install-etcd: $(HELM) kind-load ## Build image, load it in kind cluster and deploy helm chart @echo Install chart... >&2 @$(HELM) upgrade --install reports-server --namespace reports-server --create-namespace --wait ./charts/reports-server \ --set image.registry=$(KO_REGISTRY) \ - --set config.debug=true \ + --set config.etcd.enabled=true \ --set postgresql.enabled=false \ --set image.repository=$(PACKAGE) \ --set image.tag=$(GIT_SHA) diff --git a/charts/reports-server/Chart.yaml b/charts/reports-server/Chart.yaml index d04531a..5033d10 100644 --- a/charts/reports-server/Chart.yaml +++ b/charts/reports-server/Chart.yaml @@ -1,8 +1,8 @@ apiVersion: v2 name: reports-server type: application -version: 0.1.3 -appVersion: v0.1.3 +version: 0.1.4-alpha.0 +appVersion: v0.1.4-alpha.0 keywords: - kubernetes - policy reports storage diff --git a/charts/reports-server/README.md b/charts/reports-server/README.md index 62408c9..8076fa7 100644 --- a/charts/reports-server/README.md +++ b/charts/reports-server/README.md @@ -1,6 +1,6 @@ # reports-server -![Version: 0.1.3](https://img.shields.io/badge/Version-0.1.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.1.3](https://img.shields.io/badge/AppVersion-v0.1.3-informational?style=flat-square) +![Version: 0.1.4-alpha.0](https://img.shields.io/badge/Version-0.1.4--alpha.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.1.4-alpha.0](https://img.shields.io/badge/AppVersion-v0.1.4--alpha.0-informational?style=flat-square) TODO @@ -23,7 +23,7 @@ helm install reports-server --namespace reports-server --create-namespace report | Key | Type | Default | Description | |-----|------|---------|-------------| | cloudnative-pg.crds.create | bool | `false` | | -| postgresql.enabled | bool | `true` | Deploy postgresql dependency chart | +| postgresql.enabled | bool | `false` | Deploy postgresql dependency chart | | postgresql.auth.postgresPassword | string | `"reports"` | | | postgresql.auth.database | string | `"reportsdb"` | | | nameOverride | string | `""` | Name override | @@ -62,7 +62,9 @@ helm install reports-server --namespace reports-server --create-namespace report | affinity | object | `{}` | Affinity | | service.type | string | `"ClusterIP"` | Service type | | service.port | int | `443` | Service port | -| config.debug | bool | `false` | Enable debug (to use inmemorydatabase) | +| config.etcd.enabled | bool | `true` | | +| config.etcd.endpoints | string | `nil` | | +| config.etcd.insecure | bool | `true` | | | config.db.secretName | string | `""` | If set, database connection information will be read from the Secret with this name. Overrides `db.host`, `db.name`, `db.user`, and `db.password`. | | config.db.host | string | `"reports-server-cluster-rw.reports-server"` | Database host | | config.db.hostSecretKeyName | string | `"host"` | The database host will be read from this `key` in the specified Secret, when `db.secretName` is set. | diff --git a/charts/reports-server/templates/deployment.yaml b/charts/reports-server/templates/deployment.yaml index 5e68bc2..ab481d5 100644 --- a/charts/reports-server/templates/deployment.yaml +++ b/charts/reports-server/templates/deployment.yaml @@ -37,8 +37,12 @@ spec: containers: - name: reports-server args: - {{- if .Values.config.debug }} - - --debug + {{- if .Values.config.etcd.enabled }} + - --etcd + {{- if .Values.config.etcd.insecure }} + - --etcdSkipTLS + {{- end }} + - --etcdEndpoints=https://etcd-0.etcd.{{ $.Release.Namespace }}:2379,https://etcd-1.etcd.{{ $.Release.Namespace }}:2379,https://etcd-2.etcd.{{ $.Release.Namespace }}:2379 {{- else }} - --dbhost={{ include "reports-server.dbHost" . }} - --dbname={{ include "reports-server.dbName" . }} @@ -79,15 +83,15 @@ spec: {{- end}} securityContext: {{- toYaml .Values.securityContext | nindent 12 }} + volumeMounts: + - mountPath: /tmp + name: tmp-dir image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" imagePullPolicy: {{ .Values.image.pullPolicy }} ports: - name: https containerPort: 4443 protocol: TCP - volumeMounts: - - mountPath: /tmp - name: tmp-dir {{- with .Values.livenessProbe }} livenessProbe: {{- toYaml . | nindent 12 }} diff --git a/charts/reports-server/templates/etcd.yaml b/charts/reports-server/templates/etcd.yaml new file mode 100644 index 0000000..e10a8ca --- /dev/null +++ b/charts/reports-server/templates/etcd.yaml @@ -0,0 +1,170 @@ +{{- if .Values.config.etcd.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: etcd + namespace: {{ $.Release.Namespace }} + labels: + app: etcd-reports-server + {{- include "reports-server.labels" . | nindent 4 }} +spec: + type: ClusterIP + clusterIP: None + selector: + app: etcd-reports-server + publishNotReadyAddresses: true + ports: + - name: etcd-client + port: 2379 + - name: etcd-server + port: 2380 + - name: etcd-metrics + port: 8080 +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + namespace: {{ include "reports-server.fullname" . }} + name: etcd + labels: + app: etcd-reports-server + {{- include "reports-server.labels" . | nindent 4 }} +spec: + serviceName: etcd + replicas: 3 + podManagementPolicy: Parallel + updateStrategy: + type: RollingUpdate + selector: + matchLabels: + app: etcd-reports-server + template: + metadata: + labels: + app: etcd-reports-server + annotations: + serviceName: etcd + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - etcd-reports-server + topologyKey: "kubernetes.io/hostname" + containers: + - name: etcd + image: quay.io/coreos/etcd:v3.5.15 + imagePullPolicy: IfNotPresent + ports: + - name: etcd-client + containerPort: 2379 + - name: etcd-server + containerPort: 2380 + - name: etcd-metrics + containerPort: 8080 + readinessProbe: + httpGet: + path: /readyz + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 30 + livenessProbe: + httpGet: + path: /livez + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + env: + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SERVICE_NAME + valueFrom: + fieldRef: + fieldPath: metadata.annotations['serviceName'] + - name: ETCDCTL_ENDPOINTS + value: $(HOSTNAME).$(SERVICE_NAME):2379 + ## TLS client configuration for etcdctl in the container. + ## These files paths are part of the "etcd-client-certs" volume mount. + # - name: ETCDCTL_KEY + # value: /etc/etcd/certs/client/tls.key + # - name: ETCDCTL_CERT + # value: /etc/etcd/certs/client/tls.crt + # - name: ETCDCTL_CACERT + # value: /etc/etcd/certs/client/ca.crt + ## + ## Use this URI_SCHEME value for non-TLS clusters. + - name: URI_SCHEME + value: "http" + ## TLS: Use this URI_SCHEME for TLS clusters. + # - name: URI_SCHEME + # value: "https" + command: + - /usr/local/bin/etcd + args: + - --name=$(HOSTNAME) + - --data-dir=/data + - --wal-dir=/data/wal + - --listen-peer-urls=$(URI_SCHEME)://0.0.0.0:2380 + - --listen-client-urls=$(URI_SCHEME)://0.0.0.0:2379 + - --advertise-client-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2379 + - --initial-cluster-state=new + - --initial-cluster-token=etcd-$(K8S_NAMESPACE) + - --initial-cluster=etcd-0=$(URI_SCHEME)://etcd-0.$(SERVICE_NAME):2380,etcd-1=$(URI_SCHEME)://etcd-1.$(SERVICE_NAME):2380,etcd-2=$(URI_SCHEME)://etcd-2.$(SERVICE_NAME):2380 + - --initial-advertise-peer-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2380 + - --listen-metrics-urls=http://0.0.0.0:8080 + # - --auto-compaction-mode=periodic + # - --auto-compaction-retention=10m + # - --client-cert-auth + # - --trusted-ca-file=$(ETCDCTL_CACERT) + # - --cert-file=$(ETCDCTL_CERT) + # - --key-file=$(ETCDCTL_KEY) + # - --peer-client-cert-auth + # - --peer-trusted-ca-file=/etc/etcd/certs/server/ca.crt + # - --peer-cert-file=/etc/etcd/certs/server/tls.crt + # - --peer-key-file=/etc/etcd/certs/server/tls.key + volumeMounts: + - name: etcd-data + mountPath: /data + # - name: etcd-client-tls + # mountPath: "/etc/etcd/certs/client" + # readOnly: true + # - name: etcd-server-tls + # mountPath: "/etc/etcd/certs/server" + # readOnly: true + volumes: + # - name: etcd-client-tls + # secret: + # secretName: etcd-client-tls + # optional: false + # - name: etcd-server-tls + # secret: + # secretName: etcd-server-tls + # optional: false + volumeClaimTemplates: + - metadata: + name: etcd-data + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi +{{- end }} + diff --git a/charts/reports-server/values.yaml b/charts/reports-server/values.yaml index d48f1fe..5947589 100644 --- a/charts/reports-server/values.yaml +++ b/charts/reports-server/values.yaml @@ -10,7 +10,7 @@ cloudnative-pg: postgresql: # -- Deploy postgresql dependency chart - enabled: true + enabled: false auth: @@ -166,8 +166,10 @@ service: config: - # -- Enable debug (to use inmemorydatabase) - debug: false + etcd: + enabled: true + endpoints: ~ + insecure: true db: # -- If set, database connection information will be read from the Secret with this name. Overrides `db.host`, `db.name`, `db.user`, and `db.password`. diff --git a/config/install-inmemory.yaml b/config/install-etcd.yaml similarity index 52% rename from config/install-inmemory.yaml rename to config/install-etcd.yaml index fe5963a..a3eaa41 100644 --- a/config/install-inmemory.yaml +++ b/config/install-etcd.yaml @@ -10,10 +10,10 @@ metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm --- apiVersion: rbac.authorization.k8s.io/v1 @@ -24,10 +24,10 @@ metadata: rbac.authorization.k8s.io/aggregate-to-admin: 'true' rbac.authorization.k8s.io/aggregate-to-edit: 'true' rbac.authorization.k8s.io/aggregate-to-view: 'true' - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -105,10 +105,10 @@ apiVersion: rbac.authorization.k8s.io/v1 metadata: name: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -125,10 +125,10 @@ metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -145,10 +145,10 @@ metadata: name: reports-server namespace: kube-system labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -165,10 +165,10 @@ metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -181,14 +181,40 @@ subjects: --- apiVersion: v1 kind: Service +metadata: + name: etcd + namespace: reports-server + labels: + app: etcd-reports-server + helm.sh/chart: reports-server-0.1.4-alpha.0 + app.kubernetes.io/name: reports-server + app.kubernetes.io/instance: reports-server + app.kubernetes.io/version: "v0.1.4-alpha.0" + app.kubernetes.io/managed-by: Helm +spec: + type: ClusterIP + clusterIP: None + selector: + app: etcd-reports-server + publishNotReadyAddresses: true + ports: + - name: etcd-client + port: 2379 + - name: etcd-server + port: 2380 + - name: etcd-metrics + port: 8080 +--- +apiVersion: v1 +kind: Service metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP @@ -207,10 +233,10 @@ metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm spec: strategy: @@ -234,7 +260,9 @@ spec: containers: - name: reports-server args: - - --debug + - --etcd + - --etcdSkipTLS + - --etcdEndpoints=https://etcd-0.etcd.reports-server:2379,https://etcd-1.etcd.reports-server:2379,https://etcd-2.etcd.reports-server:2379 - --cert-dir=/tmp - --secure-port=4443 - --authorization-always-allow-paths=/metrics @@ -249,15 +277,15 @@ spec: runAsUser: 1000 seccompProfile: type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp-dir image: "ghcr.io/nirmata/reports-server:latest" imagePullPolicy: IfNotPresent ports: - name: https containerPort: 4443 protocol: TCP - volumeMounts: - - mountPath: /tmp - name: tmp-dir livenessProbe: failureThreshold: 10 httpGet: @@ -281,16 +309,165 @@ spec: - emptyDir: {} name: tmp-dir --- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + namespace: reports-server + name: etcd + labels: + app: etcd-reports-server + helm.sh/chart: reports-server-0.1.4-alpha.0 + app.kubernetes.io/name: reports-server + app.kubernetes.io/instance: reports-server + app.kubernetes.io/version: "v0.1.4-alpha.0" + app.kubernetes.io/managed-by: Helm +spec: + serviceName: etcd + replicas: 3 + podManagementPolicy: Parallel + updateStrategy: + type: RollingUpdate + selector: + matchLabels: + app: etcd-reports-server + template: + metadata: + labels: + app: etcd-reports-server + annotations: + serviceName: etcd + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - etcd-reports-server + topologyKey: "kubernetes.io/hostname" + containers: + - name: etcd + image: quay.io/coreos/etcd:v3.5.15 + imagePullPolicy: IfNotPresent + ports: + - name: etcd-client + containerPort: 2379 + - name: etcd-server + containerPort: 2380 + - name: etcd-metrics + containerPort: 8080 + readinessProbe: + httpGet: + path: /readyz + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 30 + livenessProbe: + httpGet: + path: /livez + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + env: + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SERVICE_NAME + valueFrom: + fieldRef: + fieldPath: metadata.annotations['serviceName'] + - name: ETCDCTL_ENDPOINTS + value: $(HOSTNAME).$(SERVICE_NAME):2379 + ## TLS client configuration for etcdctl in the container. + ## These files paths are part of the "etcd-client-certs" volume mount. + # - name: ETCDCTL_KEY + # value: /etc/etcd/certs/client/tls.key + # - name: ETCDCTL_CERT + # value: /etc/etcd/certs/client/tls.crt + # - name: ETCDCTL_CACERT + # value: /etc/etcd/certs/client/ca.crt + ## + ## Use this URI_SCHEME value for non-TLS clusters. + - name: URI_SCHEME + value: "http" + ## TLS: Use this URI_SCHEME for TLS clusters. + # - name: URI_SCHEME + # value: "https" + command: + - /usr/local/bin/etcd + args: + - --name=$(HOSTNAME) + - --data-dir=/data + - --wal-dir=/data/wal + - --listen-peer-urls=$(URI_SCHEME)://0.0.0.0:2380 + - --listen-client-urls=$(URI_SCHEME)://0.0.0.0:2379 + - --advertise-client-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2379 + - --initial-cluster-state=new + - --initial-cluster-token=etcd-$(K8S_NAMESPACE) + - --initial-cluster=etcd-0=$(URI_SCHEME)://etcd-0.$(SERVICE_NAME):2380,etcd-1=$(URI_SCHEME)://etcd-1.$(SERVICE_NAME):2380,etcd-2=$(URI_SCHEME)://etcd-2.$(SERVICE_NAME):2380 + - --initial-advertise-peer-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2380 + - --listen-metrics-urls=http://0.0.0.0:8080 + # - --auto-compaction-mode=periodic + # - --auto-compaction-retention=10m + # - --client-cert-auth + # - --trusted-ca-file=$(ETCDCTL_CACERT) + # - --cert-file=$(ETCDCTL_CERT) + # - --key-file=$(ETCDCTL_KEY) + # - --peer-client-cert-auth + # - --peer-trusted-ca-file=/etc/etcd/certs/server/ca.crt + # - --peer-cert-file=/etc/etcd/certs/server/tls.crt + # - --peer-key-file=/etc/etcd/certs/server/tls.key + volumeMounts: + - name: etcd-data + mountPath: /data + # - name: etcd-client-tls + # mountPath: "/etc/etcd/certs/client" + # readOnly: true + # - name: etcd-server-tls + # mountPath: "/etc/etcd/certs/server" + # readOnly: true + volumes: + # - name: etcd-client-tls + # secret: + # secretName: etcd-client-tls + # optional: false + # - name: etcd-server-tls + # secret: + # secretName: etcd-server-tls + # optional: false + volumeClaimTemplates: + - metadata: + name: etcd-data + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi +--- apiVersion: apiregistration.k8s.io/v1 kind: APIService metadata: name: v1alpha2.wgpolicyk8s.io namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm kube-aggregator.kubernetes.io/automanaged: "false" annotations: @@ -311,10 +488,10 @@ metadata: name: v1.reports.kyverno.io namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm kube-aggregator.kubernetes.io/automanaged: "false" annotations: diff --git a/config/install.yaml b/config/install.yaml index 30dc9b2..a3eaa41 100644 --- a/config/install.yaml +++ b/config/install.yaml @@ -6,905 +6,16 @@ metadata: --- apiVersion: v1 kind: ServiceAccount -metadata: - name: reports-server-cloudnative-pg - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm ---- -apiVersion: v1 -kind: ServiceAccount metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm --- -apiVersion: v1 -kind: Secret -metadata: - name: app-secret - namespace: reports-server - labels: - helm.sh/chart: reports-server-0.1.3 - app.kubernetes.io/name: reports-server - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" - app.kubernetes.io/managed-by: Helm -type: kubernetes.io/basic-auth -data: - username: YXBw - password: cGFzc3dvcmQ= ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: cnpg-controller-manager-config - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -data: - {} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: cnpg-default-monitoring - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm - cnpg.io/reload: "" -data: - queries: - | - backends: - query: | - SELECT sa.datname - , sa.usename - , sa.application_name - , states.state - , COALESCE(sa.count, 0) AS total - , COALESCE(sa.max_tx_secs, 0) AS max_tx_duration_seconds - FROM ( VALUES ('active') - , ('idle') - , ('idle in transaction') - , ('idle in transaction (aborted)') - , ('fastpath function call') - , ('disabled') - ) AS states(state) - LEFT JOIN ( - SELECT datname - , state - , usename - , COALESCE(application_name, '') AS application_name - , COUNT(*) - , COALESCE(EXTRACT (EPOCH FROM (max(now() - xact_start))), 0) AS max_tx_secs - FROM pg_catalog.pg_stat_activity - GROUP BY datname, state, usename, application_name - ) sa ON states.state = sa.state - WHERE sa.usename IS NOT NULL - metrics: - - datname: - usage: "LABEL" - description: "Name of the database" - - usename: - usage: "LABEL" - description: "Name of the user" - - application_name: - usage: "LABEL" - description: "Name of the application" - - state: - usage: "LABEL" - description: "State of the backend" - - total: - usage: "GAUGE" - description: "Number of backends" - - max_tx_duration_seconds: - usage: "GAUGE" - description: "Maximum duration of a transaction in seconds" - - backends_waiting: - query: | - SELECT count(*) AS total - FROM pg_catalog.pg_locks blocked_locks - JOIN pg_catalog.pg_locks blocking_locks - ON blocking_locks.locktype = blocked_locks.locktype - AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database - AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation - AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page - AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple - AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid - AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid - AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid - AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid - AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid - AND blocking_locks.pid != blocked_locks.pid - JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid - WHERE NOT blocked_locks.granted - metrics: - - total: - usage: "GAUGE" - description: "Total number of backends that are currently waiting on other queries" - - pg_database: - query: | - SELECT datname - , pg_catalog.pg_database_size(datname) AS size_bytes - , pg_catalog.age(datfrozenxid) AS xid_age - , pg_catalog.mxid_age(datminmxid) AS mxid_age - FROM pg_catalog.pg_database - WHERE datallowconn - metrics: - - datname: - usage: "LABEL" - description: "Name of the database" - - size_bytes: - usage: "GAUGE" - description: "Disk space used by the database" - - xid_age: - usage: "GAUGE" - description: "Number of transactions from the frozen XID to the current one" - - mxid_age: - usage: "GAUGE" - description: "Number of multiple transactions (Multixact) from the frozen XID to the current one" - - pg_postmaster: - query: | - SELECT EXTRACT(EPOCH FROM pg_postmaster_start_time) AS start_time - FROM pg_catalog.pg_postmaster_start_time() - metrics: - - start_time: - usage: "GAUGE" - description: "Time at which postgres started (based on epoch)" - - pg_replication: - query: "SELECT CASE WHEN ( - NOT pg_catalog.pg_is_in_recovery() - OR pg_catalog.pg_last_wal_receive_lsn() = pg_catalog.pg_last_wal_replay_lsn()) - THEN 0 - ELSE GREATEST (0, - EXTRACT(EPOCH FROM (now() - pg_catalog.pg_last_xact_replay_timestamp()))) - END AS lag, - pg_catalog.pg_is_in_recovery() AS in_recovery, - EXISTS (TABLE pg_stat_wal_receiver) AS is_wal_receiver_up, - (SELECT count(*) FROM pg_catalog.pg_stat_replication) AS streaming_replicas" - metrics: - - lag: - usage: "GAUGE" - description: "Replication lag behind primary in seconds" - - in_recovery: - usage: "GAUGE" - description: "Whether the instance is in recovery" - - is_wal_receiver_up: - usage: "GAUGE" - description: "Whether the instance wal_receiver is up" - - streaming_replicas: - usage: "GAUGE" - description: "Number of streaming replicas connected to the instance" - - pg_replication_slots: - query: | - SELECT slot_name, - slot_type, - database, - active, - (CASE pg_catalog.pg_is_in_recovery() - WHEN TRUE THEN pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_last_wal_receive_lsn(), restart_lsn) - ELSE pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), restart_lsn) - END) as pg_wal_lsn_diff - FROM pg_catalog.pg_replication_slots - WHERE NOT temporary - metrics: - - slot_name: - usage: "LABEL" - description: "Name of the replication slot" - - slot_type: - usage: "LABEL" - description: "Type of the replication slot" - - database: - usage: "LABEL" - description: "Name of the database" - - active: - usage: "GAUGE" - description: "Flag indicating whether the slot is active" - - pg_wal_lsn_diff: - usage: "GAUGE" - description: "Replication lag in bytes" - - pg_stat_archiver: - query: | - SELECT archived_count - , failed_count - , COALESCE(EXTRACT(EPOCH FROM (now() - last_archived_time)), -1) AS seconds_since_last_archival - , COALESCE(EXTRACT(EPOCH FROM (now() - last_failed_time)), -1) AS seconds_since_last_failure - , COALESCE(EXTRACT(EPOCH FROM last_archived_time), -1) AS last_archived_time - , COALESCE(EXTRACT(EPOCH FROM last_failed_time), -1) AS last_failed_time - , COALESCE(CAST(CAST('x'||pg_catalog.right(pg_catalog.split_part(last_archived_wal, '.', 1), 16) AS pg_catalog.bit(64)) AS pg_catalog.int8), -1) AS last_archived_wal_start_lsn - , COALESCE(CAST(CAST('x'||pg_catalog.right(pg_catalog.split_part(last_failed_wal, '.', 1), 16) AS pg_catalog.bit(64)) AS pg_catalog.int8), -1) AS last_failed_wal_start_lsn - , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time - FROM pg_catalog.pg_stat_archiver - metrics: - - archived_count: - usage: "COUNTER" - description: "Number of WAL files that have been successfully archived" - - failed_count: - usage: "COUNTER" - description: "Number of failed attempts for archiving WAL files" - - seconds_since_last_archival: - usage: "GAUGE" - description: "Seconds since the last successful archival operation" - - seconds_since_last_failure: - usage: "GAUGE" - description: "Seconds since the last failed archival operation" - - last_archived_time: - usage: "GAUGE" - description: "Epoch of the last time WAL archiving succeeded" - - last_failed_time: - usage: "GAUGE" - description: "Epoch of the last time WAL archiving failed" - - last_archived_wal_start_lsn: - usage: "GAUGE" - description: "Archived WAL start LSN" - - last_failed_wal_start_lsn: - usage: "GAUGE" - description: "Last failed WAL LSN" - - stats_reset_time: - usage: "GAUGE" - description: "Time at which these statistics were last reset" - - pg_stat_bgwriter: - runonserver: "<17.0.0" - query: | - SELECT checkpoints_timed - , checkpoints_req - , checkpoint_write_time - , checkpoint_sync_time - , buffers_checkpoint - , buffers_clean - , maxwritten_clean - , buffers_backend - , buffers_backend_fsync - , buffers_alloc - FROM pg_catalog.pg_stat_bgwriter - metrics: - - checkpoints_timed: - usage: "COUNTER" - description: "Number of scheduled checkpoints that have been performed" - - checkpoints_req: - usage: "COUNTER" - description: "Number of requested checkpoints that have been performed" - - checkpoint_write_time: - usage: "COUNTER" - description: "Total amount of time that has been spent in the portion of checkpoint processing where files are written to disk, in milliseconds" - - checkpoint_sync_time: - usage: "COUNTER" - description: "Total amount of time that has been spent in the portion of checkpoint processing where files are synchronized to disk, in milliseconds" - - buffers_checkpoint: - usage: "COUNTER" - description: "Number of buffers written during checkpoints" - - buffers_clean: - usage: "COUNTER" - description: "Number of buffers written by the background writer" - - maxwritten_clean: - usage: "COUNTER" - description: "Number of times the background writer stopped a cleaning scan because it had written too many buffers" - - buffers_backend: - usage: "COUNTER" - description: "Number of buffers written directly by a backend" - - buffers_backend_fsync: - usage: "COUNTER" - description: "Number of times a backend had to execute its own fsync call (normally the background writer handles those even when the backend does its own write)" - - buffers_alloc: - usage: "COUNTER" - description: "Number of buffers allocated" - - pg_stat_bgwriter_17: - runonserver: ">=17.0.0" - name: pg_stat_bgwriter - query: | - SELECT buffers_clean - , maxwritten_clean - , buffers_alloc - , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time - FROM pg_catalog.pg_stat_bgwriter - metrics: - - buffers_clean: - usage: "COUNTER" - description: "Number of buffers written by the background writer" - - maxwritten_clean: - usage: "COUNTER" - description: "Number of times the background writer stopped a cleaning scan because it had written too many buffers" - - buffers_alloc: - usage: "COUNTER" - description: "Number of buffers allocated" - - stats_reset_time: - usage: "GAUGE" - description: "Time at which these statistics were last reset" - - pg_stat_checkpointer: - runonserver: ">=17.0.0" - query: | - SELECT num_timed AS checkpoints_timed - , num_requested AS checkpoints_req - , restartpoints_timed - , restartpoints_req - , restartpoints_done - , write_time - , sync_time - , buffers_written - , EXTRACT(EPOCH FROM stats_reset) AS stats_reset_time - FROM pg_catalog.pg_stat_checkpointer - metrics: - - checkpoints_timed: - usage: "COUNTER" - description: "Number of scheduled checkpoints that have been performed" - - checkpoints_req: - usage: "COUNTER" - description: "Number of requested checkpoints that have been performed" - - restartpoints_timed: - usage: "COUNTER" - description: "Number of scheduled restartpoints due to timeout or after a failed attempt to perform it" - - restartpoints_req: - usage: "COUNTER" - description: "Number of requested restartpoints that have been performed" - - restartpoints_done: - usage: "COUNTER" - description: "Number of restartpoints that have been performed" - - write_time: - usage: "COUNTER" - description: "Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are written to disk, in milliseconds" - - sync_time: - usage: "COUNTER" - description: "Total amount of time that has been spent in the portion of processing checkpoints and restartpoints where files are synchronized to disk, in milliseconds" - - buffers_written: - usage: "COUNTER" - description: "Number of buffers written during checkpoints and restartpoints" - - stats_reset_time: - usage: "GAUGE" - description: "Time at which these statistics were last reset" - - pg_stat_database: - query: | - SELECT datname - , xact_commit - , xact_rollback - , blks_read - , blks_hit - , tup_returned - , tup_fetched - , tup_inserted - , tup_updated - , tup_deleted - , conflicts - , temp_files - , temp_bytes - , deadlocks - , blk_read_time - , blk_write_time - FROM pg_catalog.pg_stat_database - metrics: - - datname: - usage: "LABEL" - description: "Name of this database" - - xact_commit: - usage: "COUNTER" - description: "Number of transactions in this database that have been committed" - - xact_rollback: - usage: "COUNTER" - description: "Number of transactions in this database that have been rolled back" - - blks_read: - usage: "COUNTER" - description: "Number of disk blocks read in this database" - - blks_hit: - usage: "COUNTER" - description: "Number of times disk blocks were found already in the buffer cache, so that a read was not necessary (this only includes hits in the PostgreSQL buffer cache, not the operating system's file system cache)" - - tup_returned: - usage: "COUNTER" - description: "Number of rows returned by queries in this database" - - tup_fetched: - usage: "COUNTER" - description: "Number of rows fetched by queries in this database" - - tup_inserted: - usage: "COUNTER" - description: "Number of rows inserted by queries in this database" - - tup_updated: - usage: "COUNTER" - description: "Number of rows updated by queries in this database" - - tup_deleted: - usage: "COUNTER" - description: "Number of rows deleted by queries in this database" - - conflicts: - usage: "COUNTER" - description: "Number of queries canceled due to conflicts with recovery in this database" - - temp_files: - usage: "COUNTER" - description: "Number of temporary files created by queries in this database" - - temp_bytes: - usage: "COUNTER" - description: "Total amount of data written to temporary files by queries in this database" - - deadlocks: - usage: "COUNTER" - description: "Number of deadlocks detected in this database" - - blk_read_time: - usage: "COUNTER" - description: "Time spent reading data file blocks by backends in this database, in milliseconds" - - blk_write_time: - usage: "COUNTER" - description: "Time spent writing data file blocks by backends in this database, in milliseconds" - - pg_stat_replication: - primary: true - query: | - SELECT usename - , COALESCE(application_name, '') AS application_name - , COALESCE(client_addr::text, '') AS client_addr - , COALESCE(client_port::text, '') AS client_port - , EXTRACT(EPOCH FROM backend_start) AS backend_start - , COALESCE(pg_catalog.age(backend_xmin), 0) AS backend_xmin_age - , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), sent_lsn) AS sent_diff_bytes - , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), write_lsn) AS write_diff_bytes - , pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), flush_lsn) AS flush_diff_bytes - , COALESCE(pg_catalog.pg_wal_lsn_diff(pg_catalog.pg_current_wal_lsn(), replay_lsn),0) AS replay_diff_bytes - , COALESCE((EXTRACT(EPOCH FROM write_lag)),0)::float AS write_lag_seconds - , COALESCE((EXTRACT(EPOCH FROM flush_lag)),0)::float AS flush_lag_seconds - , COALESCE((EXTRACT(EPOCH FROM replay_lag)),0)::float AS replay_lag_seconds - FROM pg_catalog.pg_stat_replication - metrics: - - usename: - usage: "LABEL" - description: "Name of the replication user" - - application_name: - usage: "LABEL" - description: "Name of the application" - - client_addr: - usage: "LABEL" - description: "Client IP address" - - client_port: - usage: "LABEL" - description: "Client TCP port" - - backend_start: - usage: "COUNTER" - description: "Time when this process was started" - - backend_xmin_age: - usage: "COUNTER" - description: "The age of this standby's xmin horizon" - - sent_diff_bytes: - usage: "GAUGE" - description: "Difference in bytes from the last write-ahead log location sent on this connection" - - write_diff_bytes: - usage: "GAUGE" - description: "Difference in bytes from the last write-ahead log location written to disk by this standby server" - - flush_diff_bytes: - usage: "GAUGE" - description: "Difference in bytes from the last write-ahead log location flushed to disk by this standby server" - - replay_diff_bytes: - usage: "GAUGE" - description: "Difference in bytes from the last write-ahead log location replayed into the database on this standby server" - - write_lag_seconds: - usage: "GAUGE" - description: "Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written it" - - flush_lag_seconds: - usage: "GAUGE" - description: "Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written and flushed it" - - replay_lag_seconds: - usage: "GAUGE" - description: "Time elapsed between flushing recent WAL locally and receiving notification that this standby server has written, flushed and applied it" - - pg_settings: - query: | - SELECT name, - CASE setting WHEN 'on' THEN '1' WHEN 'off' THEN '0' ELSE setting END AS setting - FROM pg_catalog.pg_settings - WHERE vartype IN ('integer', 'real', 'bool') - ORDER BY 1 - metrics: - - name: - usage: "LABEL" - description: "Name of the setting" - - setting: - usage: "GAUGE" - description: "Setting value" ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: reports-server-cloudnative-pg - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - configmaps/status - verbs: - - get - - patch - - update -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch -- apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - persistentvolumeclaims - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - "" - resources: - - pods - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - "" - resources: - - pods/exec - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - "" - resources: - - pods/status - verbs: - - get -- apiGroups: - - "" - resources: - - secrets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - secrets/status - verbs: - - get - - patch - - update -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - create - - get - - list - - patch - - update - - watch -- apiGroups: - - "" - resources: - - services - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - admissionregistration.k8s.io - resources: - - mutatingwebhookconfigurations - verbs: - - get - - patch -- apiGroups: - - admissionregistration.k8s.io - resources: - - validatingwebhookconfigurations - verbs: - - get - - patch -- apiGroups: - - apps - resources: - - deployments - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - batch - resources: - - jobs - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - create - - get - - update -- apiGroups: - - monitoring.coreos.com - resources: - - podmonitors - verbs: - - create - - delete - - get - - list - - patch - - watch -- apiGroups: - - policy - resources: - - poddisruptionbudgets - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - backups - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - backups/status - verbs: - - get - - patch - - update -- apiGroups: - - postgresql.cnpg.io - resources: - - clusterimagecatalogs - verbs: - - get - - list - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - clusters - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - clusters/finalizers - verbs: - - update -- apiGroups: - - postgresql.cnpg.io - resources: - - clusters/status - verbs: - - get - - patch - - update - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - imagecatalogs - verbs: - - get - - list - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - poolers - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - poolers/finalizers - verbs: - - update -- apiGroups: - - postgresql.cnpg.io - resources: - - poolers/status - verbs: - - get - - patch - - update - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - scheduledbackups - verbs: - - create - - delete - - get - - list - - patch - - update - - watch -- apiGroups: - - postgresql.cnpg.io - resources: - - scheduledbackups/status - verbs: - - get - - patch - - update -- apiGroups: - - rbac.authorization.k8s.io - resources: - - rolebindings - verbs: - - create - - get - - list - - patch - - update - - watch -- apiGroups: - - rbac.authorization.k8s.io - resources: - - roles - verbs: - - create - - get - - list - - patch - - update - - watch -- apiGroups: - - snapshot.storage.k8s.io - resources: - - volumesnapshots - verbs: - - create - - get - - list - - patch - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: reports-server-cloudnative-pg-view - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -rules: -- apiGroups: - - postgresql.cnpg.io - resources: - - backups - - clusters - - poolers - - scheduledbackups - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: reports-server-cloudnative-pg-edit - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -rules: -- apiGroups: - - postgresql.cnpg.io - resources: - - backups - - clusters - - poolers - - scheduledbackups - verbs: - - create - - delete - - deletecollection - - patch - - update ---- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: @@ -913,10 +24,10 @@ metadata: rbac.authorization.k8s.io/aggregate-to-admin: 'true' rbac.authorization.k8s.io/aggregate-to-edit: 'true' rbac.authorization.k8s.io/aggregate-to-view: 'true' - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -989,34 +100,15 @@ rules: verbs: - create --- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: reports-server-cloudnative-pg - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: reports-server-cloudnative-pg -subjects: -- kind: ServiceAccount - name: reports-server-cloudnative-pg - namespace: reports-server ---- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -1033,10 +125,10 @@ metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm rules: - apiGroups: @@ -1053,10 +145,10 @@ metadata: name: reports-server namespace: kube-system labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -1073,10 +165,10 @@ metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm roleRef: apiGroup: rbac.authorization.k8s.io @@ -1090,22 +182,28 @@ subjects: apiVersion: v1 kind: Service metadata: - name: cnpg-webhook-service + name: etcd + namespace: reports-server labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg + app: etcd-reports-server + helm.sh/chart: reports-server-0.1.4-alpha.0 + app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP - ports: - - port: 443 - targetPort: webhook-server - name: webhook-server + clusterIP: None selector: - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server + app: etcd-reports-server + publishNotReadyAddresses: true + ports: + - name: etcd-client + port: 2379 + - name: etcd-server + port: 2380 + - name: etcd-metrics + port: 8080 --- apiVersion: v1 kind: Service @@ -1113,10 +211,10 @@ metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP @@ -1131,109 +229,14 @@ spec: --- apiVersion: apps/v1 kind: Deployment -metadata: - name: reports-server-cloudnative-pg - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - template: - metadata: - annotations: - checksum/config: 1ca573cbe9e62b16546981e9bdf391a41623abf066bffb9fd1dc75c4ef1999dd - labels: - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - spec: - containers: - - args: - - controller - - --leader-elect - - --config-map-name=cnpg-controller-manager-config - - --webhook-port=9443 - command: - - /manager - env: - - name: OPERATOR_IMAGE_NAME - value: "ghcr.io/cloudnative-pg/cloudnative-pg:1.24.0" - - name: OPERATOR_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - - name: MONITORING_QUERIES_CONFIGMAP - value: "cnpg-default-monitoring" - image: "ghcr.io/cloudnative-pg/cloudnative-pg:1.24.0" - imagePullPolicy: IfNotPresent - livenessProbe: - httpGet: - path: /readyz - port: 9443 - scheme: HTTPS - initialDelaySeconds: 3 - name: manager - ports: - - containerPort: 8080 - name: metrics - protocol: TCP - - containerPort: 9443 - name: webhook-server - protocol: TCP - readinessProbe: - httpGet: - path: /readyz - port: 9443 - scheme: HTTPS - initialDelaySeconds: 3 - resources: - {} - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - readOnlyRootFilesystem: true - runAsGroup: 10001 - runAsUser: 10001 - seccompProfile: - type: RuntimeDefault - volumeMounts: - - mountPath: /controller - name: scratch-data - - mountPath: /run/secrets/cnpg.io/webhook - name: webhook-certificates - securityContext: - runAsNonRoot: true - seccompProfile: - type: RuntimeDefault - serviceAccountName: reports-server-cloudnative-pg - terminationGracePeriodSeconds: 10 - volumes: - - emptyDir: {} - name: scratch-data - - name: webhook-certificates - secret: - defaultMode: 420 - optional: true - secretName: cnpg-webhook-cert ---- -apiVersion: apps/v1 -kind: Deployment metadata: name: reports-server namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm spec: strategy: @@ -1257,14 +260,9 @@ spec: containers: - name: reports-server args: - - --dbhost=reports-server-cluster-rw.reports-server - - --dbname=reportsdb - - --dbuser=app - - --dbpassword=password - - --dbsslmode=disable - - --dbsslrootcert= - - --dbsslkey= - - --dbsslcert= + - --etcd + - --etcdSkipTLS + - --etcdEndpoints=https://etcd-0.etcd.reports-server:2379,https://etcd-1.etcd.reports-server:2379,https://etcd-2.etcd.reports-server:2379 - --cert-dir=/tmp - --secure-port=4443 - --authorization-always-allow-paths=/metrics @@ -1279,15 +277,15 @@ spec: runAsUser: 1000 seccompProfile: type: RuntimeDefault + volumeMounts: + - mountPath: /tmp + name: tmp-dir image: "ghcr.io/nirmata/reports-server:latest" imagePullPolicy: IfNotPresent ports: - name: https containerPort: 4443 protocol: TCP - volumeMounts: - - mountPath: /tmp - name: tmp-dir livenessProbe: failureThreshold: 10 httpGet: @@ -1311,205 +309,154 @@ spec: - emptyDir: {} name: tmp-dir --- ---- ---- ---- ---- ---- ---- -apiVersion: postgresql.cnpg.io/v1 -kind: Cluster +apiVersion: apps/v1 +kind: StatefulSet metadata: - name: reports-server-cluster namespace: reports-server + name: etcd labels: - helm.sh/chart: reports-server-0.1.3 + app: etcd-reports-server + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm spec: - instances: 3 - primaryUpdateStrategy: unsupervised - bootstrap: - initdb: - database: reportsdb - owner: app - secret: - name: app-secret - storage: - size: 10Gi ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: MutatingWebhookConfiguration -metadata: - name: cnpg-mutating-webhook-configuration - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -webhooks: -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: cnpg-webhook-service - namespace: reports-server - path: /mutate-postgresql-cnpg-io-v1-backup - port: 443 - failurePolicy: Fail - name: mbackup.cnpg.io - rules: - - apiGroups: - - postgresql.cnpg.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - backups - sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: cnpg-webhook-service - namespace: reports-server - path: /mutate-postgresql-cnpg-io-v1-cluster - port: 443 - failurePolicy: Fail - name: mcluster.cnpg.io - rules: - - apiGroups: - - postgresql.cnpg.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - clusters - sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: cnpg-webhook-service - namespace: reports-server - path: /mutate-postgresql-cnpg-io-v1-scheduledbackup - port: 443 - failurePolicy: Fail - name: mscheduledbackup.cnpg.io - rules: - - apiGroups: - - postgresql.cnpg.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - scheduledbackups - sideEffects: None ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: cnpg-validating-webhook-configuration - labels: - helm.sh/chart: cloudnative-pg-0.22.0 - app.kubernetes.io/name: cloudnative-pg - app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "1.24.0" - app.kubernetes.io/managed-by: Helm -webhooks: -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: cnpg-webhook-service - namespace: reports-server - path: /validate-postgresql-cnpg-io-v1-backup - port: 443 - failurePolicy: Fail - name: vbackup.cnpg.io - rules: - - apiGroups: - - postgresql.cnpg.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - backups - sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: cnpg-webhook-service - namespace: reports-server - path: /validate-postgresql-cnpg-io-v1-cluster - port: 443 - failurePolicy: Fail - name: vcluster.cnpg.io - rules: - - apiGroups: - - postgresql.cnpg.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - clusters - sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: cnpg-webhook-service - namespace: reports-server - path: /validate-postgresql-cnpg-io-v1-scheduledbackup - port: 443 - failurePolicy: Fail - name: vscheduledbackup.cnpg.io - rules: - - apiGroups: - - postgresql.cnpg.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE - resources: - - scheduledbackups - sideEffects: None -- admissionReviewVersions: - - v1 - clientConfig: - service: - name: cnpg-webhook-service - namespace: reports-server - path: /validate-postgresql-cnpg-io-v1-pooler - port: 443 - failurePolicy: Fail - name: vpooler.cnpg.io - rules: - - apiGroups: - - postgresql.cnpg.io - apiVersions: - - v1 - operations: - - CREATE - - UPDATE + serviceName: etcd + replicas: 3 + podManagementPolicy: Parallel + updateStrategy: + type: RollingUpdate + selector: + matchLabels: + app: etcd-reports-server + template: + metadata: + labels: + app: etcd-reports-server + annotations: + serviceName: etcd + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - etcd-reports-server + topologyKey: "kubernetes.io/hostname" + containers: + - name: etcd + image: quay.io/coreos/etcd:v3.5.15 + imagePullPolicy: IfNotPresent + ports: + - name: etcd-client + containerPort: 2379 + - name: etcd-server + containerPort: 2380 + - name: etcd-metrics + containerPort: 8080 + readinessProbe: + httpGet: + path: /readyz + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 5 + successThreshold: 1 + failureThreshold: 30 + livenessProbe: + httpGet: + path: /livez + port: 8080 + initialDelaySeconds: 15 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + env: + - name: K8S_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: HOSTNAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: SERVICE_NAME + valueFrom: + fieldRef: + fieldPath: metadata.annotations['serviceName'] + - name: ETCDCTL_ENDPOINTS + value: $(HOSTNAME).$(SERVICE_NAME):2379 + ## TLS client configuration for etcdctl in the container. + ## These files paths are part of the "etcd-client-certs" volume mount. + # - name: ETCDCTL_KEY + # value: /etc/etcd/certs/client/tls.key + # - name: ETCDCTL_CERT + # value: /etc/etcd/certs/client/tls.crt + # - name: ETCDCTL_CACERT + # value: /etc/etcd/certs/client/ca.crt + ## + ## Use this URI_SCHEME value for non-TLS clusters. + - name: URI_SCHEME + value: "http" + ## TLS: Use this URI_SCHEME for TLS clusters. + # - name: URI_SCHEME + # value: "https" + command: + - /usr/local/bin/etcd + args: + - --name=$(HOSTNAME) + - --data-dir=/data + - --wal-dir=/data/wal + - --listen-peer-urls=$(URI_SCHEME)://0.0.0.0:2380 + - --listen-client-urls=$(URI_SCHEME)://0.0.0.0:2379 + - --advertise-client-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2379 + - --initial-cluster-state=new + - --initial-cluster-token=etcd-$(K8S_NAMESPACE) + - --initial-cluster=etcd-0=$(URI_SCHEME)://etcd-0.$(SERVICE_NAME):2380,etcd-1=$(URI_SCHEME)://etcd-1.$(SERVICE_NAME):2380,etcd-2=$(URI_SCHEME)://etcd-2.$(SERVICE_NAME):2380 + - --initial-advertise-peer-urls=$(URI_SCHEME)://$(HOSTNAME).$(SERVICE_NAME):2380 + - --listen-metrics-urls=http://0.0.0.0:8080 + # - --auto-compaction-mode=periodic + # - --auto-compaction-retention=10m + # - --client-cert-auth + # - --trusted-ca-file=$(ETCDCTL_CACERT) + # - --cert-file=$(ETCDCTL_CERT) + # - --key-file=$(ETCDCTL_KEY) + # - --peer-client-cert-auth + # - --peer-trusted-ca-file=/etc/etcd/certs/server/ca.crt + # - --peer-cert-file=/etc/etcd/certs/server/tls.crt + # - --peer-key-file=/etc/etcd/certs/server/tls.key + volumeMounts: + - name: etcd-data + mountPath: /data + # - name: etcd-client-tls + # mountPath: "/etc/etcd/certs/client" + # readOnly: true + # - name: etcd-server-tls + # mountPath: "/etc/etcd/certs/server" + # readOnly: true + volumes: + # - name: etcd-client-tls + # secret: + # secretName: etcd-client-tls + # optional: false + # - name: etcd-server-tls + # secret: + # secretName: etcd-server-tls + # optional: false + volumeClaimTemplates: + - metadata: + name: etcd-data + spec: + accessModes: ["ReadWriteOnce"] resources: - - poolers - sideEffects: None + requests: + storage: 1Gi --- apiVersion: apiregistration.k8s.io/v1 kind: APIService @@ -1517,10 +464,10 @@ metadata: name: v1alpha2.wgpolicyk8s.io namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm kube-aggregator.kubernetes.io/automanaged: "false" annotations: @@ -1541,10 +488,10 @@ metadata: name: v1.reports.kyverno.io namespace: reports-server labels: - helm.sh/chart: reports-server-0.1.3 + helm.sh/chart: reports-server-0.1.4-alpha.0 app.kubernetes.io/name: reports-server app.kubernetes.io/instance: reports-server - app.kubernetes.io/version: "v0.1.3" + app.kubernetes.io/version: "v0.1.4-alpha.0" app.kubernetes.io/managed-by: Helm kube-aggregator.kubernetes.io/automanaged: "false" annotations: diff --git a/docs/INSTALL.md b/docs/INSTALL.md index 7137dca..2940ef7 100644 --- a/docs/INSTALL.md +++ b/docs/INSTALL.md @@ -2,8 +2,6 @@ Reports-server has multiple methods for installation: YAML manifest and Helm Chart.YAML manifest is the recommended method to install reports server when kyverno or policy reports CRDs are already installed in the cluster. Helm chart is the most flexible method as it offers a wide range of configurations. -If kyverno is already installed in the cluster, follow the [migration guide](#migration). - There are three configuration to install reports server: 1. Reports server with managed postgres: Use a centralised postgres database outside of the cluster 2. Reports server with incluster postgres: Create a postgres instance in the cluster diff --git a/go.mod b/go.mod index 226d57b..406b1b9 100644 --- a/go.mod +++ b/go.mod @@ -100,6 +100,7 @@ require ( github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker v25.0.5+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.1 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.11.2 // indirect github.com/emicklei/proto v1.13.2 // indirect github.com/evanphx/json-patch v5.9.0+incompatible // indirect @@ -146,8 +147,11 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/gorilla/mux v1.8.1 // indirect + github.com/gorilla/websocket v1.5.0 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect + github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect github.com/grpc-ecosystem/go-grpc-prometheus v1.2.1-0.20210315223345-82c243799c99 // indirect + github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-retryablehttp v0.7.5 // indirect @@ -158,6 +162,7 @@ require ( github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect github.com/jinzhu/copier v0.4.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.5 // indirect @@ -211,6 +216,7 @@ require ( github.com/sigstore/timestamp-authority v1.2.2 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect + github.com/soheilhy/cmux v0.1.5 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect @@ -226,18 +232,25 @@ require ( github.com/theupdateframework/go-tuf v0.7.0 // indirect github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect + github.com/tmc/grpc-websocket-proxy v0.0.0-20220101234140-673ab2c3ae75 // indirect github.com/transparency-dev/merkle v0.0.2 // indirect github.com/vbatts/tar-split v0.11.5 // indirect github.com/xanzy/go-gitlab v0.102.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xiang90/probing v0.0.0-20221125231312-a49e3df8f510 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect github.com/zach-klippenstein/goregen v0.0.0-20160303162051-795b5e3961ea // indirect github.com/zeebo/errs v1.3.0 // indirect - go.etcd.io/etcd/api/v3 v3.5.12 // indirect - go.etcd.io/etcd/client/pkg/v3 v3.5.12 // indirect - go.etcd.io/etcd/client/v3 v3.5.12 // indirect + go.etcd.io/bbolt v1.3.11 // indirect + go.etcd.io/etcd/api/v3 v3.5.16 // indirect + go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect + go.etcd.io/etcd/client/v2 v2.305.16 // indirect + go.etcd.io/etcd/client/v3 v3.5.16 // indirect + go.etcd.io/etcd/pkg/v3 v3.5.16 // indirect + go.etcd.io/etcd/raft/v3 v3.5.16 // indirect + go.etcd.io/etcd/server/v3 v3.5.16 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect @@ -259,7 +272,7 @@ require ( golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/mod v0.16.0 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.23.0 // indirect golang.org/x/oauth2 v0.19.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.19.0 // indirect @@ -269,6 +282,7 @@ require ( golang.org/x/tools v0.19.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.172.0 // indirect + google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240311173647-c811ad7063a7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/grpc v1.62.1 // indirect diff --git a/go.sum b/go.sum index 1ef073d..a82e323 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.112.1 h1:uJSeirPke5UNZHIb4SxfZklVSiWWVqW4oXlETwZziwM= cloud.google.com/go/compute v1.25.0 h1:H1/4SqSUhjPFE7L5ddzHOfY2bCAvjwNRZPNl6Ni5oYU= cloud.google.com/go/compute v1.25.0/go.mod h1:GR7F0ZPZH8EhChlMo9FkLd7eUTwEymjqQagxzilIxIE= @@ -118,6 +119,7 @@ github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCE github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.3.2 h1:L4WppI9rctC8PdlMgyTkF8bBsy9pyKQEzBD1bHMRl+g= github.com/aliyun/credentials-go v1.3.2/go.mod h1:tlpz4uys4Rn7Ik4/piGRrTbXy2uLKvePgQJJduE+Y5c= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= github.com/aptible/supercronic v0.2.29 h1:I+3RoDspAs/ySQO+MQd6genE07csDV/ErhFOtACT5oo= @@ -164,6 +166,7 @@ github.com/aws/smithy-go v1.20.1 h1:4SZlSlMr36UEqC7XOyRVb27XMeZubNcBNN+9IgEPIQw= github.com/aws/smithy-go v1.20.1/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240116161626-88cfadc80e8f h1:mM9Ic3+hujxWGfpEf3E0fp12Lu7Xg2u2YsNb9WeliZQ= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20240116161626-88cfadc80e8f/go.mod h1:IPG+64HFPgPEx/vXYjqVpZ4lUgmzt1afdmi7ykS2Qjg= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= @@ -284,6 +287,7 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 h1:Mn26/9ZMNWSw9C9ERFA1PUxfmGpolnw2v0bKOREu5ew= github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32/go.mod h1:GIjDIg/heH5DOkXY3YJ/wNhfHsQHoXGjl8G8amsYQ1I= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= @@ -296,6 +300,8 @@ github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7 github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -329,6 +335,7 @@ github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7 github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-rod/rod v0.114.7 h1:h4pimzSOUnw7Eo41zdJA788XsawzHjJMyzCE3BrBww0= github.com/go-rod/rod v0.114.7/go.mod h1:aiedSEFg5DwG/fnNbUOTPMTTWX3MRj6vIs/a684Mthw= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= @@ -427,6 +434,7 @@ github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3 github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= @@ -497,6 +505,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E= github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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= @@ -587,6 +597,7 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= @@ -625,6 +636,7 @@ github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5X github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -666,6 +678,8 @@ github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1 h1:9Ki0qudKpc1F github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.8.1/go.mod h1:nhIgyu4YwwNgalIwTGsoAzam16jjAn3ADRSWKbWPwGI= github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00JQ/JonBiu3QvLE= github.com/sigstore/timestamp-authority v1.2.2/go.mod h1:nEah4Eq4wpliDjlY342rXclGSO7Kb9hoRrl9tqLW13A= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= @@ -696,6 +710,7 @@ github.com/spiffe/go-spiffe/v2 v2.2.0/go.mod h1:Urzb779b3+IwDJD2ZbN8fVl3Aa8G4N/P github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -703,6 +718,7 @@ github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0= github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -771,20 +787,36 @@ github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.etcd.io/bbolt v1.3.8 h1:xs88BrvEv273UsB79e0hcVrlUWmS0a8upikMFhSyAtA= go.etcd.io/bbolt v1.3.8/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= +go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= +go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.etcd.io/etcd/api/v3 v3.5.12 h1:W4sw5ZoU2Juc9gBWuLk5U6fHfNVyY1WC5g9uiXZio/c= go.etcd.io/etcd/api/v3 v3.5.12/go.mod h1:Ot+o0SWSyT6uHhA56al1oCED0JImsRiU9Dc26+C2a+4= +go.etcd.io/etcd/api/v3 v3.5.16 h1:WvmyJVbjWqK4R1E+B12RRHz3bRGy9XVfh++MgbN+6n0= +go.etcd.io/etcd/api/v3 v3.5.16/go.mod h1:1P4SlIP/VwkDmGo3OlOD7faPeP8KDIFhqvciH5EfN28= go.etcd.io/etcd/client/pkg/v3 v3.5.12 h1:EYDL6pWwyOsylrQyLp2w+HkQ46ATiOvoEdMarindU2A= go.etcd.io/etcd/client/pkg/v3 v3.5.12/go.mod h1:seTzl2d9APP8R5Y2hFL3NVlD6qC/dOT+3kvrqPyTas4= +go.etcd.io/etcd/client/pkg/v3 v3.5.16 h1:ZgY48uH6UvB+/7R9Yf4x574uCO3jIx0TRDyetSfId3Q= +go.etcd.io/etcd/client/pkg/v3 v3.5.16/go.mod h1:V8acl8pcEK0Y2g19YlOV9m9ssUe6MgiDSobSoaBAM0E= go.etcd.io/etcd/client/v2 v2.305.10 h1:MrmRktzv/XF8CvtQt+P6wLUlURaNpSDJHFZhe//2QE4= go.etcd.io/etcd/client/v2 v2.305.10/go.mod h1:m3CKZi69HzilhVqtPDcjhSGp+kA1OmbNn0qamH80xjA= +go.etcd.io/etcd/client/v2 v2.305.16 h1:kQrn9o5czVNaukf2A2At43cE9ZtWauOtf9vRZuiKXow= +go.etcd.io/etcd/client/v2 v2.305.16/go.mod h1:h9YxWCzcdvZENbfzBTFCnoNumr2ax3F19sKMqHFmXHE= go.etcd.io/etcd/client/v3 v3.5.12 h1:v5lCPXn1pf1Uu3M4laUE2hp/geOTc5uPcYYsNe1lDxg= go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw= +go.etcd.io/etcd/client/v3 v3.5.16 h1:sSmVYOAHeC9doqi0gv7v86oY/BTld0SEFGaxsU9eRhE= +go.etcd.io/etcd/client/v3 v3.5.16/go.mod h1:X+rExSGkyqxvu276cr2OwPLBaeqFu1cIl4vmRjAD/50= go.etcd.io/etcd/pkg/v3 v3.5.10 h1:WPR8K0e9kWl1gAhB5A7gEa5ZBTNkT9NdNWrR8Qpo1CM= go.etcd.io/etcd/pkg/v3 v3.5.10/go.mod h1:TKTuCKKcF1zxmfKWDkfz5qqYaE3JncKKZPFf8c1nFUs= +go.etcd.io/etcd/pkg/v3 v3.5.16 h1:cnavs5WSPWeK4TYwPYfmcr3Joz9BH+TZ6qoUtz6/+mc= +go.etcd.io/etcd/pkg/v3 v3.5.16/go.mod h1:+lutCZHG5MBBFI/U4eYT5yL7sJfnexsoM20Y0t2uNuY= go.etcd.io/etcd/raft/v3 v3.5.10 h1:cgNAYe7xrsrn/5kXMSaH8kM/Ky8mAdMqGOxyYwpP0LA= go.etcd.io/etcd/raft/v3 v3.5.10/go.mod h1:odD6kr8XQXTy9oQnyMPBOr0TVe+gT0neQhElQ6jbGRc= +go.etcd.io/etcd/raft/v3 v3.5.16 h1:zBXA3ZUpYs1AwiLGPafYAKKl/CORn/uaxYDwlNwndAk= +go.etcd.io/etcd/raft/v3 v3.5.16/go.mod h1:P4UP14AxofMJ/54boWilabqqWoW9eLodl6I5GdGzazI= go.etcd.io/etcd/server/v3 v3.5.10 h1:4NOGyOwD5sUZ22PiWYKmfxqoeh72z6EhYjNosKGLmZg= go.etcd.io/etcd/server/v3 v3.5.10/go.mod h1:gBplPHfs6YI0L+RpGkTQO7buDbHv5HJGG/Bst0/zIPo= +go.etcd.io/etcd/server/v3 v3.5.16 h1:d0/SAdJ3vVsZvF8IFVb1k8zqMZ+heGcNfft71ul9GWE= +go.etcd.io/etcd/server/v3 v3.5.16/go.mod h1:ynhyZZpdDp1Gq49jkUg5mfkDWZwXnn3eIqCqtJnrD/s= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= @@ -817,10 +849,14 @@ go.starlark.net v0.0.0-20240123142251-f86470692795 h1:LmbG8Pq7KDGkglKVn8VpZOZj6v go.starlark.net v0.0.0-20240123142251-f86470692795/go.mod h1:LcLNIzVOMp4oV+uusnpk+VU+SzXaJakUuBjoCSWH5dM= go.step.sm/crypto v0.44.2 h1:t3p3uQ7raP2jp2ha9P6xkQF85TJZh+87xmjSLaib+jk= go.step.sm/crypto v0.44.2/go.mod h1:x1439EnFhadzhkuaGX7sz03LEMQ+jV4gRamf5LCZJQQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -846,6 +882,7 @@ golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -856,6 +893,7 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -863,12 +901,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= @@ -880,11 +921,15 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg= golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -897,8 +942,10 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 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-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -907,8 +954,10 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -957,6 +1006,7 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3 golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -979,6 +1029,8 @@ google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9Ywl google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 h1:9+tzLLstTlPTRyJTh+ah5wIMsBW5c4tQwGTN3thOW9Y= google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:mqHbVIp48Muh7Ywss/AD6I5kNVKZMmAa/QEW58Gxp2s= @@ -991,7 +1043,9 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.62.1 h1:B4n+nfKzOICUXMgyrNd19h/I9oH0L1pizfk1d4zSgTk= google.golang.org/grpc v1.62.1/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= @@ -1009,6 +1063,7 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/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= @@ -1027,12 +1082,14 @@ gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYs gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/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.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= diff --git a/pkg/api/cephr.go b/pkg/api/cephr.go index dbe8a99..c23d2a0 100644 --- a/pkg/api/cephr.go +++ b/pkg/api/cephr.go @@ -336,7 +336,7 @@ func (c *cephrStore) getCephr(name string) (*reportsv1.ClusterEphemeralReport, e return nil, errorpkg.Wrapf(err, "could not find cluster ephemeral report in store") } - return val.DeepCopy(), nil + return val, nil } func (c *cephrStore) listCephr() (*reportsv1.ClusterEphemeralReportList, error) { @@ -346,7 +346,11 @@ func (c *cephrStore) listCephr() (*reportsv1.ClusterEphemeralReportList, error) } reportList := &reportsv1.ClusterEphemeralReportList{ - Items: valList, + Items: make([]reportsv1.ClusterEphemeralReport, 0, len(valList)), + } + + for _, v := range valList { + reportList.Items = append(reportList.Items, *v.DeepCopy()) } klog.Infof("value found of length:%d", len(reportList.Items)) @@ -358,12 +362,12 @@ func (c *cephrStore) createCephr(report *reportsv1.ClusterEphemeralReport) (*rep report.UID = uuid.NewUUID() report.CreationTimestamp = metav1.Now() - return report, c.store.ClusterEphemeralReports().Create(context.TODO(), *report) + return report, c.store.ClusterEphemeralReports().Create(context.TODO(), report) } func (c *cephrStore) updateCephr(report *reportsv1.ClusterEphemeralReport, _ *reportsv1.ClusterEphemeralReport) (*reportsv1.ClusterEphemeralReport, error) { report.ResourceVersion = c.store.UseResourceVersion() - return report, c.store.ClusterEphemeralReports().Update(context.TODO(), *report) + return report, c.store.ClusterEphemeralReports().Update(context.TODO(), report) } func (c *cephrStore) deleteCephr(report *reportsv1.ClusterEphemeralReport) error { diff --git a/pkg/api/cpolr.go b/pkg/api/cpolr.go index ff0942c..25a0bd2 100644 --- a/pkg/api/cpolr.go +++ b/pkg/api/cpolr.go @@ -335,7 +335,7 @@ func (c *cpolrStore) getCpolr(name string) (*v1alpha2.ClusterPolicyReport, error return nil, errorpkg.Wrapf(err, "could not find cluster policy report in store") } - return val.DeepCopy(), nil + return val, nil } func (c *cpolrStore) listCpolr() (*v1alpha2.ClusterPolicyReportList, error) { @@ -345,7 +345,11 @@ func (c *cpolrStore) listCpolr() (*v1alpha2.ClusterPolicyReportList, error) { } reportList := &v1alpha2.ClusterPolicyReportList{ - Items: valList, + Items: make([]v1alpha2.ClusterPolicyReport, 0, len(valList)), + } + + for _, v := range valList { + reportList.Items = append(reportList.Items, *v.DeepCopy()) } klog.Infof("value found of length:%d", len(reportList.Items)) @@ -357,12 +361,12 @@ func (c *cpolrStore) createCpolr(report *v1alpha2.ClusterPolicyReport) (*v1alpha report.UID = uuid.NewUUID() report.CreationTimestamp = metav1.Now() - return report, c.store.ClusterPolicyReports().Create(context.TODO(), *report) + return report, c.store.ClusterPolicyReports().Create(context.TODO(), report) } func (c *cpolrStore) updateCpolr(report *v1alpha2.ClusterPolicyReport, _ *v1alpha2.ClusterPolicyReport) (*v1alpha2.ClusterPolicyReport, error) { report.ResourceVersion = c.store.UseResourceVersion() - return report, c.store.ClusterPolicyReports().Update(context.TODO(), *report) + return report, c.store.ClusterPolicyReports().Update(context.TODO(), report) } func (c *cpolrStore) deleteCpolr(report *v1alpha2.ClusterPolicyReport) error { diff --git a/pkg/api/ephr.go b/pkg/api/ephr.go index be9dbac..39e46c8 100644 --- a/pkg/api/ephr.go +++ b/pkg/api/ephr.go @@ -356,7 +356,7 @@ func (p *ephrStore) getEphr(name, namespace string) (*reportsv1.EphemeralReport, return nil, errorpkg.Wrapf(err, "could not find ephemeral report in store") } - return val.DeepCopy(), nil + return val, nil } func (p *ephrStore) listEphr(namespace string) (*reportsv1.EphemeralReportList, error) { @@ -366,7 +366,11 @@ func (p *ephrStore) listEphr(namespace string) (*reportsv1.EphemeralReportList, } reportList := &reportsv1.EphemeralReportList{ - Items: valList, + Items: make([]reportsv1.EphemeralReport, 0, len(valList)), + } + + for _, v := range valList { + reportList.Items = append(reportList.Items, *v.DeepCopy()) } klog.Infof("value found of length:%d", len(reportList.Items)) @@ -378,12 +382,12 @@ func (p *ephrStore) createEphr(report *reportsv1.EphemeralReport) (*reportsv1.Ep report.UID = uuid.NewUUID() report.CreationTimestamp = metav1.Now() - return report, p.store.EphemeralReports().Create(context.TODO(), *report) + return report, p.store.EphemeralReports().Create(context.TODO(), report) } func (p *ephrStore) updateEphr(report *reportsv1.EphemeralReport, _ *reportsv1.EphemeralReport) (*reportsv1.EphemeralReport, error) { report.ResourceVersion = p.store.UseResourceVersion() - return report, p.store.EphemeralReports().Update(context.TODO(), *report) + return report, p.store.EphemeralReports().Update(context.TODO(), report) } func (p *ephrStore) deleteEphr(report *reportsv1.EphemeralReport) error { diff --git a/pkg/api/polr.go b/pkg/api/polr.go index 81d5587..cd5f0c5 100644 --- a/pkg/api/polr.go +++ b/pkg/api/polr.go @@ -356,7 +356,7 @@ func (p *polrStore) getPolr(name, namespace string) (*v1alpha2.PolicyReport, err return nil, errorpkg.Wrapf(err, "could not find policy report in store") } - return val.DeepCopy(), nil + return val, nil } func (p *polrStore) listPolr(namespace string) (*v1alpha2.PolicyReportList, error) { @@ -366,7 +366,11 @@ func (p *polrStore) listPolr(namespace string) (*v1alpha2.PolicyReportList, erro } reportList := &v1alpha2.PolicyReportList{ - Items: valList, + Items: make([]v1alpha2.PolicyReport, 0, len(valList)), + } + + for _, v := range valList { + reportList.Items = append(reportList.Items, *v.DeepCopy()) } klog.Infof("value found of length:%d", len(reportList.Items)) @@ -378,12 +382,12 @@ func (p *polrStore) createPolr(report *v1alpha2.PolicyReport) (*v1alpha2.PolicyR report.UID = uuid.NewUUID() report.CreationTimestamp = metav1.Now() - return report, p.store.PolicyReports().Create(context.TODO(), *report) + return report, p.store.PolicyReports().Create(context.TODO(), report) } func (p *polrStore) updatePolr(report *v1alpha2.PolicyReport, _ *v1alpha2.PolicyReport) (*v1alpha2.PolicyReport, error) { report.ResourceVersion = p.store.UseResourceVersion() - return report, p.store.PolicyReports().Update(context.TODO(), *report) + return report, p.store.PolicyReports().Update(context.TODO(), report) } func (p *polrStore) deletePolr(report *v1alpha2.PolicyReport) error { diff --git a/pkg/app/opts/options.go b/pkg/app/opts/options.go index 92c83a7..2b946b5 100644 --- a/pkg/app/opts/options.go +++ b/pkg/app/opts/options.go @@ -9,6 +9,7 @@ import ( generatedopenapi "github.com/kyverno/reports-server/pkg/api/generated/openapi" "github.com/kyverno/reports-server/pkg/server" "github.com/kyverno/reports-server/pkg/storage/db" + "github.com/kyverno/reports-server/pkg/storage/etcd" openapinamer "k8s.io/apiserver/pkg/endpoints/openapi" genericapiserver "k8s.io/apiserver/pkg/server" genericoptions "k8s.io/apiserver/pkg/server/options" @@ -32,10 +33,12 @@ type Options struct { Logging *logs.Options ShowVersion bool - Debug bool + Etcd bool Kubeconfig string // dbopts + EtcdConfig etcd.EtcdConfig + EtcdDir string DBHost string DBPort int DBUser string @@ -66,7 +69,9 @@ func (o *Options) validate() []error { func (o *Options) Flags() (fs flag.NamedFlagSets) { msfs := fs.FlagSet("policy server") - msfs.BoolVar(&o.Debug, "debug", false, "Use inmemory database for debugging") + msfs.BoolVar(&o.Etcd, "etcd", false, "Use embedded etcd database") + msfs.StringVar(&o.EtcdConfig.Endpoints, "etcdEndpoints", "", "Enpoints used for connect to etcd server") + msfs.BoolVar(&o.EtcdConfig.Insecure, "etcdSkipTLS", true, "Skip TLS verification when connecting to etcd") msfs.BoolVar(&o.ShowVersion, "version", false, "Show version") msfs.StringVar(&o.Kubeconfig, "kubeconfig", o.Kubeconfig, "The path to the kubeconfig used to connect to the Kubernetes API server and the Kubelets (defaults to in-cluster config)") msfs.StringVar(&o.DBHost, "dbhost", "reportsdb.kyverno", "Host url of postgres instance") @@ -124,10 +129,11 @@ func (o Options) ServerConfig() (*server.Config, error) { } return &server.Config{ - Apiserver: apiserver, - Rest: restConfig, - Debug: o.Debug, - DBconfig: dbconfig, + Apiserver: apiserver, + Rest: restConfig, + Embedded: o.Etcd, + EtcdConfig: &o.EtcdConfig, + DBconfig: dbconfig, }, nil } diff --git a/pkg/app/policyserver.go b/pkg/app/policyserver.go index 7c09b70..0e83130 100644 --- a/pkg/app/policyserver.go +++ b/pkg/app/policyserver.go @@ -62,6 +62,7 @@ func runCommand(o *opts.Options, stopCh <-chan struct{}) error { if err != nil { return err } + s, err := config.Complete() if err != nil { return err diff --git a/pkg/server/config.go b/pkg/server/config.go index 9ff8e73..534294f 100644 --- a/pkg/server/config.go +++ b/pkg/server/config.go @@ -11,6 +11,7 @@ import ( "github.com/kyverno/reports-server/pkg/api" "github.com/kyverno/reports-server/pkg/storage" "github.com/kyverno/reports-server/pkg/storage/db" + "github.com/kyverno/reports-server/pkg/storage/etcd" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/watch" apimetrics "k8s.io/apiserver/pkg/endpoints/metrics" @@ -28,10 +29,11 @@ import ( ) type Config struct { - Apiserver *genericapiserver.Config - Rest *rest.Config - Debug bool - DBconfig *db.PostgresConfig + Apiserver *genericapiserver.Config + Rest *rest.Config + Embedded bool + EtcdConfig *etcd.EtcdConfig + DBconfig *db.PostgresConfig } func (c Config) Complete() (*server, error) { @@ -53,16 +55,20 @@ func (c Config) Complete() (*server, error) { if err != nil { return nil, err } - store, err := storage.New(c.Debug, c.DBconfig, id) + store, err := storage.New(c.Embedded, c.DBconfig, id, c.EtcdConfig) if err != nil { klog.Error(err) return nil, err } - klog.Info("performing migration...") - if err := c.migration(store); err != nil { - klog.Error(err) - return nil, err + // Embedded runs in a stateful set in high availability deployment + // TODO: Add leader election to add embedded + if !c.Embedded { + klog.Info("performing migration...") + if err := c.migration(store); err != nil { + klog.Error(err) + return nil, err + } } if err := api.Install(store, genericServer); err != nil { @@ -138,7 +144,7 @@ func (c Config) migration(store storage.Interface) error { c.Annotations = make(map[string]string) } c.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.ClusterPolicyReports().Create(context.TODO(), c) + err := store.ClusterPolicyReports().Create(context.TODO(), &c) if err != nil { return err } @@ -170,7 +176,7 @@ func (c Config) migration(store storage.Interface) error { cpolr.Annotations = make(map[string]string) } cpolr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.ClusterPolicyReports().Create(context.TODO(), *cpolr) + err := store.ClusterPolicyReports().Create(context.TODO(), cpolr) if err != nil { klog.Error(err) } @@ -184,7 +190,7 @@ func (c Config) migration(store storage.Interface) error { cpolr.Annotations = make(map[string]string) } cpolr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.ClusterPolicyReports().Update(context.TODO(), *cpolr) + err := store.ClusterPolicyReports().Update(context.TODO(), cpolr) if err != nil { klog.Error(err) } @@ -219,7 +225,7 @@ func (c Config) migration(store storage.Interface) error { c.Annotations = make(map[string]string) } c.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.PolicyReports().Create(context.TODO(), c) + err := store.PolicyReports().Create(context.TODO(), &c) if err != nil { return err } @@ -251,7 +257,7 @@ func (c Config) migration(store storage.Interface) error { polr.Annotations = make(map[string]string) } polr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.PolicyReports().Create(context.TODO(), *polr) + err := store.PolicyReports().Create(context.TODO(), polr) if err != nil { klog.Error(err) } @@ -265,7 +271,7 @@ func (c Config) migration(store storage.Interface) error { polr.Annotations = make(map[string]string) } polr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.PolicyReports().Update(context.TODO(), *polr) + err := store.PolicyReports().Update(context.TODO(), polr) if err != nil { klog.Error(err) } @@ -300,7 +306,7 @@ func (c Config) migration(store storage.Interface) error { c.Annotations = make(map[string]string) } c.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.ClusterEphemeralReports().Create(context.TODO(), c) + err := store.ClusterEphemeralReports().Create(context.TODO(), &c) if err != nil { return err } @@ -331,7 +337,7 @@ func (c Config) migration(store storage.Interface) error { cephr.Annotations = make(map[string]string) } cephr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.ClusterEphemeralReports().Create(context.TODO(), *cephr) + err := store.ClusterEphemeralReports().Create(context.TODO(), cephr) if err != nil { klog.Error(err) } @@ -345,7 +351,7 @@ func (c Config) migration(store storage.Interface) error { cephr.Annotations = make(map[string]string) } cephr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.ClusterEphemeralReports().Update(context.TODO(), *cephr) + err := store.ClusterEphemeralReports().Update(context.TODO(), cephr) if err != nil { klog.Error(err) } @@ -379,7 +385,7 @@ func (c Config) migration(store storage.Interface) error { c.Annotations = make(map[string]string) } c.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.EphemeralReports().Create(context.TODO(), c) + err := store.EphemeralReports().Create(context.TODO(), &c) if err != nil { return err } @@ -410,7 +416,7 @@ func (c Config) migration(store storage.Interface) error { ephr.Annotations = make(map[string]string) } ephr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.EphemeralReports().Create(context.TODO(), *ephr) + err := store.EphemeralReports().Create(context.TODO(), ephr) if err != nil { klog.Error(err) } @@ -424,7 +430,7 @@ func (c Config) migration(store storage.Interface) error { ephr.Annotations = make(map[string]string) } ephr.Annotations[api.ServedByReportsServerAnnotation] = api.ServedByReportsServerValue - err := store.EphemeralReports().Update(context.TODO(), *ephr) + err := store.EphemeralReports().Update(context.TODO(), ephr) if err != nil { klog.Error(err) } diff --git a/pkg/storage/api/interface.go b/pkg/storage/api/interface.go index a3dce2f..4176dee 100644 --- a/pkg/storage/api/interface.go +++ b/pkg/storage/api/interface.go @@ -16,34 +16,34 @@ type Storage interface { } type PolicyReportsInterface interface { - Get(ctx context.Context, name, namespace string) (v1alpha2.PolicyReport, error) - List(ctx context.Context, namespace string) ([]v1alpha2.PolicyReport, error) - Create(ctx context.Context, polr v1alpha2.PolicyReport) error - Update(ctx context.Context, polr v1alpha2.PolicyReport) error + Get(ctx context.Context, name, namespace string) (*v1alpha2.PolicyReport, error) + List(ctx context.Context, namespace string) ([]*v1alpha2.PolicyReport, error) + Create(ctx context.Context, polr *v1alpha2.PolicyReport) error + Update(ctx context.Context, polr *v1alpha2.PolicyReport) error Delete(ctx context.Context, name, namespace string) error } type ClusterPolicyReportsInterface interface { - Get(ctx context.Context, name string) (v1alpha2.ClusterPolicyReport, error) - List(ctx context.Context) ([]v1alpha2.ClusterPolicyReport, error) - Create(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport) error - Update(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport) error + Get(ctx context.Context, name string) (*v1alpha2.ClusterPolicyReport, error) + List(ctx context.Context) ([]*v1alpha2.ClusterPolicyReport, error) + Create(ctx context.Context, cpolr *v1alpha2.ClusterPolicyReport) error + Update(ctx context.Context, cpolr *v1alpha2.ClusterPolicyReport) error Delete(ctx context.Context, name string) error } type EphemeralReportsInterface interface { - Get(ctx context.Context, name, namespace string) (reportsv1.EphemeralReport, error) - List(ctx context.Context, namespace string) ([]reportsv1.EphemeralReport, error) - Create(ctx context.Context, polr reportsv1.EphemeralReport) error - Update(ctx context.Context, polr reportsv1.EphemeralReport) error + Get(ctx context.Context, name, namespace string) (*reportsv1.EphemeralReport, error) + List(ctx context.Context, namespace string) ([]*reportsv1.EphemeralReport, error) + Create(ctx context.Context, polr *reportsv1.EphemeralReport) error + Update(ctx context.Context, polr *reportsv1.EphemeralReport) error Delete(ctx context.Context, name, namespace string) error } type ClusterEphemeralReportsInterface interface { - Get(ctx context.Context, name string) (reportsv1.ClusterEphemeralReport, error) - List(ctx context.Context) ([]reportsv1.ClusterEphemeralReport, error) - Create(ctx context.Context, cephr reportsv1.ClusterEphemeralReport) error - Update(ctx context.Context, cephr reportsv1.ClusterEphemeralReport) error + Get(ctx context.Context, name string) (*reportsv1.ClusterEphemeralReport, error) + List(ctx context.Context) ([]*reportsv1.ClusterEphemeralReport, error) + Create(ctx context.Context, cephr *reportsv1.ClusterEphemeralReport) error + Update(ctx context.Context, cephr *reportsv1.ClusterEphemeralReport) error Delete(ctx context.Context, name string) error } diff --git a/pkg/storage/db/cephr.go b/pkg/storage/db/cephr.go index 765bbf9..0d36f3b 100644 --- a/pkg/storage/db/cephr.go +++ b/pkg/storage/db/cephr.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" + "errors" "fmt" "sync" @@ -34,12 +35,12 @@ func NewClusterEphemeralReportStore(db *sql.DB, clusterId string) (api.ClusterEp return &cephr{db: db, clusterId: clusterId}, nil } -func (c *cephr) List(ctx context.Context) ([]reportsv1.ClusterEphemeralReport, error) { +func (c *cephr) List(ctx context.Context) ([]*reportsv1.ClusterEphemeralReport, error) { c.Lock() defer c.Unlock() klog.Infof("listing all values") - res := make([]reportsv1.ClusterEphemeralReport, 0) + res := make([]*reportsv1.ClusterEphemeralReport, 0) var jsonb string rows, err := c.db.Query("SELECT report FROM clusterephemeralreports WHERE (clusterId = $1)", c.clusterId) @@ -59,14 +60,14 @@ func (c *cephr) List(ctx context.Context) ([]reportsv1.ClusterEphemeralReport, e klog.ErrorS(err, "failed to unmarshal clusterephemeralreports") return nil, fmt.Errorf("clusterephemeralreports list: cannot convert jsonb to clusterephemeralreports: %v", err) } - res = append(res, report) + res = append(res, &report) } klog.Infof("list found length: %d", len(res)) return res, nil } -func (c *cephr) Get(ctx context.Context, name string) (reportsv1.ClusterEphemeralReport, error) { +func (c *cephr) Get(ctx context.Context, name string) (*reportsv1.ClusterEphemeralReport, error) { c.Lock() defer c.Unlock() @@ -76,25 +77,29 @@ func (c *cephr) Get(ctx context.Context, name string) (reportsv1.ClusterEphemera if err := row.Scan(&jsonb); err != nil { klog.ErrorS(err, fmt.Sprintf("clusterephemeralreport not found name=%s", name)) if err == sql.ErrNoRows { - return reportsv1.ClusterEphemeralReport{}, fmt.Errorf("clusterephemeralreport get %s: no such ephemeral report", name) + return nil, fmt.Errorf("clusterephemeralreport get %s: no such ephemeral report", name) } - return reportsv1.ClusterEphemeralReport{}, fmt.Errorf("clusterephemeralreport get %s: %v", name, err) + return nil, fmt.Errorf("clusterephemeralreport get %s: %v", name, err) } var report reportsv1.ClusterEphemeralReport err := json.Unmarshal([]byte(jsonb), &report) if err != nil { klog.ErrorS(err, "failed to unmarshal report") - return reportsv1.ClusterEphemeralReport{}, fmt.Errorf("clusterephemeralreport list: cannot convert jsonb to ephemeralreport: %v", err) + return nil, fmt.Errorf("clusterephemeralreport list: cannot convert jsonb to ephemeralreport: %v", err) } - return report, nil + return &report, nil } -func (c *cephr) Create(ctx context.Context, cephr reportsv1.ClusterEphemeralReport) error { +func (c *cephr) Create(ctx context.Context, cephr *reportsv1.ClusterEphemeralReport) error { c.Lock() defer c.Unlock() - klog.Infof("creating entry for key:%s", cephr.Name) - jsonb, err := json.Marshal(cephr) + if cephr == nil { + return errors.New("invalid cluster ephemeral report") + } + + klog.Infof("creating entry for key:%s", cephr.Name) + jsonb, err := json.Marshal(*cephr) if err != nil { klog.ErrorS(err, "failed to unmarshal cephr") return err @@ -108,11 +113,15 @@ func (c *cephr) Create(ctx context.Context, cephr reportsv1.ClusterEphemeralRepo return nil } -func (c *cephr) Update(ctx context.Context, cephr reportsv1.ClusterEphemeralReport) error { +func (c *cephr) Update(ctx context.Context, cephr *reportsv1.ClusterEphemeralReport) error { c.Lock() defer c.Unlock() - jsonb, err := json.Marshal(cephr) + if cephr == nil { + return errors.New("invalid cluster ephemeral report") + } + + jsonb, err := json.Marshal(*cephr) if err != nil { return err } diff --git a/pkg/storage/db/cpolr.go b/pkg/storage/db/cpolr.go index 8bd2b2a..ba4c742 100644 --- a/pkg/storage/db/cpolr.go +++ b/pkg/storage/db/cpolr.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" + "errors" "fmt" "sync" @@ -34,12 +35,12 @@ func NewClusterPolicyReportStore(db *sql.DB, clusterId string) (api.ClusterPolic return &cpolrdb{db: db, clusterId: clusterId}, nil } -func (c *cpolrdb) List(ctx context.Context) ([]v1alpha2.ClusterPolicyReport, error) { +func (c *cpolrdb) List(ctx context.Context) ([]*v1alpha2.ClusterPolicyReport, error) { c.Lock() defer c.Unlock() klog.Infof("listing all values") - res := make([]v1alpha2.ClusterPolicyReport, 0) + res := make([]*v1alpha2.ClusterPolicyReport, 0) var jsonb string rows, err := c.db.Query("SELECT report FROM clusterpolicyreports WHERE clusterId = $1", c.clusterId) @@ -59,14 +60,14 @@ func (c *cpolrdb) List(ctx context.Context) ([]v1alpha2.ClusterPolicyReport, err klog.ErrorS(err, "failed to unmarshal clusterpolicyreport") return nil, fmt.Errorf("clusterpolicyreport list: cannot convert jsonb to clusterpolicyreport: %v", err) } - res = append(res, report) + res = append(res, &report) } klog.Infof("list found length: %d", len(res)) return res, nil } -func (c *cpolrdb) Get(ctx context.Context, name string) (v1alpha2.ClusterPolicyReport, error) { +func (c *cpolrdb) Get(ctx context.Context, name string) (*v1alpha2.ClusterPolicyReport, error) { c.Lock() defer c.Unlock() @@ -76,25 +77,29 @@ func (c *cpolrdb) Get(ctx context.Context, name string) (v1alpha2.ClusterPolicyR if err := row.Scan(&jsonb); err != nil { klog.ErrorS(err, fmt.Sprintf("clusterpolicyreport not found name=%s", name)) if err == sql.ErrNoRows { - return v1alpha2.ClusterPolicyReport{}, fmt.Errorf("clusterpolicyreport get %s: no such policy report", name) + return nil, fmt.Errorf("clusterpolicyreport get %s: no such policy report", name) } - return v1alpha2.ClusterPolicyReport{}, fmt.Errorf("clusterpolicyreport get %s: %v", name, err) + return nil, fmt.Errorf("clusterpolicyreport get %s: %v", name, err) } var report v1alpha2.ClusterPolicyReport err := json.Unmarshal([]byte(jsonb), &report) if err != nil { klog.ErrorS(err, "failed to unmarshal report") - return v1alpha2.ClusterPolicyReport{}, fmt.Errorf("clusterpolicyreport list: cannot convert jsonb to policyreport: %v", err) + return nil, fmt.Errorf("clusterpolicyreport list: cannot convert jsonb to policyreport: %v", err) } - return report, nil + return &report, nil } -func (c *cpolrdb) Create(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport) error { +func (c *cpolrdb) Create(ctx context.Context, cpolr *v1alpha2.ClusterPolicyReport) error { c.Lock() defer c.Unlock() - klog.Infof("creating entry for key:%s", cpolr.Name) - jsonb, err := json.Marshal(cpolr) + if cpolr == nil { + return errors.New("invalid cluster policy report") + } + + klog.Infof("creating entry for key:%s", cpolr.Name) + jsonb, err := json.Marshal(*cpolr) if err != nil { klog.ErrorS(err, "failed to unmarshal cpolr") return err @@ -108,11 +113,15 @@ func (c *cpolrdb) Create(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport return nil } -func (c *cpolrdb) Update(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport) error { +func (c *cpolrdb) Update(ctx context.Context, cpolr *v1alpha2.ClusterPolicyReport) error { c.Lock() defer c.Unlock() - jsonb, err := json.Marshal(cpolr) + if cpolr == nil { + return errors.New("invalid cluster policy report") + } + + jsonb, err := json.Marshal(*cpolr) if err != nil { return err } diff --git a/pkg/storage/db/ephr.go b/pkg/storage/db/ephr.go index 9242fb7..c54013a 100644 --- a/pkg/storage/db/ephr.go +++ b/pkg/storage/db/ephr.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" + "errors" "fmt" "sync" @@ -39,12 +40,12 @@ func NewEphemeralReportStore(db *sql.DB, clusterId string) (api.EphemeralReports return &ephrdb{db: db, clusterId: clusterId}, nil } -func (p *ephrdb) List(ctx context.Context, namespace string) ([]reportsv1.EphemeralReport, error) { +func (p *ephrdb) List(ctx context.Context, namespace string) ([]*reportsv1.EphemeralReport, error) { p.Lock() defer p.Unlock() klog.Infof("listing all values for namespace:%s", namespace) - res := make([]reportsv1.EphemeralReport, 0) + res := make([]*reportsv1.EphemeralReport, 0) var jsonb string var rows *sql.Rows var err error @@ -70,14 +71,14 @@ func (p *ephrdb) List(ctx context.Context, namespace string) ([]reportsv1.Epheme klog.ErrorS(err, "cannot convert jsonb to ephemeralreport") return nil, fmt.Errorf("ephemeralreport list %q: cannot convert jsonb to ephemeralreport: %v", namespace, err) } - res = append(res, report) + res = append(res, &report) } klog.Infof("list found length: %d", len(res)) return res, nil } -func (p *ephrdb) Get(ctx context.Context, name, namespace string) (reportsv1.EphemeralReport, error) { +func (p *ephrdb) Get(ctx context.Context, name, namespace string) (*reportsv1.EphemeralReport, error) { p.Lock() defer p.Unlock() @@ -87,25 +88,29 @@ func (p *ephrdb) Get(ctx context.Context, name, namespace string) (reportsv1.Eph if err := row.Scan(&jsonb); err != nil { klog.ErrorS(err, fmt.Sprintf("ephemeralreport not found name=%s namespace=%s", name, namespace)) if err == sql.ErrNoRows { - return reportsv1.EphemeralReport{}, fmt.Errorf("ephemeralreport get %s/%s: no such ephemeral report: %v", namespace, name, err) + return nil, fmt.Errorf("ephemeralreport get %s/%s: no such ephemeral report: %v", namespace, name, err) } - return reportsv1.EphemeralReport{}, fmt.Errorf("ephemeralreport get %s/%s: %v", namespace, name, err) + return nil, fmt.Errorf("ephemeralreport get %s/%s: %v", namespace, name, err) } var report reportsv1.EphemeralReport err := json.Unmarshal([]byte(jsonb), &report) if err != nil { klog.ErrorS(err, "cannot convert jsonb to ephemeralreport") - return reportsv1.EphemeralReport{}, fmt.Errorf("ephemeralreport list %q: cannot convert jsonb to ephemeralreport: %v", namespace, err) + return nil, fmt.Errorf("ephemeralreport list %q: cannot convert jsonb to ephemeralreport: %v", namespace, err) } - return report, nil + return &report, nil } -func (p *ephrdb) Create(ctx context.Context, polr reportsv1.EphemeralReport) error { +func (p *ephrdb) Create(ctx context.Context, polr *reportsv1.EphemeralReport) error { p.Lock() defer p.Unlock() - klog.Infof("creating entry for key:%s/%s", polr.Name, polr.Namespace) - jsonb, err := json.Marshal(polr) + if polr == nil { + return errors.New("invalid ephemeral report") + } + + klog.Infof("creating entry for key:%s/%s", polr.Name, polr.Namespace) + jsonb, err := json.Marshal(*polr) if err != nil { return err } @@ -118,11 +123,15 @@ func (p *ephrdb) Create(ctx context.Context, polr reportsv1.EphemeralReport) err return nil } -func (p *ephrdb) Update(ctx context.Context, polr reportsv1.EphemeralReport) error { +func (p *ephrdb) Update(ctx context.Context, polr *reportsv1.EphemeralReport) error { p.Lock() defer p.Unlock() - jsonb, err := json.Marshal(polr) + if polr == nil { + return errors.New("invalid ephemeral report") + } + + jsonb, err := json.Marshal(*polr) if err != nil { return err } diff --git a/pkg/storage/db/new.go b/pkg/storage/db/new.go index 7f95048..93b1827 100644 --- a/pkg/storage/db/new.go +++ b/pkg/storage/db/new.go @@ -17,7 +17,7 @@ const ( ) func New(config *PostgresConfig, clusterId string) (api.Storage, error) { - klog.Infof("starting postgres db, config: %s", config.String()) + klog.Infof("starting postgres db") db, err := sql.Open("postgres", config.String()) if err != nil { klog.Error("failed to open db", err.Error()) diff --git a/pkg/storage/db/polr.go b/pkg/storage/db/polr.go index 6b25b28..8e16aa7 100644 --- a/pkg/storage/db/polr.go +++ b/pkg/storage/db/polr.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "encoding/json" + "errors" "fmt" "sync" @@ -38,12 +39,12 @@ func NewPolicyReportStore(db *sql.DB, clusterId string) (api.PolicyReportsInterf return &polrdb{db: db, clusterId: clusterId}, nil } -func (p *polrdb) List(ctx context.Context, namespace string) ([]v1alpha2.PolicyReport, error) { +func (p *polrdb) List(ctx context.Context, namespace string) ([]*v1alpha2.PolicyReport, error) { p.Lock() defer p.Unlock() klog.Infof("listing all values for namespace:%s", namespace) - res := make([]v1alpha2.PolicyReport, 0) + res := make([]*v1alpha2.PolicyReport, 0) var jsonb string var rows *sql.Rows var err error @@ -70,14 +71,14 @@ func (p *polrdb) List(ctx context.Context, namespace string) ([]v1alpha2.PolicyR klog.ErrorS(err, "cannot convert jsonb to policyreport") return nil, fmt.Errorf("policyreport list %q: cannot convert jsonb to policyreport: %v", namespace, err) } - res = append(res, report) + res = append(res, &report) } klog.Infof("list found length: %d", len(res)) return res, nil } -func (p *polrdb) Get(ctx context.Context, name, namespace string) (v1alpha2.PolicyReport, error) { +func (p *polrdb) Get(ctx context.Context, name, namespace string) (*v1alpha2.PolicyReport, error) { p.Lock() defer p.Unlock() @@ -87,25 +88,29 @@ func (p *polrdb) Get(ctx context.Context, name, namespace string) (v1alpha2.Poli if err := row.Scan(&jsonb); err != nil { klog.ErrorS(err, fmt.Sprintf("policyreport not found name=%s namespace=%s", name, namespace)) if err == sql.ErrNoRows { - return v1alpha2.PolicyReport{}, fmt.Errorf("policyreport get %s/%s: no such policy report: %v", namespace, name, err) + return nil, fmt.Errorf("policyreport get %s/%s: no such policy report: %v", namespace, name, err) } - return v1alpha2.PolicyReport{}, fmt.Errorf("policyreport get %s/%s: %v", namespace, name, err) + return nil, fmt.Errorf("policyreport get %s/%s: %v", namespace, name, err) } var report v1alpha2.PolicyReport err := json.Unmarshal([]byte(jsonb), &report) if err != nil { klog.ErrorS(err, "cannot convert jsonb to policyreport") - return v1alpha2.PolicyReport{}, fmt.Errorf("policyreport list %q: cannot convert jsonb to policyreport: %v", namespace, err) + return nil, fmt.Errorf("policyreport list %q: cannot convert jsonb to policyreport: %v", namespace, err) } - return report, nil + return &report, nil } -func (p *polrdb) Create(ctx context.Context, polr v1alpha2.PolicyReport) error { +func (p *polrdb) Create(ctx context.Context, polr *v1alpha2.PolicyReport) error { p.Lock() defer p.Unlock() - klog.Infof("creating entry for key:%s/%s", polr.Name, polr.Namespace) - jsonb, err := json.Marshal(polr) + if polr == nil { + return errors.New("invalid policy report") + } + + klog.Infof("creating entry for key:%s/%s", polr.Name, polr.Namespace) + jsonb, err := json.Marshal(*polr) if err != nil { return err } @@ -118,11 +123,15 @@ func (p *polrdb) Create(ctx context.Context, polr v1alpha2.PolicyReport) error { return nil } -func (p *polrdb) Update(ctx context.Context, polr v1alpha2.PolicyReport) error { +func (p *polrdb) Update(ctx context.Context, polr *v1alpha2.PolicyReport) error { p.Lock() defer p.Unlock() - jsonb, err := json.Marshal(polr) + if polr == nil { + return errors.New("invalid policy report") + } + + jsonb, err := json.Marshal(*polr) if err != nil { return err } diff --git a/pkg/storage/etcd/new.go b/pkg/storage/etcd/new.go new file mode 100644 index 0000000..c6883c5 --- /dev/null +++ b/pkg/storage/etcd/new.go @@ -0,0 +1,73 @@ +package etcd + +import ( + "crypto/tls" + "strings" + "time" + + reportsv1 "github.com/kyverno/kyverno/api/reports/v1" + "github.com/kyverno/reports-server/pkg/storage/api" + "github.com/kyverno/reports-server/pkg/utils" + clientv3 "go.etcd.io/etcd/client/v3" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" + "sigs.k8s.io/wg-policy-prototypes/policy-report/pkg/api/wgpolicyk8s.io/v1alpha2" +) + +var dialTimeout = 10 * time.Second + +type EtcdConfig struct { + Endpoints string + Insecure bool +} + +type etcdClient struct { + polrClient ObjectStorageNamespaced[*v1alpha2.PolicyReport] + ephrClient ObjectStorageNamespaced[*reportsv1.EphemeralReport] + cpolrClient ObjectStorageCluster[*v1alpha2.ClusterPolicyReport] + cephrClient ObjectStorageCluster[*reportsv1.ClusterEphemeralReport] +} + +func New(cfg *EtcdConfig) (api.Storage, error) { + clientCfg := clientv3.Config{ + DialTimeout: dialTimeout, + Endpoints: strings.Split(cfg.Endpoints, ","), + } + if cfg.Insecure { + clientCfg.TLS = &tls.Config{ + InsecureSkipVerify: true, //nolint:gosec + } + clientCfg.DialOptions = []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())} + } + client, err := clientv3.New(clientCfg) + if err != nil { + return nil, err + } + + return &etcdClient{ + polrClient: NewObjectStoreNamespaced[*v1alpha2.PolicyReport](client, utils.PolicyReportsGVK, utils.PolicyReportsGR), + ephrClient: NewObjectStoreNamespaced[*reportsv1.EphemeralReport](client, utils.EphemeralReportsGVK, utils.EphemeralReportsGR), + cpolrClient: NewObjectStoreCluster[*v1alpha2.ClusterPolicyReport](client, utils.ClusterPolicyReportsGVK, utils.ClusterPolicyReportsGR), + cephrClient: NewObjectStoreCluster[*reportsv1.ClusterEphemeralReport](client, utils.ClusterEphemeralReportsGVK, utils.ClusterEphemeralReportsGR), + }, nil +} + +func (e *etcdClient) Ready() bool { + return true +} + +func (e *etcdClient) PolicyReports() api.PolicyReportsInterface { + return e.polrClient +} + +func (e *etcdClient) ClusterPolicyReports() api.ClusterPolicyReportsInterface { + return e.cpolrClient +} + +func (e *etcdClient) EphemeralReports() api.EphemeralReportsInterface { + return e.ephrClient +} + +func (e *etcdClient) ClusterEphemeralReports() api.ClusterEphemeralReportsInterface { + return e.cephrClient +} diff --git a/pkg/storage/etcd/store.go b/pkg/storage/etcd/store.go new file mode 100644 index 0000000..b811885 --- /dev/null +++ b/pkg/storage/etcd/store.go @@ -0,0 +1,214 @@ +package etcd + +import ( + "context" + "encoding/json" + "fmt" + "sync" + + clientv3 "go.etcd.io/etcd/client/v3" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" +) + +type ObjectStorageNamespaced[T metav1.Object] interface { + Get(ctx context.Context, name, namespace string) (T, error) + List(ctx context.Context, namespace string) ([]T, error) + Create(ctx context.Context, obj T) error + Update(ctx context.Context, obj T) error + Delete(ctx context.Context, name, namespace string) error +} + +type objectStoreNamespaced[T metav1.Object] struct { + sync.Mutex + namespaced bool + etcdclient clientv3.KV + gvk schema.GroupVersionKind + gr schema.GroupResource +} + +func NewObjectStoreNamespaced[T metav1.Object](client clientv3.KV, gvk schema.GroupVersionKind, gr schema.GroupResource) ObjectStorageNamespaced[T] { + return &objectStoreNamespaced[T]{ + namespaced: true, + etcdclient: client, + gvk: gvk, + gr: gr, + } +} + +func (o *objectStoreNamespaced[T]) getPrefix() string { + return fmt.Sprintf("%s/%s/%s/", o.gvk.Group, o.gvk.Version, o.gvk.Kind) +} + +func (o *objectStoreNamespaced[T]) getKey(name, namespace string) string { + if o.namespaced { + return fmt.Sprintf("%s %s/%s", o.getPrefix(), namespace, name) + } else { + return fmt.Sprintf("%s %s", o.getPrefix(), name) + } +} + +func (o *objectStoreNamespaced[T]) Get(ctx context.Context, name, namespace string) (T, error) { + o.Lock() + defer o.Unlock() + + var obj T + key := o.getKey(name, namespace) + resp, err := o.etcdclient.Get(ctx, key) + if err != nil { + klog.ErrorS(err, "failed to get report kind=%s", o.gvk.String()) + return obj, err + } + klog.InfoS("get resp resp=%+v", resp) + if len(resp.Kvs) != 1 { + return obj, errors.NewNotFound(o.gr, key) + } + err = json.Unmarshal(resp.Kvs[0].Value, &obj) + if err != nil { + klog.ErrorS(err, "failed to marshal report kind=%s", o.gvk.String()) + return obj, errors.NewNotFound(o.gr, key) + } + return obj, nil +} + +func (o *objectStoreNamespaced[T]) List(ctx context.Context, namespace string) ([]T, error) { + o.Lock() + defer o.Unlock() + + var objects []T + key := o.getPrefix() + resp, err := o.etcdclient.Get(ctx, key, clientv3.WithPrefix()) + if err != nil { + klog.ErrorS(err, "failed to list report kind=%s", o.gvk.String()) + return objects, err + } + klog.InfoS("list resp resp=%+v", resp) + if len(resp.Kvs) == 0 { + return objects, nil + } + objects = make([]T, 0, len(resp.Kvs)) + for _, v := range resp.Kvs { + var obj T + err = json.Unmarshal(v.Value, &obj) + if err != nil { + return objects, errors.NewNotFound(o.gr, key) + } + objects = append(objects, obj) + } + return objects, nil +} + +func (o *objectStoreNamespaced[T]) Create(ctx context.Context, obj T) error { + o.Lock() + defer o.Unlock() + + key := o.getKey(obj.GetName(), obj.GetNamespace()) + resp, err := o.etcdclient.Get(ctx, key) + if err != nil { + klog.ErrorS(err, "failed to create report kind=%s", o.gvk.String()) + return err + } + klog.InfoS("create resp resp=%+v", resp) + if len(resp.Kvs) > 0 { + return errors.NewAlreadyExists(o.gr, key) + } + + bObject, err := json.Marshal(obj) + if err != nil { + return err + } + + _, err = o.etcdclient.Put(ctx, key, string(bObject)) + if err != nil { + return err + } + return nil +} + +func (o *objectStoreNamespaced[T]) Update(ctx context.Context, obj T) error { + o.Lock() + defer o.Unlock() + + key := o.getKey(obj.GetName(), obj.GetNamespace()) + resp, err := o.etcdclient.Get(ctx, key) + if err != nil { + klog.ErrorS(err, "failed to update report kind=%s", o.gvk.String()) + return err + } + if len(resp.Kvs) != 1 { + return errors.NewNotFound(o.gr, key) + } + + bObject, err := json.Marshal(obj) + if err != nil { + return err + } + + _, err = o.etcdclient.Put(ctx, key, string(bObject)) + if err != nil { + return err + } + return nil +} + +func (o *objectStoreNamespaced[T]) Delete(ctx context.Context, name, namespace string) error { + o.Lock() + defer o.Unlock() + + key := o.getKey(name, namespace) + resp, err := o.etcdclient.Delete(ctx, key) + if err != nil { + klog.ErrorS(err, "failed to delete report kind=%s", o.gvk.String()) + return err + } + if resp.Deleted == 0 { + return errors.NewNotFound(o.gr, key) + } + + return nil +} + +type ObjectStorageCluster[T metav1.Object] interface { + Get(ctx context.Context, name string) (T, error) + List(ctx context.Context) ([]T, error) + Create(ctx context.Context, obj T) error + Update(ctx context.Context, obj T) error + Delete(ctx context.Context, name string) error +} + +type objectStoreCluster[T metav1.Object] struct { + store ObjectStorageNamespaced[T] +} + +func NewObjectStoreCluster[T metav1.Object](client clientv3.KV, gvk schema.GroupVersionKind, gr schema.GroupResource) ObjectStorageCluster[T] { + return &objectStoreCluster[T]{ + store: &objectStoreNamespaced[T]{ + namespaced: false, + etcdclient: client, + gvk: gvk, + gr: gr, + }, + } +} + +func (o *objectStoreCluster[T]) Get(ctx context.Context, name string) (T, error) { + return o.store.Get(ctx, name, "") +} + +func (o *objectStoreCluster[T]) List(ctx context.Context) ([]T, error) { + return o.store.List(ctx, "") +} + +func (o *objectStoreCluster[T]) Create(ctx context.Context, obj T) error { + return o.store.Create(ctx, obj) +} + +func (o *objectStoreCluster[T]) Update(ctx context.Context, obj T) error { + return o.store.Update(ctx, obj) +} + +func (o *objectStoreCluster[T]) Delete(ctx context.Context, name string) error { + return o.store.Delete(ctx, name, "") +} diff --git a/pkg/storage/inmemory/cpehr.go b/pkg/storage/inmemory/cpehr.go index 4e26f84..0ec8241 100644 --- a/pkg/storage/inmemory/cpehr.go +++ b/pkg/storage/inmemory/cpehr.go @@ -20,23 +20,23 @@ func (c *cephrdb) key(name string) string { return fmt.Sprintf("cephr/%s", name) } -func (c *cephrdb) List(ctx context.Context) ([]reportsv1.ClusterEphemeralReport, error) { +func (c *cephrdb) List(ctx context.Context) ([]*reportsv1.ClusterEphemeralReport, error) { c.Lock() defer c.Unlock() klog.Infof("listing all values") - res := make([]reportsv1.ClusterEphemeralReport, 0, len(c.db.Keys())) + res := make([]*reportsv1.ClusterEphemeralReport, 0, len(c.db.Keys())) for _, k := range c.db.Keys() { v, _ := c.db.Get(k) - res = append(res, *v) + res = append(res, v) } klog.Infof("list found length: %d", len(res)) return res, nil } -func (c *cephrdb) Get(ctx context.Context, name string) (reportsv1.ClusterEphemeralReport, error) { +func (c *cephrdb) Get(ctx context.Context, name string) (*reportsv1.ClusterEphemeralReport, error) { c.Lock() defer c.Unlock() @@ -44,14 +44,14 @@ func (c *cephrdb) Get(ctx context.Context, name string) (reportsv1.ClusterEpheme klog.Infof("getting value for key:%s", key) if val, _ := c.db.Get(key); val != nil { klog.Infof("value found for key:%s", key) - return *val, nil + return val, nil } else { klog.Errorf("value not found for key:%s", key) - return reportsv1.ClusterEphemeralReport{}, errors.NewNotFound(utils.ClusterEphemeralReportsGR, key) + return nil, errors.NewNotFound(utils.ClusterEphemeralReportsGR, key) } } -func (c *cephrdb) Create(ctx context.Context, cephr reportsv1.ClusterEphemeralReport) error { +func (c *cephrdb) Create(ctx context.Context, cephr *reportsv1.ClusterEphemeralReport) error { c.Lock() defer c.Unlock() @@ -62,11 +62,11 @@ func (c *cephrdb) Create(ctx context.Context, cephr reportsv1.ClusterEphemeralRe return errors.NewAlreadyExists(utils.ClusterEphemeralReportsGR, key) } else { klog.Infof("entry created for key:%s", key) - return c.db.Store(key, cephr) + return c.db.Store(key, *cephr) } } -func (c *cephrdb) Update(ctx context.Context, cephr reportsv1.ClusterEphemeralReport) error { +func (c *cephrdb) Update(ctx context.Context, cephr *reportsv1.ClusterEphemeralReport) error { c.Lock() defer c.Unlock() @@ -77,7 +77,7 @@ func (c *cephrdb) Update(ctx context.Context, cephr reportsv1.ClusterEphemeralRe return errors.NewNotFound(utils.ClusterEphemeralReportsGR, key) } else { klog.Infof("entry updated for key:%s", key) - return c.db.Store(key, cephr) + return c.db.Store(key, *cephr) } } diff --git a/pkg/storage/inmemory/cpolr.go b/pkg/storage/inmemory/cpolr.go index 9ea5f3e..f836e33 100644 --- a/pkg/storage/inmemory/cpolr.go +++ b/pkg/storage/inmemory/cpolr.go @@ -20,23 +20,23 @@ func (c *cpolrdb) key(name string) string { return fmt.Sprintf("cpolr/%s", name) } -func (c *cpolrdb) List(ctx context.Context) ([]v1alpha2.ClusterPolicyReport, error) { +func (c *cpolrdb) List(ctx context.Context) ([]*v1alpha2.ClusterPolicyReport, error) { c.Lock() defer c.Unlock() klog.Infof("listing all values") - res := make([]v1alpha2.ClusterPolicyReport, 0, len(c.db.Keys())) + res := make([]*v1alpha2.ClusterPolicyReport, 0, len(c.db.Keys())) for _, k := range c.db.Keys() { v, _ := c.db.Get(k) - res = append(res, *v) + res = append(res, v) } klog.Infof("list found length: %d", len(res)) return res, nil } -func (c *cpolrdb) Get(ctx context.Context, name string) (v1alpha2.ClusterPolicyReport, error) { +func (c *cpolrdb) Get(ctx context.Context, name string) (*v1alpha2.ClusterPolicyReport, error) { c.Lock() defer c.Unlock() @@ -44,14 +44,14 @@ func (c *cpolrdb) Get(ctx context.Context, name string) (v1alpha2.ClusterPolicyR klog.Infof("getting value for key:%s", key) if val, _ := c.db.Get(key); val != nil { klog.Infof("value found for key:%s", key) - return *val, nil + return val, nil } else { klog.Errorf("value not found for key:%s", key) - return v1alpha2.ClusterPolicyReport{}, errors.NewNotFound(utils.ClusterPolicyReportsGR, key) + return nil, errors.NewNotFound(utils.ClusterPolicyReportsGR, key) } } -func (c *cpolrdb) Create(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport) error { +func (c *cpolrdb) Create(ctx context.Context, cpolr *v1alpha2.ClusterPolicyReport) error { c.Lock() defer c.Unlock() @@ -62,11 +62,11 @@ func (c *cpolrdb) Create(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport return errors.NewAlreadyExists(utils.ClusterPolicyReportsGR, key) } else { klog.Infof("entry created for key:%s", key) - return c.db.Store(key, cpolr) + return c.db.Store(key, *cpolr) } } -func (c *cpolrdb) Update(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport) error { +func (c *cpolrdb) Update(ctx context.Context, cpolr *v1alpha2.ClusterPolicyReport) error { c.Lock() defer c.Unlock() @@ -77,7 +77,7 @@ func (c *cpolrdb) Update(ctx context.Context, cpolr v1alpha2.ClusterPolicyReport return errors.NewNotFound(utils.ClusterPolicyReportsGR, key) } else { klog.Infof("entry updated for key:%s", key) - return c.db.Store(key, cpolr) + return c.db.Store(key, *cpolr) } } diff --git a/pkg/storage/inmemory/ephr.go b/pkg/storage/inmemory/ephr.go index bc291a3..ad9007d 100644 --- a/pkg/storage/inmemory/ephr.go +++ b/pkg/storage/inmemory/ephr.go @@ -21,17 +21,17 @@ func (e *ephrdb) key(name, namespace string) string { return fmt.Sprintf("ephr/%s/%s", namespace, name) } -func (e *ephrdb) List(ctx context.Context, namespace string) ([]reportsv1.EphemeralReport, error) { +func (e *ephrdb) List(ctx context.Context, namespace string) ([]*reportsv1.EphemeralReport, error) { e.Lock() defer e.Unlock() klog.Infof("listing all values for namespace:%s", namespace) - res := make([]reportsv1.EphemeralReport, 0) + res := make([]*reportsv1.EphemeralReport, 0) for _, k := range e.db.Keys() { if namespace == "" || strings.HasPrefix(k, fmt.Sprintf("ephr/%s/", namespace)) { v, _ := e.db.Get(k) - res = append(res, *v) + res = append(res, v) klog.Infof("value found for prefix:%s, key:%s", namespace, k) } } @@ -40,7 +40,7 @@ func (e *ephrdb) List(ctx context.Context, namespace string) ([]reportsv1.Epheme return res, nil } -func (e *ephrdb) Get(ctx context.Context, name, namespace string) (reportsv1.EphemeralReport, error) { +func (e *ephrdb) Get(ctx context.Context, name, namespace string) (*reportsv1.EphemeralReport, error) { e.Lock() defer e.Unlock() @@ -48,14 +48,14 @@ func (e *ephrdb) Get(ctx context.Context, name, namespace string) (reportsv1.Eph klog.Infof("getting value for key:%s", key) if val, _ := e.db.Get(key); val != nil { klog.Infof("value found for key:%s", key) - return *val, nil + return val, nil } else { klog.Errorf("value not found for key:%s", key) - return reportsv1.EphemeralReport{}, errors.NewNotFound(utils.EphemeralReportsGR, key) + return nil, errors.NewNotFound(utils.EphemeralReportsGR, key) } } -func (e *ephrdb) Create(ctx context.Context, ephr reportsv1.EphemeralReport) error { +func (e *ephrdb) Create(ctx context.Context, ephr *reportsv1.EphemeralReport) error { e.Lock() defer e.Unlock() @@ -66,11 +66,11 @@ func (e *ephrdb) Create(ctx context.Context, ephr reportsv1.EphemeralReport) err return errors.NewAlreadyExists(utils.EphemeralReportsGR, key) } else { klog.Infof("entry created for key:%s", key) - return e.db.Store(key, ephr) + return e.db.Store(key, *ephr) } } -func (e *ephrdb) Update(ctx context.Context, ephr reportsv1.EphemeralReport) error { +func (e *ephrdb) Update(ctx context.Context, ephr *reportsv1.EphemeralReport) error { e.Lock() defer e.Unlock() @@ -81,7 +81,7 @@ func (e *ephrdb) Update(ctx context.Context, ephr reportsv1.EphemeralReport) err return errors.NewNotFound(utils.EphemeralReportsGR, key) } else { klog.Infof("entry updated for key:%s", key) - return e.db.Store(key, ephr) + return e.db.Store(key, *ephr) } } diff --git a/pkg/storage/inmemory/polr.go b/pkg/storage/inmemory/polr.go index e6890e6..8586226 100644 --- a/pkg/storage/inmemory/polr.go +++ b/pkg/storage/inmemory/polr.go @@ -21,12 +21,12 @@ func (p *polrdb) key(name, namespace string) string { return fmt.Sprintf("polr/%s/%s", namespace, name) } -func (p *polrdb) List(ctx context.Context, namespace string) ([]v1alpha2.PolicyReport, error) { +func (p *polrdb) List(ctx context.Context, namespace string) ([]*v1alpha2.PolicyReport, error) { p.Lock() defer p.Unlock() klog.Infof("listing all values for namespace:%s", namespace) - res := make([]v1alpha2.PolicyReport, 0) + res := make([]*v1alpha2.PolicyReport, 0) for _, k := range p.db.Keys() { if namespace == "" || strings.HasPrefix(k, fmt.Sprintf("polr/%s/", namespace)) { @@ -36,7 +36,7 @@ func (p *polrdb) List(ctx context.Context, namespace string) ([]v1alpha2.PolicyR klog.Errorf("failed to get data from inmemory db: %v", err) return nil, err } - res = append(res, *v) + res = append(res, v) } } @@ -44,7 +44,7 @@ func (p *polrdb) List(ctx context.Context, namespace string) ([]v1alpha2.PolicyR return res, nil } -func (p *polrdb) Get(ctx context.Context, name, namespace string) (v1alpha2.PolicyReport, error) { +func (p *polrdb) Get(ctx context.Context, name, namespace string) (*v1alpha2.PolicyReport, error) { p.Lock() defer p.Unlock() @@ -52,14 +52,14 @@ func (p *polrdb) Get(ctx context.Context, name, namespace string) (v1alpha2.Poli klog.Infof("getting value for key:%s", key) if val, _ := p.db.Get(key); val != nil { klog.Infof("value found for key:%s", key) - return *val, nil + return val, nil } else { klog.Errorf("value not found for key:%s", key) - return v1alpha2.PolicyReport{}, errors.NewNotFound(utils.PolicyReportsGR, key) + return nil, errors.NewNotFound(utils.PolicyReportsGR, key) } } -func (p *polrdb) Create(ctx context.Context, polr v1alpha2.PolicyReport) error { +func (p *polrdb) Create(ctx context.Context, polr *v1alpha2.PolicyReport) error { p.Lock() defer p.Unlock() @@ -70,11 +70,11 @@ func (p *polrdb) Create(ctx context.Context, polr v1alpha2.PolicyReport) error { return errors.NewAlreadyExists(utils.PolicyReportsGR, key) } else { klog.Infof("entry created for key:%s", key) - return p.db.Store(key, polr) + return p.db.Store(key, *polr) } } -func (p *polrdb) Update(ctx context.Context, polr v1alpha2.PolicyReport) error { +func (p *polrdb) Update(ctx context.Context, polr *v1alpha2.PolicyReport) error { p.Lock() defer p.Unlock() @@ -85,7 +85,7 @@ func (p *polrdb) Update(ctx context.Context, polr v1alpha2.PolicyReport) error { return errors.NewNotFound(utils.PolicyReportsGR, key) } else { klog.Infof("entry updated for key:%s", key) - return p.db.Store(key, polr) + return p.db.Store(key, *polr) } } diff --git a/pkg/storage/store.go b/pkg/storage/store.go index c350d33..abe1d22 100644 --- a/pkg/storage/store.go +++ b/pkg/storage/store.go @@ -3,7 +3,7 @@ package storage import ( "github.com/kyverno/reports-server/pkg/storage/api" "github.com/kyverno/reports-server/pkg/storage/db" - "github.com/kyverno/reports-server/pkg/storage/inmemory" + "github.com/kyverno/reports-server/pkg/storage/etcd" "k8s.io/klog/v2" ) @@ -12,21 +12,24 @@ type Interface interface { api.Storage } -func New(debug bool, config *db.PostgresConfig, clusterId string) (Interface, error) { - klog.Infof("setting up storage, debug=%v", debug) - if debug { - return &store{ - db: inmemory.New(), - versioning: NewVersioning(), - }, nil +func New(embedded bool, config *db.PostgresConfig, clusterId string, etcdCfg *etcd.EtcdConfig) (Interface, error) { + klog.Infof("setting up storage, debug=%v", embedded) + var storage api.Storage + var err error + if embedded { + storage, err = etcd.New(etcdCfg) + if err != nil { + return nil, err + } + } else { + storage, err = db.New(config, clusterId) + if err != nil { + return nil, err + } } - db, err := db.New(config, clusterId) - if err != nil { - return nil, err - } return &store{ - db: db, + db: storage, versioning: NewVersioning(), }, nil } diff --git a/pkg/utils/constants.go b/pkg/utils/constants.go index 624e92f..5d690ca 100644 --- a/pkg/utils/constants.go +++ b/pkg/utils/constants.go @@ -10,4 +10,9 @@ var ( ClusterEphemeralReportsGR = reportsv1.Resource("clusterephemeralreports") PolicyReportsGR = v1alpha2.Resource("policyreports") ClusterPolicyReportsGR = v1alpha2.Resource("clusterephemeralreports") + + EphemeralReportsGVK = reportsv1.SchemeGroupVersion.WithKind("EphemeralReport") + ClusterEphemeralReportsGVK = reportsv1.SchemeGroupVersion.WithKind("ClusterEphemeralReport") + PolicyReportsGVK = v1alpha2.SchemeGroupVersion.WithKind("PolicyReport") + ClusterPolicyReportsGVK = v1alpha2.SchemeGroupVersion.WithKind("ClusterEphemeralReport") )