Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ else
GOBIN=$(shell $(GO) env GOBIN)
endif

# Set sed -i as it's different for mac vs gnu
ifeq ($(shell uname -s | tr A-Z a-z), darwin)
SED_INLINE ?= sed -i ''
else
SED_INLINE ?= sed -i
endif

MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
PROJECT_PATH := $(patsubst %/,%,$(dir $(MKFILE_PATH)))

Expand Down Expand Up @@ -199,8 +206,7 @@ bundle-custom-updates: $(YQ)
$(YQ) --inplace '.spec.displayName = "$(BUNDLE_PREFIX) 3scale operator"' $(PROJECT_PATH)/bundle/manifests/3scale-operator.clusterserviceversion.yaml
$(YQ) --inplace '.spec.provider.name = "$(BUNDLE_PREFIX)"' $(PROJECT_PATH)/bundle/manifests/3scale-operator.clusterserviceversion.yaml
$(YQ) --inplace '.annotations."operators.operatorframework.io.bundle.package.v1" = "$(BUNDLE_PREFIX)-3scale-operator"' $(PROJECT_PATH)/bundle/metadata/annotations.yaml
sed -E -i 's/(operators\.operatorframework\.io\.bundle\.package\.v1=).+/\1$(BUNDLE_PREFIX)-3scale-operator/' $(PROJECT_PATH)/bundle.Dockerfile
@echo "Update operator image reference URL"
$(SED_INLINE) -E 's/(operators\.operatorframework\.io\.bundle\.package\.v1=).+/\1$(BUNDLE_PREFIX)-3scale-operator/' $(PROJECT_PATH)/bundle.Dockerfile @echo "Update operator image reference URL"
$(YQ) --inplace '.metadata.annotations.containerImage = "$(IMG)"' $(PROJECT_PATH)/bundle/manifests/3scale-operator.clusterserviceversion.yaml
$(YQ) --inplace '.spec.install.spec.deployments[0].spec.template.spec.containers[0].image = "$(IMG)"' $(PROJECT_PATH)/bundle/manifests/3scale-operator.clusterserviceversion.yaml

Expand Down
31 changes: 29 additions & 2 deletions apis/capabilities/v1beta1/product_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ const (
// ProductFailedConditionType indicates that an error occurred during synchronization.
// The operator will retry.
ProductFailedConditionType common.ConditionType = "Failed"

// ProductPolicyConfigurationPasswordSecretField indicates the secret field name with product policy configuration
ProductPolicyConfigurationPasswordSecretField = "configuration"

// ProductPolicyConfigurationDefault is the default for a product policy configuration
ProductPolicyConfigurationDefault = `{}`
)

