Add BMH label test
This change adds a basic test to verify that SIP adds the proper labels when scheduling nodes.
This commit is contained in:
parent
77f557fd1d
commit
bddcec13ed
@ -111,3 +111,8 @@ Use kubectl apply to deliver SIP CRs and BaremetalHost CRDs to kubernetes cluste
|
||||
```
|
||||
# kustomize build config/samples | kubectl apply -f -
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
Run `make test` to execute a suite of unit and integration tests against the SIP
|
||||
operator.
|
||||
|
@ -34,6 +34,13 @@ spec:
|
||||
spec:
|
||||
description: SIPClusterSpec defines the desired state of SIPCluster
|
||||
properties:
|
||||
config:
|
||||
description: SIPClusterSpec defines the desired state of SIPCluster
|
||||
properties:
|
||||
cluster-name:
|
||||
description: Cluster NAme to be used for labeling vBMH
|
||||
type: string
|
||||
type: object
|
||||
infra:
|
||||
additionalProperties:
|
||||
properties:
|
||||
@ -41,8 +48,10 @@ spec:
|
||||
type: string
|
||||
nodeInterfaceId:
|
||||
type: string
|
||||
nodePort:
|
||||
type: integer
|
||||
nodePorts:
|
||||
items:
|
||||
type: integer
|
||||
type: array
|
||||
nodelabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
570
config/crd/bases/bmh.yaml
Normal file
570
config/crd/bases/bmh.yaml
Normal file
@ -0,0 +1,570 @@
|
||||
apiVersion: apiextensions.k8s.io/v1beta1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
labels:
|
||||
clusterctl.cluster.x-k8s.io: ""
|
||||
name: baremetalhosts.metal3.io
|
||||
spec:
|
||||
additionalPrinterColumns:
|
||||
- JSONPath: .status.operationalStatus
|
||||
description: Operational status
|
||||
name: Status
|
||||
type: string
|
||||
- JSONPath: .status.provisioning.state
|
||||
description: Provisioning status
|
||||
name: Provisioning Status
|
||||
type: string
|
||||
- JSONPath: .spec.consumerRef.name
|
||||
description: Consumer using this host
|
||||
name: Consumer
|
||||
type: string
|
||||
- JSONPath: .spec.bmc.address
|
||||
description: Address of management controller
|
||||
name: BMC
|
||||
type: string
|
||||
- JSONPath: .status.hardwareProfile
|
||||
description: The type of hardware detected
|
||||
name: Hardware Profile
|
||||
type: string
|
||||
- JSONPath: .spec.online
|
||||
description: Whether the host is online or not
|
||||
name: Online
|
||||
type: string
|
||||
- JSONPath: .status.errorMessage
|
||||
description: Most recent error
|
||||
name: Error
|
||||
type: string
|
||||
group: metal3.io
|
||||
names:
|
||||
kind: BareMetalHost
|
||||
listKind: BareMetalHostList
|
||||
plural: baremetalhosts
|
||||
shortNames:
|
||||
- bmh
|
||||
- bmhost
|
||||
singular: baremetalhost
|
||||
scope: Namespaced
|
||||
subresources:
|
||||
status: {}
|
||||
validation:
|
||||
openAPIV3Schema:
|
||||
description: BareMetalHost is the Schema for the baremetalhosts API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: 'APIVersion defines the versioned schema of this representation
|
||||
of an object. Servers should convert recognized schemas to the latest
|
||||
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind is a string value representing the REST resource this
|
||||
object represents. Servers may infer this from the endpoint the client
|
||||
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: BareMetalHostSpec defines the desired state of BareMetalHost
|
||||
properties:
|
||||
bmc:
|
||||
description: How do we connect to the BMC?
|
||||
properties:
|
||||
address:
|
||||
description: Address holds the URL for accessing the controller
|
||||
on the network.
|
||||
type: string
|
||||
credentialsName:
|
||||
description: The name of the secret containing the BMC credentials
|
||||
(requires keys "username" and "password").
|
||||
type: string
|
||||
disableCertificateVerification:
|
||||
description: DisableCertificateVerification disables verification
|
||||
of server certificates when using HTTPS to connect to the BMC.
|
||||
This is required when the server certificate is self-signed, but
|
||||
is insecure because it allows a man-in-the-middle to intercept
|
||||
the connection.
|
||||
type: boolean
|
||||
required:
|
||||
- address
|
||||
- credentialsName
|
||||
type: object
|
||||
bootMACAddress:
|
||||
description: Which MAC address will PXE boot? This is optional for some
|
||||
types, but required for libvirt VMs driven by vbmc.
|
||||
pattern: '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}'
|
||||
type: string
|
||||
bootMode:
|
||||
description: Select the method of initializing the hardware during boot.
|
||||
enum:
|
||||
- UEFI
|
||||
- legacy
|
||||
type: string
|
||||
consumerRef:
|
||||
description: ConsumerRef can be used to store information about something
|
||||
that is using a host. When it is not empty, the host is considered
|
||||
"in use".
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
type: string
|
||||
fieldPath:
|
||||
description: 'If referring to a piece of an object instead of an
|
||||
entire object, this string should contain a valid JSON/Go field
|
||||
access statement, such as desiredState.manifest.containers[2].
|
||||
For example, if the object reference is to a container within
|
||||
a pod, this would take on a value like: "spec.containers{name}"
|
||||
(where "name" refers to the name of the container that triggered
|
||||
the event) or if no container name is specified "spec.containers[2]"
|
||||
(container with index 2 in this pod). This syntax is chosen only
|
||||
to have some well-defined way of referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change
|
||||
in the future.'
|
||||
type: string
|
||||
kind:
|
||||
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||
type: string
|
||||
name:
|
||||
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
|
||||
type: string
|
||||
namespace:
|
||||
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
|
||||
type: string
|
||||
resourceVersion:
|
||||
description: 'Specific resourceVersion to which this reference is
|
||||
made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
|
||||
type: string
|
||||
uid:
|
||||
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
|
||||
type: string
|
||||
type: object
|
||||
description:
|
||||
description: Description is a human-entered text used to help identify
|
||||
the host
|
||||
type: string
|
||||
externallyProvisioned:
|
||||
description: ExternallyProvisioned means something else is managing
|
||||
the image running on the host and the operator should only manage
|
||||
the power status and hardware inventory inspection. If the Image field
|
||||
is filled in, this field is ignored.
|
||||
type: boolean
|
||||
hardwareProfile:
|
||||
description: What is the name of the hardware profile for this host?
|
||||
It should only be necessary to set this when inspection cannot automatically
|
||||
determine the profile.
|
||||
type: string
|
||||
image:
|
||||
description: Image holds the details of the image to be provisioned.
|
||||
properties:
|
||||
checksum:
|
||||
description: Checksum is the checksum for the image.
|
||||
type: string
|
||||
url:
|
||||
description: URL is a location of an image to deploy.
|
||||
type: string
|
||||
required:
|
||||
- checksum
|
||||
- url
|
||||
type: object
|
||||
networkData:
|
||||
description: NetworkData holds the reference to the Secret containing
|
||||
content of network_data.json which is passed to Config Drive
|
||||
properties:
|
||||
name:
|
||||
description: Name is unique within a namespace to reference a secret
|
||||
resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace defines the space within which the secret
|
||||
name must be unique.
|
||||
type: string
|
||||
type: object
|
||||
online:
|
||||
description: Should the server be online?
|
||||
type: boolean
|
||||
taints:
|
||||
description: Taints is the full, authoritative list of taints to apply
|
||||
to the corresponding Machine. This list will overwrite any modifications
|
||||
made to the Machine on an ongoing basis.
|
||||
items:
|
||||
description: The node this Taint is attached to has the "effect" on
|
||||
any pod that does not tolerate the Taint.
|
||||
properties:
|
||||
effect:
|
||||
description: Required. The effect of the taint on pods that do
|
||||
not tolerate the taint. Valid effects are NoSchedule, PreferNoSchedule
|
||||
and NoExecute.
|
||||
type: string
|
||||
key:
|
||||
description: Required. The taint key to be applied to a node.
|
||||
type: string
|
||||
timeAdded:
|
||||
description: TimeAdded represents the time at which the taint
|
||||
was added. It is only written for NoExecute taints.
|
||||
format: date-time
|
||||
type: string
|
||||
value:
|
||||
description: Required. The taint value corresponding to the taint
|
||||
key.
|
||||
type: string
|
||||
required:
|
||||
- effect
|
||||
- key
|
||||
type: object
|
||||
type: array
|
||||
userData:
|
||||
description: UserData holds the reference to the Secret containing the
|
||||
user data to be passed to the host before it boots.
|
||||
properties:
|
||||
name:
|
||||
description: Name is unique within a namespace to reference a secret
|
||||
resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace defines the space within which the secret
|
||||
name must be unique.
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- online
|
||||
type: object
|
||||
status:
|
||||
description: BareMetalHostStatus defines the observed state of BareMetalHost
|
||||
properties:
|
||||
errorMessage:
|
||||
description: the last error message reported by the provisioning subsystem
|
||||
type: string
|
||||
errorType:
|
||||
description: ErrorType indicates the type of failure encountered when
|
||||
the OperationalStatus is OperationalStatusError
|
||||
enum:
|
||||
- registration error
|
||||
- inspection error
|
||||
- provisioning error
|
||||
- power management error
|
||||
type: string
|
||||
goodCredentials:
|
||||
description: the last credentials we were able to validate as working
|
||||
properties:
|
||||
credentials:
|
||||
description: SecretReference represents a Secret Reference. It has
|
||||
enough information to retrieve secret in any namespace
|
||||
properties:
|
||||
name:
|
||||
description: Name is unique within a namespace to reference
|
||||
a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace defines the space within which the secret
|
||||
name must be unique.
|
||||
type: string
|
||||
type: object
|
||||
credentialsVersion:
|
||||
type: string
|
||||
type: object
|
||||
hardware:
|
||||
description: The hardware discovered to exist on the host.
|
||||
properties:
|
||||
cpu:
|
||||
description: CPU describes one processor on the host.
|
||||
properties:
|
||||
arch:
|
||||
type: string
|
||||
clockMegahertz:
|
||||
description: ClockSpeed is a clock speed in MHz
|
||||
count:
|
||||
type: integer
|
||||
flags:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
model:
|
||||
type: string
|
||||
required:
|
||||
- arch
|
||||
- clockMegahertz
|
||||
- count
|
||||
- flags
|
||||
- model
|
||||
type: object
|
||||
firmware:
|
||||
description: Firmware describes the firmware on the host.
|
||||
properties:
|
||||
bios:
|
||||
description: The BIOS for this firmware
|
||||
properties:
|
||||
date:
|
||||
description: The release/build date for this BIOS
|
||||
type: string
|
||||
vendor:
|
||||
description: The vendor name for this BIOS
|
||||
type: string
|
||||
version:
|
||||
description: The version of the BIOS
|
||||
type: string
|
||||
required:
|
||||
- date
|
||||
- vendor
|
||||
- version
|
||||
type: object
|
||||
required:
|
||||
- bios
|
||||
type: object
|
||||
hostname:
|
||||
type: string
|
||||
nics:
|
||||
items:
|
||||
description: NIC describes one network interface on the host.
|
||||
properties:
|
||||
ip:
|
||||
description: The IP address of the device
|
||||
type: string
|
||||
mac:
|
||||
description: The device MAC addr
|
||||
pattern: '[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}'
|
||||
type: string
|
||||
model:
|
||||
description: The name of the model, e.g. "virt-io"
|
||||
type: string
|
||||
name:
|
||||
description: The name of the NIC, e.g. "nic-1"
|
||||
type: string
|
||||
pxe:
|
||||
description: Whether the NIC is PXE Bootable
|
||||
type: boolean
|
||||
speedGbps:
|
||||
description: The speed of the device
|
||||
type: integer
|
||||
vlanId:
|
||||
description: The untagged VLAN ID
|
||||
format: int32
|
||||
type: integer
|
||||
vlans:
|
||||
description: The VLANs available
|
||||
items:
|
||||
description: VLAN represents the name and ID of a VLAN
|
||||
properties:
|
||||
id:
|
||||
description: VLANID is a 12-bit 802.1Q VLAN identifier
|
||||
format: int32
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
type: array
|
||||
required:
|
||||
- ip
|
||||
- mac
|
||||
- model
|
||||
- name
|
||||
- pxe
|
||||
- speedGbps
|
||||
- vlanId
|
||||
type: object
|
||||
type: array
|
||||
ramMebibytes:
|
||||
type: integer
|
||||
storage:
|
||||
items:
|
||||
description: Storage describes one storage device (disk, SSD,
|
||||
etc.) on the host.
|
||||
properties:
|
||||
hctl:
|
||||
description: The SCSI location of the device
|
||||
type: string
|
||||
model:
|
||||
description: Hardware model
|
||||
type: string
|
||||
name:
|
||||
description: A name for the disk, e.g. "disk 1 (boot)"
|
||||
type: string
|
||||
rotational:
|
||||
description: Whether this disk represents rotational storage
|
||||
type: boolean
|
||||
serialNumber:
|
||||
description: The serial number of the device
|
||||
type: string
|
||||
sizeBytes:
|
||||
description: The size of the disk in Bytes
|
||||
format: int64
|
||||
type: integer
|
||||
vendor:
|
||||
description: The name of the vendor of the device
|
||||
type: string
|
||||
wwn:
|
||||
description: The WWN of the device
|
||||
type: string
|
||||
wwnVendorExtension:
|
||||
description: The WWN Vendor extension of the device
|
||||
type: string
|
||||
wwnWithExtension:
|
||||
description: The WWN with the extension
|
||||
type: string
|
||||
required:
|
||||
- name
|
||||
- rotational
|
||||
- serialNumber
|
||||
- sizeBytes
|
||||
type: object
|
||||
type: array
|
||||
systemVendor:
|
||||
description: HardwareSystemVendor stores details about the whole
|
||||
hardware system.
|
||||
properties:
|
||||
manufacturer:
|
||||
type: string
|
||||
productName:
|
||||
type: string
|
||||
serialNumber:
|
||||
type: string
|
||||
required:
|
||||
- manufacturer
|
||||
- productName
|
||||
- serialNumber
|
||||
type: object
|
||||
required:
|
||||
- cpu
|
||||
- firmware
|
||||
- hostname
|
||||
- nics
|
||||
- ramMebibytes
|
||||
- storage
|
||||
- systemVendor
|
||||
type: object
|
||||
hardwareProfile:
|
||||
description: The name of the profile matching the hardware details.
|
||||
type: string
|
||||
lastUpdated:
|
||||
description: LastUpdated identifies when this status was last observed.
|
||||
format: date-time
|
||||
type: string
|
||||
operationHistory:
|
||||
description: OperationHistory holds information about operations performed
|
||||
on this host.
|
||||
properties:
|
||||
deprovision:
|
||||
description: OperationMetric contains metadata about an operation
|
||||
(inspection, provisioning, etc.) used for tracking metrics.
|
||||
properties:
|
||||
end:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
start:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
type: object
|
||||
inspect:
|
||||
description: OperationMetric contains metadata about an operation
|
||||
(inspection, provisioning, etc.) used for tracking metrics.
|
||||
properties:
|
||||
end:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
start:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
type: object
|
||||
provision:
|
||||
description: OperationMetric contains metadata about an operation
|
||||
(inspection, provisioning, etc.) used for tracking metrics.
|
||||
properties:
|
||||
end:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
start:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
type: object
|
||||
register:
|
||||
description: OperationMetric contains metadata about an operation
|
||||
(inspection, provisioning, etc.) used for tracking metrics.
|
||||
properties:
|
||||
end:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
start:
|
||||
format: date-time
|
||||
nullable: true
|
||||
type: string
|
||||
type: object
|
||||
type: object
|
||||
operationalStatus:
|
||||
description: OperationalStatus holds the status of the host
|
||||
enum:
|
||||
- ""
|
||||
- OK
|
||||
- discovered
|
||||
- error
|
||||
type: string
|
||||
poweredOn:
|
||||
description: indicator for whether or not the host is powered on
|
||||
type: boolean
|
||||
provisioning:
|
||||
description: Information tracked by the provisioner.
|
||||
properties:
|
||||
ID:
|
||||
description: The machine's UUID from the underlying provisioning
|
||||
tool
|
||||
type: string
|
||||
image:
|
||||
description: Image holds the details of the last image successfully
|
||||
provisioned to the host.
|
||||
properties:
|
||||
checksum:
|
||||
description: Checksum is the checksum for the image.
|
||||
type: string
|
||||
url:
|
||||
description: URL is a location of an image to deploy.
|
||||
type: string
|
||||
required:
|
||||
- checksum
|
||||
- url
|
||||
type: object
|
||||
state:
|
||||
description: An indiciator for what the provisioner is doing with
|
||||
the host.
|
||||
type: string
|
||||
required:
|
||||
- ID
|
||||
- state
|
||||
type: object
|
||||
triedCredentials:
|
||||
description: the last credentials we sent to the provisioning backend
|
||||
properties:
|
||||
credentials:
|
||||
description: SecretReference represents a Secret Reference. It has
|
||||
enough information to retrieve secret in any namespace
|
||||
properties:
|
||||
name:
|
||||
description: Name is unique within a namespace to reference
|
||||
a secret resource.
|
||||
type: string
|
||||
namespace:
|
||||
description: Namespace defines the space within which the secret
|
||||
name must be unique.
|
||||
type: string
|
||||
type: object
|
||||
credentialsVersion:
|
||||
type: string
|
||||
type: object
|
||||
required:
|
||||
- errorMessage
|
||||
- hardwareProfile
|
||||
- operationHistory
|
||||
- operationalStatus
|
||||
- poweredOn
|
||||
- provisioning
|
||||
type: object
|
||||
type: object
|
||||
version: v1alpha1
|
||||
versions:
|
||||
- name: v1alpha1
|
||||
served: true
|
||||
storage: true
|
163
pkg/controllers/sipcluster_controller_test.go
Normal file
163
pkg/controllers/sipcluster_controller_test.go
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
|
||||
|
||||
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
|
||||
|
||||
http://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 controllers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
airshipv1 "sipcluster/pkg/api/v1"
|
||||
"sipcluster/pkg/vbmh"
|
||||
)
|
||||
|
||||
var _ = Describe("SIPCluster controller", func() {
|
||||
Context("When it detects a SIPCluster", func() {
|
||||
It("Should schedule BMHs accordingly", func() {
|
||||
By("Labelling nodes")
|
||||
|
||||
// Create vBMH test objects
|
||||
nodes := []string{"master", "master", "master", "worker", "worker", "worker", "worker"}
|
||||
namespace := "default"
|
||||
for node, role := range nodes {
|
||||
vBMH, networkData := createBMH(node, namespace, role, 6)
|
||||
Expect(k8sClient.Create(context.Background(), vBMH)).Should(Succeed())
|
||||
Expect(k8sClient.Create(context.Background(), networkData)).Should(Succeed())
|
||||
}
|
||||
|
||||
// Create SIP cluster
|
||||
clusterName := "subcluster-test1"
|
||||
sipCluster := createSIPCluster(clusterName, namespace, 3, 4)
|
||||
Expect(k8sClient.Create(context.Background(), sipCluster)).Should(Succeed())
|
||||
|
||||
// Poll BMHs until SIP has scheduled them to the SIP cluster
|
||||
Eventually(func() error {
|
||||
expectedLabels := map[string]string{
|
||||
vbmh.SipScheduleLabel: "true",
|
||||
vbmh.SipClusterLabel: clusterName,
|
||||
}
|
||||
|
||||
var bmh metal3.BareMetalHost
|
||||
for node := range nodes {
|
||||
Expect(k8sClient.Get(context.Background(), types.NamespacedName{
|
||||
Name: fmt.Sprintf("node%d", node),
|
||||
Namespace: namespace,
|
||||
}, &bmh)).Should(Succeed())
|
||||
}
|
||||
|
||||
return compareLabels(expectedLabels, bmh.GetLabels())
|
||||
}, 60, 5).Should(Succeed())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func compareLabels(expected map[string]string, actual map[string]string) error {
|
||||
for k, v := range expected {
|
||||
value, exists := actual[k]
|
||||
if !exists {
|
||||
return fmt.Errorf("label %s=%s missing. Has labels %v", k, v, actual)
|
||||
}
|
||||
|
||||
if value != v {
|
||||
return fmt.Errorf("label %s=%s does not match expected label %s=%s. Has labels %v", k, value, k,
|
||||
v, actual)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createBMH(node int, namespace string, role string, rack int) (*metal3.BareMetalHost, *corev1.Secret) {
|
||||
rackLabel := fmt.Sprintf("r%d", rack)
|
||||
networkDataName := fmt.Sprintf("node%d-network-data", node)
|
||||
return &metal3.BareMetalHost{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: fmt.Sprintf("node%d", node),
|
||||
Namespace: namespace,
|
||||
Labels: map[string]string{
|
||||
"airshipit.org/vino-flavor": role,
|
||||
vbmh.SipScheduleLabel: "false",
|
||||
vbmh.RackLabel: rackLabel,
|
||||
vbmh.ServerLabel: fmt.Sprintf("stl2%so%d", rackLabel, node),
|
||||
},
|
||||
},
|
||||
Spec: metal3.BareMetalHostSpec{
|
||||
NetworkData: &corev1.SecretReference{
|
||||
Namespace: namespace,
|
||||
Name: networkDataName,
|
||||
},
|
||||
},
|
||||
}, &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: networkDataName,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
"networkData": []byte("ewoKICAgICJsaW5rcyI6IFsKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJlbm80IiwKICAgICAgICAgICAgIm5hbWUiOiAiZW5vNCIsCiAgICAgICAgICAgICJ0eXBlIjogInBoeSIsCiAgICAgICAgICAgICJtdHUiOiAxNTAwCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJlbnA1OXMwZjEiLAogICAgICAgICAgICAibmFtZSI6ICJlbnA1OXMwZjEiLAogICAgICAgICAgICAidHlwZSI6ICJwaHkiLAogICAgICAgICAgICAibXR1IjogOTEwMAogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAiaWQiOiAiZW5wMjE2czBmMCIsCiAgICAgICAgICAgICJuYW1lIjogImVucDIxNnMwZjAiLAogICAgICAgICAgICAidHlwZSI6ICJwaHkiLAogICAgICAgICAgICAibXR1IjogOTEwMAogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAiaWQiOiAiYm9uZDAiLAogICAgICAgICAgICAibmFtZSI6ICJib25kMCIsCiAgICAgICAgICAgICJ0eXBlIjogImJvbmQiLAogICAgICAgICAgICAiYm9uZF9saW5rcyI6IFsKICAgICAgICAgICAgICAgICJlbnA1OXMwZjEiLAogICAgICAgICAgICAgICAgImVucDIxNnMwZjAiCiAgICAgICAgICAgIF0sCiAgICAgICAgICAgICJib25kX21vZGUiOiAiODAyLjNhZCIsCiAgICAgICAgICAgICJib25kX3htaXRfaGFzaF9wb2xpY3kiOiAibGF5ZXIzKzQiLAogICAgICAgICAgICAiYm9uZF9taWltb24iOiAxMDAsCiAgICAgICAgICAgICJtdHUiOiA5MTAwCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJib25kMC40MSIsCiAgICAgICAgICAgICJuYW1lIjogImJvbmQwLjQxIiwKICAgICAgICAgICAgInR5cGUiOiAidmxhbiIsCiAgICAgICAgICAgICJ2bGFuX2xpbmsiOiAiYm9uZDAiLAogICAgICAgICAgICAidmxhbl9pZCI6IDQxLAogICAgICAgICAgICAibXR1IjogOTEwMCwKICAgICAgICAgICAgInZsYW5fbWFjX2FkZHJlc3MiOiBudWxsCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJib25kMC40MiIsCiAgICAgICAgICAgICJuYW1lIjogImJvbmQwLjQyIiwKICAgICAgICAgICAgInR5cGUiOiAidmxhbiIsCiAgICAgICAgICAgICJ2bGFuX2xpbmsiOiAiYm9uZDAiLAogICAgICAgICAgICAidmxhbl9pZCI6IDQyLAogICAgICAgICAgICAibXR1IjogOTEwMCwKICAgICAgICAgICAgInZsYW5fbWFjX2FkZHJlc3MiOiBudWxsCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJib25kMC40NCIsCiAgICAgICAgICAgICJuYW1lIjogImJvbmQwLjQ0IiwKICAgICAgICAgICAgInR5cGUiOiAidmxhbiIsCiAgICAgICAgICAgICJ2bGFuX2xpbmsiOiAiYm9uZDAiLAogICAgICAgICAgICAidmxhbl9pZCI6IDQ0LAogICAgICAgICAgICAibXR1IjogOTEwMCwKICAgICAgICAgICAgInZsYW5fbWFjX2FkZHJlc3MiOiBudWxsCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJib25kMC40NSIsCiAgICAgICAgICAgICJuYW1lIjogImJvbmQwLjQ1IiwKICAgICAgICAgICAgInR5cGUiOiAidmxhbiIsCiAgICAgICAgICAgICJ2bGFuX2xpbmsiOiAiYm9uZDAiLAogICAgICAgICAgICAidmxhbl9pZCI6IDQ1LAogICAgICAgICAgICAibXR1IjogOTEwMCwKICAgICAgICAgICAgInZsYW5fbWFjX2FkZHJlc3MiOiBudWxsCiAgICAgICAgfQogICAgXSwKICAgICJuZXR3b3JrcyI6IFsKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJvYW0taXB2NiIsCiAgICAgICAgICAgICJ0eXBlIjogImlwdjYiLAogICAgICAgICAgICAibGluayI6ICJib25kMC40MSIsCiAgICAgICAgICAgICJpcF9hZGRyZXNzIjogIjIwMDE6MTg5MDoxMDAxOjI5M2Q6OjE0MCIsCiAgICAgICAgICAgICJyb3V0ZXMiOiBbCiAgICAgICAgICAgICAgICB7CiAgICAgICAgICAgICAgICAgICAgIm5ldHdvcmsiOiAiOjovMCIsCiAgICAgICAgICAgICAgICAgICAgIm5ldG1hc2siOiAiOjovMCIsCiAgICAgICAgICAgICAgICAgICAgImdhdGV3YXkiOiAiMjAwMToxODkwOjEwMDE6MjkzZDo6MSIKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgXQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAiaWQiOiAib2FtLWlwdjQiLAogICAgICAgICAgICAidHlwZSI6ICJpcHY0IiwKICAgICAgICAgICAgImxpbmsiOiAiYm9uZDAuNDEiLAogICAgICAgICAgICAiaXBfYWRkcmVzcyI6ICIzMi42OC41MS4xNDAiLAogICAgICAgICAgICAibmV0bWFzayI6ICIyNTUuMjU1LjI1NS4xMjgiLAogICAgICAgICAgICAiZG5zX25hbWVzZXJ2ZXJzIjogWwogICAgICAgICAgICAgICAgIjEzNS4xODguMzQuMTI0IiwKICAgICAgICAgICAgICAgICIxMzUuMzguMjQ0LjE2IiwKICAgICAgICAgICAgICAgICIxMzUuMTg4LjM0Ljg0IgogICAgICAgICAgICBdLAogICAgICAgICAgICAicm91dGVzIjogWwogICAgICAgICAgICAgICAgewogICAgICAgICAgICAgICAgICAgICJuZXR3b3JrIjogIjAuMC4wLjAiLAogICAgICAgICAgICAgICAgICAgICJuZXRtYXNrIjogIjAuMC4wLjAiLAogICAgICAgICAgICAgICAgICAgICJnYXRld2F5IjogIjMyLjY4LjUxLjEyOSIKICAgICAgICAgICAgICAgIH0KICAgICAgICAgICAgXQogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAiaWQiOiAicHhlLWlwdjYiLAogICAgICAgICAgICAibGluayI6ICJlbm80IiwKICAgICAgICAgICAgInR5cGUiOiAiaXB2NiIsCiAgICAgICAgICAgICJpcF9hZGRyZXNzIjogImZkMDA6OTAwOjEwMDoxMzg6OjEyIgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAiaWQiOiAicHhlLWlwdjQiLAogICAgICAgICAgICAibGluayI6ICJlbm80IiwKICAgICAgICAgICAgInR5cGUiOiAiaXB2NCIsCiAgICAgICAgICAgICJpcF9hZGRyZXNzIjogIjE3Mi4zMC4wLjEyIiwKICAgICAgICAgICAgIm5ldG1hc2siOiAiMjU1LjI1NS4yNTUuMTI4IgogICAgICAgIH0sCiAgICAgICAgewogICAgICAgICAgICAiaWQiOiAic3RvcmFnZS1pcHY2IiwKICAgICAgICAgICAgImxpbmsiOiAiYm9uZDAuNDIiLAogICAgICAgICAgICAidHlwZSI6ICJpcHY2IiwKICAgICAgICAgICAgImlwX2FkZHJlc3MiOiAiZmQwMDo5MDA6MTAwOjEzOTo6MTYiCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJzdG9yYWdlLWlwdjQiLAogICAgICAgICAgICAibGluayI6ICJib25kMC40MiIsCiAgICAgICAgICAgICJ0eXBlIjogImlwdjQiLAogICAgICAgICAgICAiaXBfYWRkcmVzcyI6ICIxNzIuMzEuMC4xNiIsCiAgICAgICAgICAgICJuZXRtYXNrIjogIjI1NS4yNTUuMjU1LjEyOCIKICAgICAgICB9LAogICAgICAgIHsKICAgICAgICAgICAgImlkIjogImtzbi1pcHY2IiwKICAgICAgICAgICAgImxpbmsiOiAiYm9uZDAuNDQiLAogICAgICAgICAgICAidHlwZSI6ICJpcHY2IiwKICAgICAgICAgICAgImlwX2FkZHJlc3MiOiAiZmQwMDo5MDA6MTAwOjEzYTo6MTIiCiAgICAgICAgfSwKICAgICAgICB7CiAgICAgICAgICAgICJpZCI6ICJrc24taXB2NCIsCiAgICAgICAgICAgICJsaW5rIjogImJvbmQwLjQ0IiwKICAgICAgICAgICAgInR5cGUiOiAiaXB2NCIsCiAgICAgICAgICAgICJpcF9hZGRyZXNzIjogIjE3Mi4yOS4wLjEyIiwKICAgICAgICAgICAgIm5ldG1hc2siOiAiMjU1LjI1NS4yNTUuMTI4IgogICAgICAgIH0KICAgIF0KfQo="),
|
||||
},
|
||||
Type: corev1.SecretTypeOpaque,
|
||||
}
|
||||
}
|
||||
|
||||
func createSIPCluster(name string, namespace string, masters int, workers int) *airshipv1.SIPCluster {
|
||||
return &airshipv1.SIPCluster{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "SIPCluster",
|
||||
APIVersion: "airship.airshipit.org/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Namespace: namespace,
|
||||
},
|
||||
Spec: airshipv1.SIPClusterSpec{
|
||||
Config: &airshipv1.SipConfig{
|
||||
ClusterName: name,
|
||||
},
|
||||
Nodes: map[airshipv1.VmRoles]airshipv1.NodeSet{
|
||||
airshipv1.VmMaster: airshipv1.NodeSet{
|
||||
VmFlavor: "airshipit.org/vino-flavor=master",
|
||||
Scheduling: []airshipv1.SchedulingOptions{
|
||||
airshipv1.ServerAntiAffinity,
|
||||
},
|
||||
Count: &airshipv1.VmCount{
|
||||
Active: masters,
|
||||
Standby: 0,
|
||||
},
|
||||
},
|
||||
airshipv1.VmWorker: airshipv1.NodeSet{
|
||||
VmFlavor: "airshipit.org/vino-flavor=worker",
|
||||
Scheduling: []airshipv1.SchedulingOptions{
|
||||
airshipv1.ServerAntiAffinity,
|
||||
},
|
||||
Count: &airshipv1.VmCount{
|
||||
Active: workers,
|
||||
Standby: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
InfraServices: map[airshipv1.InfraService]airshipv1.InfraConfig{},
|
||||
},
|
||||
Status: airshipv1.SIPClusterStatus{},
|
||||
}
|
||||
}
|
@ -20,16 +20,17 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"k8s.io/client-go/rest"
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||
|
||||
airshipv1 "sipcluster/pkg/api/v1"
|
||||
// +kubebuilder:scaffold:imports
|
||||
)
|
||||
@ -54,7 +55,7 @@ var _ = BeforeSuite(func(done Done) {
|
||||
|
||||
By("bootstrapping test environment")
|
||||
testEnv = &envtest.Environment{
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
|
||||
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
|
||||
}
|
||||
|
||||
var err error
|
||||
@ -65,10 +66,29 @@ var _ = BeforeSuite(func(done Done) {
|
||||
err = airshipv1.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = metal3.AddToScheme(scheme.Scheme)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// +kubebuilder:scaffold:scheme
|
||||
|
||||
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
|
||||
k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
|
||||
Scheme: scheme.Scheme,
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = (&SIPClusterReconciler{
|
||||
Client: k8sManager.GetClient(),
|
||||
Log: ctrl.Log.WithName("controllers").WithName("SIPCluster"),
|
||||
Scheme: scheme.Scheme,
|
||||
}).SetupWithManager(k8sManager)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
go func() {
|
||||
err = k8sManager.Start(ctrl.SetupSignalHandler())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}()
|
||||
|
||||
k8sClient = k8sManager.GetClient()
|
||||
Expect(k8sClient).ToNot(BeNil())
|
||||
|
||||
close(done)
|
||||
|
Loading…
x
Reference in New Issue
Block a user