github.phpd.cn/cilium/cilium@v1.6.12/pkg/aws/eni/instances.go (about) 1 // Copyright 2019 Authors of Cilium 2 // Copyright 2017 Lyft, Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package eni 17 18 import ( 19 "time" 20 21 "github.com/cilium/cilium/pkg/aws/types" 22 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 23 "github.com/cilium/cilium/pkg/lock" 24 25 "github.com/sirupsen/logrus" 26 ) 27 28 type instanceAPI interface { 29 GetInstances(vpcs types.VpcMap, subnets types.SubnetMap) (types.InstanceMap, error) 30 GetSubnets() (types.SubnetMap, error) 31 GetVpcs() (types.VpcMap, error) 32 } 33 34 // instance is the minimal representation of an AWS instance as needed by the 35 // ENI allocator 36 type instance struct { 37 // enis is a map of all ENIs attached to the instance indexed by the 38 // ENI ID 39 enis map[string]*v2.ENI 40 } 41 42 // InstancesManager maintains the list of instances. It must be kept up to date 43 // by calling resync() regularly. 44 type InstancesManager struct { 45 mutex lock.RWMutex 46 instances types.InstanceMap 47 subnets types.SubnetMap 48 vpcs types.VpcMap 49 api instanceAPI 50 metricsAPI metricsAPI 51 } 52 53 // NewInstancesManager returns a new instances manager 54 func NewInstancesManager(api instanceAPI, metricsAPI metricsAPI) *InstancesManager { 55 return &InstancesManager{ 56 instances: types.InstanceMap{}, 57 api: api, 58 metricsAPI: metricsAPI, 59 } 60 } 61 62 // GetSubnet returns the subnet by subnet ID 63 // 64 // The returned subnet is immutable so it can be safely accessed 65 func (m *InstancesManager) GetSubnet(subnetID string) *types.Subnet { 66 m.mutex.RLock() 67 defer m.mutex.RUnlock() 68 69 return m.subnets[subnetID] 70 } 71 72 // GetSubnets returns all the tracked subnets 73 // 74 // The returned subnetMap is immutable so it can be safely accessed 75 func (m *InstancesManager) GetSubnets() types.SubnetMap { 76 m.mutex.RLock() 77 defer m.mutex.RUnlock() 78 79 subnetsCopy := make(types.SubnetMap) 80 for k, v := range m.subnets { 81 subnetsCopy[k] = v 82 } 83 84 return subnetsCopy 85 } 86 87 // FindSubnetByTags returns the subnet with the most addresses matching VPC ID, 88 // availability zone and all required tags 89 // 90 // The returned subnet is immutable so it can be safely accessed 91 func (m *InstancesManager) FindSubnetByTags(vpcID, availabilityZone string, required types.Tags) (bestSubnet *types.Subnet) { 92 m.mutex.RLock() 93 defer m.mutex.RUnlock() 94 95 for _, s := range m.subnets { 96 if s.VpcID == vpcID && s.AvailabilityZone == availabilityZone && s.Tags.Match(required) { 97 if bestSubnet == nil || bestSubnet.AvailableAddresses < s.AvailableAddresses { 98 bestSubnet = s 99 } 100 } 101 } 102 103 return 104 } 105 106 // Resync fetches the list of EC2 instances and subnets and updates the local 107 // cache in the instanceManager. It returns the time when the resync has 108 // started or time.Time{} if it did not complete. 109 func (m *InstancesManager) Resync() time.Time { 110 m.metricsAPI.IncResyncCount() 111 112 resyncStart := time.Now() 113 114 vpcs, err := m.api.GetVpcs() 115 if err != nil { 116 log.WithError(err).Warning("Unable to synchronize EC2 VPC list") 117 return time.Time{} 118 } 119 120 subnets, err := m.api.GetSubnets() 121 if err != nil { 122 log.WithError(err).Warning("Unable to retrieve EC2 subnets list") 123 return time.Time{} 124 } 125 126 instances, err := m.api.GetInstances(vpcs, subnets) 127 if err != nil { 128 log.WithError(err).Warning("Unable to synchronize EC2 interface list") 129 return time.Time{} 130 } 131 132 log.WithFields(logrus.Fields{ 133 "numENIs": len(instances), 134 "numVPCs": len(vpcs), 135 "numSubnets": len(subnets), 136 }).Info("Synchronized ENI information") 137 138 m.mutex.Lock() 139 m.instances = instances 140 m.subnets = subnets 141 m.vpcs = vpcs 142 m.mutex.Unlock() 143 144 return resyncStart 145 } 146 147 // GetENI returns the ENI of an instance at a particular interface index 148 func (m *InstancesManager) GetENI(instanceID string, index int) *v2.ENI { 149 for _, eni := range m.getENIs(instanceID) { 150 if eni.Number == index { 151 return eni 152 } 153 } 154 155 return nil 156 } 157 158 // GetENIs returns the list of ENIs associated with a particular instance 159 func (m *InstancesManager) GetENIs(instanceID string) []*v2.ENI { 160 return m.getENIs(instanceID) 161 } 162 163 // getENIs returns the list of ENIs associated with a particular instance 164 func (m *InstancesManager) getENIs(instanceID string) []*v2.ENI { 165 m.mutex.RLock() 166 defer m.mutex.RUnlock() 167 return m.instances.Get(instanceID) 168 } 169 170 // UpdateENI updates the ENI definition of an ENI for a particular instance. If 171 // the ENI is already known, the definition is updated, otherwise the ENI is 172 // added to the instance. 173 func (m *InstancesManager) UpdateENI(instanceID string, eni *v2.ENI) { 174 m.mutex.Lock() 175 m.instances.Update(instanceID, eni) 176 m.mutex.Unlock() 177 }