@@ -57,7 +57,7 @@ import (
57
57
v1core "k8s.io/client-go/kubernetes/typed/core/v1"
58
58
"k8s.io/client-go/pkg/version"
59
59
"k8s.io/client-go/tools/record"
60
- cloudprovider "k8s.io/cloud-provider"
60
+ "k8s.io/cloud-provider"
61
61
nodehelpers "k8s.io/cloud-provider/node/helpers"
62
62
servicehelpers "k8s.io/cloud-provider/service/helpers"
63
63
cloudvolume "k8s.io/cloud-provider/volume"
@@ -205,6 +205,16 @@ const volumeAttachmentStuck = "VolumeAttachmentStuck"
205
205
// Indicates that a node has volumes stuck in attaching state and hence it is not fit for scheduling more pods
206
206
const nodeWithImpairedVolumes = "NodeWithImpairedVolumes"
207
207
208
+ const (
209
+ // These constants help to identify if a node is a master or a minion
210
+ labelKeyNodeRole = "kubernetes.io/role"
211
+ nodeMasterRole = "master"
212
+ nodeMinionRole = "node"
213
+ labelKeyNodeMaster = "node-role.kubernetes.io/master"
214
+ labelKeyNodeCompute = "node-role.kubernetes.io/compute"
215
+ labelKeyNodeMinion = "node-role.kubernetes.io/node"
216
+ )
217
+
208
218
const (
209
219
// volumeAttachmentConsecutiveErrorLimit is the number of consecutive errors we will ignore when waiting for a volume to attach/detach
210
220
volumeAttachmentStatusConsecutiveErrorLimit = 10
@@ -1598,69 +1608,77 @@ func (c *Cloud) InstanceType(ctx context.Context, nodeName types.NodeName) (stri
1598
1608
// GetCandidateZonesForDynamicVolume retrieves a list of all the zones in which nodes are running
1599
1609
// It currently involves querying all instances
1600
1610
func (c * Cloud ) GetCandidateZonesForDynamicVolume () (sets.String , error ) {
1601
- // We don't currently cache this; it is currently used only in volume
1602
- // creation which is expected to be a comparatively rare occurrence.
1603
-
1604
- // TODO: Caching / expose v1.Nodes to the cloud provider?
1605
- // TODO: We could also query for subnets, I think
1606
-
1607
- // Note: It is more efficient to call the EC2 API twice with different tag
1608
- // filters than to call it once with a tag filter that results in a logical
1609
- // OR. For really large clusters the logical OR will result in EC2 API rate
1610
- // limiting.
1611
- instances := []* ec2.Instance {}
1612
-
1613
- baseFilters := []* ec2.Filter {newEc2Filter ("instance-state-name" , "running" )}
1611
+ zones := sets .NewString ()
1614
1612
1615
- filters := c . tagging . addFilters ( baseFilters )
1616
- di , err := c .describeInstances ( filters )
1613
+ // TODO: list from cache?
1614
+ nodes , err := c .kubeClient . CoreV1 (). Nodes (). List (metav1. ListOptions {} )
1617
1615
if err != nil {
1616
+ klog .Errorf ("Failed to get nodes from api server: %#v" , err )
1618
1617
return nil , err
1619
1618
}
1620
1619
1621
- instances = append (instances , di ... )
1622
-
1623
- if c .tagging .usesLegacyTags {
1624
- filters = c .tagging .addLegacyFilters (baseFilters )
1625
- di , err = c .describeInstances (filters )
1626
- if err != nil {
1627
- return nil , err
1620
+ for _ , n := range nodes .Items {
1621
+ if ! c .isNodeReady (& n ) {
1622
+ klog .V (4 ).Infof ("Ignoring not ready node %q in zone discovery" , n .Name )
1623
+ continue
1628
1624
}
1629
-
1630
- instances = append (instances , di ... )
1631
- }
1632
-
1633
- if len (instances ) == 0 {
1634
- return nil , fmt .Errorf ("no instances returned" )
1635
- }
1636
-
1637
- zones := sets .NewString ()
1638
-
1639
- for _ , instance := range instances {
1640
- // We skip over master nodes, if the installation tool labels them with one of the well-known master labels
1641
- // This avoids creating a volume in a zone where only the master is running - e.g. #34583
1642
- // This is a short-term workaround until the scheduler takes care of zone selection
1643
- master := false
1644
- for _ , tag := range instance .Tags {
1645
- tagKey := aws .StringValue (tag .Key )
1646
- if awsTagNameMasterRoles .Has (tagKey ) {
1647
- master = true
1625
+ // In some cluster provisioning software, a node can be both a minion and a master. Therefore we white-list
1626
+ // here, and only filter out node that is not minion AND is labeled as master explicitly
1627
+ if c .isMinionNode (& n ) || ! c .isMasterNode (& n ) {
1628
+ if zone , ok := n .Labels [v1 .LabelZoneFailureDomain ]; ok {
1629
+ zones .Insert (zone )
1630
+ } else {
1631
+ klog .Warningf ("Node %s does not have zone label, ignore for zone discovery." , n .Name )
1648
1632
}
1633
+ } else {
1634
+ klog .V (4 ).Infof ("Ignoring master node %q in zone discovery" , n .Name )
1649
1635
}
1636
+ }
1650
1637
1651
- if master {
1652
- klog .V (4 ).Infof ("Ignoring master instance %q in zone discovery" , aws .StringValue (instance .InstanceId ))
1653
- continue
1654
- }
1638
+ klog .V (2 ).Infof ("Found instances in zones %s" , zones )
1639
+ return zones , nil
1640
+ }
1655
1641
1656
- if instance .Placement != nil {
1657
- zone := aws .StringValue (instance .Placement .AvailabilityZone )
1658
- zones .Insert (zone )
1642
+ // isNodeReady checks node condition and return true if NodeReady is marked as true
1643
+ func (c * Cloud ) isNodeReady (node * v1.Node ) bool {
1644
+ for _ , c := range node .Status .Conditions {
1645
+ if c .Type == v1 .NodeReady {
1646
+ return c .Status == v1 .ConditionTrue
1659
1647
}
1660
1648
}
1649
+ return false
1650
+ }
1651
+
1652
+ // isMasterNode checks if the node is labeled as master
1653
+ func (c * Cloud ) isMasterNode (node * v1.Node ) bool {
1654
+ // Master node has one or more of the following labels:
1655
+ //
1656
+ // kubernetes.io/role: master
1657
+ // node-role.kubernetes.io/master: ""
1658
+ // node-role.kubernetes.io/master: "true"
1659
+ if val , ok := node .Labels [labelKeyNodeMaster ]; ok && val != "false" {
1660
+ return true
1661
+ } else if role , ok := node .Labels [labelKeyNodeRole ]; ok && role == nodeMasterRole {
1662
+ return true
1663
+ }
1664
+ return false
1665
+ }
1661
1666
1662
- klog .V (2 ).Infof ("Found instances in zones %s" , zones )
1663
- return zones , nil
1667
+ // isMinionNode checks if the node is labeled as minion
1668
+ func (c * Cloud ) isMinionNode (node * v1.Node ) bool {
1669
+ // Minion node has one or more oof the following labels:
1670
+ //
1671
+ // kubernetes.io/role: "node"
1672
+ // node-role.kubernetes.io/compute: "true"
1673
+ // node-role.kubernetes.io/node: ""
1674
+ if val , ok := node .Labels [labelKeyNodeMinion ]; ok && val != "false" {
1675
+ return true
1676
+ } else if val , ok := node .Labels [labelKeyNodeCompute ]; ok && val != "false" {
1677
+ return true
1678
+ } else if role , ok := node .Labels [labelKeyNodeRole ]; ok && role == nodeMinionRole {
1679
+ return true
1680
+ }
1681
+ return false
1664
1682
}
1665
1683
1666
1684
// GetZone implements Zones.GetZone
0 commit comments