Skip to content

Commit

Permalink
Merge pull request #584 from application-stacks/bug-160
Browse files Browse the repository at this point in the history
Validate ServiceMonitor config before update or creation
  • Loading branch information
kabicin authored Oct 24, 2023
2 parents d736b27 + b313362 commit 922d2a5
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 0 deletions.
4 changes: 4 additions & 0 deletions controllers/runtimecomponent_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,10 @@ func (r *RuntimeComponentReconciler) Reconcile(ctx context.Context, req ctrl.Req
r.ManageError(err, common.StatusConditionTypeReconciled, instance)
} else if ok {
if instance.Spec.Monitoring != nil && (instance.Spec.CreateKnativeService == nil || !*instance.Spec.CreateKnativeService) {
// Validate the monitoring endpoints' configuration before creating/updating the ServiceMonitor
if err := appstacksutils.ValidatePrometheusMonitoringEndpoints(instance, r.GetClient(), instance.GetNamespace()); err != nil {
return r.ManageError(err, common.StatusConditionTypeReconciled, instance)
}
sm := &prometheusv1.ServiceMonitor{ObjectMeta: defaultMeta}
err = r.CreateOrUpdate(sm, instance, func() error {
appstacksutils.CustomizeServiceMonitor(sm, instance)
Expand Down
89 changes: 89 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -959,6 +959,95 @@ func Validate(ba common.BaseComponent) (bool, error) {
return true, nil
}

func Contains(list []string, s string) bool {
for _, v := range list {
if v == s {
return true
}
}
return false
}

func appendNameIfUnique(names []string, name string) []string {
if len(name) > 0 && !Contains(names, name) {
return append(names, name)
}
return names
}

// Returns true if the ConfigMap is not specified as optional, otherwise return false.
func configMapShouldExist(configMapKeySelector corev1.ConfigMapKeySelector) bool {
return configMapKeySelector.Optional == nil || !*configMapKeySelector.Optional
}

// Returns true if the Secret is not specified as optional, otherwise return false.
func secretShouldExist(secretKeySelector corev1.SecretKeySelector) bool {
return secretKeySelector.Optional == nil || !*secretKeySelector.Optional
}

// Returns an error if any user specified non-optional Secret or ConfigMap for Prometheus monitoring does not exist, otherwise return nil.
func ValidatePrometheusMonitoringEndpoints(ba common.BaseComponent, client client.Client, namespace string) error {
var basicAuth *prometheusv1.BasicAuth
var oauth2 *prometheusv1.OAuth2
var bearerTokenSecret corev1.SecretKeySelector
var authorization *prometheusv1.SafeAuthorization
monitoring := ba.GetMonitoring()
if monitoring != nil {
for _, endpoint := range monitoring.GetEndpoints() {
var secretNames []string
var configMapNames []string
// BasicAuth
basicAuth = endpoint.BasicAuth
if basicAuth != nil {
if secretShouldExist(basicAuth.Username) {
secretNames = appendNameIfUnique(secretNames, basicAuth.Username.Name)
}
if secretShouldExist(basicAuth.Password) {
secretNames = appendNameIfUnique(secretNames, basicAuth.Password.Name)
}
}
// OAuth2
oauth2 = endpoint.OAuth2
if oauth2 != nil {
if oauth2.ClientID.Secret != nil && secretShouldExist(*oauth2.ClientID.Secret) {
secretNames = appendNameIfUnique(secretNames, oauth2.ClientID.Secret.Name)
}
if oauth2.ClientID.ConfigMap != nil && configMapShouldExist(*oauth2.ClientID.ConfigMap) {
configMapNames = appendNameIfUnique(configMapNames, oauth2.ClientID.ConfigMap.Name)
}
if secretShouldExist(oauth2.ClientSecret) {
secretNames = appendNameIfUnique(secretNames, oauth2.ClientSecret.Name)
}
}
// BearerTokenSecret
bearerTokenSecret = endpoint.BearerTokenSecret
if secretShouldExist(bearerTokenSecret) {
secretNames = appendNameIfUnique(secretNames, bearerTokenSecret.Name)
}
// Authorization
authorization = endpoint.Authorization
if authorization != nil && authorization.Credentials != nil && secretShouldExist(*authorization.Credentials) {
secretNames = appendNameIfUnique(secretNames, authorization.Credentials.Name)
}
// Error if any Secret is specified but does not exist
for _, secretName := range secretNames {
if err := client.Get(context.TODO(), types.NamespacedName{Name: secretName, Namespace: namespace}, &corev1.Secret{}); err != nil {
errorMessage := fmt.Sprintf("Could not find Secret '%s' in this namespace.", secretName)
return errors.New(errorMessage)
}
}
// Error if any ConfigMap is specified but does not exist
for _, configMapName := range configMapNames {
if err := client.Get(context.TODO(), types.NamespacedName{Name: configMapName, Namespace: namespace}, &corev1.ConfigMap{}); err != nil {
errorMessage := fmt.Sprintf("Could not find ConfigMap '%s' in this namespace.", configMapName)
return errors.New(errorMessage)
}
}
}
}
return nil
}

func createValidationError(msg string) error {
return fmt.Errorf("validation failed: " + msg)
}
Expand Down

0 comments on commit 922d2a5

Please sign in to comment.