WIP : Selects properly the vBMHs that match the scheduling criteria.

Extrapolate is not working..
This commit is contained in:
Rodolfo Pacheco 2020-11-05 12:45:53 -05:00
parent 41c6720e26
commit 11adcb942c
15 changed files with 188 additions and 35 deletions

View File

@ -1,7 +1,7 @@
# Image URL to use all building/pushing image targets # Image URL to use all building/pushing image targets
#IMG ?= controller:latest #IMG ?= controller:latest
IMG ?= quay.io/jezogwza/airship:sip.v1 IMG ?= quay.io/jezogwza/airship:sip.v2
# Produce CRDs that work back to Kubernetes 1.11 (no version conversion) # Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
CRD_OPTIONS ?= "crd:trivialVersions=true" CRD_OPTIONS ?= "crd:trivialVersions=true"

11
config/kustomization.yaml Normal file
View File

@ -0,0 +1,11 @@
#
# Adds namespace to all resources.
namespace: sip-system
resources:
- manager
- certmanager
- crd
- prometheus
- rbac
- webhook

View File

@ -3,7 +3,7 @@ kind: Namespace
metadata: metadata:
labels: labels:
control-plane: controller-manager control-plane: controller-manager
name: system name: sip-system
--- ---
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
@ -27,7 +27,8 @@ spec:
- /manager - /manager
args: args:
- --enable-leader-election - --enable-leader-election
image: controller:latest image: quay.io/jezogwza/airship:sip.v1
imagePullPolicy: Always
name: manager name: manager
resources: resources:
limits: limits:

View File

@ -9,4 +9,4 @@ roleRef:
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: default name: default
namespace: system namespace: sip-cluster-system

View File

@ -1,8 +1,11 @@
resources: resources:
- role.yaml - role.yaml
- role_binding.yaml - role_binding.yaml
- sipcluster_scheduler_role.yaml
- sipcluster_scheduler_binding.yaml
- leader_election_role.yaml - leader_election_role.yaml
- leader_election_role_binding.yaml - leader_election_role_binding.yaml
# Comment the following 4 lines if you want to disable # Comment the following 4 lines if you want to disable
# the auth proxy (https://github.com/brancz/kube-rbac-proxy) # the auth proxy (https://github.com/brancz/kube-rbac-proxy)
# which protects your /metrics endpoint. # which protects your /metrics endpoint.

View File

@ -9,4 +9,4 @@ roleRef:
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: default name: default
namespace: system namespace: sip-cluster-system

View File

@ -9,4 +9,4 @@ roleRef:
subjects: subjects:
- kind: ServiceAccount - kind: ServiceAccount
name: default name: default
namespace: system namespace: sip-cluster-system

View File

@ -0,0 +1,26 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: scheduler-rolebinding
namespace: metal3
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: scheduler-role
subjects:
- kind: ServiceAccount
name: default
namespace: sip-cluster-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-scheduler-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-scheduler-role
subjects:
- kind: ServiceAccount
name: default
namespace: sip-cluster-system

View File

@ -0,0 +1,47 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: scheduler-role
namespace: metal3
rules:
- apiGroups:
- metal3.io
resources:
- baremetalhosts
verbs:
- get
- list
- patch
- watch
- update
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-scheduler-role
rules:
- apiGroups:
- metal3.io
resources:
- baremetalhosts
verbs:
- get
- list
- patch
- watch
- update
- apiGroups:
- ""
resources:
- secrets
verbs:
- get
- list

View File

@ -1,5 +1,5 @@
resources: resources:
- manifests.yaml #- manifests.yaml
- service.yaml - service.yaml
configurations: configurations:

View File

