Skip to content

Commit

Permalink
switched to transformer and removed manifest pkg
Browse files Browse the repository at this point in the history
  • Loading branch information
anirudhprasad-sap committed Sep 5, 2023
1 parent 80ed0a5 commit 5fcac8a
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 149 deletions.
5 changes: 4 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"type": "go",
"request": "launch",
"mode": "auto",
"program": "main.go"
"program": "main.go",
"env": {
"POD_NAMESPACE": "cap-operator-system"
}
}
]
}
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ RUN go mod download
# Copy the go sources
COPY main.go main.go
COPY api/ api/
COPY internal/ internal/
COPY pkg/ pkg/

# Build
Expand Down
76 changes: 27 additions & 49 deletions pkg/manifests/helm.go → internal/transformer/transformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,21 @@ SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and cap-operator
SPDX-License-Identifier: Apache-2.0
*/

package manifests
package transformer

import (
"context"
"fmt"
"io/fs"
"strings"

"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/sap/component-operator-runtime/pkg/manifests"
"github.com/sap/component-operator-runtime/pkg/types"

"github.com/sap/cap-operator-lifecycle/api/v1alpha1"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
apitypes "k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/discovery"
"sigs.k8s.io/controller-runtime/pkg/client"

"github.com/sap/cap-operator-lifecycle/api/v1alpha1"
componentoperatorruntimetypes "github.com/sap/component-operator-runtime/pkg/types"
)

