From 8d8deb38beb48882af4a6f5dba4ab97c8f83fa25 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Wed, 29 Aug 2018 10:27:43 -0700 Subject: [PATCH 1/3] *: add tls util test for the case when both app and ca tls assets are present. --- pkg/tlsutil/tls.go | 5 ++ test/e2e/tls_util_test.go | 105 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 test/e2e/tls_util_test.go diff --git a/pkg/tlsutil/tls.go b/pkg/tlsutil/tls.go index ff5f4cf50ab..a962a48396f 100644 --- a/pkg/tlsutil/tls.go +++ b/pkg/tlsutil/tls.go @@ -130,6 +130,11 @@ const ( TLSCACertKey = "ca.crt" ) +// NewSDKCertGenerator returns a new CertGenerator. +func NewSDKCertGenerator() CertGenerator { + return &SDKCertGenerator{} +} + type SDKCertGenerator struct { } diff --git a/test/e2e/tls_util_test.go b/test/e2e/tls_util_test.go new file mode 100644 index 00000000000..38ac1aea47e --- /dev/null +++ b/test/e2e/tls_util_test.go @@ -0,0 +1,105 @@ +// Copyright 2018 The Operator-SDK 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 e2e + +import ( + "reflect" + "strings" + "testing" + + "github.com/operator-framework/operator-sdk/pkg/tlsutil" + framework "github.com/operator-framework/operator-sdk/test/e2e/framework" + + "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TestBothAppAndCATLSAssetsExist ensures that when both application +// and CA TLS assets exist in the k8s cluster for a given cr, +// the GenerateCert() simply returns those to the caller. +func TestBothAppAndCATLSAssetsExist(t *testing.T) { + f := framework.Global + ctx := f.NewTestCtx(t) + defer ctx.Cleanup(t) + namespace, err := ctx.GetNamespace() + if err != nil { + t.Fatal(err) + } + + // treat the Pod manifest as the input CRfor the GenerateCert(). + crKind := "Pod" + crName := "example-pod" + mCR := &v1.Pod{ + TypeMeta: metav1.TypeMeta{ + Kind: crKind, + }, + ObjectMeta: metav1.ObjectMeta{ + Name: crName, + Namespace: namespace, + }, + } + + certName := "app-cert" + appSecretName := strings.ToLower(crKind) + "-" + crName + "-" + certName + appSecret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: appSecretName, + }, + } + appSecret, err = f.KubeClient.CoreV1().Secrets(namespace).Create(appSecret) + if err != nil { + t.Fatal(err) + } + + caConfigMapAndSecretName := strings.ToLower(crKind) + "-" + crName + "-ca" + caConfigMap := &v1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: caConfigMapAndSecretName, + }, + } + caConfigMap, err = f.KubeClient.CoreV1().ConfigMaps(namespace).Create(caConfigMap) + if err != nil { + t.Fatal(err) + } + + caSecret := &v1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: caConfigMapAndSecretName, + }, + } + caSecret, err = f.KubeClient.CoreV1().Secrets(namespace).Create(caSecret) + if err != nil { + t.Fatal(err) + } + + cg := tlsutil.NewSDKCertGenerator() + ccfg := &tlsutil.CertConfig{ + CertName: certName, + } + actualAppSecret, actualCaConfigMap, actualCaSecret, err := cg.GenerateCert(mCR, nil, ccfg) + if err != nil { + t.Fatal(err) + } + + if !reflect.DeepEqual(appSecret, actualAppSecret) { + t.Fatalf("expect %v, got %v", appSecret, actualAppSecret) + } + if !reflect.DeepEqual(caConfigMap, actualCaConfigMap) { + t.Fatalf("expect %v, got %v", caConfigMap, actualCaConfigMap) + } + if !reflect.DeepEqual(caSecret, actualCaSecret) { + t.Fatalf("expect %v, got %v", caSecret, actualCaSecret) + } +} From f344bce3b97aa13430ad6ba9ecc35e2d3c022123 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Wed, 29 Aug 2018 11:58:12 -0700 Subject: [PATCH 2/3] pkg/tlsutil: use kubeclient to get secret and configmap in GenerateCert --- pkg/tlsutil/tls.go | 54 +++++++++------------------------------ test/e2e/tls_util_test.go | 2 +- 2 files changed, 13 insertions(+), 43 deletions(-) diff --git a/pkg/tlsutil/tls.go b/pkg/tlsutil/tls.go index a962a48396f..ebfa15648f0 100644 --- a/pkg/tlsutil/tls.go +++ b/pkg/tlsutil/tls.go @@ -21,13 +21,12 @@ import ( "fmt" "strings" - "github.com/operator-framework/operator-sdk/pkg/sdk" - "k8s.io/api/core/v1" apiErrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/kubernetes" ) // CertType defines the type of the cert. @@ -130,12 +129,13 @@ const ( TLSCACertKey = "ca.crt" ) -// NewSDKCertGenerator returns a new CertGenerator. -func NewSDKCertGenerator() CertGenerator { - return &SDKCertGenerator{} +// NewSDKCertGenerator constructs a new CertGenerator given the kubeClient. +func NewSDKCertGenerator(kubeClient kubernetes.Interface) CertGenerator { + return &SDKCertGenerator{KubeClient: kubeClient} } type SDKCertGenerator struct { + KubeClient kubernetes.Interface } type keyAndCert struct { @@ -152,11 +152,11 @@ func (scg *SDKCertGenerator) GenerateCert(cr runtime.Object, service *v1.Service if err != nil { return nil, nil, nil, err } - appSecret, err := getAppSecretInCluster(toAppSecretName(k, n, config.CertName), ns) + appSecret, err := getAppSecretInCluster(scg.KubeClient, toAppSecretName(k, n, config.CertName), ns) if err != nil { return nil, nil, nil, err } - caSecret, caConfigMap, err := getCASecretAndConfigMapInCluster(toCASecretAndConfigMapName(k, n), ns) + caSecret, caConfigMap, err := getCASecretAndConfigMapInCluster(scg.KubeClient, toCASecretAndConfigMapName(k, n), ns) if err != nil { return nil, nil, nil, err } @@ -194,18 +194,8 @@ func toCASecretAndConfigMapName(kind, name string) string { return strings.ToLower(kind) + "-" + name + "-ca" } -func getAppSecretInCluster(name, namespace string) (*v1.Secret, error) { - se := &v1.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - } - err := sdk.Get(se) +func getAppSecretInCluster(kubeClient kubernetes.Interface, name, namespace string) (*v1.Secret, error) { + se, err := kubeClient.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{}) if apiErrors.IsNotFound(err) { return nil, nil } @@ -217,19 +207,9 @@ func getAppSecretInCluster(name, namespace string) (*v1.Secret, error) { // getCASecretAndConfigMapInCluster gets CA secret and configmap of the given name and namespace. // it only returns both if they are found and nil if both are not found. In the case if only one of them is found, then we error out because we expect either both CA secret and configmap exit or not. -func getCASecretAndConfigMapInCluster(name, namespace string) (*v1.Secret, *v1.ConfigMap, error) { - cm := &v1.ConfigMap{ - TypeMeta: metav1.TypeMeta{ - Kind: "ConfigMap", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - } +func getCASecretAndConfigMapInCluster(kubeClient kubernetes.Interface, name, namespace string) (*v1.Secret, *v1.ConfigMap, error) { hasConfigMap := true - err := sdk.Get(cm) + cm, err := kubeClient.CoreV1().ConfigMaps(namespace).Get(name, metav1.GetOptions{}) if apiErrors.IsNotFound(err) { hasConfigMap = false } @@ -237,18 +217,8 @@ func getCASecretAndConfigMapInCluster(name, namespace string) (*v1.Secret, *v1.C return nil, nil, err } - se := &v1.Secret{ - TypeMeta: metav1.TypeMeta{ - Kind: "Secret", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: namespace, - }, - } hasSecret := true - err = sdk.Get(se) + se, err := kubeClient.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{}) if apiErrors.IsNotFound(err) { hasSecret = false } diff --git a/test/e2e/tls_util_test.go b/test/e2e/tls_util_test.go index 38ac1aea47e..7640872626f 100644 --- a/test/e2e/tls_util_test.go +++ b/test/e2e/tls_util_test.go @@ -84,7 +84,7 @@ func TestBothAppAndCATLSAssetsExist(t *testing.T) { t.Fatal(err) } - cg := tlsutil.NewSDKCertGenerator() + cg := tlsutil.NewSDKCertGenerator(f.KubeClient) ccfg := &tlsutil.CertConfig{ CertName: certName, } From 69ca6aefc397b53f9fd54dfa197345f78648dd67 Mon Sep 17 00:00:00 2001 From: fanmin shi Date: Wed, 29 Aug 2018 12:45:17 -0700 Subject: [PATCH 3/3] *: expose ToCASecretAndConfigMapName and ToAppSecretName --- pkg/tlsutil/tls.go | 8 ++++---- test/e2e/tls_util_test.go | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/pkg/tlsutil/tls.go b/pkg/tlsutil/tls.go index ebfa15648f0..4e70cffabf2 100644 --- a/pkg/tlsutil/tls.go +++ b/pkg/tlsutil/tls.go @@ -152,11 +152,11 @@ func (scg *SDKCertGenerator) GenerateCert(cr runtime.Object, service *v1.Service if err != nil { return nil, nil, nil, err } - appSecret, err := getAppSecretInCluster(scg.KubeClient, toAppSecretName(k, n, config.CertName), ns) + appSecret, err := getAppSecretInCluster(scg.KubeClient, ToAppSecretName(k, n, config.CertName), ns) if err != nil { return nil, nil, nil, err } - caSecret, caConfigMap, err := getCASecretAndConfigMapInCluster(scg.KubeClient, toCASecretAndConfigMapName(k, n), ns) + caSecret, caConfigMap, err := getCASecretAndConfigMapInCluster(scg.KubeClient, ToCASecretAndConfigMapName(k, n), ns) if err != nil { return nil, nil, nil, err } @@ -186,11 +186,11 @@ func verifyConfig(config *CertConfig) error { return nil } -func toAppSecretName(kind, name, certName string) string { +func ToAppSecretName(kind, name, certName string) string { return strings.ToLower(kind) + "-" + name + "-" + certName } -func toCASecretAndConfigMapName(kind, name string) string { +func ToCASecretAndConfigMapName(kind, name string) string { return strings.ToLower(kind) + "-" + name + "-ca" } diff --git a/test/e2e/tls_util_test.go b/test/e2e/tls_util_test.go index 7640872626f..3f794d9cd16 100644 --- a/test/e2e/tls_util_test.go +++ b/test/e2e/tls_util_test.go @@ -16,7 +16,6 @@ package e2e import ( "reflect" - "strings" "testing" "github.com/operator-framework/operator-sdk/pkg/tlsutil" @@ -38,7 +37,7 @@ func TestBothAppAndCATLSAssetsExist(t *testing.T) { t.Fatal(err) } - // treat the Pod manifest as the input CRfor the GenerateCert(). + // Use Pod as a dummy runtime object for the CR input of GenerateCert(). crKind := "Pod" crName := "example-pod" mCR := &v1.Pod{ @@ -52,10 +51,9 @@ func TestBothAppAndCATLSAssetsExist(t *testing.T) { } certName := "app-cert" - appSecretName := strings.ToLower(crKind) + "-" + crName + "-" + certName appSecret := &v1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Name: appSecretName, + Name: tlsutil.ToAppSecretName(crKind, crName, certName), }, } appSecret, err = f.KubeClient.CoreV1().Secrets(namespace).Create(appSecret) @@ -63,7 +61,7 @@ func TestBothAppAndCATLSAssetsExist(t *testing.T) { t.Fatal(err) } - caConfigMapAndSecretName := strings.ToLower(crKind) + "-" + crName + "-ca" + caConfigMapAndSecretName := tlsutil.ToCASecretAndConfigMapName(crKind, crName) caConfigMap := &v1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Name: caConfigMapAndSecretName, @@ -94,12 +92,12 @@ func TestBothAppAndCATLSAssetsExist(t *testing.T) { } if !reflect.DeepEqual(appSecret, actualAppSecret) { - t.Fatalf("expect %v, got %v", appSecret, actualAppSecret) + t.Fatalf("expect %+v, got %+v", appSecret, actualAppSecret) } if !reflect.DeepEqual(caConfigMap, actualCaConfigMap) { - t.Fatalf("expect %v, got %v", caConfigMap, actualCaConfigMap) + t.Fatalf("expect %+v, got %+v", caConfigMap, actualCaConfigMap) } if !reflect.DeepEqual(caSecret, actualCaSecret) { - t.Fatalf("expect %v, got %v", caSecret, actualCaSecret) + t.Fatalf("expect %+v, got %+v", caSecret, actualCaSecret) } }