@ -28,7 +28,10 @@ import (
airshipv1 "sipcluster/pkg/api/v1" airshipv1 "sipcluster/pkg/api/v1"
"sipcluster/pkg/controllers" "sipcluster/pkg/controllers"
// +kubebuilder:scaffold:imports // +kubebuilder:scaffold:imports
metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
) )
var ( var (
@ -41,6 +44,9 @@ func init() {
_ = airshipv1.AddToScheme(scheme) _ = airshipv1.AddToScheme(scheme)
// +kubebuilder:scaffold:scheme // +kubebuilder:scaffold:scheme
// Add Metal3 CRD
_ = metal3.AddToScheme(scheme)
} }
func main() { func main() {

View File

@ -18,6 +18,7 @@ package controllers
import ( import (
"context" "context"
"fmt"
"github.com/go-logr/logr" "github.com/go-logr/logr"
// "github.com/prometheus/common/log" // "github.com/prometheus/common/log"
@ -39,6 +40,9 @@ type SIPClusterReconciler struct {
// +kubebuilder:rbac:groups=airship.airshipit.org,resources=sipclusters,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=airship.airshipit.org,resources=sipclusters,verbs=get;list;watch;create;update;patch;delete
// +kubebuilder:rbac:groups=airship.airshipit.org,resources=sipclusters/status,verbs=get;update;patch // +kubebuilder:rbac:groups=airship.airshipit.org,resources=sipclusters/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=airship.airshipit.org,resources=sipclusters/status,verbs=get;update;patch
// +kubebuilder:rbac:groups="metal3.io",resources=baremetalhosts,verbs=get;update;patch;list
func (r *SIPClusterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { func (r *SIPClusterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) {
ctx := context.Background() ctx := context.Background()
@ -54,8 +58,9 @@ func (r *SIPClusterReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error)
return ctrl.Result{}, nil return ctrl.Result{}, nil
} }
// machines // machines
err, machines := r.gatherVM(sip) err, machines := r.gatherVBMH(sip)
if err != nil { if err != nil {
log.Error(err, "unable to gather vBMHs")
return ctrl.Result{}, err return ctrl.Result{}, err
} }
@ -97,19 +102,21 @@ func (r *SIPClusterReconciler) SetupWithManager(mgr ctrl.Manager) error {
*/ */
// machines // machines
func (r *SIPClusterReconciler) gatherVM(sip airshipv1.SIPCluster) (error, *airshipvms.MachineList) { func (r *SIPClusterReconciler) gatherVBMH(sip airshipv1.SIPCluster) (error, *airshipvms.MachineList) {
// 1- Let me retrieve all BMH that are unlabeled or already labeled with the target Tenant/CNF // 1- Let me retrieve all BMH that are unlabeled or already labeled with the target Tenant/CNF
// 2- Let me now select the one's that meet teh scheduling criteria // 2- Let me now select the one's that meet teh scheduling criteria
// If I schedule successfully then // If I schedule successfully then
// If Not complete schedule , then throw an error. // If Not complete schedule , then throw an error.
machines := &airshipvms.MachineList{} machines := &airshipvms.MachineList{}
fmt.Printf("gatherVBMH.Schedule sip:%v machines:%v\n", sip, machines)
err := machines.Schedule(sip.Spec.Nodes, r.Client) err := machines.Schedule(sip.Spec.Nodes, r.Client)
if err != nil { if err != nil {
return err, machines return err, machines
} }
// we extra the information in a generic way // we extract the information in a generic way
// So that LB and Jump Host all leverage the same // So that LB , Jump and Ath POD all leverage the same
fmt.Printf("gatherVBMH.Extrapolate sip:%v machines:%v\n", sip, machines)
err = machines.Extrapolate(sip, r.Client) err = machines.Extrapolate(sip, r.Client)
if err != nil { if err != nil {
return err, machines return err, machines

View File

@ -25,11 +25,12 @@ import (
metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1" metal3 "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client"
airshipv1 "sipcluster/pkg/api/v1" airshipv1 "sipcluster/pkg/api/v1"
//rbacv1 "k8s.io/api/rbac/v1" //rbacv1 "k8s.io/api/rbac/v1"
//"k8s.io/apimachinery/pkg/api/errors" //"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
// ScheduledState // ScheduledState
@ -51,21 +52,29 @@ const (
) )
const ( const (
BaseAirshipSelector = "airshipit.org" BaseAirshipSelector = "sip.airshipit.org"
SipScheduled = BaseAirshipSelector + "/sip-scheduled in (True, true)" SipScheduleLabelName = "sip-scheduled"
SipNotScheduled = BaseAirshipSelector + "/sip-scheduled in (False, false)" SipScheduleLabel = BaseAirshipSelector + "/" + SipScheduleLabelName
SipScheduled = SipScheduleLabel + "=true"
SipNotScheduled = SipScheduleLabel + "=false"
// This is a placeholder . Need to synchronize with ViNO the constants below // This is a placeholder . Need to synchronize with ViNO the constants below
// Probable pll this or eqivakent values from a ViNO pkg // Probable pll this or eqivakent values from a ViNO pkg
RackLabel = BaseAirshipSelector + "/rack" RackLabel = BaseAirshipSelector + "/rack"
ServerLabel = BaseAirshipSelector + "/rack" ServerLabel = BaseAirshipSelector + "/server"
// This should be a configurable thing
// But probable not in teh CR.. TBD
// TODO
VBMH_NAMESPACE = "metal3"
) )
// MAchine represents an individual BMH CR, and teh appropriate // MAchine represents an individual BMH CR, and teh appropriate
// attributes required to manage the SIP Cluster scheduling and // attributes required to manage the SIP Cluster scheduling and
// rocesing needs about thhem // rocesing needs about thhem
type Machine struct { type Machine struct {
Bmh metal3.BareMetalHost Bmh *metal3.BareMetalHost
ScheduleStatus ScheduledState ScheduleStatus ScheduledState
// scheduleLabels // scheduleLabels
// I expect to build this over time / if not might not be needed // I expect to build this over time / if not might not be needed
@ -88,17 +97,18 @@ type MachineList struct {
} }
func (ml *MachineList) Schedule(nodes map[airshipv1.VmRoles]airshipv1.NodeSet, c client.Client) error { func (ml *MachineList) Schedule(nodes map[airshipv1.VmRoles]airshipv1.NodeSet, c client.Client) error {
// Initialize teh Target list // Initialize teh Target list
ml.bmhs = ml.init(nodes) ml.bmhs = ml.init(nodes)
// IDentify vBMH's that meet the appropriate selction criteria // IDentify vBMH's that meet the appropriate selction criteria
bmList, err := ml.getVBMH(c) bmhList, err := ml.getVBMH(c)
if err != nil { if err != nil {
return err return err
} }
// Identify and Select the vBMH I actually will use // Identify and Select the vBMH I actually will use
err = ml.identifyNodes(nodes, bmList) err = ml.identifyNodes(nodes, bmhList)
if err != nil { if err != nil {
return err return err
} }
@ -106,7 +116,7 @@ func (ml *MachineList) Schedule(nodes map[airshipv1.VmRoles]airshipv1.NodeSet, c
// If I get here the MachineList should have a selected set of Machine's // If I get here the MachineList should have a selected set of Machine's
// They are in the ScheduleStatus of ToBeScheduled as well as the Role // They are in the ScheduleStatus of ToBeScheduled as well as the Role
// //
fmt.Printf("Schedule ml.bmhs size:%d\n", len(ml.bmhs))
return nil return nil
} }
@ -115,12 +125,16 @@ func (ml *MachineList) init(nodes map[airshipv1.VmRoles]airshipv1.NodeSet) []*Ma
for _, nodeCfg := range nodes { for _, nodeCfg := range nodes {
mlSize = mlSize + nodeCfg.Count.Active + nodeCfg.Count.Standby mlSize = mlSize + nodeCfg.Count.Active + nodeCfg.Count.Standby
} }
return make([]*Machine, mlSize) //fmt.Printf("Schedule.init mlSize:%d\n", mlSize)
return make([]*Machine, 0)
} }
func (ml *MachineList) getVBMH(c client.Client) (*metal3.BareMetalHostList, error) { func (ml *MachineList) getVBMH(c client.Client) (*metal3.BareMetalHostList, error) {
bmList := &metal3.BareMetalHostList{}
bmhList := &metal3.BareMetalHostList{}
// I am thinking we can add a Label for unsccheduled. // I am thinking we can add a Label for unsccheduled.
// SIP Cluster can change it to scheduled. // SIP Cluster can change it to scheduled.
// We can then simple use this to select UNSCHEDULED // We can then simple use this to select UNSCHEDULED
@ -128,24 +142,42 @@ func (ml *MachineList) getVBMH(c client.Client) (*metal3.BareMetalHostList, erro
This possible will not be needed if I figured out how to provide a != label. This possible will not be needed if I figured out how to provide a != label.
Then we can use DOESNT HAVE A TENANT LABEL Then we can use DOESNT HAVE A TENANT LABEL
*/ */
labelSelector := metav1.LabelSelector{MatchLabels: map[string]string{SipNotScheduled: "False"}} scheduleLabels := map[string]string{SipScheduleLabel: "false"}
/**
DELETE SOON, ..
labelSelector := metav1.LabelSelector{MatchLabels: scheduleLabels}
bmhSelector, err := metav1.LabelSelectorAsSelector(&labelSelector) bmhSelector, err := metav1.LabelSelectorAsSelector(&labelSelector)
if err != nil { if err != nil {
return bmList, err return bmhList, err
} }
fmt.Printf("Schedule.getVBMH bmhSelector:%v\n", bmhSelector)
// TODO Namespace where vBMH needs to be found
// Might be in THE SIP CR Peerhaps
bmListOptions := &client.ListOptions{ bmListOptions := &client.ListOptions{
LabelSelector: bmhSelector, LabelSelector: bmhSelector,
Limit: 100, Limit: 100,
Namespace: VBMH_NAMESPACE,
} }
err = c.List(context.TODO(), bmList, bmListOptions) fmt.Printf("Schedule.getVBMH bmList context.Background bmhList:%v\n bmListOptions:%v scheduleLabels:%v\n", bmhList, bmListOptions, scheduleLabels)
err = c.List(context.Background(), bmhList, bmListOptions, client.InNamespace(VBMH_NAMESPACE))
*/
err := c.List(context.Background(), bmhList, client.MatchingLabels(scheduleLabels))
if err != nil { if err != nil {
return bmList, err fmt.Printf("Schedule.getVBMH bmhList err:%v\n", err)
return bmhList, err
} }
return bmList, nil fmt.Printf("Schedule.getVBMH bmhList size:%d\n", len(bmhList.Items))
if len(bmhList.Items) > 0 {
return bmhList, nil
}
return bmhList, fmt.Errorf("Unable to identify vBMH available for scheduling. Selecting %v ", scheduleLabels)
} }
func (ml *MachineList) identifyNodes(nodes map[airshipv1.VmRoles]airshipv1.NodeSet, bmList *metal3.BareMetalHostList) error { func (ml *MachineList) identifyNodes(nodes map[airshipv1.VmRoles]airshipv1.NodeSet, bmhList *metal3.BareMetalHostList) error {
// If using the SIP Sheduled label, we now have a list of vBMH;'s // If using the SIP Sheduled label, we now have a list of vBMH;'s
// that are not scheduled // that are not scheduled
// Next I need to apply the constraints // Next I need to apply the constraints
@ -154,17 +186,18 @@ func (ml *MachineList) identifyNodes(nodes map[airshipv1.VmRoles]airshipv1.NodeS
// Only deals with AntiAffinity at : // Only deals with AntiAffinity at :
// - Racks : Dont select two machines in the same rack // - Racks : Dont select two machines in the same rack
// - Server : Dont select two machines in the same server // - Server : Dont select two machines in the same server
fmt.Printf("Schedule.identifyNodes bmList size:%d\n", len(bmhList.Items))
for nodeRole, nodeCfg := range nodes { for nodeRole, nodeCfg := range nodes {
scheduleSetMap, err := ml.initScheduleMaps(nodeCfg.Scheduling) scheduleSetMap, err := ml.initScheduleMaps(nodeCfg.Scheduling)
if err != nil { if err != nil {
return err return err
} }
err = ml.scheduleIt(nodeRole, nodeCfg, bmList, scheduleSetMap) err = ml.scheduleIt(nodeRole, nodeCfg, bmhList, scheduleSetMap)
if err != nil { if err != nil {
return err return err
} }
} }
fmt.Printf("Schedule.identifyNodes ml.bmhs size:%d\n", len(ml.bmhs))
return nil return nil
} }
@ -188,39 +221,50 @@ func (ml *MachineList) initScheduleMaps(constraints []airshipv1.SchedulingOption
} }
} }
fmt.Printf("Schedule.initScheduleMaps setMap:%v\n", setMap)
if len(setMap) > 0 { if len(setMap) > 0 {
return setMap, ErrorConstraintNotFound{} return setMap, nil
} }
return setMap, nil return setMap, ErrorConstraintNotFound{}
} }
func (ml *MachineList) scheduleIt(nodeRole airshipv1.VmRoles, nodeCfg airshipv1.NodeSet, bmList *metal3.BareMetalHostList, scheduleSetMap map[airshipv1.SchedulingOptions]*ScheduleSet) error { func (ml *MachineList) scheduleIt(nodeRole airshipv1.VmRoles, nodeCfg airshipv1.NodeSet, bmList *metal3.BareMetalHostList, scheduleSetMap map[airshipv1.SchedulingOptions]*ScheduleSet) error {
validBmh := true validBmh := true
nodeTarget := (nodeCfg.Count.Active + nodeCfg.Count.Standby) nodeTarget := (nodeCfg.Count.Active + nodeCfg.Count.Standby)
fmt.Printf("Schedule.scheduleIt nodeRole:%v nodeTarget:%d nodeCfg.VmFlavor:%s ml.bmhs len:%d \n", nodeRole, nodeTarget, nodeCfg.VmFlavor, len(ml.bmhs))
for _, bmh := range bmList.Items { for _, bmh := range bmList.Items {
fmt.Printf("---------------\n Schedule.scheduleIt bmh.ObjectMeta.Name:%s \n", bmh.ObjectMeta.Name)
for _, constraint := range nodeCfg.Scheduling { for _, constraint := range nodeCfg.Scheduling {
// Do I care about this constraint // Do I care about this constraint
if scheduleSetMap[constraint].Active() { if scheduleSetMap[constraint].Active() {
// Check if bmh has the label // Check if bmh has the label
// There is a func (host *BareMetalHost) getLabel(name string) string { // There is a func (host *BareMetalHost) getLabel(name string) string {
// Not sure why its not Public, so sing our won method // Not sure why its not Public, so using our own method
cLabelValue, cFlavorMatches := scheduleSetMap[constraint].GetLabels(bmh.Labels, nodeCfg.VmFlavor) cLabelValue, cFlavorMatches := scheduleSetMap[constraint].GetLabels(bmh.Labels, nodeCfg.VmFlavor)
// If it doesnt match the flavor its not valid
validBmh = cFlavorMatches
// If it does match the flavor
if cLabelValue != "" && cFlavorMatches { if cLabelValue != "" && cFlavorMatches {
// If its in th elist , theen this bmh is disqualified. Skip it // If its in the list already for the constraint , theen this bmh is disqualified. Skip it
if scheduleSetMap[constraint].Exists(cLabelValue) { if scheduleSetMap[constraint].Exists(cLabelValue) {
validBmh = false validBmh = false
break break
} else {
scheduleSetMap[constraint].Add(cLabelValue)
} }
} }
fmt.Printf("Schedule.scheduleIt cLabelValue:%s, cFlavorMatches:%t scheduleSetMap[%v]:%v\n", cLabelValue, cFlavorMatches, constraint, scheduleSetMap[constraint])
} }
} }
fmt.Printf("Schedule.scheduleIt nodeTarget:%d, validBmh:%t ml.bmhs len:%d\n", nodeTarget, validBmh, len(ml.bmhs))
// All the constraints have been checked // All the constraints have been checked
if validBmh { if validBmh {
// Lets add it to the list as a schedulable thing // Lets add it to the list as a schedulable thing
m := &Machine{ m := &Machine{
Bmh: bmh, Bmh: &bmh,
ScheduleStatus: ToBeScheduled, ScheduleStatus: ToBeScheduled,
VmRole: nodeRole, VmRole: nodeRole,
Data: &MachineData{ Data: &MachineData{
@ -229,6 +273,7 @@ func (ml *MachineList) scheduleIt(nodeRole airshipv1.VmRoles, nodeCfg airshipv1.
} }
// Probable need to use the nodeRole as a label here // Probable need to use the nodeRole as a label here
ml.bmhs = append(ml.bmhs, m) ml.bmhs = append(ml.bmhs, m)
fmt.Printf("Schedule.scheduleIt ADDED ml.bmhs len:%d machine:%v \n", len(ml.bmhs), m)
nodeTarget = nodeTarget - 1 nodeTarget = nodeTarget - 1
if nodeTarget == 0 { if nodeTarget == 0 {
break break
@ -239,6 +284,7 @@ func (ml *MachineList) scheduleIt(nodeRole airshipv1.VmRoles, nodeCfg airshipv1.
validBmh = true validBmh = true
} }
fmt.Printf("Schedule.scheduleIt nodeTarget:%d, ml.bmhs:%d\n", nodeTarget, len(ml.bmhs))
if nodeTarget > 0 { if nodeTarget > 0 {
return ErrorUnableToFullySchedule{ return ErrorUnableToFullySchedule{
TargetNode: nodeRole, TargetNode: nodeRole,
@ -252,7 +298,9 @@ func (ml *MachineList) scheduleIt(nodeRole airshipv1.VmRoles, nodeCfg airshipv1.
// The intention is to extract the IP information from the referenced networkData field for the BareMetalHost // The intention is to extract the IP information from the referenced networkData field for the BareMetalHost
func (ml *MachineList) Extrapolate(sip airshipv1.SIPCluster, c client.Client) error { func (ml *MachineList) Extrapolate(sip airshipv1.SIPCluster, c client.Client) error {
// Lets get the data for all selected BMH's. // Lets get the data for all selected BMH's.
fmt.Printf("Schedule.Extrapolate ml.bmhs:%d\n", len(ml.bmhs))
for _, machine := range ml.bmhs { for _, machine := range ml.bmhs {
fmt.Printf("Schedule.Extrapolate machine:%v\n", machine)
bmh := machine.Bmh bmh := machine.Bmh
// Identify Network Data Secret name // Identify Network Data Secret name
@ -492,7 +540,11 @@ func (ss *ScheduleSet) Exists(value string) bool {
return false return false
} }
func (ss *ScheduleSet) Add(labelValue string) {
ss.set[labelValue] = true
}
func (ss *ScheduleSet) GetLabels(labels map[string]string, flavorLabel string) (string, bool) { func (ss *ScheduleSet) GetLabels(labels map[string]string, flavorLabel string) (string, bool) {
fmt.Printf("Schedule.scheduleIt.GetLabels labels:%v, flavorLabel:%s\n", labels, flavorLabel)
if labels == nil { if labels == nil {
return "", false return "", false
} }