From 1e1f094516d1d4e9ea262e7fd2d9d5e5a3f51f30 Mon Sep 17 00:00:00 2001 From: Safwan Date: Fri, 18 Jul 2025 19:27:26 +0500 Subject: [PATCH] resolved comments and stuff --- Dockerfile | 11 +- .../chart/reloader/templates/clusterrole.yaml | 2 - .../chart/reloader/templates/deployment.yaml | 4 +- .../chart/reloader/templates/role.yaml | 35 ++++ .../chart/reloader/templates/rolebinding.yaml | 31 ++++ .../kubernetes/chart/reloader/values.yaml | 2 +- deployments/kubernetes/reloader.yaml | 35 +++- internal/pkg/util/util.go | 18 +- pkg/metainfo/metainfo.go | 166 +++++++++++------- 9 files changed, 221 insertions(+), 83 deletions(-) diff --git a/Dockerfile b/Dockerfile index a26d90e..75d292c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,12 @@ ARG TARGETARCH ARG GOPROXY ARG GOPRIVATE +ARG COMMIT +ARG VERSION +ARG BUILD_DATE +ARG ISDIRTY + + WORKDIR /workspace # Copy the Go Modules manifests @@ -30,7 +36,10 @@ RUN CGO_ENABLED=0 \ GOPROXY=${GOPROXY} \ GOPRIVATE=${GOPRIVATE} \ GO111MODULE=on \ - go build -ldflags="-s -w" -installsuffix 'static' -mod=mod -a -o manager ./ + go build -ldflags="-s -w -X github.com/stakater/Reloader/pkg/metainfo.Version=${VERSION} \ + -X github.com/stakater/Reloader/pkg/metainfo.Commit=${COMMIT} \ + -X github.com/stakater/Reloader/pkg/metainfo.BuildDate=${BUILD_DATE} \ + -X github.com/stakater/Reloader/pkg/metainfo.IsDirty=${ISDIRTY}" -installsuffix 'static' -mod=mod -a -o manager ./ # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details diff --git a/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml b/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml index 034370b..9f655aa 100644 --- a/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml +++ b/deployments/kubernetes/chart/reloader/templates/clusterrole.yaml @@ -31,8 +31,6 @@ rules: - list - get - watch - - create - - delete {{- if (include "reloader-namespaceSelector" .) }} - apiGroups: - "" diff --git a/deployments/kubernetes/chart/reloader/templates/deployment.yaml b/deployments/kubernetes/chart/reloader/templates/deployment.yaml index cad90e1..0dab7e5 100644 --- a/deployments/kubernetes/chart/reloader/templates/deployment.yaml +++ b/deployments/kubernetes/chart/reloader/templates/deployment.yaml @@ -151,9 +151,7 @@ spec: fieldPath: metadata.namespace - name: RELOADER_DEPLOYMENT_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name + value: {{ template "reloader-fullname" . }} {{- if .Values.reloader.enableHA }} - name: POD_NAME diff --git a/deployments/kubernetes/chart/reloader/templates/role.yaml b/deployments/kubernetes/chart/reloader/templates/role.yaml index 3ee14ae..dfb4c2c 100644 --- a/deployments/kubernetes/chart/reloader/templates/role.yaml +++ b/deployments/kubernetes/chart/reloader/templates/role.yaml @@ -103,3 +103,38 @@ rules: - create - patch {{- end }} + +--- + +{{- if .Values.reloader.rbac.enabled }} +{{- if (.Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1") }} +apiVersion: rbac.authorization.k8s.io/v1 +{{ else }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +{{- end }} +kind: Role +metadata: + annotations: +{{ include "reloader-helm3.annotations" . | indent 4 }} + labels: +{{ include "reloader-labels.chart" . | indent 4 }} +{{- if .Values.reloader.rbac.labels }} +{{ tpl (toYaml .Values.reloader.rbac.labels) . | indent 4 }} +{{- end }} +{{- if .Values.reloader.matchLabels }} +{{ tpl (toYaml .Values.reloader.matchLabels) . | indent 4 }} +{{- end }} + name: {{ template "reloader-fullname" . }}-metadata-role + namespace: {{ .Values.namespace | default .Release.Namespace }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - list + - get + - watch + - create + - update +{{- end }} \ No newline at end of file diff --git a/deployments/kubernetes/chart/reloader/templates/rolebinding.yaml b/deployments/kubernetes/chart/reloader/templates/rolebinding.yaml index dccff31..b1c2b05 100644 --- a/deployments/kubernetes/chart/reloader/templates/rolebinding.yaml +++ b/deployments/kubernetes/chart/reloader/templates/rolebinding.yaml @@ -27,3 +27,34 @@ subjects: name: {{ template "reloader-serviceAccountName" . }} namespace: {{ .Values.namespace | default .Release.Namespace }} {{- end }} + +--- +{{- if .Values.reloader.rbac.enabled }} +{{- if (.Capabilities.APIVersions.Has "rbac.authorization.k8s.io/v1") }} +apiVersion: rbac.authorization.k8s.io/v1 +{{ else }} +apiVersion: rbac.authorization.k8s.io/v1beta1 +{{- end }} +kind: RoleBinding +metadata: + annotations: +{{ include "reloader-helm3.annotations" . | indent 4 }} + labels: +{{ include "reloader-labels.chart" . | indent 4 }} +{{- if .Values.reloader.rbac.labels }} +{{ tpl (toYaml .Values.reloader.rbac.labels) . | indent 4 }} +{{- end }} +{{- if .Values.reloader.matchLabels }} +{{ tpl (toYaml .Values.reloader.matchLabels) . | indent 4 }} +{{- end }} + name: {{ template "reloader-fullname" . }}-metadata-role-binding + namespace: {{ .Values.namespace | default .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "reloader-fullname" . }}-metadata-role +subjects: + - kind: ServiceAccount + name: {{ template "reloader-serviceAccountName" . }} + namespace: {{ .Values.namespace | default .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/deployments/kubernetes/chart/reloader/values.yaml b/deployments/kubernetes/chart/reloader/values.yaml index 21c11a3..a6e79d1 100644 --- a/deployments/kubernetes/chart/reloader/values.yaml +++ b/deployments/kubernetes/chart/reloader/values.yaml @@ -17,7 +17,7 @@ fullnameOverride: "" image: name: stakater/reloader repository: ghcr.io/stakater/reloader - tag: v1.4.5 + tag: test-image # digest: sha256:1234567 pullPolicy: IfNotPresent diff --git a/deployments/kubernetes/reloader.yaml b/deployments/kubernetes/reloader.yaml index 6880bc3..1222d56 100644 --- a/deployments/kubernetes/reloader.yaml +++ b/deployments/kubernetes/reloader.yaml @@ -76,6 +76,37 @@ subjects: name: reloader-reloader namespace: default --- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: reloader-metadata-role + namespace: default +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - list + - get + - watch + - create + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: reloader-metadata-role-binding + namespace: default +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: reloader-metadata-role +subjects: + - kind: ServiceAccount + name: reloader-reloader + namespace: default +--- apiVersion: apps/v1 kind: Deployment metadata: @@ -110,9 +141,7 @@ spec: fieldPath: metadata.namespace - name: RELOADER_DEPLOYMENT_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name + value: default image: "ghcr.io/stakater/reloader:latest" imagePullPolicy: IfNotPresent diff --git a/internal/pkg/util/util.go b/internal/pkg/util/util.go index 5322f01..74455fa 100644 --- a/internal/pkg/util/util.go +++ b/internal/pkg/util/util.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "os" - "runtime/debug" "sort" "strings" @@ -72,14 +71,8 @@ func PublishMetaInfoConfigmap(clientset kubernetes.Interface) { return } - info, ok := debug.ReadBuildInfo() - - if !ok { - return - } - metaInfo := &metainfo.MetaInfo{ - BuildInfo: *metainfo.NewBuildInfo(info), + BuildInfo: *metainfo.NewBuildInfo(), ReloaderOptions: *metainfo.GetReloaderOptions(), DeploymentInfo: metav1.ObjectMeta{ Name: os.Getenv("RELOADER_DEPLOYMENT_NAME"), @@ -90,13 +83,12 @@ func PublishMetaInfoConfigmap(clientset kubernetes.Interface) { configMap := metaInfo.ToConfigMap() if _, err := clientset.CoreV1().ConfigMaps(namespace).Get(context.Background(), configMap.Name, metav1.GetOptions{}); err == nil { - logrus.Info("Meta info configmap already exists, deleting it") - err = clientset.CoreV1().ConfigMaps(namespace).Delete(context.Background(), configMap.Name, metav1.DeleteOptions{}) + logrus.Info("Meta info configmap already exists, updating it") + _, err = clientset.CoreV1().ConfigMaps(namespace).Update(context.Background(), configMap, metav1.UpdateOptions{}) if err != nil { - logrus.Warn("Failed to delete existing meta info configmap: ", err) - return + logrus.Warn("Failed to update existing meta info configmap: ", err) } - logrus.Info("Deleted existing meta info configmap") + return } _, err := clientset.CoreV1().ConfigMaps(namespace).Create(context.Background(), configMap, metav1.CreateOptions{}) diff --git a/pkg/metainfo/metainfo.go b/pkg/metainfo/metainfo.go index a3dece8..54b0be8 100644 --- a/pkg/metainfo/metainfo.go +++ b/pkg/metainfo/metainfo.go @@ -2,7 +2,8 @@ package metainfo import ( "encoding/json" - "runtime/debug" + "fmt" + "runtime" "strconv" "time" @@ -11,44 +12,86 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// Version, Commit, BuildDate, and IsDirty are set during the build process +// using the -X linker flag to inject these values into the binary. +// They provide metadata about the build version, commit hash, build date, and whether there are +// uncommitted changes in the source code at the time of build. +// This information is useful for debugging and tracking the specific build of the Reloader binary. +var Version = "dev" +var Commit = "unknown" +var BuildDate = "unknown" +var IsDirty = "false" + const ( MetaInfoConfigmapName = "reloader-meta-info" - MetaInfoConfigmapLabel = "reloader.stakater.com/meta-info" + MetaInfoConfigmapLabelKey = "reloader.stakater.com/meta-info" MetaInfoConfigmapLabelValue = "reloader-oss" ) +// ReloaderOptions contains all configurable options for the Reloader controller. +// These options control how Reloader behaves when watching for changes in ConfigMaps and Secrets. type ReloaderOptions struct { - AutoReloadAll bool `json:"autoReloadAll"` - ConfigmapUpdateOnChangeAnnotation string `json:"configmapUpdateOnChangeAnnotation"` - SecretUpdateOnChangeAnnotation string `json:"secretUpdateOnChangeAnnotation"` - ReloaderAutoAnnotation string `json:"reloaderAutoAnnotation"` - IgnoreResourceAnnotation string `json:"ignoreResourceAnnotation"` - ConfigmapReloaderAutoAnnotation string `json:"configmapReloaderAutoAnnotation"` - SecretReloaderAutoAnnotation string `json:"secretReloaderAutoAnnotation"` - ConfigmapExcludeReloaderAnnotation string `json:"configmapExcludeReloaderAnnotation"` - SecretExcludeReloaderAnnotation string `json:"secretExcludeReloaderAnnotation"` - AutoSearchAnnotation string `json:"autoSearchAnnotation"` - SearchMatchAnnotation string `json:"searchMatchAnnotation"` - RolloutStrategyAnnotation string `json:"rolloutStrategyAnnotation"` - LogFormat string `json:"logFormat"` - LogLevel string `json:"logLevel"` - IsArgoRollouts bool `json:"isArgoRollouts"` - ReloadStrategy string `json:"reloadStrategy"` - ReloadOnCreate bool `json:"reloadOnCreate"` - ReloadOnDelete bool `json:"reloadOnDelete"` - SyncAfterRestart bool `json:"syncAfterRestart"` - EnableHA bool `json:"enableHA"` - WebhookUrl string `json:"webhookUrl"` - ResourcesToIgnore []string `json:"resourcesToIgnore"` - NamespaceSelectors []string `json:"namespaceSelectors"` - ResourceSelectors []string `json:"resourceSelectors"` - NamespacesToIgnore []string `json:"namespacesToIgnore"` + // AutoReloadAll enables automatic reloading of all resources when their corresponding ConfigMaps/Secrets are updated + AutoReloadAll bool `json:"autoReloadAll"` + // ConfigmapUpdateOnChangeAnnotation is the annotation key used to detect changes in ConfigMaps specified by name + ConfigmapUpdateOnChangeAnnotation string `json:"configmapUpdateOnChangeAnnotation"` + // SecretUpdateOnChangeAnnotation is the annotation key used to detect changes in Secrets specified by name + SecretUpdateOnChangeAnnotation string `json:"secretUpdateOnChangeAnnotation"` + // ReloaderAutoAnnotation is the annotation key used to detect changes in any referenced ConfigMaps or Secrets + ReloaderAutoAnnotation string `json:"reloaderAutoAnnotation"` + // IgnoreResourceAnnotation is the annotation key used to ignore resources from being watched + IgnoreResourceAnnotation string `json:"ignoreResourceAnnotation"` + // ConfigmapReloaderAutoAnnotation is the annotation key used to detect changes in ConfigMaps only + ConfigmapReloaderAutoAnnotation string `json:"configmapReloaderAutoAnnotation"` + // SecretReloaderAutoAnnotation is the annotation key used to detect changes in Secrets only + SecretReloaderAutoAnnotation string `json:"secretReloaderAutoAnnotation"` + // ConfigmapExcludeReloaderAnnotation is the annotation key containing comma-separated list of ConfigMaps to exclude from watching + ConfigmapExcludeReloaderAnnotation string `json:"configmapExcludeReloaderAnnotation"` + // SecretExcludeReloaderAnnotation is the annotation key containing comma-separated list of Secrets to exclude from watching + SecretExcludeReloaderAnnotation string `json:"secretExcludeReloaderAnnotation"` + // AutoSearchAnnotation is the annotation key used to detect changes in ConfigMaps/Secrets tagged with SearchMatchAnnotation + AutoSearchAnnotation string `json:"autoSearchAnnotation"` + // SearchMatchAnnotation is the annotation key used to tag ConfigMaps/Secrets to be found by AutoSearchAnnotation + SearchMatchAnnotation string `json:"searchMatchAnnotation"` + // RolloutStrategyAnnotation is the annotation key used to define the rollout update strategy for workloads + RolloutStrategyAnnotation string `json:"rolloutStrategyAnnotation"` + // LogFormat specifies the log format to use (json, or empty string for default text format) + LogFormat string `json:"logFormat"` + // LogLevel specifies the log level to use (trace, debug, info, warning, error, fatal, panic) + LogLevel string `json:"logLevel"` + // IsArgoRollouts indicates whether support for Argo Rollouts is enabled + IsArgoRollouts bool `json:"isArgoRollouts"` + // ReloadStrategy specifies the strategy used to trigger resource reloads (env-vars or annotations) + ReloadStrategy string `json:"reloadStrategy"` + // ReloadOnCreate indicates whether to trigger reloads when ConfigMaps/Secrets are created + ReloadOnCreate bool `json:"reloadOnCreate"` + // ReloadOnDelete indicates whether to trigger reloads when ConfigMaps/Secrets are deleted + ReloadOnDelete bool `json:"reloadOnDelete"` + // SyncAfterRestart indicates whether to sync add events after Reloader restarts (only works when ReloadOnCreate is true) + SyncAfterRestart bool `json:"syncAfterRestart"` + // EnableHA indicates whether High Availability mode is enabled with leader election + EnableHA bool `json:"enableHA"` + // WebhookUrl is the URL to send webhook notifications to instead of performing reloads + WebhookUrl string `json:"webhookUrl"` + // ResourcesToIgnore is a list of resource types to ignore (e.g., "configmaps" or "secrets") + ResourcesToIgnore []string `json:"resourcesToIgnore"` + // NamespaceSelectors is a list of label selectors to filter namespaces to watch + NamespaceSelectors []string `json:"namespaceSelectors"` + // ResourceSelectors is a list of label selectors to filter ConfigMaps and Secrets to watch + ResourceSelectors []string `json:"resourceSelectors"` + // NamespacesToIgnore is a list of namespace names to ignore when watching for changes + NamespacesToIgnore []string `json:"namespacesToIgnore"` } +// MetaInfo contains comprehensive metadata about the Reloader instance. +// This includes build information, configuration options, and deployment details. type MetaInfo struct { - BuildInfo BuildInfo `json:"buildInfo"` - ReloaderOptions ReloaderOptions `json:"reloaderOptions"` - DeploymentInfo metav1.ObjectMeta `json:"deploymentInfo"` + // BuildInfo contains information about the build version, commit, and compilation details + BuildInfo BuildInfo `json:"buildInfo"` + // ReloaderOptions contains all the configuration options and flags used by this Reloader instance + ReloaderOptions ReloaderOptions `json:"reloaderOptions"` + // DeploymentInfo contains metadata about the Kubernetes deployment of this Reloader instance + DeploymentInfo metav1.ObjectMeta `json:"deploymentInfo"` } func GetReloaderOptions() *ReloaderOptions { @@ -81,34 +124,28 @@ func GetReloaderOptions() *ReloaderOptions { } } +// BuildInfo contains information about the build and version of the Reloader binary. +// This includes Go version, release version, commit details, and build timestamp. type BuildInfo struct { - GoVersion string `json:"goversion"` - Version string `json:"version"` - Checksum string `json:"checksum"` - CommitHash string `json:"commitHash"` - IsDirty bool `json:"isDirty"` + // GoVersion is the version of Go used to compile the binary + GoVersion string `json:"goVersion"` + // ReleaseVersion is the version tag or branch of the Reloader release + ReleaseVersion string `json:"releaseVersion"` + // CommitHash is the Git commit hash of the source code used to build this binary + CommitHash string `json:"commitHash"` + // IsDirty indicates whether the working directory had uncommitted changes when built + IsDirty bool `json:"isDirty"` + // CommitTime is the timestamp of the Git commit used to build this binary CommitTime time.Time `json:"commitTime"` } -func NewBuildInfo(info *debug.BuildInfo) *BuildInfo { - infoMap := make(map[string]string) - infoMap["goversion"] = info.GoVersion - infoMap["version"] = info.Main.Version - infoMap["checksum"] = info.Main.Sum - - for _, setting := range info.Settings { - if setting.Key == "vcs.revision" || setting.Key == "vcs.time" || setting.Key == "vcs.modified" { - infoMap[setting.Key] = setting.Value - } - } - +func NewBuildInfo() *BuildInfo { metaInfo := &BuildInfo{ - GoVersion: info.GoVersion, - Version: info.Main.Version, - Checksum: info.Main.Sum, - CommitHash: infoMap["vcs.revision"], - IsDirty: parseBool(infoMap["vcs.modified"]), - CommitTime: ParseTime(infoMap["vcs.time"]), + GoVersion: runtime.Version(), + ReleaseVersion: Version, + CommitHash: Commit, + IsDirty: parseBool(IsDirty), + CommitTime: ParseUTCTime(BuildDate), } return metaInfo @@ -120,7 +157,7 @@ func (m *MetaInfo) ToConfigMap() *v1.ConfigMap { Name: MetaInfoConfigmapName, Namespace: m.DeploymentInfo.Namespace, Labels: map[string]string{ - MetaInfoConfigmapLabel: MetaInfoConfigmapLabelValue, + MetaInfoConfigmapLabelKey: MetaInfoConfigmapLabelValue, }, }, Data: map[string]string{ @@ -131,27 +168,36 @@ func (m *MetaInfo) ToConfigMap() *v1.ConfigMap { } } -func NewMetaInfo(configmap *v1.ConfigMap) *MetaInfo { +func NewMetaInfo(configmap *v1.ConfigMap) (*MetaInfo, error) { var buildInfo BuildInfo if val, ok := configmap.Data["buildInfo"]; ok { - _ = json.Unmarshal([]byte(val), &buildInfo) + err := json.Unmarshal([]byte(val), &buildInfo) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal buildInfo: %w", err) + } } var reloaderOptions ReloaderOptions if val, ok := configmap.Data["reloaderOptions"]; ok { - _ = json.Unmarshal([]byte(val), &reloaderOptions) + err := json.Unmarshal([]byte(val), &reloaderOptions) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal reloaderOptions: %w", err) + } } var deploymentInfo metav1.ObjectMeta if val, ok := configmap.Data["deploymentInfo"]; ok { - _ = json.Unmarshal([]byte(val), &deploymentInfo) + err := json.Unmarshal([]byte(val), &deploymentInfo) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal deploymentInfo: %w", err) + } } return &MetaInfo{ BuildInfo: buildInfo, ReloaderOptions: reloaderOptions, DeploymentInfo: deploymentInfo, - } + }, nil } func toJson(data interface{}) string { @@ -173,7 +219,7 @@ func parseBool(value string) bool { return result } -func ParseTime(value string) time.Time { +func ParseUTCTime(value string) time.Time { if value == "" { return time.Time{} // Return zero time if value is empty }