github.com/Azure/aad-pod-identity@v1.8.17/pkg/mic/vmss.go (about)

     1  package mic
     2  
     3  import (
     4  	"path"
     5  
     6  	"github.com/Azure/aad-pod-identity/pkg/cloudprovider"
     7  
     8  	"github.com/Azure/go-autorest/autorest/azure"
     9  	corev1 "k8s.io/api/core/v1"
    10  	"k8s.io/apimachinery/pkg/api/errors"
    11  )
    12  
    13  type vmssGroup struct {
    14  	nodes map[string]bool // index of node refs assigned to this vmss group
    15  }
    16  
    17  type vmssGroupList struct {
    18  	groups  map[string]*vmssGroup
    19  	nodeIdx map[string]*vmssGroup // index node refs for matching to a vmss group
    20  }
    21  
    22  func (ls *vmssGroupList) addNode(vmss, node string) {
    23  	g := ls.groups[vmss]
    24  	if g == nil {
    25  		g = &vmssGroup{nodes: make(map[string]bool)}
    26  		ls.groups[vmss] = g
    27  	}
    28  	g.nodes[node] = true
    29  	ls.nodeIdx[node] = g
    30  }
    31  
    32  // getByNode takes a node reference and returns the vmss group it belongs to
    33  func (ls *vmssGroupList) getByNode(ref string) *vmssGroup {
    34  	return ls.nodeIdx[ref]
    35  }
    36  
    37  // get takes a vmss id and returns the corresponding vmss group
    38  func (ls *vmssGroupList) get(id string) *vmssGroup {
    39  	return ls.groups[id]
    40  }
    41  
    42  func (g *vmssGroup) hasNode(ref string) bool {
    43  	if g.nodes == nil {
    44  		return false
    45  	}
    46  	return g.nodes[ref]
    47  }
    48  
    49  func vmssFromNodeRef(nc NodeGetter, ref string) (string, bool, error) {
    50  	n, err := nc.Get(ref)
    51  	if err != nil {
    52  		if !errors.IsNotFound(err) {
    53  			return "", false, err
    54  		}
    55  		return "", false, nil
    56  	}
    57  
    58  	return isVMSS(n)
    59  }
    60  
    61  // getVMSSGroups takes a list of node references and groups them by vmss ID
    62  // nodes not in a vmss are elided
    63  func getVMSSGroups(nc NodeGetter, refs map[string]bool) (*vmssGroupList, error) {
    64  	ls := &vmssGroupList{groups: make(map[string]*vmssGroup), nodeIdx: make(map[string]*vmssGroup)}
    65  	for ref := range refs {
    66  		id, ok, err := vmssFromNodeRef(nc, ref)
    67  		if err != nil {
    68  			if !errors.IsNotFound(err) {
    69  				return nil, err
    70  			}
    71  			continue
    72  		}
    73  
    74  		if !ok {
    75  			continue
    76  		}
    77  
    78  		ls.addNode(id, ref)
    79  	}
    80  
    81  	return ls, nil
    82  }
    83  
    84  func isVMSS(n *corev1.Node) (string, bool, error) {
    85  	r, err := cloudprovider.ParseResourceID(n.Spec.ProviderID)
    86  	if err != nil && n.Spec.ProviderID != "" {
    87  		return "", false, err
    88  	}
    89  
    90  	if r.ResourceType != cloudprovider.VMSSResourceType {
    91  		return "", false, nil
    92  	}
    93  	return makeVMSSID(r), true, nil
    94  }
    95  
    96  func makeVMSSID(r azure.Resource) string {
    97  	return path.Join(r.SubscriptionID, r.ResourceGroup, r.ResourceName)
    98  }
    99  
   100  func getVMSSName(vmssID string) string {
   101  	_, resourceName := path.Split(vmssID)
   102  	return resourceName
   103  }
   104  
   105  // Either get a vmss group by node reference or lookup the vmss ID from the node's provider ID.
   106  // The reason for this is we may have request to delete an identity from a node and it is the last identity, so
   107  // the node will not be referenced by any pods and will be absent from the group list
   108  //
   109  // This does end up caching any missing node references into the vmss group list.
   110  func getVMSSGroupFromPossiblyUnreferencedNode(nc NodeGetter, groups *vmssGroupList, ref string) (*vmssGroup, error) {
   111  	vmss := groups.getByNode(ref)
   112  	if vmss != nil {
   113  		return vmss, nil
   114  	}
   115  
   116  	vmssID, isVMSS, err := vmssFromNodeRef(nc, ref)
   117  	if err != nil && !errors.IsNotFound(err) {
   118  		return nil, err
   119  	}
   120  	if isVMSS {
   121  		groups.addNode(vmssID, ref) // cache this reference so we don't have to parse again
   122  		return groups.get(vmssID), nil
   123  	}
   124  
   125  	// not a vmss
   126  	return nil, nil
   127  }