Skip to content

Commit

Permalink
Merge pull request #720 from 3scale/reconcile-apicast-environment
Browse files Browse the repository at this point in the history
Reconcile apicast environment
  • Loading branch information
eguzki authored Mar 4, 2022
2 parents e61fb4b + a9673a6 commit 3c880bc
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 13 deletions.
35 changes: 22 additions & 13 deletions pkg/3scale/amp/component/apicast.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const (

HTTPSCertificatesMountPath = "/var/run/secrets/tls"
HTTPSCertificatesVolumeName = "https-certificates"

APIcastEnvironmentConfigMapName = "apicast-environment"
)

const (
Expand Down Expand Up @@ -132,11 +134,8 @@ func (apicast *Apicast) StagingDeploymentConfig() *appsv1.DeploymentConfig {
},
Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: apicast.Options.StagingPodTemplateLabels,
Annotations: map[string]string{
"prometheus.io/scrape": "true",
"prometheus.io/port": "9421",
},
Labels: apicast.Options.StagingPodTemplateLabels,
Annotations: apicast.podAnnotations(),
},
Spec: v1.PodSpec{
Affinity: apicast.Options.StagingAffinity,
Expand Down Expand Up @@ -228,11 +227,8 @@ func (apicast *Apicast) ProductionDeploymentConfig() *appsv1.DeploymentConfig {
},
Template: &v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: apicast.Options.ProductionPodTemplateLabels,
Annotations: map[string]string{
"prometheus.io/scrape": "true",
"prometheus.io/port": "9421",
},
Labels: apicast.Options.ProductionPodTemplateLabels,
Annotations: apicast.podAnnotations(),
},
Spec: v1.PodSpec{
Affinity: apicast.Options.ProductionAffinity,
Expand Down Expand Up @@ -291,9 +287,9 @@ func (apicast *Apicast) buildApicastCommonEnv() []v1.EnvVar {
result := []v1.EnvVar{
helper.EnvVarFromSecret("THREESCALE_PORTAL_ENDPOINT", "system-master-apicast", SystemSecretSystemMasterApicastProxyConfigsEndpointFieldName),
helper.EnvVarFromSecret("BACKEND_ENDPOINT_OVERRIDE", BackendSecretBackendListenerSecretName, BackendSecretBackendListenerServiceEndpointFieldName),
helper.EnvVarFromConfigMap("APICAST_MANAGEMENT_API", "apicast-environment", "APICAST_MANAGEMENT_API"),
helper.EnvVarFromConfigMap("OPENSSL_VERIFY", "apicast-environment", "OPENSSL_VERIFY"),
helper.EnvVarFromConfigMap("APICAST_RESPONSE_CODES", "apicast-environment", "APICAST_RESPONSE_CODES"),
helper.EnvVarFromConfigMap("APICAST_MANAGEMENT_API", APIcastEnvironmentConfigMapName, "APICAST_MANAGEMENT_API"),
helper.EnvVarFromConfigMap("OPENSSL_VERIFY", APIcastEnvironmentConfigMapName, "OPENSSL_VERIFY"),
helper.EnvVarFromConfigMap("APICAST_RESPONSE_CODES", APIcastEnvironmentConfigMapName, "APICAST_RESPONSE_CODES"),
}

if apicast.Options.ExtendedMetrics {
Expand Down Expand Up @@ -810,6 +806,19 @@ func (apicast *Apicast) stagingServicePorts() []v1.ServicePort {
return ports
}

func (apicast *Apicast) podAnnotations() map[string]string {
annotations := map[string]string{
"prometheus.io/scrape": "true",
"prometheus.io/port": "9421",
}

for key, val := range apicast.Options.AdditionalPodAnnotations {
annotations[key] = val
}

return annotations
}

// AnnotationsValuesWithAnnotationKeyPrefix returns the annotation values from
// annotations whose keys have the prefix keyPrefix
func AnnotationsValuesWithAnnotationKeyPrefix(annotations map[string]string, keyPrefix string) []string {
Expand Down
2 changes: 2 additions & 0 deletions pkg/3scale/amp/component/apicast_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ type ApicastOptions struct {
StagingHTTPProxy *string
StagingHTTPSProxy *string
StagingNoProxy *string

AdditionalPodAnnotations map[string]string `validate:"required"`
}

func NewApicastOptions() *ApicastOptions {
Expand Down
28 changes: 28 additions & 0 deletions pkg/3scale/amp/operator/apicast_options_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"hash/fnv"
"strconv"

v1 "k8s.io/api/core/v1"
Expand All @@ -24,6 +25,10 @@ type ApicastOptionsProvider struct {
secretSource *helper.SecretSource
}

const (
APIcastEnvironmentCMAnnotation = "apps.3scale.net/env-configmap-hash"
)

func NewApicastOptionsProvider(apimanager *appsv1alpha1.APIManager, client client.Client) *ApicastOptionsProvider {
return &ApicastOptionsProvider{
apimanager: apimanager,
Expand Down Expand Up @@ -95,6 +100,9 @@ func (a *ApicastOptionsProvider) GetApicastOptions() (*component.ApicastOptions,

a.setProxyConfigurations()

// Pod Annotations. Used to rollout apicast deployment if any secrets/configmap changes
a.apicastOptions.AdditionalPodAnnotations = a.additionalPodAnnotations()

err = a.apicastOptions.Validate()
if err != nil {
return nil, fmt.Errorf("GetApicastOptions validating: %w", err)
Expand Down Expand Up @@ -414,3 +422,23 @@ func (a *ApicastOptionsProvider) setProductionProxyConfigurations() {
a.apicastOptions.ProductionHTTPSProxy = a.apimanager.Spec.Apicast.ProductionSpec.HTTPSProxy
a.apicastOptions.ProductionNoProxy = a.apimanager.Spec.Apicast.ProductionSpec.NoProxy
}

func (a *ApicastOptionsProvider) additionalPodAnnotations() map[string]string {
annotations := map[string]string{
APIcastEnvironmentCMAnnotation: a.envConfigMapHash(),
}

return annotations
}

// APIcast environment hash
// When any of the fields used to compute the hash change the value, the hash will change
// and the apicast deployment will rollout
func (a *ApicastOptionsProvider) envConfigMapHash() string {
h := fnv.New32a()
h.Write([]byte(a.apicastOptions.ManagementAPI))
h.Write([]byte(a.apicastOptions.OpenSSLVerify))
h.Write([]byte(a.apicastOptions.ResponseCodes))
val := h.Sum32()
return fmt.Sprint(val)
}
1 change: 1 addition & 0 deletions pkg/3scale/amp/operator/apicast_options_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ func defaultApicastOptions() *component.ApicastOptions {
Namespace: namespace,
ProductionTracingConfig: &component.APIcastTracingConfig{TracingLibrary: component.APIcastDefaultTracingLibrary},
StagingTracingConfig: &component.APIcastTracingConfig{TracingLibrary: component.APIcastDefaultTracingLibrary},
AdditionalPodAnnotations: map[string]string{APIcastEnvironmentCMAnnotation: "788712912"},
}
}

Expand Down
22 changes: 22 additions & 0 deletions pkg/3scale/amp/operator/apicast_reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func (r *ApicastReconciler) Reconcile() (reconcile.Result, error) {
apicastTracingConfigAnnotationsMutator, // Should be always after volume mutator
apicastCustomEnvAnnotationsMutator, // Should be always after volume mutator
portsMutator,
apicastPodTemplateEnvConfigMapAnnotationsMutator,
)
err = r.ReconcileDeploymentConfig(apicast.StagingDeploymentConfig(), stagingDCMutator)
if err != nil {
Expand All @@ -101,6 +102,7 @@ func (r *ApicastReconciler) Reconcile() (reconcile.Result, error) {
apicastTracingConfigAnnotationsMutator, // Should be always after volume mutator
apicastCustomEnvAnnotationsMutator, // Should be always after volume
portsMutator,
apicastPodTemplateEnvConfigMapAnnotationsMutator,
)
err = r.ReconcileDeploymentConfig(apicast.ProductionDeploymentConfig(), productionDCMutator)
if err != nil {
Expand Down Expand Up @@ -474,6 +476,26 @@ func apicastCustomEnvAnnotationsMutator(desired, existing *appsv1.DeploymentConf
return updated
}

func apicastPodTemplateEnvConfigMapAnnotationsMutator(desired, existing *appsv1.DeploymentConfig) bool {
// Only reconcile the pod annotation regarding apicast-environment hash
desiredVal, ok := desired.Spec.Template.Annotations[APIcastEnvironmentCMAnnotation]
if !ok {
return false
}

updated := false
existingVal, ok := existing.Spec.Template.Annotations[APIcastEnvironmentCMAnnotation]
if !ok || existingVal != desiredVal {
if existing.Spec.Template.Annotations == nil {
existing.Spec.Template.Annotations = map[string]string{}
}
existing.Spec.Template.Annotations[APIcastEnvironmentCMAnnotation] = desiredVal
updated = true
}

return updated
}

func Apicast(apimanager *appsv1alpha1.APIManager, cl client.Client) (*component.Apicast, error) {
optsProvider := NewApicastOptionsProvider(apimanager, cl)
opts, err := optsProvider.GetApicastOptions()
Expand Down
2 changes: 2 additions & 0 deletions pkg/3scale/amp/prometheusrules/apicast_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ func apicastOptions(ns string) (*component.ApicastOptions, error) {
o.StagingTracingConfig = &component.APIcastTracingConfig{TracingLibrary: component.APIcastDefaultTracingLibrary}
o.ProductionTracingConfig = &component.APIcastTracingConfig{TracingLibrary: component.APIcastDefaultTracingLibrary}

o.AdditionalPodAnnotations = map[string]string{}

return o, o.Validate()
}

Expand Down
1 change: 1 addition & 0 deletions pkg/3scale/amp/template/adapters/apicast.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ func (a *Apicast) options() (*component.ApicastOptions, error) {

// Currently, only used for monitoring resources. Thus, it does not apply to templates.
ao.Namespace = "${NAMESPACE}"
ao.AdditionalPodAnnotations = map[string]string{}

err := ao.Validate()
return ao, err
Expand Down

0 comments on commit 3c880bc

Please sign in to comment.