github.com/verrazzano/verrazzano@v1.7.0/application-operator/controllers/namespace/fluentd_configmap_test.go (about) 1 // Copyright (c) 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package namespace 5 6 import ( 7 "context" 8 "fmt" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/verrazzano/verrazzano/pkg/constants" 13 corev1 "k8s.io/api/core/v1" 14 "k8s.io/apimachinery/pkg/api/errors" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 "k8s.io/apimachinery/pkg/types" 17 k8scheme "k8s.io/client-go/kubernetes/scheme" 18 "sigs.k8s.io/controller-runtime/pkg/client/fake" 19 ) 20 21 const ( 22 testNamespace = "unit-test-ns" 23 testLogID = "ocid1.log.oc1.test" 24 ) 25 26 const fluentdConfig = `| 27 # Common config 28 @include general.conf 29 30 # Input sources 31 @include systemd-input.conf 32 @include kubernetes-input.conf 33 34 # Parsing/Filtering 35 @include systemd-filter.conf 36 @include kubernetes-filter.conf 37 38 # Send to storage 39 @include output.conf 40 # Start namespace logging configs 41 # End namespace logging configs 42 @include oci-logging-system.conf 43 @include oci-logging-default-app.conf 44 ` 45 46 // TestAddAndRemoveNamespaceLogging tests adding and removing namespace logging config to the Fluentd config map. 47 func TestAddAndRemoveNamespaceLogging(t *testing.T) { 48 asserts := assert.New(t) 49 50 // GIVEN a system Fluentd config map 51 // WHEN I add namespace-specific logging configuration 52 // THEN the config map gets updated in the cluster and contains the new logging config 53 cm := newConfigMap() 54 cm.Data = make(map[string]string) 55 cm.Data[fluentdConfigKey] = fluentdConfig 56 57 client := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(cm).Build() 58 59 updated, err := addNamespaceLogging(context.TODO(), client, testNamespace, testLogID) 60 asserts.NoError(err) 61 asserts.True(updated) 62 63 // fetch the config map and make sure it was updated correctly 64 cm = &corev1.ConfigMap{} 65 err = client.Get(context.TODO(), types.NamespacedName{Name: fluentdConfigMapName, Namespace: constants.VerrazzanoSystemNamespace}, cm) 66 asserts.NoError(err) 67 68 nsConfigKey := fmt.Sprintf(nsConfigKeyTemplate, testNamespace) 69 includeSection := fmt.Sprintf("%s\n@include oci-logging-ns-unit-test-ns.conf\n", startNamespaceConfigsMarker) 70 asserts.Contains(cm.Data[fluentdConfigKey], includeSection) 71 asserts.Contains(cm.Data, nsConfigKey) 72 asserts.Contains(cm.Data[nsConfigKey], testLogID) 73 74 // GIVEN a system Fluentd config map with namespace-specific logging config 75 // WHEN I remove the namespace-specific logging configuration 76 // THEN the config map gets updated in the cluster and the config map matches the state prior to adding the config 77 updated, err = removeNamespaceLogging(context.TODO(), client, testNamespace) 78 asserts.NoError(err) 79 asserts.True(updated) 80 81 // fetch the config map and make sure the namespace logging config was removed 82 cm = &corev1.ConfigMap{} 83 err = client.Get(context.TODO(), types.NamespacedName{Name: fluentdConfigMapName, Namespace: constants.VerrazzanoSystemNamespace}, cm) 84 asserts.NoError(err) 85 asserts.Equal(fluentdConfig, cm.Data[fluentdConfigKey]) 86 asserts.NotContains(cm.Data, nsConfigKey) 87 } 88 89 // TestMissingFluentdConfigMap tests the cases where the system Fluentd config map is not found. 90 func TestMissingFluentdConfigMap(t *testing.T) { 91 asserts := assert.New(t) 92 93 // GIVEN there is no system Fluentd config map 94 // WHEN I add namespace-specific logging configuration 95 // THEN an error is returned 96 client := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).Build() 97 _, err := addNamespaceLogging(context.TODO(), client, testNamespace, testLogID) 98 asserts.Error(err) 99 asserts.Contains(err.Error(), "must exist") 100 101 // GIVEN there is no system Fluentd config map 102 // WHEN I attempt to remove namespace-specific logging configuration 103 // THEN no error is returned and the config map has not been created 104 updated, err := removeNamespaceLogging(context.TODO(), client, testNamespace) 105 asserts.NoError(err) 106 asserts.False(updated) 107 108 cm := &corev1.ConfigMap{} 109 err = client.Get(context.TODO(), types.NamespacedName{Name: fluentdConfigMapName, Namespace: constants.VerrazzanoSystemNamespace}, cm) 110 asserts.True(errors.IsNotFound(err)) 111 } 112 113 // TestAddNamespaceLoggingAlreadyExists tests the case where we add logging config and it already exists in the config map. 114 // Since this operation is idempotent the config map should not be updated. 115 func TestAddNamespaceLoggingAlreadyExists(t *testing.T) { 116 asserts := assert.New(t) 117 118 // GIVEN a system Fluentd config map 119 // WHEN I add namespace-specific logging configuration and I attempt to add the same logging configuration 120 // THEN the config map is not updated a second time 121 cm := newConfigMap() 122 cm.Data = make(map[string]string) 123 cm.Data[fluentdConfigKey] = fluentdConfig 124 125 client := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(cm).Build() 126 127 updated, err := addNamespaceLogging(context.TODO(), client, testNamespace, testLogID) 128 asserts.NoError(err) 129 asserts.True(updated) 130 131 updated, err = addNamespaceLogging(context.TODO(), client, testNamespace, testLogID) 132 asserts.NoError(err) 133 asserts.False(updated) 134 } 135 136 // TestRemoveNamespaceLoggingDoesNotExist tests the case where we remove logging config and it does not exist in the config map. 137 // Since this operation is idempotent the config map should not be updated. 138 func TestRemoveNamespaceLoggingDoesNotExist(t *testing.T) { 139 asserts := assert.New(t) 140 141 // GIVEN a system Fluentd config map that does not contain namespace-specific logging config 142 // WHEN I attempt to remove the logging config 143 // THEN the config map is not updated 144 cm := newConfigMap() 145 cm.Data = make(map[string]string) 146 cm.Data[fluentdConfigKey] = fluentdConfig 147 148 client := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(cm).Build() 149 150 updated, err := removeNamespaceLogging(context.TODO(), client, testNamespace) 151 asserts.NoError(err) 152 asserts.False(updated) 153 } 154 155 // TestUpdateExistingLoggingConfig tests the case where the logging config already exists but the log id is updated. 156 func TestUpdateExistingLoggingConfig(t *testing.T) { 157 asserts := assert.New(t) 158 159 // GIVEN a system Fluentd config map that contains namespace-specific logging config 160 // WHEN I attempt to add logging config for the same namespace and the log id has changed 161 // THEN the config map is updated and it contains the updated log id 162 cm := newConfigMap() 163 cm.Data = make(map[string]string) 164 cm.Data[fluentdConfigKey] = fluentdConfig 165 166 client := fake.NewClientBuilder().WithScheme(k8scheme.Scheme).WithObjects(cm).Build() 167 168 updated, err := addNamespaceLogging(context.TODO(), client, testNamespace, testLogID) 169 asserts.NoError(err) 170 asserts.True(updated) 171 172 // add logging config with an updated log id 173 updatedLogID := "ocid1.log.oc1.updated" 174 updated, err = addNamespaceLogging(context.TODO(), client, testNamespace, updatedLogID) 175 asserts.NoError(err) 176 asserts.True(updated) 177 178 // fetch the config map and confirm that the config exists and it references the updated log id 179 cm = &corev1.ConfigMap{} 180 err = client.Get(context.TODO(), types.NamespacedName{Name: fluentdConfigMapName, Namespace: constants.VerrazzanoSystemNamespace}, cm) 181 asserts.NoError(err) 182 183 nsConfigKey := fmt.Sprintf(nsConfigKeyTemplate, testNamespace) 184 includeSection := fmt.Sprintf("%s\n@include oci-logging-ns-unit-test-ns.conf\n", startNamespaceConfigsMarker) 185 asserts.Contains(cm.Data[fluentdConfigKey], includeSection) 186 asserts.Contains(cm.Data, nsConfigKey) 187 asserts.Contains(cm.Data[nsConfigKey], updatedLogID) 188 } 189 190 // newConfigMap returns a ConfigMap populated with the system Fluentd config map name and namespace, and 191 // a creation timestamp. 192 func newConfigMap() *corev1.ConfigMap { 193 return &corev1.ConfigMap{ 194 ObjectMeta: metav1.ObjectMeta{ 195 Name: fluentdConfigMapName, 196 Namespace: constants.VerrazzanoSystemNamespace, 197 CreationTimestamp: metav1.Now(), 198 }, 199 } 200 }