Skip to content

Commit

Permalink
Merge pull request #786 from weisdd/feature/credentials-annotation
Browse files Browse the repository at this point in the history
feat: regenerate grafana deployment when credentials get changed
  • Loading branch information
pb82 committed Jul 12, 2022
2 parents 1640704 + e945ca1 commit 32bfcb1
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 36 deletions.
2 changes: 2 additions & 0 deletions controllers/constants/constants.go
Expand Up @@ -22,7 +22,9 @@ const (
GrafanaHealthEndpoint = "/api/health"
GrafanaPodLabel = "grafana"
LastConfigAnnotation = "last-config"
LastCredentialsAnnotation = "last-credentials"
LastConfigEnvVar = "LAST_CONFIG"
LastCredentialsEnvVar = "LAST_CREDENTIALS"
LastDatasourcesConfigEnvVar = "LAST_DATASOURCES"
GrafanaAdminSecretName = "grafana-admin-credentials" // #nosec G101
DefaultAdminUser = "admin"
Expand Down
24 changes: 16 additions & 8 deletions controllers/grafana/grafana_reconciler.go
Expand Up @@ -14,10 +14,11 @@ import (
)

type GrafanaReconciler struct {
DsHash string
ConfigHash string
PluginsEnv string
Plugins *PluginsHelperImpl
DsHash string
ConfigHash string
CredentialsHash string
PluginsEnv string
Plugins *PluginsHelperImpl
}

func NewGrafanaReconciler() *GrafanaReconciler {
Expand Down Expand Up @@ -225,13 +226,20 @@ func (i *GrafanaReconciler) getGrafanaAdminUserSecretDesiredState(state *common.
}

if state.AdminSecret == nil {
secret := model.AdminSecret(cr)
i.CredentialsHash = secret.Annotations[constants.LastCredentialsAnnotation]

return common.GenericCreateAction{
Ref: model.AdminSecret(cr),
Ref: secret,
Msg: "create admin credentials secret",
}
}

secret := model.AdminSecretReconciled(cr, state.AdminSecret)
i.CredentialsHash = secret.Annotations[constants.LastCredentialsAnnotation]

return common.GenericUpdateAction{
Ref: model.AdminSecretReconciled(cr, state.AdminSecret),
Ref: secret,
Msg: "update admin credentials secret",
}
}
Expand Down Expand Up @@ -265,14 +273,14 @@ func (i *GrafanaReconciler) getGrafanaRouteDesiredState(state *common.ClusterSta
func (i *GrafanaReconciler) getGrafanaDeploymentDesiredState(state *common.ClusterState, cr *v1alpha1.Grafana) common.ClusterAction {
if state.GrafanaDeployment == nil {
return common.GenericCreateAction{
Ref: model.GrafanaDeployment(cr, i.ConfigHash, i.DsHash),
Ref: model.GrafanaDeployment(cr, i.ConfigHash, i.DsHash, i.CredentialsHash),
Msg: "create grafana deployment",
}
}

return common.GenericUpdateAction{
Ref: model.GrafanaDeploymentReconciled(cr, state.GrafanaDeployment,
i.ConfigHash, i.PluginsEnv, i.DsHash),
i.ConfigHash, i.PluginsEnv, i.DsHash, i.CredentialsHash),
Msg: "update grafana deployment",
}
}
Expand Down
34 changes: 28 additions & 6 deletions controllers/model/adminUserSecret.go
@@ -1,6 +1,9 @@
package model

import (
"bytes"
"crypto/sha256"
"fmt"
"os"

"github.com/grafana-operator/grafana-operator/v4/api/integreatly/v1alpha1"
Expand Down Expand Up @@ -32,34 +35,53 @@ func getAdminPassword(cr *v1alpha1.Grafana, current *v12.Secret) []byte {
return []byte(cr.Spec.Config.Security.AdminPassword)
}

func getData(cr *v1alpha1.Grafana, current *v12.Secret) map[string][]byte {
func getData(cr *v1alpha1.Grafana, current *v12.Secret) (map[string][]byte, string) {
user := getAdminUser(cr, current)
password := getAdminPassword(cr, current)

credentials := map[string][]byte{
constants.GrafanaAdminUserEnvVar: getAdminUser(cr, current),
constants.GrafanaAdminPasswordEnvVar: getAdminPassword(cr, current),
constants.GrafanaAdminUserEnvVar: user,
constants.GrafanaAdminPasswordEnvVar: password,
}

h := sha256.New()
h.Write(bytes.Join([][]byte{user, password}, []byte(":")))
hash := fmt.Sprintf("%x", h.Sum(nil))

// Make the credentials available to the environment when running the operator
// outside of the cluster
os.Setenv(constants.GrafanaAdminUserEnvVar, string(credentials[constants.GrafanaAdminUserEnvVar]))
os.Setenv(constants.GrafanaAdminPasswordEnvVar, string(credentials[constants.GrafanaAdminPasswordEnvVar]))

return credentials
return credentials, hash
}

func AdminSecret(cr *v1alpha1.Grafana) *v12.Secret {
data, hash := getData(cr, nil)

return &v12.Secret{
ObjectMeta: v1.ObjectMeta{
Name: constants.GrafanaAdminSecretName,
Namespace: cr.Namespace,
Annotations: map[string]string{
constants.LastCredentialsAnnotation: hash,
},
},
Data: getData(cr, nil),
Data: data,
Type: v12.SecretTypeOpaque,
}
}

func AdminSecretReconciled(cr *v1alpha1.Grafana, currentState *v12.Secret) *v12.Secret {
data, hash := getData(cr, currentState)

reconciled := currentState.DeepCopy()
reconciled.Data = getData(cr, currentState)
reconciled.Data = data

reconciled.Annotations = map[string]string{
constants.LastCredentialsAnnotation: hash,
}

return reconciled
}

Expand Down
46 changes: 26 additions & 20 deletions controllers/model/grafanaDeployment.go
Expand Up @@ -83,23 +83,23 @@ func getResources(cr *v1alpha1.Grafana) v13.ResourceRequirements {
}

func getAffinities(cr *v1alpha1.Grafana) *v13.Affinity {
var affinity = v13.Affinity{}
affinity := v13.Affinity{}
if cr.Spec.Deployment != nil && cr.Spec.Deployment.Affinity != nil {
affinity = *cr.Spec.Deployment.Affinity
}
return &affinity
}

func getSecurityContext(cr *v1alpha1.Grafana) *v13.PodSecurityContext {
var securityContext = v13.PodSecurityContext{}
securityContext := v13.PodSecurityContext{}
if cr.Spec.Deployment != nil && cr.Spec.Deployment.SecurityContext != nil {
securityContext = *cr.Spec.Deployment.SecurityContext
}
return &securityContext
}

func getContainerSecurityContext(cr *v1alpha1.Grafana) *v13.SecurityContext {
var containerSecurityContext = v13.SecurityContext{}
containerSecurityContext := v13.SecurityContext{}
if cr.Spec.Deployment != nil && cr.Spec.Deployment.ContainerSecurityContext != nil {
containerSecurityContext = *cr.Spec.Deployment.ContainerSecurityContext
}
Expand All @@ -118,15 +118,15 @@ func getDeploymentStrategy(cr *v1alpha1.Grafana) v1.DeploymentStrategy {
}

func getDeploymentLabels(cr *v1alpha1.Grafana) map[string]string {
var labels = map[string]string{}
labels := map[string]string{}
if cr.Spec.Deployment != nil && cr.Spec.Deployment.Labels != nil {
labels = cr.Spec.Deployment.Labels
}
return labels
}

func getDeploymentAnnotations(cr *v1alpha1.Grafana, existing map[string]string) map[string]string {
var annotations = map[string]string{}
annotations := map[string]string{}
// Add fixed annotations
annotations["prometheus.io/scrape"] = "true"
annotations["prometheus.io/port"] = fmt.Sprintf("%v", GetGrafanaPort(cr))
Expand All @@ -148,7 +148,7 @@ func getRollingUpdateStrategy() *v1.RollingUpdateDeployment {
}

func getPodAnnotations(cr *v1alpha1.Grafana, existing map[string]string) map[string]string {
var annotations = map[string]string{}
annotations := map[string]string{}
// Add fixed annotations
annotations["prometheus.io/scrape"] = "true"
annotations["prometheus.io/port"] = fmt.Sprintf("%v", GetGrafanaPort(cr))
Expand All @@ -161,7 +161,7 @@ func getPodAnnotations(cr *v1alpha1.Grafana, existing map[string]string) map[str
}

func getPodLabels(cr *v1alpha1.Grafana) map[string]string {
var labels = map[string]string{}
labels := map[string]string{}
if cr.Spec.Deployment != nil && cr.Spec.Deployment.Labels != nil {
labels = cr.Spec.Deployment.Labels
}
Expand All @@ -170,7 +170,7 @@ func getPodLabels(cr *v1alpha1.Grafana) map[string]string {
}

func getNodeSelectors(cr *v1alpha1.Grafana) map[string]string {
var nodeSelector = map[string]string{}
nodeSelector := map[string]string{}

if cr.Spec.Deployment != nil && cr.Spec.Deployment.NodeSelector != nil {
nodeSelector = cr.Spec.Deployment.NodeSelector
Expand All @@ -196,7 +196,7 @@ func getTolerations(cr *v1alpha1.Grafana) []v13.Toleration {

func getVolumes(cr *v1alpha1.Grafana) []v13.Volume { // nolint
var volumes []v13.Volume // nolint
var volumeOptional = true
volumeOptional := true

volumes = append(volumes, v13.Volume{
Name: constants.GrafanaProvisionPluginVolumeName,
Expand Down Expand Up @@ -451,7 +451,7 @@ func getVolumeMounts(cr *v1alpha1.Grafana) []v13.VolumeMount {
func getLivenessProbe(cr *v1alpha1.Grafana, delay, timeout, failure int32) *v13.Probe {
var period int32 = 10
var success int32 = 1
var scheme = v13.URISchemeHTTP
scheme := v13.URISchemeHTTP
if cr.Spec.Config.Server != nil && cr.Spec.Config.Server.Protocol == "https" {
scheme = v13.URISchemeHTTPS
}
Expand Down Expand Up @@ -499,7 +499,7 @@ func getLivenessProbe(cr *v1alpha1.Grafana, delay, timeout, failure int32) *v13.
func getReadinessProbe(cr *v1alpha1.Grafana, delay, timeout, failure int32) *v13.Probe {
var period int32 = 10
var success int32 = 1
var scheme = v13.URISchemeHTTP
scheme := v13.URISchemeHTTP
if cr.Spec.Config.Server != nil && cr.Spec.Config.Server.Protocol == "https" {
scheme = v13.URISchemeHTTPS
}
Expand Down Expand Up @@ -544,7 +544,7 @@ func getReadinessProbe(cr *v1alpha1.Grafana, delay, timeout, failure int32) *v13
}
}

func getContainers(cr *v1alpha1.Grafana, configHash, dsHash string) []v13.Container { // nolint
func getContainers(cr *v1alpha1.Grafana, configHash, dsHash, credentialsHash string) []v13.Container { // nolint
var containers []v13.Container // nolint
var image string

Expand All @@ -566,6 +566,10 @@ func getContainers(cr *v1alpha1.Grafana, configHash, dsHash string) []v13.Contai
Name: constants.LastDatasourcesConfigEnvVar,
Value: dsHash,
},
{
Name: constants.LastCredentialsEnvVar,
Value: credentialsHash,
},
}
if cr.Spec.Deployment != nil && cr.Spec.Deployment.HttpProxy != nil && cr.Spec.Deployment.HttpProxy.Enabled {
envVars = append(envVars, v13.EnvVar{
Expand Down Expand Up @@ -637,7 +641,8 @@ func getContainers(cr *v1alpha1.Grafana, configHash, dsHash string) []v13.Contai
},
Key: constants.GrafanaAdminPasswordEnvVar,
},
}})
},
})
}
}

Expand Down Expand Up @@ -682,7 +687,7 @@ func getInitContainers(cr *v1alpha1.Grafana, plugins string) []v13.Container {
}
}

var volumeName = constants.GrafanaPluginsVolumeName
volumeName := constants.GrafanaPluginsVolumeName

if cr.Spec.Deployment != nil {
for _, item := range cr.Spec.Deployment.ExtraVolumeMounts {
Expand Down Expand Up @@ -712,7 +717,7 @@ func getInitContainers(cr *v1alpha1.Grafana, plugins string) []v13.Container {
}
}

func getDeploymentSpec(cr *v1alpha1.Grafana, annotations map[string]string, configHash, plugins, dsHash string) v1.DeploymentSpec {
func getDeploymentSpec(cr *v1alpha1.Grafana, annotations map[string]string, configHash, plugins, dsHash, credentialsHash string) v1.DeploymentSpec {
return v1.DeploymentSpec{
Replicas: getReplicas(cr),
Selector: &v12.LabelSelector{
Expand All @@ -733,7 +738,7 @@ func getDeploymentSpec(cr *v1alpha1.Grafana, annotations map[string]string, conf
SecurityContext: getSecurityContext(cr),
Volumes: getVolumes(cr),
InitContainers: getInitContainers(cr, plugins),
Containers: getContainers(cr, configHash, dsHash),
Containers: getContainers(cr, configHash, dsHash, credentialsHash),
ServiceAccountName: constants.GrafanaServiceAccountName,
TerminationGracePeriodSeconds: getTerminationGracePeriod(cr),
PriorityClassName: getPodPriorityClassName(cr),
Expand All @@ -743,15 +748,15 @@ func getDeploymentSpec(cr *v1alpha1.Grafana, annotations map[string]string, conf
}
}

func GrafanaDeployment(cr *v1alpha1.Grafana, configHash, dsHash string) *v1.Deployment {
func GrafanaDeployment(cr *v1alpha1.Grafana, configHash, dsHash, credentialsHash string) *v1.Deployment {
return &v1.Deployment{
ObjectMeta: v12.ObjectMeta{
Name: constants.GrafanaDeploymentName,
Namespace: cr.Namespace,
Labels: getDeploymentLabels(cr),
Annotations: getDeploymentAnnotations(cr, nil),
},
Spec: getDeploymentSpec(cr, nil, configHash, "", dsHash),
Spec: getDeploymentSpec(cr, nil, configHash, "", dsHash, credentialsHash),
}
}

Expand All @@ -762,12 +767,13 @@ func GrafanaDeploymentSelector(cr *v1alpha1.Grafana) client.ObjectKey {
}
}

func GrafanaDeploymentReconciled(cr *v1alpha1.Grafana, currentState *v1.Deployment, configHash, plugins, dshash string) *v1.Deployment {
func GrafanaDeploymentReconciled(cr *v1alpha1.Grafana, currentState *v1.Deployment, configHash, plugins, dshash, credentialsHash string) *v1.Deployment {
reconciled := currentState.DeepCopy()
reconciled.Spec = getDeploymentSpec(cr,
currentState.Spec.Template.Annotations,
configHash,
plugins,
dshash)
dshash,
credentialsHash)
return reconciled
}
4 changes: 2 additions & 2 deletions controllers/model/grafanaDeployment_test.go
Expand Up @@ -22,7 +22,7 @@ func TestGrafanaDeployment_httpProxy(t *testing.T) {
},
},
}
deployment := GrafanaDeployment(cr, "", "")
deployment := GrafanaDeployment(cr, "", "", "")
for _, container := range deployment.Spec.Template.Spec.Containers {
if container.Name != "grafana" {
continue
Expand Down Expand Up @@ -51,7 +51,7 @@ func TestGrafanaDeployment_httpProxy(t *testing.T) {
},
},
}
deployment := GrafanaDeployment(cr, "", "")
deployment := GrafanaDeployment(cr, "", "", "")
for _, container := range deployment.Spec.Template.Spec.Containers {
if container.Name != "grafana" {
continue
Expand Down

0 comments on commit 32bfcb1

Please sign in to comment.