| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -30,24 +30,101 @@ import (
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					v1 "k8s.io/api/core/v1"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					resourcev1alpha2 "k8s.io/api/resource/v1alpha2"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"k8s.io/apimachinery/pkg/labels"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"k8s.io/apimachinery/pkg/types"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"k8s.io/client-go/informers"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"k8s.io/client-go/kubernetes"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					listersv1 "k8s.io/client-go/listers/core/v1"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"k8s.io/dynamic-resource-allocation/controller"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					"k8s.io/klog/v2"
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				type Resources struct {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					DriverName         string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					DontSetReservedFor bool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					NodeLocal          bool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					Nodes              []string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					MaxAllocations     int
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					Shareable          bool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Nodes is a fixed list of node names on which resources are
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// available. Mutually exclusive with NodeLabels.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					Nodes []string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// NodeLabels are labels which determine on which nodes resources are
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// available. Mutually exclusive with Nodes.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					NodeLabels     labels.Set
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					MaxAllocations int
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					Shareable      bool
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// AllocateWrapper, if set, gets called for each Allocate call.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					AllocateWrapper AllocateWrapperType
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func (r Resources) AllNodes(nodeLister listersv1.NodeLister) []string {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if len(r.NodeLabels) > 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Determine nodes with resources dynamically.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						nodes, _ := nodeLister.List(labels.SelectorFromValidatedSet(r.NodeLabels))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						nodeNames := make([]string, 0, len(nodes))
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for _, node := range nodes {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							nodeNames = append(nodeNames, node.Name)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return nodeNames
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return r.Nodes
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func (r Resources) NewAllocation(node string, data []byte) *resourcev1alpha2.AllocationResult {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					allocation := &resourcev1alpha2.AllocationResult{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Shareable: r.Shareable,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					allocation.ResourceHandles = []resourcev1alpha2.ResourceHandle{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							DriverName: r.DriverName,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							Data:       string(data),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if node == "" && len(r.NodeLabels) > 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// Available on all nodes matching the labels.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						var requirements []v1.NodeSelectorRequirement
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for key, value := range r.NodeLabels {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							requirements = append(requirements, v1.NodeSelectorRequirement{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								Key:      key,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								Operator: v1.NodeSelectorOpIn,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								Values:   []string{value},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							})
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						allocation.AvailableOnNodes = &v1.NodeSelector{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							NodeSelectorTerms: []v1.NodeSelectorTerm{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									MatchExpressions: requirements,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					} else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						var nodes []string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if node != "" {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// Local to one node.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							nodes = append(nodes, node)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						} else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							// Available on the fixed set of nodes.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							nodes = r.Nodes
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if len(nodes) > 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							allocation.AvailableOnNodes = &v1.NodeSelector{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								NodeSelectorTerms: []v1.NodeSelectorTerm{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										MatchExpressions: []v1.NodeSelectorRequirement{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												Key:      "kubernetes.io/hostname",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												Operator: v1.NodeSelectorOpIn,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
												Values:   nodes,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return allocation
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				type AllocateWrapperType func(ctx context.Context, claimAllocations []*controller.ClaimAllocation,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					selectedNode string,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					handler func(ctx context.Context,
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -57,8 +134,8 @@ type AllocateWrapperType func(ctx context.Context, claimAllocations []*controlle
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				type ExampleController struct {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					clientset  kubernetes.Interface
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					nodeLister listersv1.NodeLister
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					resources  Resources
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					driverName string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					mutex sync.Mutex
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// allocated maps claim.UID to the node (if network-attached) or empty (if not).
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -70,11 +147,10 @@ type ExampleController struct {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					numAllocations, numDeallocations int64
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func NewController(clientset kubernetes.Interface, driverName string, resources Resources) *ExampleController {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func NewController(clientset kubernetes.Interface, resources Resources) *ExampleController {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					c := &ExampleController{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						clientset:  clientset,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						resources:  resources,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						driverName: driverName,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						clientset: clientset,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						resources: resources,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						allocated:     make(map[types.UID]string),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						claimsPerNode: make(map[string]int),
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -84,7 +160,8 @@ func NewController(clientset kubernetes.Interface, driverName string, resources
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				func (c *ExampleController) Run(ctx context.Context, workers int) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					informerFactory := informers.NewSharedInformerFactory(c.clientset, 0 /* resync period */)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ctrl := controller.New(ctx, c.driverName, c, c.clientset, informerFactory)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ctrl := controller.New(ctx, c.resources.DriverName, c, c.clientset, informerFactory)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					c.nodeLister = informerFactory.Core().V1().Nodes().Lister()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ctrl.SetReservedFor(!c.resources.DontSetReservedFor)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					informerFactory.Start(ctx.Done())
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					ctrl.Run(workers)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -190,13 +267,14 @@ func (c *ExampleController) allocateOne(ctx context.Context, claim *resourcev1al
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						logger.V(3).V(3).Info("already allocated")
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					} else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						logger.V(3).Info("starting", "selectedNode", selectedNode)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						nodes := c.resources.AllNodes(c.nodeLister)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if c.resources.NodeLocal {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							node = selectedNode
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if node == "" {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								// If none has been selected because we do immediate allocation,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								// then we need to pick one ourselves.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								var viableNodes []string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								for _, n := range c.resources.Nodes {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								for _, n := range nodes {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									if c.resources.MaxAllocations == 0 ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										c.claimsPerNode[n] < c.resources.MaxAllocations {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										viableNodes = append(viableNodes, n)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -209,7 +287,7 @@ func (c *ExampleController) allocateOne(ctx context.Context, claim *resourcev1al
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								// number of allocations (even spreading) or the most (packing).
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								node = viableNodes[rand.Intn(len(viableNodes))]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								logger.V(3).Info("picked a node ourselves", "selectedNode", selectedNode)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							} else if !contains(c.resources.Nodes, node) ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							} else if !contains(nodes, node) ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								c.resources.MaxAllocations > 0 &&
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									c.claimsPerNode[node] >= c.resources.MaxAllocations {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								return nil, fmt.Errorf("resources exhausted on node %q", node)
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -222,9 +300,6 @@ func (c *ExampleController) allocateOne(ctx context.Context, claim *resourcev1al
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					allocation := &resourcev1alpha2.AllocationResult{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						Shareable: c.resources.Shareable,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					p := parameters{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						EnvVars:  make(map[string]string),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						NodeName: node,
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -235,33 +310,7 @@ func (c *ExampleController) allocateOne(ctx context.Context, claim *resourcev1al
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if err != nil {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return nil, fmt.Errorf("encode parameters: %w", err)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					allocation.ResourceHandles = []resourcev1alpha2.ResourceHandle{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							DriverName: c.driverName,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							Data:       string(data),
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					var nodes []string
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if node != "" {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						nodes = append(nodes, node)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					} else {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						nodes = c.resources.Nodes
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if len(nodes) > 0 {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						allocation.AvailableOnNodes = &v1.NodeSelector{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							NodeSelectorTerms: []v1.NodeSelectorTerm{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									MatchExpressions: []v1.NodeSelectorRequirement{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										{
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											Key:      "kubernetes.io/hostname",
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											Operator: v1.NodeSelectorOpIn,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
											Values:   nodes,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
										},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							},
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					allocation := c.resources.NewAllocation(node, data)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if !alreadyAllocated {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						c.numAllocations++
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						c.allocated[claim.UID] = node
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -303,6 +352,7 @@ func (c *ExampleController) UnsuitableNodes(ctx context.Context, pod *v1.Pod, cl
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						// All nodes are suitable.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						return nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					nodes := c.resources.AllNodes(c.nodeLister)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if c.resources.NodeLocal {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for _, claim := range claims {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							claim.UnsuitableNodes = nil
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -312,7 +362,7 @@ func (c *ExampleController) UnsuitableNodes(ctx context.Context, pod *v1.Pod, cl
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								// can only work if a node has capacity left
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								// for all of them. Also, nodes that the driver
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								// doesn't run on cannot be used.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if !contains(c.resources.Nodes, node) ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								if !contains(nodes, node) ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									c.claimsPerNode[node]+len(claims) > c.resources.MaxAllocations {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
									claim.UnsuitableNodes = append(claim.UnsuitableNodes, node)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				@@ -325,7 +375,7 @@ func (c *ExampleController) UnsuitableNodes(ctx context.Context, pod *v1.Pod, cl
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for _, claim := range claims {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						claim.UnsuitableNodes = nil
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						for _, node := range potentialNodes {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if !contains(c.resources.Nodes, node) ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							if !contains(nodes, node) ||
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								allocations+len(claims) > c.resources.MaxAllocations {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
								claim.UnsuitableNodes = append(claim.UnsuitableNodes, node)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							}
 | 
			
		
		
	
	
		
			
				
					
					| 
						
					 | 
				
			
			 | 
			 | 
			
				 
 |