anchor.diff:  Only use nodes with the 'region' label defined and prefer nodes with the 'zone' label defined
   ----
   {
  -	"predicates" : [
  -		{"name" : "RequireRegion", "argument" : {"labelsPresence" : {"labels" : ["region"], "presence" : true}}},
  -
  -	],
  -	"priorities" : [
  -		{"name" : "ZonePreferred", "weight" : 1, "argument" : {"labelPreference" : {"label" : "zone", "presence" : true}}},
  -	]
  -}
  -----
  -
  -Combining fixed and configurable predicates and priority functions
  -----
  -{
  -	"predicates" : [
  +	"kind" : "Policy",
  +	"version" : "v1",
  +	"predicates" : [
  +		...
  +		{"name" : "RequireRegion", "argument" : {"labelsPresence" : {"labels" : ["region"], "presence" : true}}}
  +
  +	],
  +	"priorities" : [
  +		...
  +		{"name" : "ZonePreferred", "weight" : 1, "argument" : {"labelPreference" : {"label" : "zone", "presence" : true}}}
  +	]
  +}
  +----
  +
  +Random configuration example combining static and configurable predicates and priority functions
  +----
  +{
  +	"kind" : "Policy",
  +	"version" : "v1",
  +	"predicates" : [
  +		...
   		{"name" : "RegionAffinity", "argument" : {"serviceAffinity" : {"labels" : ["region"]}}},
   		{"name" : "RequireRegion", "argument" : {"labelsPresence" : {"labels" : ["region"], "presence" : true}}},
   		{"name" : "BuildingNodesAvoid", "argument" : {"labelsPresence" : {"labels" : ["building"], "presence" : false}}},
   		{"name" : "PodFitsPorts"},
  -		{"name" : "MatchNodeSelector}
  -	],
  -	"priorities" : [
  +		{"name" : "MatchNodeSelector"}
  +	],
  +	"priorities" : [
  +		...
   		{"name" : "ZoneSpread", "weight" : 2, "argument" : {"serviceAntiAffinity" : {"label" : "zone"}}},
   		{"name" : "ZonePreferred", "weight" : 1, "argument" : {"labelPreference" : {"label" : "zone", "presence" : true}}},
   		{"name" : "ServiceSpreadingPriority", "weight" : 1}
   	]
   }
   ----
  +
  +
  +== Scheduler Extensibility
  +As is the case with almost everything else in Kubernetes/OpenShift, the scheduler is built using a plugin model and the current implementation itself is a plugin.  There are two ways to extend the scheduler functionality.
  +
  +=== Enhancements
  +The scheduler functionality can be enhanced by adding new predicates and priority functions.  They can either be contributed upstream or maintained separately.  These predicates and priority functions would need to be registered with the scheduler factory and then specified in the scheduler policy file.
  +
  +=== Replacement
  +Since the scheduler is a plugin, it can be replaced in favor of an alternate implementation.  The scheduler code has a clean separation that watches new pods as they get created and identifies the most suitable node to host them.  It then creates bindings (pod to node bindings) for the pods using the master API.
  
positive.code: The nodes are sorted based on their scores and the node with the highest score is selected to host the pod. If multiple nodes have the same high score, then one of them is selected at random. 
  
  
  == Scheduler Policy
  The selection of the predicate and priority functions defines the policy for the scheduler.  Several predicate and priority functions are provided within Kubernetes.  There are two ways to define the scheduler policy.  Administrators can either specify an algorithm provider or they can provide a JSON configuration file that specifies the predicates and priority functions to configure the scheduler.  Both the algorithm provider and the configuration file can be specified using the command line for the scheduler executable.  
  
  
  === Algorithm Providers
  'Providers' can be created to specify a pre-determined combination of the predicates and priority functions along with their weights. A few providers, including a default provider, have been created for providing the scheduler configuration.  Creating a provider is not something that a user/administrator can do.  However, administrators can select a particular algorithm provider for their scheduler configuration via the command line.
  
  
  === Available Predicates
  A custom set of predicates can be specified to configure the scheduler.  There are several predicates provided out-of-the-box in Kubernetes.  Some of these predicates can be customized by providing certain parameters.  Multiple predicates can be combined to provide additional filtering of nodes.
  
  ==== Fixed Predicates
  
  1. 'PodFitsPorts' deems a node to be fit for hosting a pod based on the absence of port conflicts
  1. 'PodFitsResources' determines a fit baased resource availability.  The nodes can declare their resource capacities and then pods can specify what resources they require.  Fit is based on requested, rather than used resources.
  1. 'NoDiskConflict' determines fit based on non-conflicting disk volumes.  It evaluates if a pod can fit due to the volumes it requests, and those that are already mounted.
  1. 'MatchNodeSelector' determines fit based on node selector query that is defined in the pod.
  1. 'HostName' determines fit based on the presence of the Host parameter and a string match with the name of the host
  
  ==== Configurable Predicates
  
  1. 'ServiceAffinity' filters out nodes that do not belong to the specified topological level defined by the provided labels.  This predicate takes in a list of labels and ensures affinity within the nodes (that have the same label values) for pods belonging to the same service.  If the pod specifies a value for the labels in its NodeSelector, then the nodes matching those labels are the ones where the pod is scheduled.  If the pod does not specify the labels in its NodeSelector, then the first pod can be placed on any node based on availability and all subsequent pods of the service will be scheduled on nodes that have the same label values.
  1. 'LabelsPresence' checks whether a particular node has a certain label defined or not, regardless of value
  
  
  === Available Priority Functions
  A custom set of priority functionis can be specified to configure the scheduler.  There are several priority functions provided out-of-the-box in Kubernetes.  Some of these priority functions can be customized by providing certain parameters.  Multiple priority functions can be combined and weights can be given to each in order to impact the prioritization. The default weight is 1.
  
  ==== Fixed Priority Functions
  
  1. 'LeastRequestedPriority' favors nodes with fewer requested resources.  It calculates the percentage of memory and CPU requested by pods scheduled on the node, and prioritizes nodes that have the highest available/remaining capacity.
  1. 'ServiceSpreadingPriority' spreads pods by minimizing the number of pods belonging to the same service onto the same machine
  1. 'EqualPriority' gives an equal weight of one to all nodes
  
  ==== Configurable Priority Functions
  
  1. 'ServiceAntiAffinity' takes a label and ensures a good spread of the pods belonging to the same service across the group of nodes based on the label values.  It gives the same score to all nodes that have the same value for the specified label.  It gives a highter score to nodes within a group with the least concentration of pods.
  
  
  == Affinity and Anti Affinity
  One of the important use cases for scheduling within OpenShift is to support flexible affinity and anti-affinity policies.  Administrators can define multiple topological levels for their infrastructure (nodes).  This is done by specifying labels on nodes (eg: region = r1, zone = z1, rack = s1). These label names have no particular meaning and administrators are free to name their infrastructure levels anything (eg, city/building/room).  Also, administrators can define any number of nested levels for their infrastructure topology, with three levels being usually adequate (eg. regions --> zones --> racks).  Lastly, administrators can specify affinity and anti-affinity rules at each of these levels in any combination.
  
  
  == Sample Policy Configurations
  Three topological levels defined as region (affinity) --> zone (affinity) --> rack (anti-affinity)
  ----
  {
  	"predicates" : [
  		{"name" : "RegionZoneAffinity", "argument" : {"serviceAffinity" : {"labels" : ["region", "zone"]}}}
  	],
  	"priorities" : [
  		{"name" : "RackSpread", "weight" : 1, "argument" : {"serviceAntiAffinity" : {"label" : "rack"}}}
  	]
  }
  
negative.code: Three topological levels defined as city (affinity) --> building (anti-affinity) --> room (anti-affinity)
  ----
  {
  	"kind" : "Policy",
  	"version" : "v1",
  	"predicates" : [
  		...
  		{"name" : "CityAffinity", "argument" : {"serviceAffinity" : {"labels" : ["city"]}}}
  	],
  	"priorities" : [
  		...
  		{"name" : "BuildingSpread", "weight" : 1, "argument" : {"serviceAntiAffinity" : {"label" : "building"}}},
  		{"name" : "RoomSpread", "weight" : 1, "argument" : {"serviceAntiAffinity" : {"label" : "room"}}}
  	]
  