github.com/verrazzano/verrazzano@v1.7.0/application-operator/mcagent/mcagent_cattle_agent_test.go (about) 1 // Copyright (c) 2022, 2023, 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 mcagent 5 6 import ( 7 "context" 8 "encoding/json" 9 "fmt" 10 "io" 11 "net/http" 12 "net/http/httptest" 13 "os" 14 "testing" 15 16 "github.com/stretchr/testify/assert" 17 "go.uber.org/zap" 18 corev1 "k8s.io/api/core/v1" 19 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 20 "k8s.io/apimachinery/pkg/runtime" 21 "sigs.k8s.io/controller-runtime/pkg/client/fake" 22 ) 23 24 // TestSyncer_syncCattleClusterAgent tests the syncCattleClusterAgent of Syncer 25 // GIVEN a call to syncCattleClusterAgent 26 // WHEN there exists no previous cattle agent hash 27 // THEN update the cattle-cluster-agent deployment, create the cattle-credential secret and update the hash 28 func TestSyncer_syncCattleClusterAgent(t *testing.T) { 29 asserts := assert.New(t) 30 log := zap.S().With("test") 31 32 scheme := runtime.NewScheme() 33 err := corev1.SchemeBuilder.AddToScheme(scheme) 34 asserts.NoError(err) 35 36 secret, err := getSampleSecret("testdata/registration-manifest.yaml") 37 asserts.NoError(err) 38 39 adminClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&secret).Build() 40 41 server := newServer() 42 defer server.Close() 43 44 err = createFakeKubeConfig(server.URL) 45 defer deleteFakeKubeConfig() 46 asserts.NoError(err) 47 48 kubeConfigPath, err := getFakeKubeConfigPath() 49 asserts.NoError(err) 50 51 s := Syncer{ 52 AdminClient: adminClient, 53 Log: log, 54 ManagedClusterName: "cluster1", 55 Context: context.TODO(), 56 } 57 58 newCattleAgentHash, err := s.syncCattleClusterAgent("", kubeConfigPath) 59 asserts.NoError(err) 60 asserts.NotEmpty(newCattleAgentHash) 61 } 62 63 // TestSyncer_syncCattleClusterAgentNoRancherManifest tests the syncCattleClusterAgent of Syncer 64 // GIVEN a call to syncCattleClusterAgent 65 // WHEN the registration manifest doesn't have the required rancher resources 66 // THEN do nothing and return 67 func TestSyncer_syncCattleClusterAgentNoRancherManifest(t *testing.T) { 68 asserts := assert.New(t) 69 log := zap.S().With("test") 70 71 scheme := runtime.NewScheme() 72 err := corev1.SchemeBuilder.AddToScheme(scheme) 73 asserts.NoError(err) 74 75 secret, err := getSampleSecret("testdata/incomplete-registration-manifest.yaml") 76 asserts.NoError(err) 77 78 adminClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&secret).Build() 79 80 s := Syncer{ 81 AdminClient: adminClient, 82 Log: log, 83 ManagedClusterName: "cluster1", 84 Context: context.TODO(), 85 } 86 87 newCattleAgentHash, err := s.syncCattleClusterAgent("", "") 88 asserts.NoError(err) 89 asserts.Empty(newCattleAgentHash) 90 } 91 92 // TestSyncer_syncCattleClusterAgentHashExists tests the syncCattleClusterAgent of Syncer 93 func TestSyncer_syncCattleClusterAgentHashExists(t *testing.T) { 94 asserts := assert.New(t) 95 log := zap.S().With("test") 96 97 scheme := runtime.NewScheme() 98 err := corev1.SchemeBuilder.AddToScheme(scheme) 99 asserts.NoError(err) 100 101 secret, err := getSampleSecret("testdata/registration-manifest.yaml") 102 asserts.NoError(err) 103 104 adminClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(&secret).Build() 105 106 server := newServer() 107 defer server.Close() 108 109 err = createFakeKubeConfig(server.URL) 110 defer deleteFakeKubeConfig() 111 asserts.NoError(err) 112 113 kubeConfigPath, err := getFakeKubeConfigPath() 114 asserts.NoError(err) 115 116 // Initialise the cattleAgentHash with a random hash string 117 previousCattleAgentHash := "[1 61 83 140 196 214 70 37 227 165 192 170 234 13 222 47 123]" 118 119 s := Syncer{ 120 AdminClient: adminClient, 121 Log: log, 122 ManagedClusterName: "cluster1", 123 Context: context.TODO(), 124 } 125 126 // GIVEN a call to syncCattleClusterAgent 127 // WHEN a hash already exists 128 // THEN if the hash has changed, update the resources and the hash 129 newCattleAgentHash, err := s.syncCattleClusterAgent(previousCattleAgentHash, kubeConfigPath) 130 asserts.NoError(err) 131 asserts.NotEmpty(newCattleAgentHash) 132 asserts.NotEqual(previousCattleAgentHash, newCattleAgentHash) 133 134 previousCattleAgentHash = newCattleAgentHash 135 136 // GIVEN a call to syncCattleClusterAgent 137 // WHEN a hash already exists 138 // THEN if the hash has not changed, do nothing 139 newerCattleAgentHash, err := s.syncCattleClusterAgent(previousCattleAgentHash, "") 140 asserts.NoError(err) 141 asserts.NotEmpty(newerCattleAgentHash) 142 asserts.Equal(previousCattleAgentHash, newerCattleAgentHash) 143 } 144 145 // newServer returns a httptest server which the 146 // dynamic client and discovery client can send 147 // GET/POST/PATCH/DELETE requests to instead of a real cluster 148 func newServer() *httptest.Server { 149 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 150 var obj interface{} 151 switch req.URL.Path { 152 case "/api/v1/namespaces/cattle-system": 153 obj = &metav1.APIVersions{ 154 TypeMeta: metav1.TypeMeta{ 155 Kind: "APIVersions", 156 }, 157 Versions: []string{ 158 "v1", 159 }, 160 } 161 case "/api": 162 obj = &metav1.APIVersions{ 163 Versions: []string{ 164 "v1", 165 }, 166 } 167 case "/api/v1": 168 obj = &metav1.APIResourceList{ 169 GroupVersion: "v1", 170 APIResources: []metav1.APIResource{ 171 {Name: "secrets", Namespaced: true, Kind: "Secret"}, 172 }, 173 } 174 case "/apis/apps/v1/namespaces/cattle-system/deployments/cattle-cluster-agent": 175 body, _ := io.ReadAll(req.Body) 176 w.Write(body) 177 return 178 case "/api/v1/namespaces/cattle-system/secrets": 179 body, _ := io.ReadAll(req.Body) 180 w.Write(body) 181 return 182 default: 183 w.WriteHeader(http.StatusNotFound) 184 return 185 } 186 output, err := json.Marshal(obj) 187 if err != nil { 188 return 189 } 190 w.Header().Set("Content-Type", "application/json") 191 w.WriteHeader(http.StatusOK) 192 w.Write(output) 193 })) 194 return server 195 } 196 197 // createFakeKubeConfig creates a fake kubeconfig 198 // in the pwd with the url of the httptest server 199 func createFakeKubeConfig(url string) error { 200 fakeKubeConfig, err := os.Create("dummy-kubeconfig") 201 defer fakeKubeConfig.Close() 202 203 if err != nil { 204 return err 205 } 206 207 _, err = fmt.Fprintf(fakeKubeConfig, `apiVersion: v1 208 clusters: 209 - cluster: 210 # This is dummy data 211 certificate-authority-data: RFVNTVkgQ0VSVElGSUNBVEU= 212 server: %s 213 name: user-test 214 users: 215 - name: user-test 216 contexts: 217 - context: 218 cluster: user-test 219 user: user-test 220 name: user-test 221 current-context: user-test`, url) 222 223 return err 224 } 225 226 func getFakeKubeConfigPath() (string, error) { 227 pwd, err := os.Getwd() 228 229 if err != nil { 230 return pwd, err 231 } 232 233 pwd = pwd + "/dummy-kubeconfig" 234 return pwd, nil 235 } 236 237 func deleteFakeKubeConfig() error { 238 err := os.Remove("dummy-kubeconfig") 239 return err 240 }