-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #6635 from sbueringer/pr-runtime-sdk-test-extensio…
…n-impl 🌱 test/extension: add first version of server lib & topology mutation
- Loading branch information
Showing
13 changed files
with
671 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
internal/controllers/topology/cluster/patches/variables/merge.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/* | ||
Copyright 2021 The Kubernetes 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 variables | ||
|
||
import ( | ||
"encoding/json" | ||
|
||
"github.com/pkg/errors" | ||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | ||
) | ||
|
||
// MergeVariableMaps merges variables. | ||
// This func is useful when merging global and template-specific variables. | ||
// NOTE: In case a variable exists in multiple maps, the variable from the latter map is preserved. | ||
// NOTE: The builtin variable object is merged instead of simply overwritten. | ||
func MergeVariableMaps(variableMaps ...map[string]apiextensionsv1.JSON) (map[string]apiextensionsv1.JSON, error) { | ||
res := make(map[string]apiextensionsv1.JSON) | ||
|
||
for _, variableMap := range variableMaps { | ||
for variableName, variableValue := range variableMap { | ||
// If the variable already exits and is the builtin variable, merge it. | ||
if _, ok := res[variableName]; ok && variableName == BuiltinsName { | ||
mergedV, err := mergeBuiltinVariables(res[variableName], variableValue) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to merge builtin variables") | ||
} | ||
res[variableName] = *mergedV | ||
continue | ||
} | ||
res[variableName] = variableValue | ||
} | ||
} | ||
|
||
return res, nil | ||
} | ||
|
||
// mergeBuiltinVariables merges builtin variable objects. | ||
// NOTE: In case a variable exists in multiple builtin variables, the variable from the latter map is preserved. | ||
func mergeBuiltinVariables(variableList ...apiextensionsv1.JSON) (*apiextensionsv1.JSON, error) { | ||
builtins := &Builtins{} | ||
|
||
// Unmarshal all variables into builtins. | ||
// NOTE: This accumulates the fields on the builtins. | ||
// Fields will be overwritten by later Unmarshals if fields are | ||
// set on multiple variables. | ||
for _, variable := range variableList { | ||
if err := json.Unmarshal(variable.Raw, builtins); err != nil { | ||
return nil, errors.Wrapf(err, "failed to unmarshal builtin variable") | ||
} | ||
} | ||
|
||
// Marshal builtins to JSON. | ||
builtinVariableJSON, err := json.Marshal(builtins) | ||
if err != nil { | ||
return nil, errors.Wrapf(err, "failed to marshal builtin variable") | ||
} | ||
|
||
return &apiextensionsv1.JSON{ | ||
Raw: builtinVariableJSON, | ||
}, nil | ||
} |
51 changes: 51 additions & 0 deletions
51
internal/controllers/topology/cluster/patches/variables/merge_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* | ||
Copyright 2021 The Kubernetes 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 variables | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/gomega" | ||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | ||
) | ||
|
||
func TestMergeVariables(t *testing.T) { | ||
t.Run("Merge variables", func(t *testing.T) { | ||
g := NewWithT(t) | ||
|
||
m, err := MergeVariableMaps( | ||
map[string]apiextensionsv1.JSON{ | ||
BuiltinsName: {Raw: []byte(`{"cluster":{"name":"cluster-name","namespace":"default","topology":{"class":"clusterClass1","version":"v1.21.1"}}}`)}, | ||
"a": {Raw: []byte("a-different")}, | ||
"c": {Raw: []byte("c")}, | ||
}, | ||
map[string]apiextensionsv1.JSON{ | ||
// Verify that builtin variables are merged correctly and | ||
// the latter variables take precedent ("cluster-name-overwrite"). | ||
BuiltinsName: {Raw: []byte(`{"controlPlane":{"replicas":3},"cluster":{"name":"cluster-name-overwrite"}}`)}, | ||
"a": {Raw: []byte("a")}, | ||
"b": {Raw: []byte("b")}, | ||
}, | ||
) | ||
g.Expect(err).To(BeNil()) | ||
|
||
g.Expect(m).To(HaveKeyWithValue(BuiltinsName, apiextensionsv1.JSON{Raw: []byte(`{"cluster":{"name":"cluster-name-overwrite","namespace":"default","topology":{"version":"v1.21.1","class":"clusterClass1"}},"controlPlane":{"replicas":3}}`)})) | ||
g.Expect(m).To(HaveKeyWithValue("a", apiextensionsv1.JSON{Raw: []byte("a")})) | ||
g.Expect(m).To(HaveKeyWithValue("b", apiextensionsv1.JSON{Raw: []byte("b")})) | ||
g.Expect(m).To(HaveKeyWithValue("c", apiextensionsv1.JSON{Raw: []byte("c")})) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
Copyright 2022 The Kubernetes 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 topologymutation contains the handlers for the topologymutation webhook. | ||
package topologymutation | ||
|
||
import ( | ||
"context" | ||
"strconv" | ||
|
||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" | ||
"k8s.io/apimachinery/pkg/runtime" | ||
"k8s.io/apimachinery/pkg/runtime/serializer" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
|
||
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" | ||
patchvariables "sigs.k8s.io/cluster-api/internal/controllers/topology/cluster/patches/variables" | ||
infrav1 "sigs.k8s.io/cluster-api/test/infrastructure/docker/api/v1beta1" | ||
) | ||
|
||
// NewHandler returns a new topology mutation Handler. | ||
func NewHandler(scheme *runtime.Scheme) *Handler { | ||
return &Handler{ | ||
decoder: serializer.NewCodecFactory(scheme).UniversalDecoder( | ||
infrav1.GroupVersion, | ||
), | ||
} | ||
} | ||
|
||
// Handler is a topology mutation handler. | ||
type Handler struct { | ||
decoder runtime.Decoder | ||
} | ||
|
||
// GeneratePatches returns a function that generates patches for the given request. | ||
func (h *Handler) GeneratePatches(ctx context.Context, req *runtimehooksv1.GeneratePatchesRequest, resp *runtimehooksv1.GeneratePatchesResponse) { | ||
log := ctrl.LoggerFrom(ctx) | ||
log.Info("GeneratePatches called") | ||
|
||
walkTemplates(h.decoder, req, resp, func(obj runtime.Object, variables map[string]apiextensionsv1.JSON) error { | ||
if dockerClusterTemplate, ok := obj.(*infrav1.DockerClusterTemplate); ok { | ||
if err := patchDockerClusterTemplate(dockerClusterTemplate, variables); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
}) | ||
} | ||
|
||
// patchDockerClusterTemplate patches the DockerClusterTepmlate. | ||
func patchDockerClusterTemplate(dockerClusterTemplate *infrav1.DockerClusterTemplate, templateVariables map[string]apiextensionsv1.JSON) error { | ||
// Get the variable value as JSON string. | ||
value, err := patchvariables.GetVariableValue(templateVariables, "lbImageRepository") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Unquote the JSON string. | ||
stringValue, err := strconv.Unquote(string(value.Raw)) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
dockerClusterTemplate.Spec.Template.Spec.LoadBalancer.ImageRepository = stringValue | ||
return nil | ||
} | ||
|
||
// ValidateTopology returns a function that validates the given request. | ||
func (h *Handler) ValidateTopology(ctx context.Context, _ *runtimehooksv1.ValidateTopologyRequest, resp *runtimehooksv1.ValidateTopologyResponse) { | ||
log := ctrl.LoggerFrom(ctx) | ||
log.Info("ValidateTopology called") | ||
|
||
resp.Status = runtimehooksv1.ResponseStatusSuccess | ||
} |
Oops, something went wrong.