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 }