Skip to content

Commit

Permalink
Implement the label and annotation overwriting for service (knative#1033
Browse files Browse the repository at this point in the history
)

* Add the ServiceDeployment into the APIs

* Implement the ServicesTransformer

* Update the deps and manifests

* Update the CRDs with the new field services
  • Loading branch information
Vincent authored Apr 12, 2022
1 parent fb31b0a commit f7f71c5
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 0 deletions.
19 changes: 19 additions & 0 deletions config/crd/bases/operator.knative.dev_knativeeventings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1664,6 +1664,25 @@ spec:
type: object
type: object
type: array
services:
description: A mapping of service name to override
type: array
items:
type: object
properties:
name:
description: The name of the service
type: string
labels:
additionalProperties:
type: string
description: Labels overrides labels for the service
type: object
annotations:
additionalProperties:
type: string
description: Annotations overrides labels for the service
type: object
source:
description: The source configuration for Knative Eventing
properties:
Expand Down
19 changes: 19 additions & 0 deletions config/crd/bases/operator.knative.dev_knativeservings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1696,6 +1696,25 @@ spec:
type: object
type: object
type: array
services:
description: A mapping of service name to override
type: array
items:
type: object
properties:
name:
description: The name of the service
type: string
labels:
additionalProperties:
type: string
description: Labels overrides labels for the service
type: object
annotations:
additionalProperties:
type: string
description: Annotations overrides labels for the service
type: object
ingress:
description: The ingress configuration for Knative Serving
properties:
Expand Down
26 changes: 26 additions & 0 deletions pkg/apis/operator/base/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ type KComponentSpec interface {

// GetDeploymentOverride gets the deployment configurations to override.
GetDeploymentOverride() []DeploymentOverride

// GetServiceOverride gets the service configurations to override.
GetServiceOverride() []ServiceOverride
}

