Merge "[#45] iso generation pulls network data from ephemeral host"
This commit is contained in:
commit
dc9de0114b
@ -7,72 +7,137 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// TODO (dukov) This should depend on cluster api version once it is
|
||||
// fully available for Metal3. In other words:
|
||||
// - Secret for v1alpha1
|
||||
// - KubeAdmConfig for v1alpha2
|
||||
EphemeralClusterConfKind = "Secret"
|
||||
UserDataKind = "Secret"
|
||||
NetworkDataKind = "Secret"
|
||||
BareMetalHostKind = "BareMetalHost"
|
||||
EphemeralHostLabel = "airshipit.org/ephemeral-node=true"
|
||||
EphemeralUserDataLabel = "airshipit.org/ephemeral-user-data=true"
|
||||
networkDataKey = "networkData"
|
||||
userDataKey = "userData"
|
||||
)
|
||||
|
||||
func decodeData(cfg document.Document, key string) ([]byte, error) {
|
||||
data, err := cfg.GetStringMap("data")
|
||||
// GetCloudData reads YAML document input and generates cloud-init data for
|
||||
// ephemeral node.
|
||||
func GetCloudData(docBundle document.Bundle) (userData []byte, netConf []byte, err error) {
|
||||
userData, err = getUserData(docBundle)
|
||||
|
||||
if err != nil {
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: key}
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
res, ok := data[key]
|
||||
if !ok {
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: key}
|
||||
netConf, err = getNetworkData(docBundle)
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return b64.StdEncoding.DecodeString(res)
|
||||
return userData, netConf, err
|
||||
}
|
||||
|
||||
// getDataFromSecret extracts data from Secret with respect to overrides
|
||||
func getDataFromSecret(cfg document.Document, key string) ([]byte, error) {
|
||||
data, err := cfg.GetStringMap("stringData")
|
||||
func getUserData(docBundle document.Bundle) ([]byte, error) {
|
||||
// find the user-data document
|
||||
selector := document.NewSelector().ByKind(UserDataKind).ByLabel(EphemeralUserDataLabel)
|
||||
docs, err := docBundle.Select(selector)
|
||||
if err != nil {
|
||||
return decodeData(cfg, key)
|
||||
return nil, err
|
||||
}
|
||||
var userDataDoc document.Document = &document.Factory{}
|
||||
switch numDocsFound := len(docs); {
|
||||
case numDocsFound == 0:
|
||||
return nil, document.ErrDocNotFound{Selector: selector}
|
||||
case numDocsFound > 1:
|
||||
return nil, document.ErrMultipleDocsFound{Selector: selector}
|
||||
case numDocsFound == 1:
|
||||
userDataDoc = docs[0]
|
||||
}
|
||||
|
||||
// finally, try and retrieve the data we want from the document
|
||||
userData, err := decodeData(userDataDoc, userDataKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return userData, nil
|
||||
}
|
||||
|
||||
func getNetworkData(docBundle document.Bundle) ([]byte, error) {
|
||||
// find the baremetal host indicated as the ephemeral node
|
||||
selector := document.NewSelector().ByKind(BareMetalHostKind).ByLabel(EphemeralHostLabel)
|
||||
docs, err := docBundle.Select(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var bmhDoc document.Document = &document.Factory{}
|
||||
switch numDocsFound := len(docs); {
|
||||
case numDocsFound == 0:
|
||||
return nil, document.ErrDocNotFound{Selector: selector}
|
||||
case numDocsFound > 1:
|
||||
return nil, document.ErrMultipleDocsFound{Selector: selector}
|
||||
case numDocsFound == 1:
|
||||
bmhDoc = docs[0]
|
||||
}
|
||||
|
||||
// extract the network data document pointer from the bmh document
|
||||
netConfDocName, err := bmhDoc.GetString("spec.networkData.name")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netConfDocNamespace, err := bmhDoc.GetString("spec.networkData.namespace")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// try and find these documents in our bundle
|
||||
selector = document.NewSelector().ByKind(NetworkDataKind).ByNamespace(netConfDocNamespace).ByName(netConfDocName)
|
||||
docs, err = docBundle.Select(selector)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var networkDataDoc document.Document = &document.Factory{}
|
||||
switch numDocsFound := len(docs); {
|
||||
case numDocsFound == 0:
|
||||
return nil, document.ErrDocNotFound{Selector: selector}
|
||||
case numDocsFound > 1:
|
||||
return nil, document.ErrMultipleDocsFound{Selector: selector}
|
||||
case numDocsFound == 1:
|
||||
networkDataDoc = docs[0]
|
||||
}
|
||||
|
||||
// finally, try and retrieve the data we want from the document
|
||||
netData, err := decodeData(networkDataDoc, networkDataKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return netData, nil
|
||||
}
|
||||
|
||||
func decodeData(cfg document.Document, key string) ([]byte, error) {
|
||||
var needsBase64Decode = false
|
||||
|
||||
// TODO(alanmeadows): distinguish between missing net-data key
|
||||
// and missing data/stringData keys in the Secret
|
||||
data, err := cfg.GetStringMap("data")
|
||||
if err == nil {
|
||||
needsBase64Decode = true
|
||||
} else {
|
||||
// we'll catch any error below
|
||||
data, err = cfg.GetStringMap("stringData")
|
||||
if err != nil {
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: "data or stringData"}
|
||||
}
|
||||
}
|
||||
|
||||
res, ok := data[key]
|
||||
if !ok {
|
||||
return decodeData(cfg, key)
|
||||
return nil, ErrDataNotSupplied{DocName: cfg.GetName(), Key: key}
|
||||
}
|
||||
|
||||
if needsBase64Decode {
|
||||
return b64.StdEncoding.DecodeString(res)
|
||||
}
|
||||
return []byte(res), nil
|
||||
}
|
||||
|
||||
// GetCloudData reads YAML document input and generates cloud-init data for
|
||||
// node (i.e. Cluster API Machine) with bootstrap label.
|
||||
func GetCloudData(docBundle document.Bundle, bsSelector string) ([]byte, []byte, error) {
|
||||
var userData []byte
|
||||
var netConf []byte
|
||||
docs, err := docBundle.GetByLabel(bsSelector)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
var ephemeralCfg document.Document
|
||||
for _, doc := range docs {
|
||||
if doc.GetKind() == EphemeralClusterConfKind {
|
||||
ephemeralCfg = doc
|
||||
break
|
||||
}
|
||||
}
|
||||
if ephemeralCfg == nil {
|
||||
return nil, nil, document.ErrDocNotFound{
|
||||
Selector: bsSelector,
|
||||
Kind: EphemeralClusterConfKind,
|
||||
}
|
||||
}
|
||||
|
||||
netConf, err = getDataFromSecret(ephemeralCfg, "netconfig")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
userData, err = getDataFromSecret(ephemeralCfg, "userdata")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return userData, netConf, nil
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"sigs.k8s.io/kustomize/v3/pkg/types"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
"opendev.org/airship/airshipctl/testutil"
|
||||
@ -16,54 +17,90 @@ func TestGetCloudData(t *testing.T) {
|
||||
require.NoError(t, err, "Building Bundle Failed")
|
||||
|
||||
tests := []struct {
|
||||
selector string
|
||||
labelFilter string
|
||||
expectedUserData []byte
|
||||
expectedNetData []byte
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
selector: "test=test",
|
||||
labelFilter: "test=validdocset",
|
||||
expectedUserData: []byte("cloud-init"),
|
||||
expectedNetData: []byte("net-config"),
|
||||
expectedErr: nil,
|
||||
},
|
||||
{
|
||||
labelFilter: "test=ephemeralmissing",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: document.ErrDocNotFound{
|
||||
Selector: "test=test",
|
||||
Kind: "Secret",
|
||||
Selector: document.NewSelector().
|
||||
ByLabel("airshipit.org/ephemeral-node=true").
|
||||
ByKind("BareMetalHost"),
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: "airshipit.org/ephemeral=false",
|
||||
labelFilter: "test=ephemeralduplicate",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: ErrDataNotSupplied{
|
||||
DocName: "node1-bmc-secret1",
|
||||
Key: "netconfig",
|
||||
expectedErr: document.ErrMultipleDocsFound{
|
||||
Selector: document.NewSelector().
|
||||
ByLabel("airshipit.org/ephemeral-node=true").
|
||||
ByKind("BareMetalHost"),
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: "test=nodataforcfg",
|
||||
labelFilter: "test=networkdatabadpointer",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: ErrDataNotSupplied{
|
||||
DocName: "node1-bmc-secret2",
|
||||
Key: "netconfig",
|
||||
expectedErr: document.ErrDocNotFound{
|
||||
Selector: document.NewSelector().
|
||||
ByKind("Secret").
|
||||
ByNamespace("networkdatabadpointer-missing").
|
||||
ByName("networkdatabadpointer-missing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
selector: "airshipit.org/ephemeral=true",
|
||||
expectedUserData: []byte("cloud-init"),
|
||||
expectedNetData: []byte("netconfig\n"),
|
||||
expectedErr: nil,
|
||||
labelFilter: "test=networkdatamalformed",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: ErrDataNotSupplied{DocName: "networkdatamalformed-malformed", Key: networkDataKey},
|
||||
},
|
||||
{
|
||||
selector: "some-data in (true, True)",
|
||||
expectedUserData: []byte("cloud-init"),
|
||||
expectedNetData: []byte("netconfig\n"),
|
||||
expectedErr: nil,
|
||||
labelFilter: "test=networkdatamissing",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: types.NoFieldError{Field: "spec.networkData.name"},
|
||||
},
|
||||
{
|
||||
labelFilter: "test=userdatamalformed",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: ErrDataNotSupplied{DocName: "userdatamalformed-somesecret", Key: userDataKey},
|
||||
},
|
||||
{
|
||||
labelFilter: "test=userdatamissing",
|
||||
expectedUserData: nil,
|
||||
expectedNetData: nil,
|
||||
expectedErr: document.ErrDocNotFound{
|
||||
Selector: document.NewSelector().
|
||||
ByKind("Secret").
|
||||
ByLabel("airshipit.org/ephemeral-user-data=true"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
actualUserData, actualNetData, actualErr := GetCloudData(bundle, tt.selector)
|
||||
// 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()
|
||||
require.NoError(t, err, "GetAllDocuments failed")
|
||||
require.NotZero(t, docs)
|
||||
|
||||
actualUserData, actualNetData, actualErr := GetCloudData(filteredBundle)
|
||||
|
||||
assert.Equal(t, tt.expectedUserData, actualUserData)
|
||||
assert.Equal(t, tt.expectedNetData, actualNetData)
|
||||
|
@ -11,6 +11,17 @@ type ErrDataNotSupplied struct {
|
||||
Key string
|
||||
}
|
||||
|
||||
// ErrDuplicateNetworkDataDocuments error returned if multiple network documents
|
||||
// were found with the same name in the same namespace
|
||||
type ErrDuplicateNetworkDataDocuments struct {
|
||||
DocName string
|
||||
Namespace string
|
||||
}
|
||||
|
||||
func (e ErrDataNotSupplied) Error() string {
|
||||
return fmt.Sprintf("Document %s has no key %s", e.DocName, e.Key)
|
||||
}
|
||||
|
||||
func (e ErrDuplicateNetworkDataDocuments) Error() string {
|
||||
return fmt.Sprintf("Found more than one document with the name %s in namespace %s", e.DocName, e.Namespace)
|
||||
}
|
||||
|
36
pkg/bootstrap/cloudinit/testdata/ephemeralduplicate.yaml
vendored
Normal file
36
pkg/bootstrap/cloudinit/testdata/ephemeralduplicate.yaml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
# 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
|
27
pkg/bootstrap/cloudinit/testdata/ephemeralmissing.yaml
vendored
Normal file
27
pkg/bootstrap/cloudinit/testdata/ephemeralmissing.yaml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
# 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
|
@ -1,2 +1,9 @@
|
||||
resources:
|
||||
- secret.yaml
|
||||
- ephemeralduplicate.yaml
|
||||
- ephemeralmissing.yaml
|
||||
- networkdatabadpointer.yaml
|
||||
- networkdatamalformed.yaml
|
||||
- networkdatamissing.yaml
|
||||
- userdatamalformed.yaml
|
||||
- userdatamissing.yaml
|
||||
- validdocset.yaml
|
38
pkg/bootstrap/cloudinit/testdata/networkdatabadpointer.yaml
vendored
Normal file
38
pkg/bootstrap/cloudinit/testdata/networkdatabadpointer.yaml
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
# 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
|
50
pkg/bootstrap/cloudinit/testdata/networkdatamalformed.yaml
vendored
Normal file
50
pkg/bootstrap/cloudinit/testdata/networkdatamalformed.yaml
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
# 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
|
||||
namespace: malformed
|
||||
metadata:
|
||||
labels:
|
||||
test: networkdatamalformed
|
||||
name: networkdatamalformed-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
|
46
pkg/bootstrap/cloudinit/testdata/networkdatamissing.yaml
vendored
Normal file
46
pkg/bootstrap/cloudinit/testdata/networkdatamissing.yaml
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
# 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
|
41
pkg/bootstrap/cloudinit/testdata/secret.yaml
vendored
41
pkg/bootstrap/cloudinit/testdata/secret.yaml
vendored
@ -1,41 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
airshipit.org/ephemeral: "true"
|
||||
name: node1-bmc-secret
|
||||
type: Opaque
|
||||
data:
|
||||
netconfig: bmV0Y29uZmlnCg==
|
||||
stringData:
|
||||
userdata: cloud-init
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
labels:
|
||||
airshipit.org/ephemeral: "false"
|
||||
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
|
12
pkg/bootstrap/cloudinit/testdata/userdatamalformed.yaml
vendored
Normal file
12
pkg/bootstrap/cloudinit/testdata/userdatamalformed.yaml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# 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
|
11
pkg/bootstrap/cloudinit/testdata/userdatamissing.yaml
vendored
Normal file
11
pkg/bootstrap/cloudinit/testdata/userdatamissing.yaml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# 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"
|
66
pkg/bootstrap/cloudinit/testdata/validdocset.yaml
vendored
Normal file
66
pkg/bootstrap/cloudinit/testdata/validdocset.yaml
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
# 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
|
||||
namespace: metal3
|
||||
metadata:
|
||||
labels:
|
||||
test: validdocset
|
||||
name: master-1-networkdata
|
||||
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
|
@ -119,8 +119,7 @@ func generateBootstrapIso(
|
||||
) error {
|
||||
cntVol := strings.Split(cfg.Container.Volume, ":")[1]
|
||||
log.Print("Creating cloud-init for ephemeral K8s")
|
||||
label := document.EphemeralClusterSelector
|
||||
userData, netConf, err := cloudinit.GetCloudData(docBundle, label)
|
||||
userData, netConf, err := cloudinit.GetCloudData(docBundle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
65
pkg/bootstrap/isogen/testdata/secret.yaml
vendored
65
pkg/bootstrap/isogen/testdata/secret.yaml
vendored
@ -1,11 +1,66 @@
|
||||
# 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:
|
||||
airshipit.org/ephemeral: "true"
|
||||
name: node1-bmc-secret
|
||||
test: validdocset
|
||||
name: master-1-bmc
|
||||
type: Opaque
|
||||
data:
|
||||
netconfig: bmV0Y29uZmlnCg==
|
||||
stringData:
|
||||
userdata: cloud-init
|
||||
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
|
||||
namespace: metal3
|
||||
metadata:
|
||||
labels:
|
||||
test: validdocset
|
||||
name: master-1-networkdata
|
||||
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
|
@ -77,7 +77,7 @@ func (infra *Infra) Deploy() error {
|
||||
}
|
||||
if len(docs) == 0 {
|
||||
return document.ErrDocNotFound{
|
||||
Selector: ls,
|
||||
Selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,7 @@ type Bundle interface {
|
||||
SetFileSystem(FileSystem) error
|
||||
GetFileSystem() FileSystem
|
||||
Select(selector Selector) ([]Document, error)
|
||||
SelectBundle(selector Selector) (Bundle, error)
|
||||
GetByGvk(string, string, string) ([]Document, error)
|
||||
GetByName(string) (Document, error)
|
||||
GetByAnnotation(annotationSelector string) ([]Document, error)
|
||||
@ -207,6 +208,37 @@ func (b *BundleFactory) Select(selector Selector) ([]Document, error) {
|
||||
return docSet, err
|
||||
}
|
||||
|
||||
// SelectBundle offers an interface to pass a Selector, built on top of kustomize Selector
|
||||
// to the bundle returning a new Bundle that matches the criteria. This is useful
|
||||
// where you want to actually prune the underlying bundle you are working with
|
||||
// rather then getting back the matching documents for scenarios like
|
||||
// test cases where you want to pass in custom "filtered" bundles
|
||||
// specific to the test case
|
||||
func (b *BundleFactory) SelectBundle(selector Selector) (Bundle, error) {
|
||||
// use the kustomize select method
|
||||
resources, err := b.ResMap.Select(selector.Selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create a blank resourcemap and append the found resources
|
||||
// into the new resource map
|
||||
resourceMap := resmap.New()
|
||||
for _, res := range resources {
|
||||
if err = resourceMap.Append(res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// return a new bundle with the same options and filesystem
|
||||
// as this one but with a reduced resourceMap
|
||||
return &BundleFactory{
|
||||
KustomizeBuildOptions: b.KustomizeBuildOptions,
|
||||
ResMap: resourceMap,
|
||||
FileSystem: b.FileSystem,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetByAnnotation is a convenience method to get documents for a particular annotation
|
||||
func (b *BundleFactory) GetByAnnotation(annotationSelector string) ([]Document, error) {
|
||||
// Construct kustomize annotation selector
|
||||
|
@ -6,10 +6,18 @@ import (
|
||||
|
||||
// ErrDocNotFound returned if desired document not found
|
||||
type ErrDocNotFound struct {
|
||||
Selector string
|
||||
Kind string
|
||||
Selector Selector
|
||||
}
|
||||
|
||||
// ErrMultipleDocsFound returned if desired document not found
|
||||
type ErrMultipleDocsFound struct {
|
||||
Selector Selector
|
||||
}
|
||||
|
||||
func (e ErrDocNotFound) Error() string {
|
||||
return fmt.Sprintf("Document filtered by selector %s with Kind %s not found", e.Selector, e.Kind)
|
||||
return fmt.Sprintf("Document filtered by selector %q found no documents", e.Selector)
|
||||
}
|
||||
|
||||
func (e ErrMultipleDocsFound) Error() string {
|
||||
return fmt.Sprintf("Document filtered by selector %q found more than one document", e.Selector)
|
||||
}
|
||||
|
@ -26,12 +26,24 @@ func (s Selector) ByName(name string) Selector {
|
||||
return s
|
||||
}
|
||||
|
||||
// ByNamespace select by namepace
|
||||
func (s Selector) ByNamespace(namespace string) Selector {
|
||||
s.Namespace = namespace
|
||||
return s
|
||||
}
|
||||
|
||||
// ByGvk select by gvk
|
||||
func (s Selector) ByGvk(group, version, kind string) Selector {
|
||||
s.Gvk = gvk.Gvk{Group: group, Version: version, Kind: kind}
|
||||
return s
|
||||
}
|
||||
|
||||
// ByKind select by Kind
|
||||
func (s Selector) ByKind(kind string) Selector {
|
||||
s.Gvk = gvk.Gvk{Kind: kind}
|
||||
return s
|
||||
}
|
||||
|
||||
// ByLabel select by label selector
|
||||
func (s Selector) ByLabel(labelSelector string) Selector {
|
||||
if s.LabelSelector != "" {
|
||||
|
@ -94,8 +94,7 @@ func getRemoteDirectConfig(settings *environment.AirshipCTLSettings) (*config.Re
|
||||
}
|
||||
if len(docs) == 0 {
|
||||
return nil, "", document.ErrDocNotFound{
|
||||
Selector: ls,
|
||||
Kind: AirshipHostKind,
|
||||
Selector: selector,
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user