github.com/kyma-project/kyma-environment-broker@v0.0.1/common/hyperscaler/shared_pool_test.go (about)

     1  package hyperscaler
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/kyma-project/kyma-environment-broker/common/gardener"
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  	corev1 "k8s.io/api/core/v1"
    10  	machineryv1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    12  	"k8s.io/apimachinery/pkg/runtime"
    13  )
    14  
    15  func TestSharedPool_SharedCredentialsSecretBinding(t *testing.T) {
    16  
    17  	for _, euAccess := range []bool{false, true} {
    18  		for _, testCase := range []struct {
    19  			description    string
    20  			secretBindings []runtime.Object
    21  			shoots         []runtime.Object
    22  			hyperscaler    Type
    23  			expectedSecret string
    24  		}{
    25  			{
    26  				description: "should get only Secret Bindings with proper hyperscaler",
    27  				secretBindings: []runtime.Object{
    28  					newSecretBinding("sb1", "s1", "gcp", true, euAccess),
    29  					newSecretBinding("sb2", "s2", "azure", true, euAccess),
    30  					newSecretBinding("sb3", "s3", "aws", true, euAccess),
    31  				},
    32  				shoots: []runtime.Object{
    33  					newShoot("sh1", "sb1"),
    34  					newShoot("sh2", "sb1"),
    35  					newShoot("sh3", "sb1"),
    36  					newShoot("sh4", "sb2"),
    37  				},
    38  				hyperscaler:    "gcp",
    39  				expectedSecret: "s1",
    40  			},
    41  			{
    42  				description: "should ignore not shared Secret Bindings",
    43  				secretBindings: []runtime.Object{
    44  					newSecretBinding("sb1", "s1", "gcp", true, euAccess),
    45  					newSecretBinding("sb2", "s2", "gcp", false, euAccess),
    46  					newSecretBinding("sb3", "s3", "gcp", false, euAccess),
    47  				},
    48  				shoots: []runtime.Object{
    49  					newShoot("sh1", "sb1"),
    50  					newShoot("sh2", "sb1"),
    51  					newShoot("sh3", "sb1"),
    52  					newShoot("sh4", "sb2"),
    53  				},
    54  				hyperscaler:    "gcp",
    55  				expectedSecret: "s1",
    56  			},
    57  			{
    58  				description: "should get least used Secret Binding for GCP",
    59  				secretBindings: []runtime.Object{
    60  					newSecretBinding("sb1", "s1", "gcp", true, euAccess),
    61  					newSecretBinding("sb2", "s2", "gcp", true, euAccess),
    62  					newSecretBinding("sb3", "s3", "gcp", true, euAccess),
    63  				},
    64  				shoots: []runtime.Object{
    65  					newShoot("sh1", "sb1"),
    66  					newShoot("sh2", "sb1"),
    67  					newShoot("sh3", "sb1"),
    68  					newShoot("sh4", "sb2"),
    69  					newShoot("sh5", "sb2"),
    70  					newShoot("sh6", "sb3"),
    71  				},
    72  				hyperscaler:    "gcp",
    73  				expectedSecret: "s3",
    74  			},
    75  			{
    76  				description: "should get least used Secret Binding for Azure",
    77  				secretBindings: []runtime.Object{
    78  					newSecretBinding("sb1", "s1", "azure", true, euAccess),
    79  					newSecretBinding("sb2", "s2", "azure", true, euAccess),
    80  					newSecretBinding("sb3", "s3", "aws", true, euAccess),
    81  				},
    82  				shoots: []runtime.Object{
    83  					newShoot("sh1", "sb1"),
    84  					newShoot("sh2", "sb1"),
    85  					newShoot("sh3", "sb2"),
    86  				},
    87  				hyperscaler:    "azure",
    88  				expectedSecret: "s2",
    89  			},
    90  			{
    91  				description: "should get least used Secret Binding for AWS",
    92  				secretBindings: []runtime.Object{
    93  					newSecretBinding("sb1", "s1", "aws", true, euAccess),
    94  					newSecretBinding("sb2", "s2", "aws", true, euAccess),
    95  				},
    96  				shoots: []runtime.Object{
    97  					newShoot("sh1", "sb2"),
    98  				},
    99  				hyperscaler:    "aws",
   100  				expectedSecret: "s1",
   101  			},
   102  		} {
   103  			t.Run(testCase.description, func(t *testing.T) {
   104  				// given
   105  				gardenerFake := gardener.NewDynamicFakeClient(append(testCase.shoots, testCase.secretBindings...)...)
   106  				pool := NewSharedGardenerAccountPool(gardenerFake, testNamespace)
   107  
   108  				// when
   109  				secretBinding, err := pool.SharedCredentialsSecretBinding(testCase.hyperscaler, euAccess)
   110  				require.NoError(t, err)
   111  
   112  				// then
   113  				assert.Equal(t, testCase.expectedSecret, secretBinding.GetSecretRefName())
   114  			})
   115  		}
   116  	}
   117  }
   118  
   119  func TestSharedPool_SharedCredentialsSecretBinding_Errors(t *testing.T) {
   120  	t.Run("should return error when no Secret Bindings for hyperscaler found", func(t *testing.T) {
   121  		// given
   122  		gardenerFake := gardener.NewDynamicFakeClient(
   123  			newSecretBinding("sb1", "s1", "azure", true, false),
   124  			newSecretBinding("sb2", "s2", "gcp", false, false),
   125  		)
   126  		pool := NewSharedGardenerAccountPool(gardenerFake, testNamespace)
   127  
   128  		// when
   129  		_, err := pool.SharedCredentialsSecretBinding("gcp", false)
   130  
   131  		// then
   132  		require.Error(t, err)
   133  		assert.Contains(t, err.Error(), "no shared secret binding found")
   134  	})
   135  }
   136  
   137  func newSecret(name string) *corev1.Secret {
   138  	return &corev1.Secret{
   139  		ObjectMeta: machineryv1.ObjectMeta{
   140  			Name: name, Namespace: testNamespace,
   141  		},
   142  		Data: map[string][]byte{
   143  			"credentials": []byte(name),
   144  		},
   145  	}
   146  }
   147  
   148  func newSecretBinding(name, secretName, hyperscaler string, shared bool, euAccess bool) *unstructured.Unstructured {
   149  	secretBinding := &unstructured.Unstructured{
   150  		Object: map[string]interface{}{
   151  			"metadata": map[string]interface{}{
   152  				"name":      name,
   153  				"namespace": testNamespace,
   154  				"labels": map[string]interface{}{
   155  					"hyperscalerType": hyperscaler,
   156  				},
   157  			},
   158  			"secretRef": map[string]interface{}{
   159  				"name":      secretName,
   160  				"namespace": testNamespace,
   161  			},
   162  		},
   163  	}
   164  	secretBinding.SetGroupVersionKind(secretBindingGVK)
   165  
   166  	if shared {
   167  		labels := secretBinding.GetLabels()
   168  		labels["shared"] = "true"
   169  		secretBinding.SetLabels(labels)
   170  	}
   171  	applyEuAccess(secretBinding, euAccess)
   172  
   173  	return secretBinding
   174  }
   175  
   176  func newShoot(name, secretBinding string) *unstructured.Unstructured {
   177  	shoot := &unstructured.Unstructured{
   178  		Object: map[string]interface{}{
   179  			"metadata": map[string]interface{}{
   180  				"name":      name,
   181  				"namespace": testNamespace,
   182  			},
   183  			"spec": map[string]interface{}{
   184  				"secretBindingName": secretBinding,
   185  			},
   186  		},
   187  	}
   188  	shoot.SetGroupVersionKind(shootGVK)
   189  	return shoot
   190  }