// KComponentStatus is a common interface for status mutations of all known types.
Expand Down Expand Up @@ -134,6 +137,10 @@ type CommonSpec struct {
// +optional
DeploymentOverride []DeploymentOverride `json:"deployments,omitempty"`

// ServiceOverride overrides Service configurations such as labels and annotations.
// +optional
ServiceOverride []ServiceOverride `json:"services,omitempty"`

// Override containers' resource requirements
// +optional
Version string `json:"version,omitempty"`
Expand Down Expand Up @@ -191,6 +198,11 @@ func (c *CommonSpec) GetDeploymentOverride() []DeploymentOverride {
return c.DeploymentOverride
}

// GetServiceOverride implements KComponentSpec.
func (c *CommonSpec) GetServiceOverride() []ServiceOverride {
return c.ServiceOverride
}

// ConfigMapData is a nested map of maps representing all upstream ConfigMaps. The first
// level key is the key to the ConfigMap itself (i.e. "logging") while the second level
// is the data to be filled into the respective ConfigMap.
Expand Down Expand Up @@ -252,6 +264,20 @@ type DeploymentOverride struct {
Resources []ResourceRequirementsOverride `json:"resources,omitempty"`
}

// ServiceOverride defines the configurations of the service to override.
type ServiceOverride struct {
// Name is the name of the service to override.
Name string `json:"name"`

// Labels overrides labels for the service and its template.
// +optional
Labels map[string]string `json:"labels,omitempty"`

// Annotations overrides labels for the service and its template.
// +optional
Annotations map[string]string `json:"annotations,omitempty"`
}

// ResourceRequirementsOverride enables the user to override any container's
// resource requests/limits specified in the embedded manifest
type ResourceRequirementsOverride struct {
Expand Down
37 changes: 37 additions & 0 deletions pkg/apis/operator/base/zz_generated.deepcopy.go

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

73 changes: 73 additions & 0 deletions pkg/reconciler/common/services_override.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
Copyright 2022 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package common

import (
mf "github.com/manifestival/manifestival"
"go.uber.org/zap"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/kubernetes/scheme"
"knative.dev/operator/pkg/apis/operator/base"
)

// ServicesTransform transforms services based on the configuration in `spec.service`.
func ServicesTransform(obj base.KComponent, log *zap.SugaredLogger) mf.Transformer {
overrides := obj.GetSpec().GetServiceOverride()
if overrides == nil {
return nil
}
return func(u *unstructured.Unstructured) error {
for _, override := range overrides {
if u.GetKind() == "Service" && u.GetName() == override.Name {
service := &corev1.Service{}
if err := scheme.Scheme.Convert(u, service, nil); err != nil {
return err
}
overrideLabels(&override, service)
overrideAnnotations(&override, service)
if err := scheme.Scheme.Convert(service, u, nil); err != nil {
return err
}
// Avoid superfluous updates from converted zero defaults
u.SetCreationTimestamp(metav1.Time{})
}
}
return nil
}
}

func overrideAnnotations(override *base.ServiceOverride, service *corev1.Service) {
if service.GetAnnotations() == nil {
service.Annotations = map[string]string{}
}

for key, val := range override.Annotations {
service.Annotations[key] = val
}
}

func overrideLabels(override *base.ServiceOverride, service *corev1.Service) {
if service.GetLabels() == nil {
service.Labels = map[string]string{}
}

for key, val := range override.Labels {
service.Labels[key] = val
}
}
103 changes: 103 additions & 0 deletions pkg/reconciler/common/services_override_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
Copyright 2022 The Knative Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package common

import (
"testing"

corev1 "k8s.io/api/core/v1"

"github.com/google/go-cmp/cmp"
mf "github.com/manifestival/manifestival"
"k8s.io/client-go/kubernetes/scheme"
"knative.dev/operator/pkg/apis/operator/base"
servingv1beta1 "knative.dev/operator/pkg/apis/operator/v1beta1"
)

type expServices struct {
expLabels map[string]string
expAnnotations map[string]string
}

func TestServicesTransform(t *testing.T) {
tests := []struct {
name string
override []base.ServiceOverride
expServices map[string]expServices
}{{
name: "simple override",
override: []base.ServiceOverride{
{
Name: "controller",
Labels: map[string]string{"a": "b"},
Annotations: map[string]string{"c": "d"},
},
},
expServices: map[string]expServices{"controller": {
expLabels: map[string]string{"serving.knative.dev/release": "v0.13.0", "a": "b", "app": "controller"},
expAnnotations: map[string]string{"c": "d"},
}},
}, {
name: "no override",
override: nil,
expServices: map[string]expServices{"controller": {
expLabels: map[string]string{"serving.knative.dev/release": "v0.13.0", "app": "controller"},
expAnnotations: nil,
}},
}}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
manifest, err := mf.NewManifest("testdata/manifest.yaml")
if err != nil {
t.Fatalf("Failed to create manifest: %v", err)
}

ks := &servingv1beta1.KnativeServing{
Spec: servingv1beta1.KnativeServingSpec{
CommonSpec: base.CommonSpec{
ServiceOverride: test.override,
},
},
}

manifest, err = manifest.Transform(ServicesTransform(ks, log))
if err != nil {
t.Fatalf("Failed to transform manifest: %v", err)
}

for expName, d := range test.expServices {
for _, u := range manifest.Resources() {
if u.GetKind() == "Service" && u.GetName() == expName {
got := &corev1.Service{}
if err := scheme.Scheme.Convert(&u, got, nil); err != nil {
t.Fatalf("Failed to convert unstructured to deployment: %v", err)
}

if diff := cmp.Diff(got.GetLabels(), d.expLabels); diff != "" {
t.Fatalf("Unexpected labels: %v", diff)
}

if diff := cmp.Diff(got.GetAnnotations(), d.expAnnotations); diff != "" {
t.Fatalf("Unexpected annotations: %v", diff)
}
}
}
}
})
}
}
1 change: 1 addition & 0 deletions pkg/reconciler/common/transformers.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func transformers(ctx context.Context, obj base.KComponent) []mf.Transformer {
ConfigMapTransform(obj.GetSpec().GetConfig(), logger),
ResourceRequirementsTransform(obj, logger),
DeploymentsTransform(obj, logger),
ServicesTransform(obj, logger),
}
}

Expand Down

0 comments on commit f7f71c5

Please sign in to comment.