github.com/imran-kn/cilium-fork@v1.6.9/pkg/aws/ec2/mock/mock.go (about) 1 // Copyright 2019 Authors of Cilium 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mock 16 17 import ( 18 "fmt" 19 "net" 20 "time" 21 22 "github.com/cilium/cilium/pkg/aws/types" 23 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2" 24 "github.com/cilium/cilium/pkg/lock" 25 "github.com/cilium/cilium/pkg/uuid" 26 27 "golang.org/x/time/rate" 28 "k8s.io/kubernetes/pkg/registry/core/service/ipallocator" 29 ) 30 31 type eniMap map[string]*v2.ENI 32 33 // Operation is an EC2 API operation that this mock API supports 34 type Operation int 35 36 const ( 37 AllOperations Operation = iota 38 CreateNetworkInterface 39 DeleteNetworkInterface 40 AttachNetworkInterface 41 ModifyNetworkInterface 42 AssignPrivateIpAddresses 43 UnassignPrivateIpAddresses 44 TagENI 45 MaxOperation 46 ) 47 48 type API struct { 49 mutex lock.RWMutex 50 unattached map[string]*v2.ENI 51 enis map[string]eniMap 52 subnets map[string]*types.Subnet 53 vpcs map[string]*types.Vpc 54 errors map[Operation]error 55 delays map[Operation]time.Duration 56 allocator *ipallocator.Range 57 limiter *rate.Limiter 58 } 59 60 func NewAPI(subnets []*types.Subnet, vpcs []*types.Vpc) *API { 61 _, cidr, _ := net.ParseCIDR("10.0.0.0/8") 62 cidrRange, err := ipallocator.NewCIDRRange(cidr) 63 if err != nil { 64 panic(err) 65 } 66 67 api := &API{ 68 unattached: map[string]*v2.ENI{}, 69 enis: map[string]eniMap{}, 70 subnets: map[string]*types.Subnet{}, 71 vpcs: map[string]*types.Vpc{}, 72 allocator: cidrRange, 73 errors: map[Operation]error{}, 74 delays: map[Operation]time.Duration{}, 75 } 76 77 for _, s := range subnets { 78 api.subnets[s.ID] = s 79 } 80 81 for _, v := range vpcs { 82 api.vpcs[v.ID] = v 83 } 84 85 return api 86 } 87 88 // SetMockError modifies the mock API to return an error for a particular 89 // operation 90 func (e *API) SetMockError(op Operation, err error) { 91 e.mutex.Lock() 92 e.errors[op] = err 93 e.mutex.Unlock() 94 } 95 96 func (e *API) setDelayLocked(op Operation, delay time.Duration) { 97 if delay == time.Duration(0) { 98 delete(e.delays, op) 99 } else { 100 e.delays[op] = delay 101 } 102 } 103 104 // SetDelay specifies the delay which should be simulated for an individual EC2 105 // API operation 106 func (e *API) SetDelay(op Operation, delay time.Duration) { 107 e.mutex.Lock() 108 if op == AllOperations { 109 for op := AllOperations + 1; op < MaxOperation; op++ { 110 e.setDelayLocked(op, delay) 111 } 112 } else { 113 e.setDelayLocked(op, delay) 114 } 115 e.mutex.Unlock() 116 } 117 118 // SetLimiter adds a rate limiter to all simulated API calls 119 func (e *API) SetLimiter(limit float64, burst int) { 120 e.limiter = rate.NewLimiter(rate.Limit(limit), burst) 121 } 122 123 func (e *API) rateLimit() { 124 e.mutex.RLock() 125 if e.limiter == nil { 126 e.mutex.RUnlock() 127 return 128 } 129 130 r := e.limiter.Reserve() 131 e.mutex.RUnlock() 132 if delay := r.Delay(); delay != time.Duration(0) && delay != rate.InfDuration { 133 time.Sleep(delay) 134 } 135 } 136 137 func (e *API) simulateDelay(op Operation) { 138 e.mutex.RLock() 139 delay, ok := e.delays[op] 140 e.mutex.RUnlock() 141 if ok { 142 time.Sleep(delay) 143 } 144 } 145 146 func (e *API) CreateNetworkInterface(toAllocate int64, subnetID, desc string, groups []string) (string, *v2.ENI, error) { 147 e.rateLimit() 148 e.simulateDelay(CreateNetworkInterface) 149 150 e.mutex.Lock() 151 defer e.mutex.Unlock() 152 153 if err, ok := e.errors[CreateNetworkInterface]; ok { 154 return "", nil, err 155 } 156 157 subnet, ok := e.subnets[subnetID] 158 if !ok { 159 return "", nil, fmt.Errorf("subnet %s not found", subnetID) 160 } 161 162 if int(toAllocate) > subnet.AvailableAddresses { 163 return "", nil, fmt.Errorf("subnet %s has not enough addresses available", subnetID) 164 } 165 166 eniID := uuid.NewUUID().String() 167 eni := &v2.ENI{ 168 ID: eniID, 169 Description: desc, 170 Subnet: v2.AwsSubnet{ 171 ID: subnetID, 172 }, 173 SecurityGroups: groups, 174 } 175 176 for i := int64(0); i < toAllocate; i++ { 177 ip, err := e.allocator.AllocateNext() 178 if err != nil { 179 panic("Unable to allocate IP from allocator") 180 } 181 eni.Addresses = append(eni.Addresses, ip.String()) 182 } 183 184 subnet.AvailableAddresses -= int(toAllocate) 185 186 e.unattached[eniID] = eni 187 return eniID, eni, nil 188 } 189 190 func (e *API) DeleteNetworkInterface(eniID string) error { 191 e.rateLimit() 192 e.simulateDelay(DeleteNetworkInterface) 193 194 e.mutex.Lock() 195 defer e.mutex.Unlock() 196 197 if err, ok := e.errors[DeleteNetworkInterface]; ok { 198 return err 199 } 200 201 delete(e.unattached, eniID) 202 for _, enis := range e.enis { 203 if _, ok := enis[eniID]; ok { 204 delete(enis, eniID) 205 return nil 206 } 207 } 208 return fmt.Errorf("ENI ID %s not found", eniID) 209 } 210 211 func (e *API) AttachNetworkInterface(index int64, instanceID, eniID string) (string, error) { 212 e.rateLimit() 213 e.simulateDelay(AttachNetworkInterface) 214 215 e.mutex.Lock() 216 defer e.mutex.Unlock() 217 218 if err, ok := e.errors[AttachNetworkInterface]; ok { 219 return "", err 220 } 221 222 eni, ok := e.unattached[eniID] 223 if !ok { 224 return "", fmt.Errorf("ENI ID %s does not exist", eniID) 225 } 226 227 delete(e.unattached, eniID) 228 229 if _, ok := e.enis[instanceID]; !ok { 230 e.enis[instanceID] = eniMap{} 231 } 232 233 eni.Number = int(index) 234 235 e.enis[instanceID][eniID] = eni 236 237 return "", nil 238 } 239 240 func (e *API) ModifyNetworkInterface(eniID, attachmentID string, deleteOnTermination bool) error { 241 e.rateLimit() 242 e.simulateDelay(ModifyNetworkInterface) 243 244 e.mutex.Lock() 245 defer e.mutex.Unlock() 246 247 if err, ok := e.errors[ModifyNetworkInterface]; ok { 248 return err 249 } 250 251 return nil 252 } 253 254 func (e *API) AssignPrivateIpAddresses(eniID string, addresses int64) error { 255 e.rateLimit() 256 e.simulateDelay(AssignPrivateIpAddresses) 257 258 e.mutex.Lock() 259 defer e.mutex.Unlock() 260 261 if err, ok := e.errors[AssignPrivateIpAddresses]; ok { 262 return err 263 } 264 265 for _, enis := range e.enis { 266 if eni, ok := enis[eniID]; ok { 267 subnet, ok := e.subnets[eni.Subnet.ID] 268 if !ok { 269 return fmt.Errorf("subnet %s not found", eni.Subnet.ID) 270 } 271 272 if int(addresses) > subnet.AvailableAddresses { 273 return fmt.Errorf("subnet %s has not enough addresses available", eni.Subnet.ID) 274 } 275 276 for i := int64(0); i < addresses; i++ { 277 ip, err := e.allocator.AllocateNext() 278 if err != nil { 279 panic("Unable to allocate IP from allocator") 280 } 281 eni.Addresses = append(eni.Addresses, ip.String()) 282 } 283 subnet.AvailableAddresses -= int(addresses) 284 return nil 285 } 286 } 287 return fmt.Errorf("Unable to find ENI with ID %s", eniID) 288 } 289 290 func (e *API) UnassignPrivateIpAddresses(eniID string, addresses []string) error { 291 e.rateLimit() 292 e.simulateDelay(UnassignPrivateIpAddresses) 293 294 e.mutex.Lock() 295 defer e.mutex.Unlock() 296 297 if err, ok := e.errors[UnassignPrivateIpAddresses]; ok { 298 return err 299 } 300 301 releaseMap := make(map[string]int) 302 for _, addr := range addresses { 303 // Validate given addresses 304 ipaddr := net.ParseIP(addr) 305 if ipaddr == nil { 306 return fmt.Errorf("Invalid IP address %s", addr) 307 } 308 releaseMap[addr] = 0 309 } 310 311 for _, enis := range e.enis { 312 eni, ok := enis[eniID] 313 if !ok { 314 continue 315 } 316 subnet, ok := e.subnets[eni.Subnet.ID] 317 if !ok { 318 return fmt.Errorf("subnet %s not found", eni.Subnet.ID) 319 } 320 321 addressesAfterRelease := []string{} 322 323 for _, address := range eni.Addresses { 324 _, ok := releaseMap[address] 325 if !ok { 326 addressesAfterRelease = append(addressesAfterRelease, address) 327 } else { 328 ip := net.ParseIP(address) 329 e.allocator.Release(ip) 330 subnet.AvailableAddresses++ 331 } 332 } 333 eni.Addresses = addressesAfterRelease 334 return nil 335 } 336 return fmt.Errorf("Unable to find ENI with ID %s", eniID) 337 } 338 339 func (e *API) GetInstances(vpcs types.VpcMap, subnets types.SubnetMap) (types.InstanceMap, error) { 340 instances := types.InstanceMap{} 341 342 e.mutex.RLock() 343 defer e.mutex.RUnlock() 344 345 for instanceID, enis := range e.enis { 346 for _, eni := range enis { 347 if subnets != nil { 348 if subnet, ok := subnets[eni.Subnet.ID]; ok { 349 eni.Subnet.CIDR = subnet.CIDR 350 } 351 } 352 353 if vpcs != nil { 354 if vpc, ok := vpcs[eni.VPC.ID]; ok { 355 eni.VPC.PrimaryCIDR = vpc.PrimaryCIDR 356 } 357 } 358 359 instances.Add(instanceID, eni) 360 } 361 } 362 363 return instances, nil 364 } 365 366 func (e *API) GetVpcs() (types.VpcMap, error) { 367 vpcs := types.VpcMap{} 368 369 e.mutex.RLock() 370 defer e.mutex.RUnlock() 371 372 for _, v := range e.vpcs { 373 vpcs[v.ID] = v 374 } 375 return vpcs, nil 376 } 377 378 func (e *API) GetSubnets() (types.SubnetMap, error) { 379 subnets := types.SubnetMap{} 380 381 e.mutex.RLock() 382 defer e.mutex.RUnlock() 383 384 for _, s := range e.subnets { 385 subnets[s.ID] = s 386 } 387 return subnets, nil 388 }