/* 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 https://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 cloudinit import ( "strings" "testing" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "opendev.org/airship/airshipctl/pkg/document" testdoc "opendev.org/airship/airshipctl/testutil/document" ) type testData struct { docsCfg []string secret string ephUser string ephNode string bmh string selectorNamespace string selectorName string mockErr1 interface{} mockErr2 interface{} mockErr3 interface{} } const ( ephNode = "airshipit.org/ephemeral-node in (True, true)" secret = "Secret" bmh = "BareMetalHost" ephUser = "airshipit.org/ephemeral-user-data in (True, true)" ephUserData = `apiVersion: v1 kind: Secret metadata: labels: airshipit.org/ephemeral-user-data: 'true' name: networkdatamalformed-malformed type: Opaque stringData: userData: cloud-init ` ephUserDataMalformed = `apiVersion: v1 kind: Secret metadata: labels: airshipit.org/ephemeral-user-data: 'true' test: userdatamalformed name: userdatamalformed-somesecret type: Opaque stringData: no-user-data: this secret has the right label but is missing the 'user-data' key ` ephUserDataNoLabel = `apiVersion: v1 kind: Secret metadata: labels: test: userdatamissing name: userdatamissing-somesecret type: Opaque stringData: userData: "this secret lacks the label airshipit.org/ephemeral-user-data: true"` ephUserDataCredentials = `apiVersion: v1 kind: Secret metadata: labels: name: master-1-bmc type: Opaque stringData: username: foobar password: goober ` bmhMaster1 = `apiVersion: metal3.io/v1alpha1 kind: BareMetalHost metadata: labels: airshipit.org/ephemeral-node: 'true' name: master-1 spec: bmc: address: ipmi://127.0.0.1 credentialsName: master-1-bmc networkData: name: master-1-networkdata namespace: metal3 ` netDataMalFormed = `apiVersion: v1 kind: Secret metadata: labels: name: networkdatamalformed-malformed namespace: malformed type: Opaque stringData: no-net-data-key: the required 'net-data' key is missing ` bmhDuplicate = `apiVersion: metal3.io/v1alpha1 kind: BareMetalHost metadata: labels: test: ephemeralduplicate airshipit.org/ephemeral-node: 'true' name: ephemeralduplicate-master-1 ` ephMissing = `apiVersion: v1 kind: Secret metadata: labels: test: ephemeralmissing name: ephemeralmissing type: Opaque ` ephNetValid = `apiVersion: v1 kind: Secret metadata: labels: test: validdocset name: master-1-networkdata namespace: metal3 type: Opaque stringData: networkData: net-config ` ) func getValidDocSet() []string { return []string{ ephUserData, bmhMaster1, ephNetValid, ephUserDataCredentials, } } func getEphemeralMissing() []string { return []string{ ephUserData, ephMissing, bmhMaster1, } } func getEphemeralDuplicate() []string { return []string{ ephUserData, bmhDuplicate, bmhDuplicate, } } func getNetworkBadPointer() []string { return []string{ ephUserData, bmhMaster1, ephUserDataCredentials, } } func getNetDataMalformed() []string { return []string{ ephUserData, bmhMaster1, netDataMalFormed, ephUserDataCredentials, } } func getUserDataMalformed() []string { return []string{ ephUserDataMalformed, } } func getUserDataMissing() []string { return []string{ ephUserDataNoLabel, } } func createTestBundle(t *testing.T, td testData) document.Bundle { bundle := &testdoc.MockBundle{} allDocs := make([]document.Document, len(td.docsCfg)) returnedDocs := make(map[string]document.Document) for i, cfg := range td.docsCfg { doc, err := document.NewDocumentFromBytes([]byte(cfg)) require.NoError(t, err) allDocs[i] = doc kind, selectorMap, name, namespace := doc.GetKind(), doc.GetLabels(), doc.GetName(), doc.GetNamespace() // We use data in the document to determine which document should be returned from each mock // function call. if _, ok := selectorMap[strings.TrimSuffix(td.ephUser, " in (True, true)")]; ok && kind == td.secret { returnedDocs["userDataDoc"] = doc // initialize these two key-value pairs so that we avoid // memory address errors. These will be overwritten. returnedDocs["bmhDoc"] = doc returnedDocs["ephOrBmhDoc"] = doc } else if _, ok := selectorMap[strings.TrimSuffix(td.ephNode, " in (True, true)")]; ok && kind == td.bmh { returnedDocs["bmhDoc"] = doc } else if kind == td.secret && name == td.selectorName && namespace == td.selectorNamespace { returnedDocs["ephOrBmhDoc"] = doc } } bundle.On("GetAllDocuments").Return(allDocs, nil) bundle.On("SelectOne", mock.MatchedBy(func(selector document.Selector) bool { return selector.Kind == td.secret && selector.LabelSelector == td.ephUser })). Return(returnedDocs["userDataDoc"], td.mockErr1) bundle.On("SelectOne", mock.MatchedBy(func(selector document.Selector) bool { return selector.Kind == td.bmh && selector.LabelSelector == td.ephNode })). Return(returnedDocs["bmhDoc"], td.mockErr2) bundle.On("SelectOne", mock.MatchedBy(func(selector document.Selector) bool { return selector.Kind == td.secret && selector.Namespace == td.selectorNamespace && selector.Name == td.selectorName })). Return(returnedDocs["ephOrBmhDoc"], td.mockErr3) return bundle }