var (
Expand All @@ -67,7 +73,7 @@ var (
Name: "apicast",
Version: "builtin",
Configuration: runtime.RawExtension{
Raw: []byte(`{}`),
Raw: []byte(ProductPolicyConfigurationDefault),
},
Enabled: true,
}
Expand Down Expand Up @@ -844,7 +850,12 @@ type PolicyConfig struct {

// Configuration defines the policy configuration
// +kubebuilder:pruning:PreserveUnknownFields
Configuration runtime.RawExtension `json:"configuration"`
// +optional
Configuration runtime.RawExtension `json:"configuration,omitempty"`

// ConfigurationRef Secret reference containing policy configuration
// +optional
ConfigurationRef corev1.SecretReference `json:"configurationRef,omitempty"`

// Enabled defines activation state
Enabled bool `json:"enabled"`
Expand Down Expand Up @@ -1225,6 +1236,22 @@ func (product *Product) SetDefaults(logger logr.Logger) bool {
updated = true
}

// Configuration must have default value to maintain backwards compatability if overwritten with older CRD
// where field is required
// Using required field and kubebuilder default was not possible due to not being able to have an empty object
// in CRD manifest
defaultConfigurationSet := false
for idx := range product.Spec.Policies {
if product.Spec.Policies[idx].Configuration.Raw == nil {
product.Spec.Policies[idx].Configuration.Raw = []byte(ProductPolicyConfigurationDefault)
defaultConfigurationSet = true
}
}

if defaultConfigurationSet {
updated = true
}

return updated
}

Expand Down
1 change: 1 addition & 0 deletions apis/capabilities/v1beta1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion bundle/manifests/capabilities.3scale.net_products.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,17 @@ spec:
description: Configuration defines the policy configuration
type: object
x-kubernetes-preserve-unknown-fields: true
configurationRef:
description: ConfigurationRef Secret reference containing policy configuration
properties:
name:
description: name is unique within a namespace to reference a secret resource.
type: string
namespace:
description: namespace defines the space within which the secret name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
enabled:
description: Enabled defines activation state
type: boolean
Expand All @@ -756,7 +767,6 @@ spec:
description: Version defines the policy version
type: string
required:
- configuration
- enabled
- name
- version
Expand Down
15 changes: 14 additions & 1 deletion config/crd/bases/capabilities.3scale.net_products.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,20 @@ spec:
description: Configuration defines the policy configuration
type: object
x-kubernetes-preserve-unknown-fields: true
configurationRef:
description: ConfigurationRef Secret reference containing policy
configuration
properties:
name:
description: name is unique within a namespace to reference
a secret resource.
type: string
namespace:
description: namespace defines the space within which the
secret name must be unique.
type: string
type: object
x-kubernetes-map-type: atomic
enabled:
description: Enabled defines activation state
type: boolean
Expand All @@ -959,7 +973,6 @@ spec:
description: Version defines the policy version
type: string
required:
- configuration
- enabled
- name
- version
Expand Down
65 changes: 55 additions & 10 deletions controllers/capabilities/product_policies.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ import (
"fmt"
"reflect"

capabilitiesv1beta1 "github.com/3scale/3scale-operator/apis/capabilities/v1beta1"
threescaleapi "github.com/3scale/3scale-porta-go-client/client"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
)

func (t *ProductThreescaleReconciler) syncPolicies(_ interface{}) error {
Expand All @@ -15,7 +18,10 @@ func (t *ProductThreescaleReconciler) syncPolicies(_ interface{}) error {
return fmt.Errorf("Error sync product [%s] policies: %w", t.resource.Spec.SystemName, err)
}

desired := t.convertResourcePolicies()
desired, err := t.convertResourcePolicies()
if err != nil {
return err
}

// Compare Go unmarshalled objects (not byte arrays)
// resilient to serialization differences like map key order differences or quotes.
Expand All @@ -33,13 +39,33 @@ func (t *ProductThreescaleReconciler) syncPolicies(_ interface{}) error {
}

// Convert Policies from []capabilitiesv1beta1.PolicyConfig to *threescaleapi.PoliciesConfigList to be comparable
func (t *ProductThreescaleReconciler) convertResourcePolicies() *threescaleapi.PoliciesConfigList {
func (t *ProductThreescaleReconciler) convertResourcePolicies() (*threescaleapi.PoliciesConfigList, error) {
policies := &threescaleapi.PoliciesConfigList{
Policies: []threescaleapi.PolicyConfig{},
}

for _, crdPolicy := range t.resource.Spec.Policies {
var configuration map[string]interface{}
configuration, err := t.convertPolicyConfiguration(crdPolicy)
if err != nil {
return nil, err
}

policies.Policies = append(policies.Policies, threescaleapi.PolicyConfig{
Name: crdPolicy.Name,
Version: crdPolicy.Version,
Enabled: crdPolicy.Enabled,
Configuration: configuration,
})
}

return policies, nil
}

func (t *ProductThreescaleReconciler) convertPolicyConfiguration(crdPolicy capabilitiesv1beta1.PolicyConfig) (map[string]interface{}, error) {
configuration := map[string]interface{}{}

// If plain value is not the default - use plain value as precedence over secret
if string(crdPolicy.Configuration.Raw) != capabilitiesv1beta1.ProductPolicyConfigurationDefault {
// CRD validation ensures no error happens
// "configuration` type is object
//properties:
Expand All @@ -49,13 +75,32 @@ func (t *ProductThreescaleReconciler) convertResourcePolicies() *threescaleapi.P
// x-kubernetes-preserve-unknown-fields: true
_ = json.Unmarshal(crdPolicy.Configuration.Raw, &configuration)

policies.Policies = append(policies.Policies, threescaleapi.PolicyConfig{
Name: crdPolicy.Name,
Version: crdPolicy.Version,
Enabled: crdPolicy.Enabled,
Configuration: configuration,
})
return configuration, nil
}

// If policy is defined in secretRef
if crdPolicy.ConfigurationRef.Name != "" {
// Get configuration from secret reference
secret := &corev1.Secret{}
namespace := t.resource.Namespace
if crdPolicy.ConfigurationRef.Namespace != "" {
namespace = crdPolicy.ConfigurationRef.Namespace
}

if err := t.Client().Get(t.Context(), types.NamespacedName{Name: crdPolicy.ConfigurationRef.Name, Namespace: namespace}, secret); err != nil {
return nil, err
}

configurationByteArray, ok := secret.Data[capabilitiesv1beta1.ProductPolicyConfigurationPasswordSecretField]
if !ok {
return nil, fmt.Errorf("not found configuration field in secret (ns: %s, name: %s) field: %s",
namespace, crdPolicy.ConfigurationRef.Name, capabilitiesv1beta1.ProductPolicyConfigurationPasswordSecretField)
}

if err := json.Unmarshal(configurationByteArray, &configuration); err != nil {
return nil, err
}
}

return policies
return configuration, nil
}
Loading