const (
Expand All @@ -33,42 +27,26 @@ const (
annotationDNSNames = "dns.gardener.cloud/dnsnames"
)

type HelmGenerator struct {
resourceGenerator *manifests.HelmGenerator
client client.Client
type transformer struct {
client client.Client
}

type unstructurableMap struct {
data map[string]any
}

func (m *unstructurableMap) ToUnstructured() map[string]any {
return runtime.DeepCopyJSON(m.data)
}

var _ Generator = &HelmGenerator{}

func NewHelmGenerator(name string, fsys fs.FS, chartPath string, client client.Client, discoveryClient discovery.DiscoveryInterface) (*HelmGenerator, error) {
resourceGenerator, err := manifests.NewHelmGenerator(name, fsys, chartPath, client, discoveryClient)
if err != nil {
return nil, err
}
g := HelmGenerator{resourceGenerator: resourceGenerator, client: client}
return &g, nil
func NewParameterTransformer(client client.Client) *transformer {
return &transformer{client: client}
}

func (g *HelmGenerator) Generate(namespace string, name string, parameters types.Unstructurable) ([]client.Object, error) {
func (t *transformer) TransformParameters(namespace string, name string, parameters componentoperatorruntimetypes.Unstructurable) (componentoperatorruntimetypes.Unstructurable, error) {
parameterMap := parameters.ToUnstructured()

if err := g.fillDomain(parameterMap); err != nil {
if err := t.fillDomain(parameterMap); err != nil {
return nil, err
}

if err := g.fillDNSTarget(parameterMap); err != nil {
if err := t.fillDNSTarget(parameterMap); err != nil {
return nil, err
}

return g.resourceGenerator.Generate(namespace, name, &unstructurableMap{data: parameterMap})
return componentoperatorruntimetypes.UnstructurableMap(parameterMap), nil
}

func trimDNSTarget(dnsTarget string) string {
Expand All @@ -80,7 +58,7 @@ func trimDNSTarget(dnsTarget string) string {
return strings.ReplaceAll(dnsTarget, "*", "x")
}

func (g *HelmGenerator) fillDNSTarget(parameters map[string]any) error {
func (t *transformer) fillDNSTarget(parameters map[string]any) error {
// get DNSTarget
subscriptionServer := parameters["subscriptionServer"].(map[string]interface{})
if subscriptionServer["dnsTarget"] != nil { // already filled in CRO
Expand All @@ -98,7 +76,7 @@ func (g *HelmGenerator) fillDNSTarget(parameters map[string]any) error {
return fmt.Errorf("cannot get dnsTarget; provide ingressGatewayLabels/app and ingressGatewayLabels/istio values in the CRO")
}

dnsTarget, err := g.getDNSTarget(&v1alpha1.IngressGatewayLabels{App: ingressGatewayLabels["app"].(string), Istio: ingressGatewayLabels["istio"].(string)})
dnsTarget, err := t.getDNSTarget(&v1alpha1.IngressGatewayLabels{App: ingressGatewayLabels["app"].(string), Istio: ingressGatewayLabels["istio"].(string)})
if err != nil {
return err
}
Expand All @@ -108,7 +86,7 @@ func (g *HelmGenerator) fillDNSTarget(parameters map[string]any) error {
return nil
}

func (g *HelmGenerator) getDNSTarget(ingressGatewayLabels *v1alpha1.IngressGatewayLabels) (dnsTarget string, err error) {
func (t *transformer) getDNSTarget(ingressGatewayLabels *v1alpha1.IngressGatewayLabels) (dnsTarget string, err error) {

ctx := context.TODO()

Expand All @@ -120,7 +98,7 @@ func (g *HelmGenerator) getDNSTarget(ingressGatewayLabels *v1alpha1.IngressGatew

// Get relevant Ingress Gateway pods
ingressPods := &corev1.PodList{TypeMeta: metav1.TypeMeta{Kind: "Pod"}}
err = g.client.List(ctx, ingressPods, &client.ListOptions{Namespace: metav1.NamespaceAll, LabelSelector: ingressLabelSelector})
err = t.client.List(ctx, ingressPods, &client.ListOptions{Namespace: metav1.NamespaceAll, LabelSelector: ingressLabelSelector})
if err != nil {
return "", err
}
Expand All @@ -143,7 +121,7 @@ func (g *HelmGenerator) getDNSTarget(ingressGatewayLabels *v1alpha1.IngressGatew
}

// Get dnsTarget
ingressGWSvc, err := g.getIngressGatewayService(ctx, relevantsPodsNames)
ingressGWSvc, err := t.getIngressGatewayService(ctx, relevantsPodsNames)
if err != nil {
return "", err
}
Expand All @@ -169,10 +147,10 @@ func getIngressGatewayLabels(ingressGatewayLabels *v1alpha1.IngressGatewayLabels
return ingressLabels
}

func (g *HelmGenerator) getLoadBalancerSvcs(ctx context.Context) ([]corev1.Service, error) {
func (t *transformer) getLoadBalancerSvcs(ctx context.Context) ([]corev1.Service, error) {
// List all services in the same namespace as the istio-ingressgateway pod namespace
svcList := &corev1.ServiceList{TypeMeta: metav1.TypeMeta{Kind: "Service"}}
if err := g.client.List(ctx, svcList, &client.ListOptions{Namespace: istioIngressGWNamespace}); err != nil {
if err := t.client.List(ctx, svcList, &client.ListOptions{Namespace: istioIngressGWNamespace}); err != nil {
return nil, err
}

Expand All @@ -186,8 +164,8 @@ func (g *HelmGenerator) getLoadBalancerSvcs(ctx context.Context) ([]corev1.Servi
return loadBalancerSvcs, nil
}

func (g *HelmGenerator) getIngressGatewayService(ctx context.Context, relevantPodNames map[string]struct{}) (*corev1.Service, error) {
loadBalancerSvcs, err := g.getLoadBalancerSvcs(ctx)
func (t *transformer) getIngressGatewayService(ctx context.Context, relevantPodNames map[string]struct{}) (*corev1.Service, error) {
loadBalancerSvcs, err := t.getLoadBalancerSvcs(ctx)
if err != nil {
return nil, err
}
Expand All @@ -196,7 +174,7 @@ func (g *HelmGenerator) getIngressGatewayService(ctx context.Context, relevantPo
podList := &corev1.PodList{TypeMeta: metav1.TypeMeta{Kind: "Pod"}}
for _, svc := range loadBalancerSvcs {
// Get all matching ingress GW pods in the ingress gw namespace via ingress gw service selectors
err := g.client.List(ctx, podList, &client.ListOptions{LabelSelector: labels.SelectorFromValidatedSet(svc.Spec.Selector)})
err := t.client.List(ctx, podList, &client.ListOptions{LabelSelector: labels.SelectorFromValidatedSet(svc.Spec.Selector)})
if err != nil {
return nil, err
}
Expand All @@ -219,10 +197,10 @@ func (g *HelmGenerator) getIngressGatewayService(ctx context.Context, relevantPo
return &ingressGwSvc, nil
}

func (g *HelmGenerator) fillDomain(parameters map[string]any) error {
func (t *transformer) fillDomain(parameters map[string]any) error {
// get domain
subscriptionServer := parameters["subscriptionServer"].(map[string]interface{})
domain, err := g.getDomain(subscriptionServer["subDomain"].(string))
domain, err := t.getDomain(subscriptionServer["subDomain"].(string))
if err != nil {
return err
}
Expand All @@ -233,7 +211,7 @@ func (g *HelmGenerator) fillDomain(parameters map[string]any) error {
return nil
}

func (g *HelmGenerator) getDomain(subDomain string) (string, error) {
func (t *transformer) getDomain(subDomain string) (string, error) {
configMapObj := &corev1.ConfigMap{
TypeMeta: metav1.TypeMeta{
Kind: "ConfigMap",
Expand All @@ -248,7 +226,7 @@ func (g *HelmGenerator) getDomain(subDomain string) (string, error) {
}

ctx := context.TODO()
err := g.client.Get(ctx, apitypes.NamespacedName{Namespace: configMapObj.GetNamespace(), Name: configMapObj.GetName()}, configMapObj)
err := t.client.Get(ctx, apitypes.NamespacedName{Namespace: configMapObj.GetNamespace(), Name: configMapObj.GetName()}, configMapObj)
if err != nil {
return "", err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,18 @@
SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and cap-operator contributors
SPDX-License-Identifier: Apache-2.0
*/
package manifests
package transformer

import (
"testing"

"golang.org/x/exp/slices"
componentoperatorruntimetypes "github.com/sap/component-operator-runtime/pkg/types"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
fake "sigs.k8s.io/controller-runtime/pkg/client/fake"

fakediscovery "k8s.io/client-go/discovery/fake"
fakeclientset "k8s.io/client-go/kubernetes/fake"
)

func ContainsFunc(clientObjects []client.Object, name string, kind string) bool {
return slices.ContainsFunc(clientObjects, func(object client.Object) bool {
return object.GetName() == name && object.GetObjectKind().GroupVersionKind().Kind == kind
})
}

func TestHelmResourceGenerator(t *testing.T) {
func TestTransformer(t *testing.T) {
tests := []struct {
name string
dnsTargetFilled bool
Expand Down Expand Up @@ -96,48 +86,7 @@ func TestHelmResourceGenerator(t *testing.T) {

kubeClient := clientBuilder.Build()

fakeclientset := fakeclientset.NewSimpleClientset()
fakeDiscovery, ok := fakeclientset.Discovery().(*fakediscovery.FakeDiscovery)
if !ok {
t.Error("fake discovery client creation failed")
}
fakeDiscovery.Resources = []*metav1.APIResourceList{
{
GroupVersion: "cert.gardener.cloud/v1alpha1",
TypeMeta: metav1.TypeMeta{
Kind: "APIResourceList",
APIVersion: "v1",
},
APIResources: []metav1.APIResource{
{
Name: "certificates",
SingularName: "certificate",
Namespaced: true,
Kind: "Certificate",
},
},
},
{
GroupVersion: "dns.gardener.cloud/v1alpha1",
TypeMeta: metav1.TypeMeta{
Kind: "APIResourceList",
APIVersion: "v1",
},
APIResources: []metav1.APIResource{
{
Name: "dnsentries",
SingularName: "dnsentry",
Namespaced: true,
Kind: "DNSEntry",
},
},
},
}

helmGenerator, err := NewHelmGenerator("cap-operator.sme.sap.com", nil, "../../chart", kubeClient, fakeDiscovery)
if err != nil {
t.Error(err)
}
transformer := NewParameterTransformer(kubeClient)

parameter := make(map[string]interface{})

Expand All @@ -157,7 +106,7 @@ func TestHelmResourceGenerator(t *testing.T) {
}
}

clientObjects, err := helmGenerator.Generate("cap-operator-system", "cap-operator", &unstructurableMap{parameter})
transformedParameters, err := transformer.TransformParameters("cap-operator-system", "cap-operator.sme.sap.com", componentoperatorruntimetypes.UnstructurableMap(parameter))
if !tt.expectError && err != nil {
t.Error(err)
}
Expand All @@ -170,33 +119,12 @@ func TestHelmResourceGenerator(t *testing.T) {
t.Log(err)
return
}

if len(clientObjects) != 24 {
t.Error("wrong number of returned client objects")
}

if !ContainsFunc(clientObjects, "cap-operator-controller", "Deployment") {
t.Error("controller deployment not found")
}

if !ContainsFunc(clientObjects, "cap-operator-subscription-server", "Deployment") {
t.Error("subscription-server deployment not found")
}

if !ContainsFunc(clientObjects, "cap-operator-webhook", "Deployment") {
t.Error("webhook deployment not found")
}

if !ContainsFunc(clientObjects, "cap-operator-subscription-server", "VirtualService") {
t.Error("virutal service not found")
}

if !ContainsFunc(clientObjects, "cap-operator-subscription-server", "Gateway") {
t.Error("gateway not found")
transformedParametersMap := transformedParameters.ToUnstructured()
if transformedParametersMap["subscriptionServer"].(map[string]interface{})["dnsTarget"].(string) != "public-ingress.some.cluster.sap" {
t.Error("unexpected value returned")
}

if !ContainsFunc(clientObjects, "cap-operator-subscription-server", "DNSEntry") {
t.Error("DNSEntry not found")
if transformedParametersMap["subscriptionServer"].(map[string]interface{})["domain"].(string) != "cop.some.cluster.sap" {
t.Error("unexpected value returned")
}
})
}
Expand Down
16 changes: 0 additions & 16 deletions pkg/manifests/types.go

This file was deleted.

10 changes: 9 additions & 1 deletion pkg/operator/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/sap/component-operator-runtime/pkg/operator"

operatorv1alpha1 "github.com/sap/cap-operator-lifecycle/api/v1alpha1"
"github.com/sap/cap-operator-lifecycle/internal/transformer"
)

const Name = "cap-operator.sme.sap.com"
Expand Down Expand Up @@ -107,7 +108,14 @@ func (o *Operator) Setup(mgr ctrl.Manager, discoveryClient discovery.DiscoveryIn
return errors.Wrap(err, "error checking manifest directory")
}

resourceGenerator, err := manifests.NewHelmGenerator(Name, nil, chartDir, mgr.GetClient(), discoveryClient)
resourceGenerator, err := manifests.NewHelmGeneratorWithParameterTransformer(
o.options.Name,
nil,
chartDir,
mgr.GetClient(),
discoveryClient,
transformer.NewParameterTransformer(mgr.GetClient()),
)
if err != nil {
return errors.Wrap(err, "error initializing resource generator")
}
Expand Down
Loading

0 comments on commit 5fcac8a

Please sign in to comment.