...

Source file src/github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/auditconfig/iamauditconfig_controller_integration_test.go

Documentation: github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/auditconfig

     1  // Copyright 2022 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  //go:build integration
    16  // +build integration
    17  
    18  package auditconfig_test
    19  
    20  import (
    21  	"context"
    22  	"errors"
    23  	"reflect"
    24  	"strings"
    25  	"testing"
    26  
    27  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/iam/v1beta1"
    28  	iamv1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/apis/iam/v1beta1"
    29  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/auditconfig"
    30  	kcciamclient "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/controller/iam/iamclient"
    31  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/k8s"
    32  	testcontroller "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/controller"
    33  	testreconciler "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/controller/reconciler"
    34  	testgcp "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/gcp"
    35  	testiam "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/iam"
    36  	testk8s "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/k8s"
    37  	testmain "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/main"
    38  	"github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/resourcefixture"
    39  	testservicemappingloader "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/test/servicemappingloader"
    40  	tfprovider "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/tf/provider"
    41  
    42  	"github.com/google/go-cmp/cmp"
    43  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    44  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    45  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    46  	"sigs.k8s.io/controller-runtime/pkg/manager"
    47  	"sigs.k8s.io/controller-runtime/pkg/reconcile"
    48  )
    49  
    50  var (
    51  	mgr                     manager.Manager
    52  	expectedReconcileResult = reconcile.Result{RequeueAfter: k8s.MeanReconcileReenqueuePeriod}
    53  )
    54  
    55  func TestReconcileIAMAuditConfigResourceLevelCreate(t *testing.T) {
    56  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
    57  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
    58  			{
    59  				LogType: "DATA_WRITE",
    60  			},
    61  			{
    62  				LogType:         "DATA_READ",
    63  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
    64  			},
    65  		}
    66  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
    67  		testReconcileResourceLevelCreate(t, mgr, k8sAuditConfig)
    68  	}
    69  	testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunWithAuditConfigs)
    70  }
    71  
    72  func TestReconcileIAMAuditConfigResourceLevelCreateWithExternalRef(t *testing.T) {
    73  	shouldRun := func(fixture resourcefixture.ResourceFixture) bool {
    74  		return testiam.ShouldRunWithAuditConfigs(fixture) && testiam.ShouldRunWithExternalRef(fixture)
    75  	}
    76  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
    77  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
    78  			{
    79  				LogType: "DATA_WRITE",
    80  			},
    81  			{
    82  				LogType:         "DATA_READ",
    83  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
    84  			},
    85  		}
    86  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
    87  		testReconcileResourceLevelCreate(t, mgr, k8sAuditConfig)
    88  	}
    89  	testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, shouldRun)
    90  }
    91  
    92  func testReconcileResourceLevelCreate(t *testing.T, mgr manager.Manager, k8sAuditConfig *iamv1beta1.IAMAuditConfig) {
    93  	provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
    94  	smLoader := testservicemappingloader.New(t)
    95  	kubeClient := mgr.GetClient()
    96  	tfIamClient := kcciamclient.New(provider, smLoader, kubeClient, nil, nil).TFIAMClient
    97  	reconciler := testreconciler.New(t, mgr, provider)
    98  	if _, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig); !errors.Is(err, kcciamclient.NotFoundError) {
    99  		t.Fatalf("unexpected error value: got '%v', want '%v'", err, kcciamclient.NotFoundError)
   100  	}
   101  	if err := kubeClient.Create(context.TODO(), k8sAuditConfig); err != nil {
   102  		t.Fatalf("error creating k8s resource: %v", err)
   103  	}
   104  	preReconcileGeneration := k8sAuditConfig.GetGeneration()
   105  	resource, err := auditconfig.ToK8sResource(k8sAuditConfig)
   106  	if err != nil {
   107  		t.Fatalf("error converting object %v to k8sResource: %v", k8sAuditConfig, err)
   108  	}
   109  	u, err := resource.MarshalAsUnstructured()
   110  	if err != nil {
   111  		t.Fatalf("error marshalling %v as unstructured: %v", k8sAuditConfig, err)
   112  	}
   113  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, testreconciler.ExpectedSuccessfulReconcileResultFor(reconciler, u), nil)
   114  	gcpAuditConfig, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig)
   115  	if err != nil {
   116  		t.Fatalf("error retrieving GCP audit config: %v", err)
   117  	}
   118  	assertSameAuditConfigs(t, k8sAuditConfig, gcpAuditConfig)
   119  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err != nil {
   120  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   121  	}
   122  	testcontroller.AssertReadyCondition(t, k8sAuditConfig.Status.Conditions)
   123  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMAuditConfigGVK.Kind, &k8sAuditConfig.ObjectMeta, k8s.UpToDate)
   124  	assertObservedGenerationEquals(t, k8sAuditConfig, preReconcileGeneration)
   125  }
   126  
   127  func TestReconcileIAMAuditConfigResourceLevelUpdate(t *testing.T) {
   128  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   129  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   130  			{
   131  				LogType: "DATA_WRITE",
   132  			},
   133  		}
   134  		newAuditLogConfigs := []iamv1beta1.AuditLogConfig{
   135  			{
   136  				LogType: "DATA_WRITE",
   137  			},
   138  			{
   139  				LogType:         "DATA_READ",
   140  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   141  			},
   142  		}
   143  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   144  		newK8sAuditConfig := k8sAuditConfig.DeepCopy()
   145  		newK8sAuditConfig.Spec.AuditLogConfigs = newAuditLogConfigs
   146  		testReconcileResourceLevelUpdate(t, mgr, k8sAuditConfig, newK8sAuditConfig)
   147  	}
   148  	testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunWithAuditConfigs)
   149  }
   150  
   151  func TestReconcileIAMAuditConfigResourceLevelUpdateWithExternalRef(t *testing.T) {
   152  	shouldRun := func(fixture resourcefixture.ResourceFixture) bool {
   153  		return testiam.ShouldRunWithAuditConfigs(fixture) && testiam.ShouldRunWithExternalRef(fixture)
   154  	}
   155  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   156  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   157  			{
   158  				LogType: "DATA_WRITE",
   159  			},
   160  		}
   161  		newAuditLogConfigs := []iamv1beta1.AuditLogConfig{
   162  			{
   163  				LogType: "DATA_WRITE",
   164  			},
   165  			{
   166  				LogType:         "DATA_READ",
   167  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   168  			},
   169  		}
   170  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   171  		newK8sAuditConfig := k8sAuditConfig.DeepCopy()
   172  		newK8sAuditConfig.Spec.AuditLogConfigs = newAuditLogConfigs
   173  		testReconcileResourceLevelUpdate(t, mgr, k8sAuditConfig, newK8sAuditConfig)
   174  	}
   175  	testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, shouldRun)
   176  }
   177  
   178  func testReconcileResourceLevelUpdate(t *testing.T, mgr manager.Manager, k8sAuditConfig, newK8sAuditConfig *iamv1beta1.IAMAuditConfig) {
   179  	provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
   180  	smLoader := testservicemappingloader.New(t)
   181  	kubeClient := mgr.GetClient()
   182  	tfIamClient := kcciamclient.New(provider, smLoader, kubeClient, nil, nil).TFIAMClient
   183  	reconciler := testreconciler.New(t, mgr, provider)
   184  	if _, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig); !errors.Is(err, kcciamclient.NotFoundError) {
   185  		t.Fatalf("unexpected error value: got '%v', want '%v'", err, kcciamclient.NotFoundError)
   186  	}
   187  	if err := kubeClient.Create(context.TODO(), k8sAuditConfig); err != nil {
   188  		t.Fatalf("error creating k8s resource: %v", err)
   189  	}
   190  	preReconcileGeneration := k8sAuditConfig.GetGeneration()
   191  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   192  	gcpAuditConfig, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig)
   193  	if err != nil {
   194  		t.Fatalf("error retrieving GCP audit config: %v", err)
   195  	}
   196  	assertSameAuditConfigs(t, k8sAuditConfig, gcpAuditConfig)
   197  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err != nil {
   198  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   199  	}
   200  	assertObservedGenerationEquals(t, k8sAuditConfig, preReconcileGeneration)
   201  	newK8sAuditConfig.SetResourceVersion(k8sAuditConfig.GetResourceVersion())
   202  	if err := kubeClient.Update(context.TODO(), newK8sAuditConfig); err != nil {
   203  		t.Fatalf("error updating k8s resource: %v", err)
   204  	}
   205  	preReconcileGeneration = newK8sAuditConfig.GetGeneration()
   206  	reconciler.ReconcileObjectMeta(newK8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   207  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(newK8sAuditConfig), newK8sAuditConfig); err != nil {
   208  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   209  	}
   210  	gcpAuditConfig, err = tfIamClient.GetAuditConfig(context.TODO(), newK8sAuditConfig)
   211  	if err != nil {
   212  		t.Fatalf("error retrieving GCP audit config: %v", err)
   213  	}
   214  	assertSameAuditConfigs(t, newK8sAuditConfig, gcpAuditConfig)
   215  	testcontroller.AssertReadyCondition(t, newK8sAuditConfig.Status.Conditions)
   216  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMAuditConfigGVK.Kind, &newK8sAuditConfig.ObjectMeta, k8s.UpToDate)
   217  	assertObservedGenerationEquals(t, newK8sAuditConfig, preReconcileGeneration)
   218  }
   219  
   220  func TestReconcileIAMAuditConfigResourceLevelNoChanges(t *testing.T) {
   221  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   222  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   223  			{
   224  				LogType: "DATA_WRITE",
   225  			},
   226  			{
   227  				LogType:         "DATA_READ",
   228  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   229  			},
   230  		}
   231  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   232  		testReconcileResourceLevelNoChanges(t, mgr, k8sAuditConfig)
   233  	}
   234  	testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunWithAuditConfigs)
   235  }
   236  
   237  func TestReconcileIAMAuditConfigResourceLevelNoChangesWithExternalRef(t *testing.T) {
   238  	shouldRun := func(fixture resourcefixture.ResourceFixture) bool {
   239  		return testiam.ShouldRunWithAuditConfigs(fixture) && testiam.ShouldRunWithExternalRef(fixture)
   240  	}
   241  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   242  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   243  			{
   244  				LogType: "DATA_WRITE",
   245  			},
   246  			{
   247  				LogType:         "DATA_READ",
   248  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   249  			},
   250  		}
   251  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   252  		testReconcileResourceLevelNoChanges(t, mgr, k8sAuditConfig)
   253  	}
   254  	testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, shouldRun)
   255  }
   256  
   257  func testReconcileResourceLevelNoChanges(t *testing.T, mgr manager.Manager, k8sAuditConfig *iamv1beta1.IAMAuditConfig) {
   258  	provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
   259  	smLoader := testservicemappingloader.New(t)
   260  	kubeClient := mgr.GetClient()
   261  	tfIamClient := kcciamclient.New(provider, smLoader, kubeClient, nil, nil).TFIAMClient
   262  	reconciler := testreconciler.New(t, mgr, provider)
   263  	if _, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig); !errors.Is(err, kcciamclient.NotFoundError) {
   264  		t.Fatalf("unexpected error value: got '%v', want '%v'", err, kcciamclient.NotFoundError)
   265  	}
   266  	if err := kubeClient.Create(context.TODO(), k8sAuditConfig); err != nil {
   267  		t.Fatalf("error creating k8s resource: %v", err)
   268  	}
   269  	preReconcileGeneration := k8sAuditConfig.GetGeneration()
   270  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   271  	gcpAuditConfig, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig)
   272  	if err != nil {
   273  		t.Fatalf("error retrieving GCP audit config: %v", err)
   274  	}
   275  	assertSameAuditConfigs(t, k8sAuditConfig, gcpAuditConfig)
   276  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err != nil {
   277  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   278  	}
   279  	assertObservedGenerationEquals(t, k8sAuditConfig, preReconcileGeneration)
   280  	preReconcileGeneration = k8sAuditConfig.GetGeneration()
   281  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   282  	newK8sAuditConfig := &iamv1beta1.IAMAuditConfig{}
   283  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), newK8sAuditConfig); err != nil {
   284  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   285  	}
   286  	gcpAuditConfig, err = tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig)
   287  	if err != nil {
   288  		t.Fatalf("error retrieving GCP audit config: %v", err)
   289  	}
   290  	assertSameAuditConfigs(t, newK8sAuditConfig, gcpAuditConfig)
   291  	if k8sAuditConfig.GetResourceVersion() != newK8sAuditConfig.GetResourceVersion() {
   292  		t.Errorf("reconcile that was expected to be a no-op resulted in a write to the API server")
   293  	}
   294  	testcontroller.AssertReadyCondition(t, newK8sAuditConfig.Status.Conditions)
   295  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMAuditConfigGVK.Kind, &newK8sAuditConfig.ObjectMeta, k8s.UpToDate)
   296  	assertObservedGenerationEquals(t, newK8sAuditConfig, preReconcileGeneration)
   297  }
   298  
   299  func TestReconcileIAMAuditConfigResourceLevelDelete(t *testing.T) {
   300  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   301  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   302  			{
   303  				LogType: "DATA_WRITE",
   304  			},
   305  			{
   306  				LogType:         "DATA_READ",
   307  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   308  			},
   309  		}
   310  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   311  		testReconcileResourceLevelDelete(t, mgr, k8sAuditConfig)
   312  	}
   313  	testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunWithAuditConfigs)
   314  }
   315  
   316  func TestReconcileIAMAuditConfigResourceLevelDeleteWithExternalRef(t *testing.T) {
   317  	shouldRun := func(fixture resourcefixture.ResourceFixture) bool {
   318  		return testiam.ShouldRunWithAuditConfigs(fixture) && testiam.ShouldRunWithExternalRef(fixture)
   319  	}
   320  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   321  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   322  			{
   323  				LogType: "DATA_WRITE",
   324  			},
   325  			{
   326  				LogType:         "DATA_READ",
   327  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   328  			},
   329  		}
   330  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   331  		testReconcileResourceLevelDelete(t, mgr, k8sAuditConfig)
   332  	}
   333  	testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, shouldRun)
   334  }
   335  
   336  func testReconcileResourceLevelDelete(t *testing.T, mgr manager.Manager, k8sAuditConfig *iamv1beta1.IAMAuditConfig) {
   337  	provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
   338  	smLoader := testservicemappingloader.New(t)
   339  	kubeClient := mgr.GetClient()
   340  	tfIamClient := kcciamclient.New(provider, smLoader, kubeClient, nil, nil).TFIAMClient
   341  	reconciler := testreconciler.New(t, mgr, provider)
   342  	if _, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig); !errors.Is(err, kcciamclient.NotFoundError) {
   343  		t.Fatalf("unexpected error value: got '%v', want '%v'", err, kcciamclient.NotFoundError)
   344  	}
   345  	if err := kubeClient.Create(context.TODO(), k8sAuditConfig); err != nil {
   346  		t.Fatalf("error creating k8s resource: %v", err)
   347  	}
   348  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   349  	gcpAuditConfig, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig)
   350  	if err != nil {
   351  		t.Fatalf("error retrieving GCP audit config: %v", err)
   352  	}
   353  	assertSameAuditConfigs(t, k8sAuditConfig, gcpAuditConfig)
   354  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err != nil {
   355  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   356  	}
   357  	testcontroller.AssertReadyCondition(t, k8sAuditConfig.Status.Conditions)
   358  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMAuditConfigGVK.Kind, &k8sAuditConfig.ObjectMeta, k8s.UpToDate)
   359  	if err := kubeClient.Delete(context.TODO(), k8sAuditConfig); err != nil {
   360  		t.Fatalf("error deleting k8s resource: %v", err)
   361  	}
   362  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, testreconciler.ExpectedRequeueReconcileStruct, nil)
   363  	_, err = tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig)
   364  	if err != nil {
   365  		t.Fatalf("expected audit config to exist in GCP, but got error: %v", err)
   366  	}
   367  	testk8s.RemoveDeletionDefenderFinalizer(t, k8sAuditConfig, v1beta1.IAMAuditConfigGVK, kubeClient)
   368  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   369  	if _, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig); !errors.Is(err, kcciamclient.NotFoundError) {
   370  		t.Fatalf("unexpected error value: got '%v', want '%v'", err, kcciamclient.NotFoundError)
   371  	}
   372  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err == nil || !apierrors.IsNotFound(err) {
   373  		t.Fatalf("unexpected error value: %v", err)
   374  	}
   375  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, v1beta1.IAMAuditConfigGVK.Kind, &k8sAuditConfig.ObjectMeta, k8s.Deleted)
   376  }
   377  
   378  func TestReconcileIAMAuditConfigResourceLevelDeleteParentFirst(t *testing.T) {
   379  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   380  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   381  			{
   382  				LogType: "DATA_WRITE",
   383  			},
   384  			{
   385  				LogType:         "DATA_READ",
   386  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   387  			},
   388  		}
   389  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   390  		testReconcileResourceLevelDeleteParentFirst(t, mgr, k8sAuditConfig, refResource)
   391  	}
   392  	testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunWithAuditConfigs)
   393  }
   394  
   395  func TestReconcileIAMAuditConfigResourceLevelDeleteParentFirstWithExternalRef(t *testing.T) {
   396  	shouldRun := func(fixture resourcefixture.ResourceFixture) bool {
   397  		return testiam.ShouldRunWithAuditConfigs(fixture) && testiam.ShouldRunWithExternalRef(fixture)
   398  	}
   399  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   400  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   401  			{
   402  				LogType: "DATA_WRITE",
   403  			},
   404  			{
   405  				LogType:         "DATA_READ",
   406  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   407  			},
   408  		}
   409  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   410  		testReconcileResourceLevelDeleteParentFirst(t, mgr, k8sAuditConfig, refResource)
   411  	}
   412  	testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, shouldRun)
   413  }
   414  
   415  func testReconcileResourceLevelDeleteParentFirst(t *testing.T, mgr manager.Manager, k8sAuditConfig *iamv1beta1.IAMAuditConfig, refResource *unstructured.Unstructured) {
   416  	provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
   417  	smLoader := testservicemappingloader.New(t)
   418  	kubeClient := mgr.GetClient()
   419  	tfIamClient := kcciamclient.New(provider, smLoader, kubeClient, nil, nil).TFIAMClient
   420  	reconciler := testreconciler.New(t, mgr, provider)
   421  	if _, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig); !errors.Is(err, kcciamclient.NotFoundError) {
   422  		t.Fatalf("unexpected error value: got '%v', want '%v'", err, kcciamclient.NotFoundError)
   423  	}
   424  	if err := kubeClient.Create(context.TODO(), k8sAuditConfig); err != nil {
   425  		t.Fatalf("error creating k8s resource: %v", err)
   426  	}
   427  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   428  	gcpAuditConfig, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig)
   429  	if err != nil {
   430  		t.Fatalf("error retrieving GCP audit config: %v", err)
   431  	}
   432  	assertSameAuditConfigs(t, k8sAuditConfig, gcpAuditConfig)
   433  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err != nil {
   434  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   435  	}
   436  	testcontroller.AssertReadyCondition(t, k8sAuditConfig.Status.Conditions)
   437  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, iamv1beta1.IAMAuditConfigGVK.Kind, &k8sAuditConfig.ObjectMeta, k8s.UpToDate)
   438  
   439  	// First, delete the parent resource of the IAMAuditConfig
   440  	if err := kubeClient.Delete(context.TODO(), refResource); err != nil {
   441  		t.Fatalf("error deleting parent resource: %v", err)
   442  	}
   443  	testk8s.RemoveDeletionDefenderFinalizerForUnstructured(t, refResource, kubeClient)
   444  	reconciler.Reconcile(refResource, expectedReconcileResult, nil)
   445  
   446  	// Then, delete the IAMAuditConfig
   447  	if err := kubeClient.Delete(context.TODO(), k8sAuditConfig); err != nil {
   448  		t.Fatalf("error deleting k8s resource: %v", err)
   449  	}
   450  	testk8s.RemoveDeletionDefenderFinalizer(t, k8sAuditConfig, v1beta1.IAMAuditConfigGVK, kubeClient)
   451  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   452  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err == nil || !apierrors.IsNotFound(err) {
   453  		t.Fatalf("unexpected error value: %v", err)
   454  	}
   455  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, v1beta1.IAMAuditConfigGVK.Kind, &k8sAuditConfig.ObjectMeta, k8s.Deleted)
   456  }
   457  
   458  func TestReconcileIAMAuditConfigResourceLevelAcquire(t *testing.T) {
   459  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   460  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   461  			{
   462  				LogType: "DATA_WRITE",
   463  			},
   464  			{
   465  				LogType:         "DATA_READ",
   466  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   467  			},
   468  		}
   469  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   470  		testReconcileResourceLevelAcquire(t, mgr, k8sAuditConfig)
   471  	}
   472  	testiam.RunResourceLevelTest(t, mgr, testFunc, testiam.ShouldRunWithAuditConfigs)
   473  }
   474  
   475  func TestReconcileIAMAuditConfigResourceLevelAcquireWithExternalRef(t *testing.T) {
   476  	shouldRun := func(fixture resourcefixture.ResourceFixture) bool {
   477  		return testiam.ShouldRunWithAuditConfigs(fixture) && testiam.ShouldRunWithExternalRef(fixture)
   478  	}
   479  	testFunc := func(t *testing.T, _ string, mgr manager.Manager, rc testiam.IAMResourceContext, refResource *unstructured.Unstructured, resourceRef v1beta1.ResourceReference) {
   480  		auditLogConfigs := []iamv1beta1.AuditLogConfig{
   481  			{
   482  				LogType: "DATA_WRITE",
   483  			},
   484  			{
   485  				LogType:         "DATA_READ",
   486  				ExemptedMembers: []v1beta1.Member{v1beta1.Member(testgcp.GetIAMPolicyBindingMember(t))},
   487  			},
   488  		}
   489  		k8sAuditConfig := newIAMAuditConfigFixture(t, refResource, resourceRef, "allServices", auditLogConfigs)
   490  		testReconcileResourceLevelAcquire(t, mgr, k8sAuditConfig)
   491  	}
   492  	testiam.RunResourceLevelTestWithExternalRef(t, mgr, testFunc, shouldRun)
   493  }
   494  
   495  func testReconcileResourceLevelAcquire(t *testing.T, mgr manager.Manager, k8sAuditConfig *iamv1beta1.IAMAuditConfig) {
   496  	provider := tfprovider.NewOrLogFatal(tfprovider.DefaultConfig)
   497  	smLoader := testservicemappingloader.New(t)
   498  	kubeClient := mgr.GetClient()
   499  	tfIamClient := kcciamclient.New(provider, smLoader, kubeClient, nil, nil).TFIAMClient
   500  	reconciler := testreconciler.New(t, mgr, provider)
   501  
   502  	// Create resource in GCP
   503  	if _, err := tfIamClient.SetAuditConfig(context.TODO(), k8sAuditConfig); err != nil {
   504  		t.Fatalf("error creating GCP audit config: %v", err)
   505  	}
   506  
   507  	// Acquire IAM Audit Config
   508  	if err := kubeClient.Create(context.TODO(), k8sAuditConfig); err != nil {
   509  		t.Fatalf("error creating k8s resource: %v", err)
   510  	}
   511  	preReconcileGeneration := k8sAuditConfig.GetGeneration()
   512  	reconciler.ReconcileObjectMeta(k8sAuditConfig.ObjectMeta, iamv1beta1.IAMAuditConfigGVK.Kind, expectedReconcileResult, nil)
   513  	if _, err := tfIamClient.GetAuditConfig(context.TODO(), k8sAuditConfig); err != nil {
   514  		t.Fatalf("error retrieving GCP audit config: %v", err)
   515  	}
   516  	if err := kubeClient.Get(context.TODO(), k8s.GetNamespacedName(k8sAuditConfig), k8sAuditConfig); err != nil {
   517  		t.Fatalf("unexpected error getting k8s resource: %v", err)
   518  	}
   519  	testcontroller.AssertReadyCondition(t, k8sAuditConfig.Status.Conditions)
   520  	testcontroller.AssertEventRecordedForObjectMetaAndKind(t, kubeClient, v1beta1.IAMAuditConfigGVK.Kind, &k8sAuditConfig.ObjectMeta, k8s.UpToDate)
   521  	assertObservedGenerationEquals(t, k8sAuditConfig, preReconcileGeneration)
   522  }
   523  
   524  func assertSameAuditConfigs(t *testing.T, k8sAuditConfig *iamv1beta1.IAMAuditConfig, gcpAuditConfig *iamv1beta1.IAMAuditConfig) {
   525  	if k8sAuditConfig.Spec.Service != gcpAuditConfig.Spec.Service {
   526  		t.Fatalf("GCP audit config has incorrect service: got %v, want %v", gcpAuditConfig.Spec.Service, k8sAuditConfig.Spec.Service)
   527  	}
   528  	if !reflect.DeepEqual(k8sAuditConfig.Spec.ResourceReference, gcpAuditConfig.Spec.ResourceReference) {
   529  		diff := cmp.Diff(k8sAuditConfig.Spec.ResourceReference, gcpAuditConfig.Spec.ResourceReference)
   530  		t.Fatalf("GCP audit config has incorrect resource reference. Diff (-want, +got):\n%v", diff)
   531  	}
   532  	if !testiam.SameAuditLogConfigs(k8sAuditConfig.Spec.AuditLogConfigs, gcpAuditConfig.Spec.AuditLogConfigs) {
   533  		t.Fatalf("GCP audit config has incorrect set of audit log configs; got: %v, want: %v", gcpAuditConfig.Spec.AuditLogConfigs, k8sAuditConfig.Spec.AuditLogConfigs)
   534  	}
   535  }
   536  
   537  func assertObservedGenerationEquals(t *testing.T, k8sAuditConfig *iamv1beta1.IAMAuditConfig, preReconcileGeneration int64) {
   538  	if k8sAuditConfig.Status.ObservedGeneration != preReconcileGeneration {
   539  		t.Errorf("observedGeneration %v doesn't match with the pre-reconcile generation %v", k8sAuditConfig.Status.ObservedGeneration, preReconcileGeneration)
   540  	}
   541  }
   542  
   543  func newIAMAuditConfigFixture(t *testing.T, refResource *unstructured.Unstructured, resourceRef iamv1beta1.ResourceReference, service string, auditLogConfigs []iamv1beta1.AuditLogConfig) *iamv1beta1.IAMAuditConfig {
   544  	return &iamv1beta1.IAMAuditConfig{
   545  		TypeMeta: metav1.TypeMeta{
   546  			APIVersion: iamv1beta1.IAMAuditConfigGVK.GroupKind().String(),
   547  			Kind:       iamv1beta1.IAMAuditConfigGVK.Kind,
   548  		},
   549  		ObjectMeta: metav1.ObjectMeta{
   550  			Name:      testcontroller.UniqueName(t, name(t)),
   551  			Namespace: refResource.GetNamespace(),
   552  		},
   553  		Spec: iamv1beta1.IAMAuditConfigSpec{
   554  			ResourceReference: resourceRef,
   555  			Service:           service,
   556  			AuditLogConfigs:   auditLogConfigs,
   557  		},
   558  	}
   559  }
   560  
   561  func name(t *testing.T) string {
   562  	// Necessary to remove the "/$KIND" portion of the subtest name
   563  	name := strings.ToLower(testcontroller.Name(t))
   564  	return strings.Split(name, "/")[0]
   565  }
   566  
   567  func TestMain(m *testing.M) {
   568  	testmain.TestMainForIntegrationTests(m, &mgr)
   569  }
   570  

View as plain text