diff --git a/pkg/bootstrap/cloudinit/cloud-init_test.go b/pkg/bootstrap/cloudinit/cloud-init_test.go index e7fd061a1..16c47d738 100644 --- a/pkg/bootstrap/cloudinit/cloud-init_test.go +++ b/pkg/bootstrap/cloudinit/cloud-init_test.go @@ -35,24 +35,22 @@ var ( } validSelectors = selectors{ userDataSelector: document.NewSelector(). - ByKind("Secret"). - ByLabel("airshipit.org/ephemeral-user-data in (True, true)"), + ByKind(secret). + ByLabel(ephUser), userDataKey: defaultUserDataKey, networkConfigSelector: document.NewSelector(). - ByKind("BareMetalHost"). - ByLabel("airshipit.org/ephemeral-node in (True, true)"), + ByKind(bmh). + ByLabel(ephNode), networkConfigKey: defaultNetworkConfigKey, } ) func TestGetCloudData(t *testing.T) { - bundle, err := document.NewBundleByPath("testdata") - require.NoError(t, err, "Building Bundle Failed") - tests := []struct { name string selectors labelFilter string + testBundle document.Bundle expectedUserData []byte expectedNetData []byte expectedErr error @@ -64,6 +62,18 @@ func TestGetCloudData(t *testing.T) { expectedUserData: []byte("cloud-init"), expectedNetData: []byte("net-config"), expectedErr: nil, + testBundle: createTestBundle(t, testData{ + docsCfg: getValidDocSet(), + secret: "Secret", + bmh: "BareMetalHost", + ephNode: "airshipit.org/ephemeral-node in (True, true)", + ephUser: "airshipit.org/ephemeral-user-data in (True, true)", + selectorNamespace: "metal3", + selectorName: "master-1-networkdata", + mockErr1: nil, + mockErr2: nil, + mockErr3: nil, + }), }, { name: "BareMetalHost document not found", @@ -74,8 +84,24 @@ func TestGetCloudData(t *testing.T) { expectedErr: document.ErrDocNotFound{ Selector: document.NewSelector(). ByLabel(document.EphemeralHostSelector). - ByKind("BareMetalHost"), + ByKind(bmh), }, + testBundle: createTestBundle(t, testData{ + docsCfg: getEphemeralMissing(), + secret: "Secret", + bmh: "BareMetalHost", + ephNode: "airshipit.org/ephemeral-node in (True, true)", + ephUser: "airshipit.org/ephemeral-user-data in (True, true)", + selectorNamespace: "", + selectorName: "", + mockErr1: nil, + mockErr2: document.ErrDocNotFound{ + Selector: document.NewSelector(). + ByLabel(document.EphemeralHostSelector). + ByKind(bmh), + }, + mockErr3: nil, + }), }, { name: "BareMetalHost document duplication", @@ -86,8 +112,24 @@ func TestGetCloudData(t *testing.T) { expectedErr: document.ErrMultiDocsFound{ Selector: document.NewSelector(). ByLabel(document.EphemeralHostSelector). - ByKind("BareMetalHost"), + ByKind(bmh), }, + testBundle: createTestBundle(t, testData{ + docsCfg: getEphemeralDuplicate(), + secret: "Secret", + bmh: "BareMetalHost", + ephNode: "airshipit.org/ephemeral-node in (True, true)", + ephUser: "airshipit.org/ephemeral-user-data in (True, true)", + selectorNamespace: "", + selectorName: "", + mockErr1: nil, + mockErr2: document.ErrMultiDocsFound{ + Selector: document.NewSelector(). + ByLabel(document.EphemeralHostSelector). + ByKind(bmh), + }, + mockErr3: nil, + }), }, { name: "Bad network data document reference", @@ -97,10 +139,27 @@ func TestGetCloudData(t *testing.T) { expectedNetData: nil, expectedErr: document.ErrDocNotFound{ Selector: document.NewSelector(). - ByKind("Secret"). + ByKind(secret). ByNamespace("networkdatabadpointer-missing"). ByName("networkdatabadpointer-missing"), }, + testBundle: createTestBundle(t, testData{ + docsCfg: getNetworkBadPointer(), + secret: "Secret", + bmh: "BareMetalHost", + ephNode: "airshipit.org/ephemeral-node in (True, true)", + ephUser: "airshipit.org/ephemeral-user-data in (True, true)", + selectorNamespace: "metal3", + selectorName: "master-1-networkdata", + mockErr1: nil, + mockErr2: nil, + mockErr3: document.ErrDocNotFound{ + Selector: document.NewSelector(). + ByKind(secret). + ByNamespace("networkdatabadpointer-missing"). + ByName("networkdatabadpointer-missing"), + }, + }), }, { name: "Bad network data document structure", @@ -112,6 +171,18 @@ func TestGetCloudData(t *testing.T) { DocName: "networkdatamalformed-malformed", Key: defaultNetworkConfigKey, }, + testBundle: createTestBundle(t, testData{ + docsCfg: getNetDataMalformed(), + secret: "Secret", + bmh: "BareMetalHost", + ephNode: "airshipit.org/ephemeral-node in (True, true)", + ephUser: "airshipit.org/ephemeral-user-data in (True, true)", + selectorNamespace: "metal3", + selectorName: "master-1-networkdata", + mockErr1: nil, + mockErr2: nil, + mockErr3: nil, + }), }, { name: "Bad user data document structure", @@ -123,6 +194,18 @@ func TestGetCloudData(t *testing.T) { DocName: "userdatamalformed-somesecret", Key: defaultUserDataKey, }, + testBundle: createTestBundle(t, testData{ + docsCfg: getUserDataMalformed(), + secret: "Secret", + bmh: "BareMetalHost", + ephNode: "airshipit.org/ephemeral-node in (True, true)", + ephUser: "airshipit.org/ephemeral-user-data in (True, true)", + selectorNamespace: "", + selectorName: "", + mockErr1: nil, + mockErr2: nil, + mockErr3: nil, + }), }, { name: "User data document not found", @@ -132,26 +215,36 @@ func TestGetCloudData(t *testing.T) { expectedNetData: nil, expectedErr: document.ErrDocNotFound{ Selector: document.NewSelector(). - ByKind("Secret"). + ByKind(secret). ByLabel(document.EphemeralUserDataSelector), }, + testBundle: createTestBundle(t, testData{ + docsCfg: getUserDataMissing(), + secret: "Secret", + bmh: "BareMetalHost", + ephNode: "airshipit.org/ephemeral-node in (True, true)", + ephUser: "airshipit.org/ephemeral-user-data in (True, true)", + selectorNamespace: "", + selectorName: "", + mockErr1: document.ErrDocNotFound{ + Selector: document.NewSelector(). + ByKind(secret). + ByLabel(document.EphemeralUserDataSelector), + }, + mockErr2: nil, + mockErr3: nil, + }), }, } - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - // prune the bundle down using the label filter for the specific test - selector := document.NewSelector().ByLabel(tt.labelFilter) - filteredBundle, err := bundle.SelectBundle(selector) - require.NoError(t, err, "Building filtered bundle for %s failed", tt.labelFilter) - // ensure each test case filter has at least one document - docs, err := filteredBundle.GetAllDocuments() + docs, err := tt.testBundle.GetAllDocuments() require.NoError(t, err, "GetAllDocuments failed") require.NotZero(t, docs) actualUserData, actualNetData, actualErr := GetCloudData( - filteredBundle, + tt.testBundle, tt.userDataSelector, tt.userDataKey, tt.networkConfigSelector, diff --git a/pkg/bootstrap/cloudinit/cloud-init_testutils.go b/pkg/bootstrap/cloudinit/cloud-init_testutils.go new file mode 100644 index 000000000..e2cfd2af2 --- /dev/null +++ b/pkg/bootstrap/cloudinit/cloud-init_testutils.go @@ -0,0 +1,231 @@ +/* + 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 +} diff --git a/pkg/bootstrap/cloudinit/testdata/ephemeralduplicate.yaml b/pkg/bootstrap/cloudinit/testdata/ephemeralduplicate.yaml deleted file mode 100644 index 714b5b128..000000000 --- a/pkg/bootstrap/cloudinit/testdata/ephemeralduplicate.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# in this document set, we have no ephemerally labeled node -# which should cause an error -apiVersion: v1 -kind: Secret -metadata: - labels: - test: ephemeralduplicate - name: ephemeralduplicate -type: Opaque ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - test: ephemeralduplicate - airshipit.org/ephemeral-node: 'true' - name: ephemeralduplicate-master-1 ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - test: ephemeralduplicate - airshipit.org/ephemeral-node: 'true' - name: ephemeralduplicate-master-2 ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/ephemeral-user-data: 'true' - test: ephemeralduplicate - name: ephemeralduplicate-airship-isogen-userdata -type: Opaque -stringData: - userData: cloudinit \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/ephemeralmissing.yaml b/pkg/bootstrap/cloudinit/testdata/ephemeralmissing.yaml deleted file mode 100644 index 3bd2302b8..000000000 --- a/pkg/bootstrap/cloudinit/testdata/ephemeralmissing.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# in this document set, we have no ephemerally labeled node -# which should cause an error -apiVersion: v1 -kind: Secret -metadata: - labels: - test: ephemeralmissing - name: ephemeralmissing -type: Opaque ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - test: ephemeralmissing - name: ephemeralmissing-master-1 ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/ephemeral-user-data: 'true' - test: ephemeralmissing - name: ephemeralmissing-airship-isogen-userdata -type: Opaque -stringData: - userData: cloud-init \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/kustomization.yaml b/pkg/bootstrap/cloudinit/testdata/kustomization.yaml deleted file mode 100644 index c301ece0e..000000000 --- a/pkg/bootstrap/cloudinit/testdata/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -resources: - - ephemeralduplicate.yaml - - ephemeralmissing.yaml - - networkdatabadpointer.yaml - - networkdatamalformed.yaml - - networkdatamissing.yaml - - userdatamalformed.yaml - - userdatamissing.yaml - - validdocset.yaml \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/networkdatabadpointer.yaml b/pkg/bootstrap/cloudinit/testdata/networkdatabadpointer.yaml deleted file mode 100644 index c7701b550..000000000 --- a/pkg/bootstrap/cloudinit/testdata/networkdatabadpointer.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# in this document set, we have an ephemeral node however -# it lacks a networkData clause -apiVersion: v1 -kind: Secret -metadata: - labels: - test: networkdatabadpointer - name: networkdatabadpointer-master-1-bmc -type: Opaque -stringData: - username: foobar - password: goober ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - airshipit.org/ephemeral-node: 'true' - test: networkdatabadpointer - name: networkdatabadpointer-master-1 -spec: - bmc: - address: ipmi://127.0.0.1 - credentialsName: networkdatabadpointer-master-1-bmc - networkData: - name: networkdatabadpointer-missing - namespace: networkdatabadpointer-missing ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/ephemeral-user-data: 'true' - test: networkdatabadpointer - name: networkdatabadpointer-airship-isogen-userdata -type: Opaque -stringData: - userData: cloud-init \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/networkdatamalformed.yaml b/pkg/bootstrap/cloudinit/testdata/networkdatamalformed.yaml deleted file mode 100644 index b2733d2ea..000000000 --- a/pkg/bootstrap/cloudinit/testdata/networkdatamalformed.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# in this document set, we have an ephemeral node with -# resolvable network data, but it is malformed lacking -# the proper field -apiVersion: v1 -kind: Secret -metadata: - labels: - test: networkdatamalformed - name: networkdatamalformed-master-1-bmc -type: Opaque -stringData: - username: foobar - password: goober ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - test: networkdatamalformed - name: networkdatamalformed-malformed - namespace: malformed -type: Opaque -stringData: - no-net-data-key: the required 'net-data' key is missing ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - airshipit.org/ephemeral-node: 'true' - test: networkdatamalformed - name: networkdatamalformed-master-1 -spec: - bmc: - address: ipmi://127.0.0.1 - credentialsName: networkdatamalformed-master-1-bmc - networkData: - name: networkdatamalformed-malformed - namespace: malformed ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/ephemeral-user-data: 'true' - test: networkdatamalformed - name: networkdatamalformed-airship-isogen-userdata -type: Opaque -stringData: - userData: cloud-init \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/networkdatamissing.yaml b/pkg/bootstrap/cloudinit/testdata/networkdatamissing.yaml deleted file mode 100644 index d40ef57bb..000000000 --- a/pkg/bootstrap/cloudinit/testdata/networkdatamissing.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# in this document set, we have an ephemeral node with -# but it lacks a networkData clause -apiVersion: v1 -kind: Secret -metadata: - labels: - test: networkdatamissing - name: networkdatamissing-master-1-bmc -type: Opaque -stringData: - username: foobar - password: goober ---- -apiVersion: v1 -kind: Secret -namespace: missing -metadata: - labels: - test: missing - name: networkdatamissing-missing -type: Opaque -stringData: - networkData: there is network data here, but we have no reference to it ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - airshipit.org/ephemeral-node: 'true' - test: networkdatamissing - name: networkdatamissing-master-1 -spec: - bmc: - address: ipmi://127.0.0.1 - credentialsName: networkdatamissing-master-1-bmc ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/ephemeral-user-data: 'true' - test: networkdatamissing - name: networkdatamissing-airship-isogen-userdata -type: Opaque -stringData: - userData: cloud-init \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/secret.yaml b/pkg/bootstrap/cloudinit/testdata/secret.yaml deleted file mode 100644 index 173efb7a0..000000000 --- a/pkg/bootstrap/cloudinit/testdata/secret.yaml +++ /dev/null @@ -1,41 +0,0 @@ -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/node-role: "control-plane" - name: node1-bmc-secret -type: Opaque -data: - netconfig: bmV0Y29uZmlnCg== -stringData: - userdata: cloud-init ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/node-role: "worker" - name: node1-bmc-secret1 -type: Opaque ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - test: nodataforcfg - name: node1-bmc-secret2 -type: Opaque -data: - foo: bmV0Y29uZmlnCg== ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - some-data: "True" - name: node1-bmc-in-secret2 -type: Opaque -data: - netconfig: bmV0Y29uZmlnCg== -stringData: - userdata: cloud-init diff --git a/pkg/bootstrap/cloudinit/testdata/userdatamalformed.yaml b/pkg/bootstrap/cloudinit/testdata/userdatamalformed.yaml deleted file mode 100644 index 892f25e98..000000000 --- a/pkg/bootstrap/cloudinit/testdata/userdatamalformed.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# in this document set, we have a secret that contains a label for our -# iso generation userdata, but it is malformed lacking a user-data key -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 \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/userdatamissing.yaml b/pkg/bootstrap/cloudinit/testdata/userdatamissing.yaml deleted file mode 100644 index a8237cbac..000000000 --- a/pkg/bootstrap/cloudinit/testdata/userdatamissing.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# in this document set, we lack a document that contains our ephemeral -# iso generation userdata -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" \ No newline at end of file diff --git a/pkg/bootstrap/cloudinit/testdata/validdocset.yaml b/pkg/bootstrap/cloudinit/testdata/validdocset.yaml deleted file mode 100644 index de63c0d1b..000000000 --- a/pkg/bootstrap/cloudinit/testdata/validdocset.yaml +++ /dev/null @@ -1,66 +0,0 @@ -# in this document set, we have an ephemeral node with -# the right label, resolvable/valid network data and -# a user-data secret with the right label -# -# we also introduce a second baremetal host that is not -# labeled as the ephemeral node to facilitate testing -apiVersion: v1 -kind: Secret -metadata: - labels: - test: validdocset - name: master-1-bmc -type: Opaque -stringData: - username: foobar - password: goober ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - airshipit.org/ephemeral-user-data: 'true' - test: validdocset - name: airship-isogen-userdata -type: Opaque -stringData: - userData: cloud-init ---- -apiVersion: v1 -kind: Secret -metadata: - labels: - test: validdocset - name: master-1-networkdata - namespace: metal3 -type: Opaque -stringData: - networkData: net-config ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - test: validdocset - name: master-2 - bmc: - address: ipmi://127.0.0.1 - credentialsName: master-2-bmc - networkData: - name: master-2-networkdata - namespace: metal3 ---- -apiVersion: metal3.io/v1alpha1 -kind: BareMetalHost -metadata: - labels: - airshipit.org/ephemeral-node: 'true' - test: validdocset - name: master-1 -spec: - bmc: - address: ipmi://127.0.0.1 - credentialsName: master-1-bmc - networkData: - name: master-1-networkdata - namespace: metal3 \ No newline at end of file