func (m *Manager) NodeHasPackLeftAttributes(node *corev1.Node, nag *assignmentsv1alpha1.NodeAssignmentGroup) bool {
	lk := getLabelKey(nag.Name)
	for k := range node.GetLabels() {
		if k == lk {
			return true
		}
	}
	for _, t := range node.Spec.Taints {
		if t.Key == lk {
			return true
		}
	}
	return false
}
NodeHasPackLeftAttributes checks to see if the given node has any labels or taints that have come from a given nag
package packleft
import (
	"encoding/json"
	"fmt"
	"sort"
	assignmentsv1alpha1 "github.com/domoinc/kube-valet/pkg/apis/assignments/v1alpha1"
	valet "github.com/domoinc/kube-valet/pkg/client/clientset/versioned"
	"github.com/domoinc/kube-valet/pkg/utils"
	logging "github.com/op/go-logging"
	"github.com/prometheus/client_golang/prometheus"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/types"
	"k8s.io/apimachinery/pkg/util/strategicpatch"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/tools/cache"
	"k8s.io/client-go/util/retry"
)
const (
	PackLeftFinalizer string = "packleft.nag.finalizer.kube-valet.io"
)
type Manager struct {
	nagIndex    cache.Indexer
	nodeIndex   cache.Indexer
	podIndex    cache.Indexer
	valetClient valet.Interface
	kubeClient  kubernetes.Interface
	log         *logging.Logger
}
func NewManager(nagIndex cache.Indexer, nodeIndex cache.Indexer, podIndex cache.Indexer, kubeClient kubernetes.Interface, valetClient valet.Interface) *Manager {
	return &Manager{
		nagIndex:    nagIndex,
		nodeIndex:   nodeIndex,
		podIndex:    podIndex,
		kubeClient:  kubeClient,
		valetClient: valetClient,
		log:         logging.MustGetLogger("PackLeftSchedulingManager"),
	}
}
func (m *Manager) RebalanceNag(nag *assignmentsv1alpha1.NodeAssignmentGroup, metric *prometheus.GaugeVec) {
	m.ensureFinalizer(nag)
	packLeftNodeGroups := m.getPackLeftNodeGroups(nag)
	m.log.Debugf("found %d node groups for nag %s with", len(packLeftNodeGroups), nag.Name)
	for assignmentName, nodes := range packLeftNodeGroups {
		if len(nodes) != 0 {
			m.log.Infof("rebalancing  %d nodes in assignment %s.%s", len(nodes), nag.Name, assignmentName)
			labelKey := getLabelKey(nag.Name)
			if assignment, ok := m.getAssignmentByName(assignmentName, nag); ok {
				m.balanceNodes(nodes, labelKey, nag, assignment, metric)
			} else {
				m.log.Warningf("Assignment %s doesn't exist in the NodeAssignmentGroup", assignmentName)
			}
		} else {
			m.log.Warningf("No nodes found for assignment %s on nag %s", assignmentName, nag.Name)
		}
	}
}
func (m *Manager) CleanAllNodes(nag *assignmentsv1alpha1.NodeAssignmentGroup) error {
	labelKey := getLabelKey(nag.Name)
	for _, obj := range m.nodeIndex.List() {
		node := obj.(*corev1.Node)
		if (!m.NodeHasPackLeftAssignment(node, nag) && m.NodeHasPackLeftAttributes(node, nag)) || !NodeCanBeBalanced(node) {
			newNode := m.unassignNode(node, labelKey)
			if err := m.patchNodeState(node, newNode); err != nil {
				return err
			}
		}
	}
	return nil
}
func (m *Manager) CleanUnassignedNodes(nag *assignmentsv1alpha1.NodeAssignmentGroup) {
	m.log.Infof("Cleaning nag %s", nag.Name)
	labelKey := getLabelKey(nag.Name)
	for _, obj := range m.nodeIndex.List() {
		node := obj.(*corev1.Node)
		if !m.NodeHasPackLeftAssignment(node, nag) && m.NodeHasPackLeftAttributes(node, nag) {
			m.log.Debugf("Node '%s' has packleft attributes for nag '%s' but is not assigned to it anymore. Clearing attributes", node.Name, nag.Name)
			newNode := m.unassignNode(node, labelKey)
			m.patchNodeState(node, newNode)
		}
	}
}