diff --git a/apis/crd/v1alpha1/cloudentityselector_types.go b/apis/crd/v1alpha1/cloudentityselector_types.go index b25577df..5a282132 100644 --- a/apis/crd/v1alpha1/cloudentityselector_types.go +++ b/apis/crd/v1alpha1/cloudentityselector_types.go @@ -45,9 +45,9 @@ type VirtualMachineSelector struct { // CloudEntitySelectorSpec defines the desired state of CloudEntitySelector. type CloudEntitySelectorSpec struct { // AccountName specifies the name of CloudProviderAccount. - AccountName string `json:"accountName,omitempty"` + AccountName string `json:"accountName"` // AccountNamespace specifies the namespace of CloudProviderAccount. - AccountNamespace string `json:"accountNamespace,omitempty"` + AccountNamespace string `json:"accountNamespace"` // VMSelector selects the VirtualMachines the user has modify privilege. // VMSelector is mandatory, at least one selector under VMSelector is required. // It is an array, VirtualMachines satisfying any item on VMSelector are selected(ORed). diff --git a/config/crd/bases/crd.cloud.antrea.io_cloudentityselectors.yaml b/config/crd/bases/crd.cloud.antrea.io_cloudentityselectors.yaml index 3380ba6a..93ebc267 100644 --- a/config/crd/bases/crd.cloud.antrea.io_cloudentityselectors.yaml +++ b/config/crd/bases/crd.cloud.antrea.io_cloudentityselectors.yaml @@ -96,6 +96,8 @@ spec: type: object type: array required: + - accountName + - accountNamespace - vmSelector type: object status: diff --git a/config/nephe.yml b/config/nephe.yml index 286a9d42..5f18ec6e 100644 --- a/config/nephe.yml +++ b/config/nephe.yml @@ -113,6 +113,8 @@ spec: type: object type: array required: + - accountName + - accountNamespace - vmSelector type: object status: diff --git a/pkg/accountmanager/manager.go b/pkg/accountmanager/manager.go index 47dfda91..58b5bc75 100644 --- a/pkg/accountmanager/manager.go +++ b/pkg/accountmanager/manager.go @@ -55,8 +55,7 @@ type Interface interface { type AccountManager struct { client.Client - Log logr.Logger - + Log logr.Logger mutex sync.RWMutex Inventory inventory.Interface accPollers map[types.NamespacedName]*accountPoller @@ -105,7 +104,7 @@ func (a *AccountManager) AddAccount(namespacedName *types.NamespacedName, accoun if !exists { if !util.DoesCesCrExistsForAccount(a.Client, namespacedName) { a.Log.Info("Starting account poller", "account", namespacedName) - go wait.Until(accPoller.doAccountPolling, time.Duration(accPoller.PollIntvInSeconds)*time.Second, accPoller.ch) + go wait.Until(accPoller.doAccountPolling, time.Duration(accPoller.pollIntvInSeconds)*time.Second, accPoller.ch) } else { a.Log.V(1).Info("Ignoring start of account poller", "account", namespacedName) if ctrlsync.GetControllerSyncStatusInstance().IsControllerSynced(ctrlsync.ControllerTypeCPA) && !config.initialized { @@ -131,9 +130,8 @@ func (a *AccountManager) RemoveAccount(namespacedName *types.NamespacedName) err // Stop and remove the poller. _ = a.removeAccountPoller(namespacedName) - // Cleanup inventory data for this account. + // Cleanup vpc inventory data for this account, vm inventory is deleted in removeAccountPoller. _ = a.Inventory.DeleteVpcsFromCache(namespacedName) - _ = a.Inventory.DeleteVmsFromCache(namespacedName) defer func() { // Remove account config. @@ -204,12 +202,11 @@ func (a *AccountManager) RemoveResourceFiltersFromAccount(accNamespacedName *typ selectorNamespacedName *types.NamespacedName) error { cloudProviderType, ok := a.getAccountProviderType(accNamespacedName) if !ok { - // If we cannot find cloud provider type, that means CPA may not be added or it's already removed. + // If we cannot find cloud provider type, that means CPA may not be added, or it's already removed. return fmt.Errorf(fmt.Sprintf("failed to delete selector %v, account %v: provider type not found", selectorNamespacedName, accNamespacedName)) } cloudInterface, _ := cloud.GetCloudInterface(cloudProviderType) - a.Log.V(1).Info("Removing selectors for account", "name", accNamespacedName) cloudInterface.RemoveAccountResourcesSelector(accNamespacedName, selectorNamespacedName) // Delete selector config from the account config. a.removeSelectorFromAccountConfig(accNamespacedName, selectorNamespacedName) @@ -220,7 +217,7 @@ func (a *AccountManager) RemoveResourceFiltersFromAccount(accNamespacedName *typ return fmt.Errorf(fmt.Sprintf("failed to delete selector %v, account %v: %v", selectorNamespacedName, accNamespacedName, errorMsgAccountPollerNotFound)) } - accPoller.removeSelector(accNamespacedName) + _ = accPoller.inventory.DeleteVmsFromCache(accNamespacedName, selectorNamespacedName) accPoller.restartPoller(accNamespacedName) return nil } @@ -247,20 +244,19 @@ func (a *AccountManager) addAccountPoller(cloudInterface cloud.CloudInterface, n accPoller, exists := a.getAccountPoller(namespacedName) if exists { // Update the polling interval. - accPoller.PollIntvInSeconds = *account.Spec.PollIntervalInSeconds + accPoller.pollIntvInSeconds = *account.Spec.PollIntervalInSeconds return accPoller, true } // Add and init the new poller. poller := &accountPoller{ - Client: a.Client, - log: a.Log.WithName("Poller"), - PollIntvInSeconds: *account.Spec.PollIntervalInSeconds, - cloudInterface: cloudInterface, - namespacedName: namespacedName, - selector: nil, - ch: make(chan struct{}), - inventory: a.Inventory, + Client: a.Client, + log: a.Log.WithName("Poller"), + pollIntvInSeconds: *account.Spec.PollIntervalInSeconds, + cloudInterface: cloudInterface, + accountNamespacedName: namespacedName, + ch: make(chan struct{}), + inventory: a.Inventory, } poller.initVmSelectorCache() @@ -277,7 +273,7 @@ func (a *AccountManager) removeAccountPoller(namespacedName *types.NamespacedNam if !exists { return fmt.Errorf(fmt.Sprintf("%v %v", errorMsgAccountPollerNotFound, namespacedName)) } - accPoller.removeSelector(namespacedName) + _ = accPoller.inventory.DeleteAllVmsFromCache(namespacedName) accPoller.stopPoller() a.mutex.Lock() @@ -391,7 +387,7 @@ func (a *AccountManager) handleAddProviderAccountError(namespacedName *types.Nam // Account poller is removed upon any error in the plug-in. _ = a.removeAccountPoller(namespacedName) _ = a.Inventory.DeleteVpcsFromCache(namespacedName) - _ = a.Inventory.DeleteVmsFromCache(namespacedName) + _ = a.Inventory.DeleteAllVmsFromCache(namespacedName) // TODO: require lock to write into account config structure. config.initialized = false if strings.Contains(err.Error(), util.ErrorMsgSecretReference) { diff --git a/pkg/accountmanager/poller.go b/pkg/accountmanager/poller.go index d03c5d14..02014f0d 100644 --- a/pkg/accountmanager/poller.go +++ b/pkg/accountmanager/poller.go @@ -32,6 +32,7 @@ import ( runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" "antrea.io/nephe/pkg/cloudprovider/cloud" "antrea.io/nephe/pkg/inventory" + nephetypes "antrea.io/nephe/pkg/types" ) const ( @@ -42,15 +43,14 @@ type accountPoller struct { client.Client log logr.Logger - PollIntvInSeconds uint - PollDone bool - cloudInterface cloud.CloudInterface - namespacedName *types.NamespacedName - selector *crdv1alpha1.CloudEntitySelector - vmSelector cache.Indexer - ch chan struct{} - mutex sync.RWMutex - inventory inventory.Interface + pollIntvInSeconds uint + pollDone bool + cloudInterface cloud.CloudInterface + accountNamespacedName *types.NamespacedName + vmSelector cache.Indexer + ch chan struct{} + mutex sync.RWMutex + inventory inventory.Interface } // initVmSelectorCache inits account poller selector cache and its indexers. @@ -126,16 +126,6 @@ func (p *accountPoller) addOrUpdateSelector(selector *crdv1alpha1.CloudEntitySel } } } - - // Store selector to filter cloud resources based on selector. - p.selector = selector -} - -// removeSelector reset selector in account poller. -func (p *accountPoller) removeSelector(accountNamespacedName *types.NamespacedName) { - p.selector = nil - // Remove VMs from the cache when selectors are removed. - _ = p.inventory.DeleteVmsFromCache(accountNamespacedName) } // doAccountPolling calls the cloud plugin and fetches the cloud inventory. Once successful poll, updates the cloud @@ -145,44 +135,42 @@ func (p *accountPoller) doAccountPolling() { p.mutex.Lock() defer p.mutex.Unlock() - p.PollDone = false + p.pollDone = false // Ignoring error since it is captured in the CloudProviderAccount CR's status field. - _ = p.cloudInterface.DoInventoryPoll(p.namespacedName) + _ = p.cloudInterface.DoInventoryPoll(p.accountNamespacedName) defer func() { - p.PollDone = true + p.pollDone = true // Update status on CPA CR after polling. p.updateAccountStatus(p.cloudInterface) }() - // TODO: Avoid calling plugin to get VPC inventory from snapshot. - vpcMap, err := p.cloudInterface.GetVpcInventory(p.namespacedName) + cloudInventory, err := p.cloudInterface.GetCloudInventory(p.accountNamespacedName) if err != nil { - p.log.Error(err, "failed to fetch cloud vpc list from internal snapshot", "account", - p.namespacedName.String()) + p.log.Error(err, "failed to fetch cloud inventory from internal snapshot", "account", + p.accountNamespacedName) return } - _ = p.inventory.BuildVpcCache(vpcMap, p.namespacedName) - // Perform VM Operations only when CES is added. - vmCount := 0 - if p.selector != nil { - // TODO: Avoid calling plugin to get VM inventory from snapshot. - virtualMachines := p.getComputeResources(p.cloudInterface) - // TODO: We are walking thru virtual map twice. Once here and second one in BuildVmCAche. - // May be expose Add, Delete, Update routine in inventory and we do the calculation here. + p.processCloudInventory(cloudInventory) +} + +// processCloudInventory fetches vpc and vm inventory from the snapshot and updates respective cache inventory. +func (p *accountPoller) processCloudInventory(cloudInventory *nephetypes.CloudInventory) { + _ = p.inventory.BuildVpcCache(cloudInventory.VpcMap, p.accountNamespacedName) + + // VMs are stored per selector in the VmMap. + for selectorNamespacedName, virtualMachines := range cloudInventory.VmMap { + // Maybe expose, Add, Delete, Update routine in inventory, and do the calculation here. p.updateAgentState(virtualMachines) - p.inventory.BuildVmCache(virtualMachines, p.namespacedName) - vmCount = len(virtualMachines) + p.inventory.BuildVmCache(virtualMachines, p.accountNamespacedName, &selectorNamespacedName) } - p.log.Info("Discovered compute resources statistics", "Account", p.namespacedName, - "Vpcs", len(vpcMap), "VirtualMachines", vmCount) } // updateAccountStatus updates status of a CPA object when it's changed. func (p *accountPoller) updateAccountStatus(cloudInterface cloud.CloudInterface) { discoveredStatus := crdv1alpha1.CloudProviderAccountStatus{} - status, err := cloudInterface.GetAccountStatus(p.namespacedName) + status, err := cloudInterface.GetAccountStatus(p.accountNamespacedName) if err != nil { discoveredStatus.Error = fmt.Sprintf("failed to get account status, err %v", err) } else if status != nil { @@ -191,14 +179,14 @@ func (p *accountPoller) updateAccountStatus(cloudInterface cloud.CloudInterface) updateStatusFunc := func() error { account := &crdv1alpha1.CloudProviderAccount{} - if err := p.Get(context.TODO(), *p.namespacedName, account); err != nil { + if err := p.Get(context.TODO(), *p.accountNamespacedName, account); err != nil { return nil } if account.Status != discoveredStatus { account.Status.Error = discoveredStatus.Error - p.log.Info("Setting CPA status", "account", p.namespacedName, "message", discoveredStatus.Error) + p.log.Info("Setting CPA status", "account", p.accountNamespacedName, "message", discoveredStatus.Error) if err = p.Client.Status().Update(context.TODO(), account); err != nil { - p.log.Error(err, "failed to update CPA status, retrying", "account", p.namespacedName) + p.log.Error(err, "failed to update CPA status, retrying", "account", p.accountNamespacedName) return err } } @@ -206,7 +194,7 @@ func (p *accountPoller) updateAccountStatus(cloudInterface cloud.CloudInterface) } if err := retry.RetryOnConflict(retry.DefaultRetry, updateStatusFunc); err != nil { - p.log.Error(err, "failed to update CPA status", "account", p.namespacedName) + p.log.Error(err, "failed to update CPA status", "account", p.accountNamespacedName) } } @@ -217,15 +205,6 @@ func (p *accountPoller) updateAgentState(vms map[string]*runtimev1alpha1.Virtual } } -func (p *accountPoller) getComputeResources(cloudInterface cloud.CloudInterface) map[string]*runtimev1alpha1.VirtualMachine { - virtualMachines, e := cloudInterface.InstancesGivenProviderAccount(p.namespacedName) - if e != nil { - p.log.Error(e, "failed to discover compute resources", "account", p.namespacedName) - return map[string]*runtimev1alpha1.VirtualMachine{} - } - return virtualMachines -} - // getVmSelectorMatch returns a VMSelector for a VirtualMachine only if it is agented. func (p *accountPoller) getVmSelectorMatch(vm *runtimev1alpha1.VirtualMachine) *crdv1alpha1.VirtualMachineSelector { vmSelectors, _ := p.vmSelector.ByIndex(virtualMachineSelectorMatchIndexerByID, vm.Status.CloudId) @@ -278,7 +257,7 @@ func (p *accountPoller) waitForPollDone(accountNamespacedName *types.NamespacedN if err := wait.PollImmediate(100*time.Millisecond, defaultPollTimeout, func() (done bool, err error) { p.mutex.RLock() defer p.mutex.RUnlock() - if p.PollDone { + if p.pollDone { return true, nil } return false, nil @@ -300,7 +279,7 @@ func (p *accountPoller) restartPoller(name *types.NamespacedName) { p.log.Info("Restarting account poller", "account", name) p.ch = make(chan struct{}) - go wait.Until(p.doAccountPolling, time.Duration(p.PollIntvInSeconds)*time.Second, p.ch) + go wait.Until(p.doAccountPolling, time.Duration(p.pollIntvInSeconds)*time.Second, p.ch) } // stopPoller stops account poller thread if it's running. diff --git a/pkg/accountmanager/poller_test.go b/pkg/accountmanager/poller_test.go index 84af2c6c..a4617f2c 100644 --- a/pkg/accountmanager/poller_test.go +++ b/pkg/accountmanager/poller_test.go @@ -37,6 +37,7 @@ import ( "antrea.io/nephe/pkg/inventory" "antrea.io/nephe/pkg/labels" "antrea.io/nephe/pkg/testing/cloud" + nephetypes "antrea.io/nephe/pkg/types" ) var _ = Describe("Account Poller", func() { @@ -169,24 +170,26 @@ var _ = Describe("Account Poller", func() { }) It("Remove selector", func() { vmLabelsMap := map[string]string{ - labels.CloudAccountName: testAccountNamespacedName.Name, - labels.CloudAccountNamespace: testAccountNamespacedName.Namespace, - labels.CloudVmUID: "ubuntu", - labels.CloudVpcUID: "vpcid", - labels.VpcName: "vpc", + labels.CloudAccountName: testAccountNamespacedName.Name, + labels.CloudAccountNamespace: testAccountNamespacedName.Namespace, + labels.CloudSelectorName: testCesNamespacedName.Name, + labels.CloudSelectorNamespace: testCesNamespacedName.Namespace, + labels.CloudVmUID: "ubuntu", + labels.CloudVpcUID: "vpcid", + labels.VpcName: "vpc", } vmList := make(map[string]*runtimev1alpha1.VirtualMachine) vmObj := new(runtimev1alpha1.VirtualMachine) vmObj.Name = "ubuntu" - vmObj.Namespace = testAccountNamespacedName.Namespace + vmObj.Namespace = testCesNamespacedName.Namespace vmObj.Labels = vmLabelsMap vmList["ubuntu"] = vmObj - accountPollerObj.inventory.BuildVmCache(vmList, &testAccountNamespacedName) + accountPollerObj.inventory.BuildVmCache(vmList, &testAccountNamespacedName, &testCesNamespacedName) vms := accountPollerObj.inventory.GetAllVms() Expect(len(vms)).To(Equal(1)) // Delete VMs from cache. - accountPollerObj.removeSelector(&testAccountNamespacedName) + _ = accountPollerObj.inventory.DeleteVmsFromCache(&testAccountNamespacedName, &testCesNamespacedName) vms = accountPollerObj.inventory.GetAllVms() Expect(len(vms)).To(Equal(0)) }) @@ -208,62 +211,64 @@ var _ = Describe("Account Poller", func() { _ = fakeClient.Create(context.Background(), secret) _ = fakeClient.Create(context.Background(), account) - accountPollerObj.namespacedName = &testAccountNamespacedName + accountPollerObj.accountNamespacedName = &testAccountNamespacedName mockCloudInterface.EXPECT().DoInventoryPoll(&testAccountNamespacedName).Return(nil).AnyTimes() mockCloudInterface.EXPECT().GetAccountStatus(&testAccountNamespacedName).Return(&v1alpha1. CloudProviderAccountStatus{}, nil).AnyTimes() // Invalid VPC. - mockCloudInterface.EXPECT().GetVpcInventory(&testAccountNamespacedName).Return(nil, + mockCloudInterface.EXPECT().GetCloudInventory(&testAccountNamespacedName).Return(nil, fmt.Errorf("error")).Times(1) accountPollerObj.doAccountPolling() Expect(len(accountPollerObj.inventory.GetAllVpcs())).To(Equal(0)) // Empty VPC. - mockCloudInterface.EXPECT().GetVpcInventory(&testAccountNamespacedName).Return(nil, + cloudInventory := nephetypes.CloudInventory{} + mockCloudInterface.EXPECT().GetCloudInventory(&testAccountNamespacedName).Return(&cloudInventory, nil).Times(1) accountPollerObj.doAccountPolling() Expect(len(accountPollerObj.inventory.GetAllVpcs())).To(Equal(0)) // Valid VPC. - mockCloudInterface.EXPECT().GetVpcInventory(&testAccountNamespacedName).Return(vpcList, + cloudInventory = nephetypes.CloudInventory{VpcMap: vpcList} + mockCloudInterface.EXPECT().GetCloudInventory(&testAccountNamespacedName).Return(&cloudInventory, nil).Times(1) accountPollerObj.doAccountPolling() Expect(len(accountPollerObj.inventory.GetAllVpcs())).To(Equal(len(vpcList))) - - accountPollerObj.selector = ces vmLabelsMap := map[string]string{ - labels.CloudAccountName: testAccountNamespacedName.Name, - labels.CloudAccountNamespace: testAccountNamespacedName.Namespace, - labels.CloudVmUID: "ubuntu", - labels.CloudVpcUID: "vpcid", - labels.VpcName: "vpc", + labels.CloudAccountName: testAccountNamespacedName.Name, + labels.CloudAccountNamespace: testAccountNamespacedName.Namespace, + labels.CloudSelectorName: testCesNamespacedName.Name, + labels.CloudSelectorNamespace: testCesNamespacedName.Namespace, + labels.CloudVmUID: "ubuntu", + labels.CloudVpcUID: "vpcid", + labels.VpcName: "vpc", } vmList := make(map[string]*runtimev1alpha1.VirtualMachine) vmObj := new(runtimev1alpha1.VirtualMachine) vmObj.Name = "ubuntu" - vmObj.Namespace = testAccountNamespacedName.Namespace + vmObj.Namespace = testCesNamespacedName.Namespace vmObj.Labels = vmLabelsMap vmList["ubuntu"] = vmObj + cloudInventory = nephetypes.CloudInventory{VpcMap: vpcList} // Invalid VMs. - mockCloudInterface.EXPECT().InstancesGivenProviderAccount(&testAccountNamespacedName).Return( - nil, fmt.Errorf("error")).Times(1) - mockCloudInterface.EXPECT().GetVpcInventory(&testAccountNamespacedName).Return(vpcList, + mockCloudInterface.EXPECT().GetCloudInventory(&testAccountNamespacedName).Return(&cloudInventory, nil).Times(1) accountPollerObj.doAccountPolling() Expect(len(accountPollerObj.inventory.GetAllVms())).To(Equal(0)) // Valid VMs. - mockCloudInterface.EXPECT().InstancesGivenProviderAccount(&testAccountNamespacedName).Return(vmList, - nil).Times(1) - mockCloudInterface.EXPECT().GetVpcInventory(&testAccountNamespacedName).Return(vpcList, + vmMap := make(map[types.NamespacedName]map[string]*runtimev1alpha1.VirtualMachine) + vmMap[testCesNamespacedName] = vmList + cloudInventory = nephetypes.CloudInventory{VpcMap: vpcList, VmMap: vmMap} + mockCloudInterface.EXPECT().GetCloudInventory(&testAccountNamespacedName).Return(&cloudInventory, nil).Times(1) accountPollerObj.doAccountPolling() Expect(len(accountPollerObj.inventory.GetAllVms())).To(Equal(len(vmList))) }) It("Update account status", func() { - accountPollerObj.namespacedName = &testAccountNamespacedName + accountPollerObj.accountNamespacedName = &testAccountNamespacedName _ = fakeClient.Create(context.Background(), secret) _ = fakeClient.Create(context.Background(), account) @@ -283,11 +288,13 @@ var _ = Describe("Account Poller", func() { }) It("Get vm selector match", func() { vmLabelsMap := map[string]string{ - labels.CloudAccountName: testAccountNamespacedName.Name, - labels.CloudAccountNamespace: testAccountNamespacedName.Namespace, - labels.CloudVmUID: "ubuntu", - labels.CloudVpcUID: "vpcid", - labels.VpcName: "vpc", + labels.CloudAccountName: testAccountNamespacedName.Name, + labels.CloudAccountNamespace: testAccountNamespacedName.Namespace, + labels.CloudSelectorName: testCesNamespacedName.Name, + labels.CloudSelectorNamespace: testCesNamespacedName.Namespace, + labels.CloudVmUID: "ubuntu", + labels.CloudVpcUID: "vpcid", + labels.VpcName: "vpc", } vmStatus := &runtimev1alpha1.VirtualMachineStatus{ Provider: runtimev1alpha1.AWSCloudProvider, @@ -298,7 +305,7 @@ var _ = Describe("Account Poller", func() { vmList := make(map[string]*runtimev1alpha1.VirtualMachine) vmObj := new(runtimev1alpha1.VirtualMachine) vmObj.Name = "ubuntu" - vmObj.Namespace = testAccountNamespacedName.Namespace + vmObj.Namespace = testCesNamespacedName.Namespace vmObj.Labels = vmLabelsMap vmObj.Status = *vmStatus vmList["ubuntu"] = vmObj diff --git a/pkg/apiserver/registry/inventory/virtualmachine/rest_test.go b/pkg/apiserver/registry/inventory/virtualmachine/rest_test.go index 7fa8fe5e..81560766 100644 --- a/pkg/apiserver/registry/inventory/virtualmachine/rest_test.go +++ b/pkg/apiserver/registry/inventory/virtualmachine/rest_test.go @@ -54,8 +54,10 @@ var _ = Describe("Virtual Machine", func() { Namespace: "default", Name: "targetId", Labels: map[string]string{ - nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, - nephelabels.CloudAccountName: accountNamespacedName.Name, + nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, + nephelabels.CloudAccountName: accountNamespacedName.Name, + nephelabels.CloudSelectorName: "selector01", + nephelabels.CloudSelectorNamespace: "default", }, }, Status: runtimev1alpha1.VirtualMachineStatus{ @@ -74,6 +76,12 @@ var _ = Describe("Virtual Machine", func() { ObjectMeta: metav1.ObjectMeta{ Namespace: "non-default", Name: "targetId-nondefault", + Labels: map[string]string{ + nephelabels.CloudSelectorName: "selector01", + nephelabels.CloudSelectorNamespace: "non-default", + nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, + nephelabels.CloudAccountName: accountNamespacedName.Name, + }, }, Status: runtimev1alpha1.VirtualMachineStatus{ Tags: map[string]string{ @@ -86,8 +94,10 @@ var _ = Describe("Virtual Machine", func() { Namespace: "default", Name: "targetId2", Labels: map[string]string{ - nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, - nephelabels.CloudAccountName: accountNamespacedName.Name, + nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, + nephelabels.CloudAccountName: accountNamespacedName.Name, + nephelabels.CloudSelectorName: "selector01", + nephelabels.CloudSelectorNamespace: "default", }, }, Status: runtimev1alpha1.VirtualMachineStatus{ @@ -113,8 +123,8 @@ var _ = Describe("Virtual Machine", func() { for i, cachedVM := range cachedVMs { vmMap := make(map[string]*runtimev1alpha1.VirtualMachine) vmMap[cachedVM.Name] = cachedVM - namespacedName := types.NamespacedName{Namespace: cachedVM.Namespace, Name: "accountID"} - cloudInventory.BuildVmCache(vmMap, &namespacedName) + namespacedName := types.NamespacedName{Namespace: cachedVM.Namespace, Name: "selector01"} + cloudInventory.BuildVmCache(vmMap, &accountNamespacedName, &namespacedName) rest := NewREST(cloudInventory, l) actualVM, err := rest.Get(request.NewDefaultContext(), cachedVM.Name, &metav1.GetOptions{}) if cachedVM.Name == "targetId-nondefault" { @@ -136,8 +146,9 @@ var _ = Describe("Virtual Machine", func() { for _, cachedVM := range cachedVMs { vmMap[cachedVM.Name] = cachedVM } - namespacedName := types.NamespacedName{Namespace: cacheTest1.Namespace, Name: "accountID"} - cloudInventory.BuildVmCache(vmMap, &namespacedName) + accountNamespacedName := types.NamespacedName{Namespace: cacheTest1.Namespace, Name: "accountID"} + namespacedName := types.NamespacedName{Namespace: accountNamespacedName.Namespace, Name: "selector01"} + cloudInventory.BuildVmCache(vmMap, &accountNamespacedName, &namespacedName) }) expectedVMList1 := &runtimev1alpha1.VirtualMachineList{ @@ -267,9 +278,11 @@ var _ = Describe("Virtual Machine", func() { Namespace: "non-default1", Name: "targetId4", Labels: map[string]string{ - nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, - nephelabels.CloudAccountName: accountNamespacedName.Name, - nephelabels.VpcName: "testNetworkID", + nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, + nephelabels.CloudAccountName: accountNamespacedName.Name, + nephelabels.VpcName: "testNetworkID", + nephelabels.CloudSelectorName: "selector01", + nephelabels.CloudSelectorNamespace: "non-default1", }, }, Status: runtimev1alpha1.VirtualMachineStatus{ @@ -287,8 +300,10 @@ var _ = Describe("Virtual Machine", func() { Namespace: "default", Name: "targetId", Labels: map[string]string{ - nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, - nephelabels.CloudAccountName: accountNamespacedName.Name, + nephelabels.CloudAccountNamespace: accountNamespacedName.Namespace, + nephelabels.CloudAccountName: accountNamespacedName.Name, + nephelabels.CloudSelectorName: "selector01", + nephelabels.CloudSelectorNamespace: "default", }, }, Status: runtimev1alpha1.VirtualMachineStatus{ @@ -318,8 +333,9 @@ var _ = Describe("Virtual Machine", func() { } vmMap := make(map[string]*runtimev1alpha1.VirtualMachine) vmMap[cacheTest4.Name] = cacheTest4 - namespacedName := types.NamespacedName{Namespace: cacheTest4.Namespace, Name: cacheTest4.Labels[nephelabels.CloudAccountName]} - cloudInventory.BuildVmCache(vmMap, &namespacedName) + namespacedName := types.NamespacedName{Namespace: cacheTest4.Labels[nephelabels.CloudSelectorNamespace], + Name: cacheTest4.Labels[nephelabels.CloudSelectorName]} + cloudInventory.BuildVmCache(vmMap, &accountNamespacedName, &namespacedName) rest := NewREST(cloudInventory, l) actualTable, err := rest.ConvertToTable(request.NewDefaultContext(), cacheTest4, &metav1.TableOptions{}) @@ -337,16 +353,16 @@ var _ = Describe("Virtual Machine", func() { } cloudInventory1 := inventory.InitInventory() vmMap := make(map[string]*runtimev1alpha1.VirtualMachine) - namespacedName := types.NamespacedName{Namespace: accountNamespacedName.Namespace, Name: accountNamespacedName.Name} - cloudInventory1.BuildVmCache(vmMap, &namespacedName) + namespacedName := types.NamespacedName{Namespace: accountNamespacedName.Namespace, Name: "selector01"} + cloudInventory1.BuildVmCache(vmMap, &accountNamespacedName, &namespacedName) rest := NewREST(cloudInventory1, l) watcher, err := rest.Watch(request.NewDefaultContext(), &internalversion.ListOptions{}) Expect(err).Should(BeNil()) vmMap[cacheTest1.Name] = cacheTest1 - cloudInventory1.BuildVmCache(vmMap, &namespacedName) + cloudInventory1.BuildVmCache(vmMap, &accountNamespacedName, &namespacedName) vmMap[cacheTest1.Name] = cacheTest5 - cloudInventory1.BuildVmCache(vmMap, &namespacedName) - err = cloudInventory1.DeleteVmsFromCache(&namespacedName) + cloudInventory1.BuildVmCache(vmMap, &accountNamespacedName, &namespacedName) + err = cloudInventory1.DeleteVmsFromCache(&accountNamespacedName, &namespacedName) Expect(err).Should(BeNil()) for _, expectedEvent := range expectedEvents { ev := <-watcher.ResultChan() diff --git a/pkg/apiserver/webhook/cloudentityselector_webhook.go b/pkg/apiserver/webhook/cloudentityselector_webhook.go index edaef3b7..b5e193da 100644 --- a/pkg/apiserver/webhook/cloudentityselector_webhook.go +++ b/pkg/apiserver/webhook/cloudentityselector_webhook.go @@ -23,11 +23,9 @@ import ( "github.com/go-logr/logr" admissionv1 "k8s.io/api/admission/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" controllerclient "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/webhook/admission" "antrea.io/nephe/apis/crd/v1alpha1" @@ -48,10 +46,11 @@ var ( "use vpc matchID instead of vpc matchName" errorMsgMatchIDNameTogether = "matchID and matchName are not supported together, " + "configure either matchID or matchName in an EntityMatch" - errorMsgAccountNameUpdate = "account name update not allowed" - errorMsgSameAccountUsage = "account in a namespace can be owner of only one CloudEntitySelector" - errorMsgOwnerAccountNotFound = "failed to find owner account" - errorMsgInvalidCloudType = "invalid cloud provider type" + errorMsgAccountNameUpdate = "account name update not allowed" + errorMsgAccountNamespaceUpdate = "account namespace update not allowed" + errorMsgReferencedAccountNotFound = "failed to find the referenced CloudProviderAccount" + errorMsgInvalidCloudType = "invalid cloud provider type" + errorMsgVpcOrVmMatchNotAvailable = "either vpcMatch or vmMatch is mandatory" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! @@ -76,20 +75,20 @@ func (v *CESMutator) Handle(_ context.Context, req admission.Request) admission. } v.Log.V(1).Info("CES Mutator", "name", selector.Name) - // make sure selector has owner reference. - // set owner account only if resource CloudProviderAccount with CloudEntitySelector account name in this Namespace exists. - ownerReference := metav1.GetControllerOf(selector) + // make sure referenced CloudProviderAccount exists. accountNameSpacedName := &types.NamespacedName{ - Namespace: selector.Namespace, + Namespace: selector.Spec.AccountNamespace, Name: selector.Spec.AccountName, } - ownerAccount := &v1alpha1.CloudProviderAccount{} - err = v.Client.Get(context.TODO(), *accountNameSpacedName, ownerAccount) + referencedAccount := &v1alpha1.CloudProviderAccount{} + err = v.Client.Get(context.TODO(), *accountNameSpacedName, referencedAccount) if err != nil { - v.Log.Error(err, errorMsgOwnerAccountNotFound, "account", *accountNameSpacedName) - return admission.Errored(http.StatusBadRequest, err) + v.Log.Error(err, errorMsgReferencedAccountNotFound, "CloudEntitySelector", selector, "Account name", selector.Spec.AccountName, + "Account namespace", selector.Spec.AccountNamespace) + return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s, account name : %s, account namespace: %s", + errorMsgReferencedAccountNotFound, selector.Spec.AccountName, selector.Spec.AccountNamespace)) } - cloudProviderType, err := util.GetAccountProviderType(ownerAccount) + cloudProviderType, err := util.GetAccountProviderType(referencedAccount) if err != nil { v.Log.Error(err, errorMsgInvalidCloudType) return admission.Errored(http.StatusBadRequest, err) @@ -108,13 +107,6 @@ func (v *CESMutator) Handle(_ context.Context, req admission.Request) admission. } } } - if ownerReference == nil { - err = controllerutil.SetControllerReference(ownerAccount, selector, v.Sh) - if err != nil { - v.Log.Error(err, "failed to set owner account", "CloudEntitySelector", selector, "account", *accountNameSpacedName) - return admission.Errored(http.StatusBadRequest, err) - } - } marshaledSelector, err := json.Marshal(selector) if err != nil { @@ -173,16 +165,6 @@ func (v *CESValidator) validateCreate(req admission.Request) admission.Response v.Log.Error(err, "Failed to decode CloudEntitySelector", "CESValidator", req.Name) return admission.Errored(http.StatusBadRequest, err) } - // make sure owner exists. Default will try to populate if owner with provided account name exists. - if selector.GetObjectMeta().GetOwnerReferences() == nil { - return admission.Errored(http.StatusBadRequest, fmt.Errorf("%s %v", errorMsgOwnerAccountNotFound, - selector.Spec.AccountName)) - } - - // make sure no existing CloudEntitySelector has same account as this CloudEntitySelector as its owner. - if err := v.validateNoOwnerConflict(selector); err != nil { - return admission.Errored(http.StatusBadRequest, err) - } // make sure unsupported match combinations are not configured. if err := v.validateMatchSections(selector); err != nil { @@ -192,26 +174,6 @@ func (v *CESValidator) validateCreate(req admission.Request) admission.Response return admission.Allowed("") } -// validateNoOwnerConflict makes sure no two CloudEntitySelectors have same account owner. -func (r *CESValidator) validateNoOwnerConflict(selector *v1alpha1.CloudEntitySelector) error { - cloudEntitySelectorList := &v1alpha1.CloudEntitySelectorList{} - err := r.Client.List(context.TODO(), cloudEntitySelectorList, controllerclient.InNamespace(selector.Namespace)) - if err != nil { - return err - } - - namespace := selector.GetNamespace() - accName := selector.Spec.AccountName - for _, item := range cloudEntitySelectorList.Items { - if strings.Compare(strings.TrimSpace(item.Spec.AccountName), strings.TrimSpace(accName)) == 0 { - return fmt.Errorf("CloudEntitySelector %v/%v with owner as account %v/%v already exists."+ - "(%s)", namespace, item.GetName(), namespace, accName, errorMsgSameAccountUsage) - } - } - - return nil -} - // ValidateUpdate implements webhook validations for CES update operation. func (v *CESValidator) validateUpdate(req admission.Request) admission.Response { newSelector := &v1alpha1.CloudEntitySelector{} @@ -228,12 +190,25 @@ func (v *CESValidator) validateUpdate(req admission.Request) admission.Response } } - // account name update not allowed. - oldAccName := strings.TrimSpace(oldSelector.Spec.AccountName) - newAccountName := strings.TrimSpace(newSelector.Spec.AccountName) - if strings.Compare(oldAccName, newAccountName) != 0 { - return admission.Errored(http.StatusBadRequest, fmt.Errorf( - "%s (old:%v, new:%v)", errorMsgAccountNameUpdate, oldAccName, newAccountName)) + // TODO: remove null string check for name and namespace later. + // account Name update not allowed. + if oldSelector.Spec.AccountName != "" { + oldAccName := strings.TrimSpace(oldSelector.Spec.AccountName) + newAccountName := strings.TrimSpace(newSelector.Spec.AccountName) + if strings.Compare(oldAccName, newAccountName) != 0 { + return admission.Errored(http.StatusBadRequest, fmt.Errorf( + "%s (old:%v, new:%v)", errorMsgAccountNameUpdate, oldAccName, newAccountName)) + } + } + + // account Namespace update not allowed. + if oldSelector.Spec.AccountNamespace != "" { + oldAccNamespace := strings.TrimSpace(oldSelector.Spec.AccountNamespace) + newAccountNamespace := strings.TrimSpace(newSelector.Spec.AccountNamespace) + if strings.Compare(oldAccNamespace, newAccountNamespace) != 0 { + return admission.Errored(http.StatusBadRequest, fmt.Errorf( + "%s (old:%v, new:%v)", errorMsgAccountNamespaceUpdate, oldAccNamespace, newAccountNamespace)) + } } // make sure unsupported match combinations are not configured. @@ -250,24 +225,31 @@ func (v *CESValidator) validateDelete(_ admission.Request) admission.Response { return admission.Allowed("") } -// GetOwnerAccount fetches the CPA account owning the current CES. -func (v *CESValidator) GetOwnerAccount(selector *v1alpha1.CloudEntitySelector) (*v1alpha1.CloudProviderAccount, error) { - accountNameSpacedName := &types.NamespacedName{ - Namespace: selector.Namespace, +// getReferencedAccount fetches the CPA account referenced by the current CES. +func (v *CESValidator) getReferencedAccount(selector *v1alpha1.CloudEntitySelector) (*v1alpha1.CloudProviderAccount, error) { + accountNamespacedName := &types.NamespacedName{ + Namespace: selector.Spec.AccountNamespace, Name: selector.Spec.AccountName, } - ownerAccount := &v1alpha1.CloudProviderAccount{} - err := v.Client.Get(context.TODO(), *accountNameSpacedName, ownerAccount) + referencedAccount := &v1alpha1.CloudProviderAccount{} + err := v.Client.Get(context.TODO(), *accountNamespacedName, referencedAccount) if err != nil { - v.Log.Error(err, errorMsgOwnerAccountNotFound, "CloudEntitySelector", selector, - "account", *accountNameSpacedName) + v.Log.Error(err, errorMsgReferencedAccountNotFound, "CloudEntitySelector", selector, + "Account name", selector.Spec.AccountName, "Account namespace", selector.Spec.AccountNamespace) return nil, err } - return ownerAccount, err + return referencedAccount, err } // validateMatchSections checks for unsupported selector match combinations and errors out. func (v *CESValidator) validateMatchSections(selector *v1alpha1.CloudEntitySelector) error { + // Empty vpcMatch and empty vmMatch section are not supported. + for _, m := range selector.Spec.VMSelector { + if m.VpcMatch == nil && len(m.VMMatch) == 0 { + return fmt.Errorf("%s", errorMsgVpcOrVmMatchNotAvailable) + } + } + // MatchID and MatchName are not supported together in an EntityMatch, applicable for both vpcMatch, vmMatch section. for _, m := range selector.Spec.VMSelector { if m.VpcMatch != nil { @@ -284,11 +266,11 @@ func (v *CESValidator) validateMatchSections(selector *v1alpha1.CloudEntitySelec } } - ownerAccount, err := v.GetOwnerAccount(selector) + referencedAccount, err := v.getReferencedAccount(selector) if err != nil { return err } - cloudProviderType, err := util.GetAccountProviderType(ownerAccount) + cloudProviderType, err := util.GetAccountProviderType(referencedAccount) if err != nil { v.Log.Error(err, errorMsgInvalidCloudType) return err diff --git a/pkg/apiserver/webhook/cloudentityselector_webhook_test.go b/pkg/apiserver/webhook/cloudentityselector_webhook_test.go index f9bf7b08..cf55e467 100644 --- a/pkg/apiserver/webhook/cloudentityselector_webhook_test.go +++ b/pkg/apiserver/webhook/cloudentityselector_webhook_test.go @@ -40,24 +40,26 @@ import ( var _ = Describe("CloudEntitySelectorWebhook", func() { Context("Validation of CES webhook workflow", func() { var ( - testAccountNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "account01"} - testAccountNamespacedName2 = types.NamespacedName{Namespace: "namespace01", Name: "account02"} - testSecretNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "secret01"} - credentials = "credentials" - testAbc = "abc" - testDef = "def" - testXyz = "xyz" - account *v1alpha1.CloudProviderAccount - selector *v1alpha1.CloudEntitySelector - validator *CESValidator - mutator *CESMutator - fakeClient k8sclient.WithWatch - err error - newScheme *runtime.Scheme - pollIntv uint = 1 - encodedSelector []byte - decoder *admission.Decoder - selectorReq admission.Request + testAccountNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "account01"} + testAccountDifferentNamespace = types.NamespacedName{Namespace: "namespace02", Name: "account02"} + testSelectorNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "selector01"} + testSelectorDifferentNamespace = types.NamespacedName{Namespace: "namespace02", Name: "selector02"} + testSecretNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "secret01"} + credentials = "credentials" + testAbc = "abc" + testDef = "def" + testXyz = "xyz" + account *v1alpha1.CloudProviderAccount + selector *v1alpha1.CloudEntitySelector + validator *CESValidator + mutator *CESMutator + fakeClient k8sclient.WithWatch + err error + newScheme *runtime.Scheme + pollIntv uint = 1 + encodedSelector []byte + decoder *admission.Decoder + selectorReq admission.Request ) BeforeEach(func() { @@ -81,18 +83,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -136,18 +132,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -175,8 +165,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -196,18 +186,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { oldSelector := &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -219,18 +203,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { } selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName2.Name, - Namespace: testAccountNamespacedName2.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account02", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName2.Name, + AccountName: testAccountDifferentNamespace.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -254,8 +232,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Update, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -278,18 +256,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -313,8 +285,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -333,13 +305,6 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { ObjectMeta: metav1.ObjectMeta{ Name: testAccountNamespacedName.Name, Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, }, Spec: v1alpha1.CloudProviderAccountSpec{ PollIntervalInSeconds: &pollIntv, @@ -358,18 +323,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -392,8 +351,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -413,18 +372,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -452,8 +405,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -472,18 +425,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -518,8 +465,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -538,18 +485,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VMMatch: []v1alpha1.EntityMatch{ @@ -584,8 +525,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -604,18 +545,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -654,8 +589,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -674,18 +609,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VMMatch: []v1alpha1.EntityMatch{ @@ -717,8 +646,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -737,18 +666,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VMMatch: []v1alpha1.EntityMatch{ @@ -780,8 +703,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -799,18 +722,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -848,8 +765,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -868,18 +785,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -917,8 +828,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -937,18 +848,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -983,8 +888,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1002,18 +907,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VMMatch: []v1alpha1.EntityMatch{ @@ -1045,8 +944,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1065,18 +964,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VMMatch: []v1alpha1.EntityMatch{ @@ -1108,8 +1001,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1121,7 +1014,7 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("Got admission response %+v\n", response))) Expect(response.AdmissionResponse.Allowed).To(BeTrue()) }) - It("Mutator Workflow when owner account is not found", func() { + It("Mutator Workflow when referenced account is not found", func() { encodedSelector, _ = json.Marshal(selector) selectorReq = admission.Request{ AdmissionRequest: v1.AdmissionRequest{ @@ -1135,8 +1028,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1154,13 +1047,6 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { ObjectMeta: metav1.ObjectMeta{ Name: testAccountNamespacedName.Name, Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, }, Spec: v1alpha1.CloudProviderAccountSpec{ PollIntervalInSeconds: &pollIntv, @@ -1179,18 +1065,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -1221,8 +1101,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1239,13 +1119,6 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { ObjectMeta: metav1.ObjectMeta{ Name: testAccountNamespacedName.Name, Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, }, Spec: v1alpha1.CloudProviderAccountSpec{ PollIntervalInSeconds: &pollIntv, @@ -1267,8 +1140,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1297,8 +1170,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{}, }, @@ -1325,8 +1198,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{}, }, @@ -1338,7 +1211,7 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Expect(response.Result.Code).Should(BeEquivalentTo(400)) }) - It("Validate CES with already existing CES with same owner account", func() { + It("Validate multiple CES for a CPA", func() { err = fakeClient.Create(context.Background(), account) Expect(err).Should(BeNil()) @@ -1346,18 +1219,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Expect(err).Should(BeNil()) newSelector := &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -1381,8 +1248,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1391,8 +1258,7 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { } response := validator.Handle(context.Background(), selectorReq) _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("Got admission response %+v\n", response))) - Expect(response.AdmissionResponse.Allowed).To(BeFalse()) - Expect(response.String()).Should(ContainSubstring(errorMsgSameAccountUsage)) + Expect(response.AdmissionResponse.Allowed).To(BeTrue()) }) It("Validate update during CES Update with vpcMatch matchID matchName in same selector", func() { err = fakeClient.Create(context.Background(), account) @@ -1400,18 +1266,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { oldSelector := &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -1423,18 +1283,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { } selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -1459,8 +1313,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Update, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1482,18 +1336,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { oldSelector := &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -1518,8 +1366,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Update, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1552,8 +1400,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Update, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1586,8 +1434,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Update, Object: runtime.RawExtension{}, OldObject: runtime.RawExtension{ @@ -1601,24 +1449,109 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Expect(response.AdmissionResponse.Allowed).To(BeFalse()) Expect(response.Result.Code).Should(BeEquivalentTo(400)) }) - It("Validate vmMatch matchID matchName in same selector", func() { + It("Validate empty vmMatch sections", func() { err = fakeClient.Create(context.Background(), account) Expect(err).Should(BeNil()) selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VMMatch: []v1alpha1.EntityMatch{}, + }, + }, + }, + } + encodedSelector, _ = json.Marshal(selector) + selectorReq = admission.Request{ + AdmissionRequest: v1.AdmissionRequest{ + Kind: metav1.GroupVersionKind{ + Group: "", + Version: "v1alpha1", + Kind: "CloudEntitySelector", + }, + Resource: metav1.GroupVersionResource{ + Group: "", + Version: "v1alpha1", + Resource: "CloudEntitySelectors", + }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, + Operation: v1.Create, + Object: runtime.RawExtension{ + Raw: encodedSelector, + }, + }, + } + + response := validator.Handle(context.Background(), selectorReq) + _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("Got admission response %+v\n", response))) + Expect(response.AdmissionResponse.Allowed).To(BeFalse()) + Expect(response.String()).Should(ContainSubstring(errorMsgVpcOrVmMatchNotAvailable)) + }) + It("Validate empty vpcMatch section", func() { + err = fakeClient.Create(context.Background(), account) + Expect(err).Should(BeNil()) + + selector = &v1alpha1.CloudEntitySelector{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", + VpcMatch: nil, }, }, }, + } + encodedSelector, _ = json.Marshal(selector) + selectorReq = admission.Request{ + AdmissionRequest: v1.AdmissionRequest{ + Kind: metav1.GroupVersionKind{ + Group: "", + Version: "v1alpha1", + Kind: "CloudEntitySelector", + }, + Resource: metav1.GroupVersionResource{ + Group: "", + Version: "v1alpha1", + Resource: "CloudEntitySelectors", + }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, + Operation: v1.Create, + Object: runtime.RawExtension{ + Raw: encodedSelector, + }, + }, + } + response := validator.Handle(context.Background(), selectorReq) + _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("Got admission response %+v\n", response))) + Expect(response.AdmissionResponse.Allowed).To(BeFalse()) + Expect(response.String()).Should(ContainSubstring(errorMsgVpcOrVmMatchNotAvailable)) + }) + It("Validate vmMatch matchID matchName in same selector", func() { + err = fakeClient.Create(context.Background(), account) + Expect(err).Should(BeNil()) + + selector = &v1alpha1.CloudEntitySelector{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, + }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VMMatch: []v1alpha1.EntityMatch{ @@ -1644,8 +1577,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1682,8 +1615,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1695,7 +1628,7 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Expect(response.AdmissionResponse.Allowed).To(BeFalse()) Expect(response.String()).Should(ContainSubstring(util.ErrorMsgUnknownCloudProvider)) }) - It("Validate when owner account not found", func() { + It("Validate when referenced account not found", func() { encodedSelector, _ = json.Marshal(selector) selectorReq = admission.Request{ AdmissionRequest: v1.AdmissionRequest{ @@ -1709,8 +1642,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1736,8 +1669,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Connect, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1753,18 +1686,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { BeforeEach(func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -1792,8 +1719,8 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Version: "v1alpha1", Resource: "CloudEntitySelectors", }, - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, Operation: v1.Create, Object: runtime.RawExtension{ Raw: encodedSelector, @@ -1812,18 +1739,12 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { It("Validate update CES CR failure", func() { oldSelector := &v1alpha1.CloudEntitySelector{ ObjectMeta: metav1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/v1alpha1", - Kind: "CloudProviderAccount", - Name: "account01", - }, - }, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -1864,5 +1785,172 @@ var _ = Describe("CloudEntitySelectorWebhook", func() { Expect(response.String()).Should(ContainSubstring(sync.ErrorMsgControllerInitializing)) }) }) + It("Validate CES update when CPA, CES are in different namespace", func() { + err = fakeClient.Create(context.Background(), account) + Expect(err).Should(BeNil()) + + oldSelector := &v1alpha1.CloudEntitySelector{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VpcMatch: &v1alpha1.EntityMatch{ + MatchID: testXyz, + }, + }, + }, + }, + } + + encodedOldSelector, _ := json.Marshal(oldSelector) + encodedSelector, _ = json.Marshal(selector) + selectorReq = admission.Request{ + AdmissionRequest: v1.AdmissionRequest{ + Kind: metav1.GroupVersionKind{ + Group: "", + Version: "v1alpha1", + Kind: "CloudEntitySelector", + }, + Resource: metav1.GroupVersionResource{ + Group: "", + Version: "v1alpha1", + Resource: "CloudEntitySelectors", + }, + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + Operation: v1.Update, + Object: runtime.RawExtension{ + Raw: encodedSelector, + }, + OldObject: runtime.RawExtension{ + Raw: encodedOldSelector, + }, + }, + } + + response := validator.Handle(context.Background(), selectorReq) + _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("Got admission response %+v\n", response))) + Expect(response.AdmissionResponse.Allowed).To(BeTrue()) + }) + It("Validate CES add when CPA, CES are in different namespace", func() { + err = fakeClient.Create(context.Background(), account) + Expect(err).Should(BeNil()) + selector = &v1alpha1.CloudEntitySelector{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VpcMatch: &v1alpha1.EntityMatch{ + MatchID: testAbc, + }, + }, + }, + }, + } + + encodedSelector, _ = json.Marshal(selector) + selectorReq = admission.Request{ + AdmissionRequest: v1.AdmissionRequest{ + Kind: metav1.GroupVersionKind{ + Group: "", + Version: "v1alpha1", + Kind: "CloudEntitySelector", + }, + Resource: metav1.GroupVersionResource{ + Group: "", + Version: "v1alpha1", + Resource: "CloudEntitySelectors", + }, + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + Operation: v1.Create, + Object: runtime.RawExtension{ + Raw: encodedSelector, + }, + }, + } + response := validator.Handle(context.Background(), selectorReq) + _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("Got admission response %+v\n", response))) + Expect(response.AdmissionResponse.Allowed).To(BeTrue()) + }) + It("Validate CPA account namespace update during CES Update", func() { + err = fakeClient.Create(context.Background(), account) + Expect(err).Should(BeNil()) + + oldSelector := &v1alpha1.CloudEntitySelector{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VpcMatch: &v1alpha1.EntityMatch{ + MatchID: testAbc, + }, + }, + }, + }, + } + selector = &v1alpha1.CloudEntitySelector{ + ObjectMeta: metav1.ObjectMeta{ + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountDifferentNamespace.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VpcMatch: &v1alpha1.EntityMatch{ + MatchID: testDef, + }, + }, + }, + }, + } + encodedOldSelector, _ := json.Marshal(oldSelector) + encodedSelector, _ = json.Marshal(selector) + selectorReq = admission.Request{ + AdmissionRequest: v1.AdmissionRequest{ + Kind: metav1.GroupVersionKind{ + Group: "", + Version: "v1alpha1", + Kind: "CloudEntitySelector", + }, + Resource: metav1.GroupVersionResource{ + Group: "", + Version: "v1alpha1", + Resource: "CloudEntitySelectors", + }, + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + Operation: v1.Update, + Object: runtime.RawExtension{ + Raw: encodedSelector, + }, + OldObject: runtime.RawExtension{ + Raw: encodedOldSelector, + }, + }, + } + + response := validator.Handle(context.Background(), selectorReq) + _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("Got admission response %+v\n", response))) + Expect(response.AdmissionResponse.Allowed).To(BeFalse()) + Expect(response.String()).Should(ContainSubstring(errorMsgAccountNamespaceUpdate)) + }) }) }) diff --git a/pkg/cloudprovider/cloud/cloud.go b/pkg/cloudprovider/cloud/cloud.go index 0dfb249a..5b4cf469 100644 --- a/pkg/cloudprovider/cloud/cloud.go +++ b/pkg/cloudprovider/cloud/cloud.go @@ -27,6 +27,7 @@ import ( "antrea.io/nephe/pkg/cloudprovider/plugins/aws" "antrea.io/nephe/pkg/cloudprovider/plugins/azure" "antrea.io/nephe/pkg/logging" + nephetypes "antrea.io/nephe/pkg/types" ) // CloudInterface is an abstract providing set of methods to be implemented by cloud providers. @@ -57,15 +58,12 @@ type AccountMgmtInterface interface { DoInventoryPoll(accountNamespacedName *types.NamespacedName) error // ResetInventoryCache resets cloud snapshot and poll stats to nil. ResetInventoryCache(accountNamespacedName *types.NamespacedName) error - // GetVpcInventory gets vpc inventory from internal stored snapshot. - GetVpcInventory(accountNamespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.Vpc, error) } -// ComputeInterface is an abstract providing set of methods to get Instance details to be implemented by cloud providers. +// ComputeInterface is an abstract providing set of methods to get inventory details to be implemented by cloud providers. type ComputeInterface interface { - // InstancesGivenProviderAccount returns all VM instances of a given cloud provider account, as a map of - // runtime VirtualMachine objects. - InstancesGivenProviderAccount(namespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.VirtualMachine, error) + // GetCloudInventory gets VPC and VM inventory from plugin snapshot for a given cloud provider account. + GetCloudInventory(accountNamespacedName *types.NamespacedName) (*nephetypes.CloudInventory, error) } type SecurityInterface interface { diff --git a/pkg/cloudprovider/plugins/aws/aws_account_impl.go b/pkg/cloudprovider/plugins/aws/aws_account_impl.go index c128d001..899270a5 100644 --- a/pkg/cloudprovider/plugins/aws/aws_account_impl.go +++ b/pkg/cloudprovider/plugins/aws/aws_account_impl.go @@ -19,7 +19,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" crdv1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" - runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" ) // AddProviderAccount adds and initializes given account of a cloud provider. @@ -55,8 +54,3 @@ func (c *awsCloud) DoInventoryPoll(accountNamespacedName *types.NamespacedName) func (c *awsCloud) ResetInventoryCache(accountNamespacedName *types.NamespacedName) error { return c.cloudCommon.ResetInventoryCache(accountNamespacedName) } - -// GetVpcInventory pulls cloud vpc inventory from internal snapshot. -func (c *awsCloud) GetVpcInventory(accountNamespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.Vpc, error) { - return c.cloudCommon.GetVpcInventory(accountNamespacedName) -} diff --git a/pkg/cloudprovider/plugins/aws/aws_compute_impl.go b/pkg/cloudprovider/plugins/aws/aws_compute_impl.go index 79b2f89b..d93fff88 100644 --- a/pkg/cloudprovider/plugins/aws/aws_compute_impl.go +++ b/pkg/cloudprovider/plugins/aws/aws_compute_impl.go @@ -17,13 +17,10 @@ package aws import ( "k8s.io/apimachinery/pkg/types" - runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" + nephetypes "antrea.io/nephe/pkg/types" ) -// InstancesGivenProviderAccount returns all VM instances of a given cloud provider account, as a map of -// runtime VirtualMachine objects. -func (c *awsCloud) InstancesGivenProviderAccount(accountNamespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.VirtualMachine, - error) { - vmInternalObjectsMap, err := c.cloudCommon.GetCloudAccountComputeInternalResourceObjects(accountNamespacedName) - return vmInternalObjectsMap, err +// GetCloudInventory pulls cloud vpc and vm inventory from internal snapshot. +func (c *awsCloud) GetCloudInventory(accountNamespacedName *types.NamespacedName) (*nephetypes.CloudInventory, error) { + return c.cloudCommon.GetCloudInventory(accountNamespacedName) } diff --git a/pkg/cloudprovider/plugins/aws/aws_crd_helpers.go b/pkg/cloudprovider/plugins/aws/aws_crd_helpers.go index 153a3b6d..1256b59e 100644 --- a/pkg/cloudprovider/plugins/aws/aws_crd_helpers.go +++ b/pkg/cloudprovider/plugins/aws/aws_crd_helpers.go @@ -31,8 +31,9 @@ import ( const ResourceNameTagKey = "Name" // ec2InstanceToInternalVirtualMachineObject converts ec2 instance to VirtualMachine runtime object. -func ec2InstanceToInternalVirtualMachineObject(instance *ec2.Instance, vpcs map[string]*ec2.Vpc, namespace string, - account *types.NamespacedName, region string) *runtimev1alpha1.VirtualMachine { +func ec2InstanceToInternalVirtualMachineObject(instance *ec2.Instance, vpcs map[string]*ec2.Vpc, + selectorNamespacedName *types.NamespacedName, accountNamespacedName *types.NamespacedName, + region string) *runtimev1alpha1.VirtualMachine { vmTags := make(map[string]string) if len(instance.Tags) > 0 { for _, tag := range instance.Tags { @@ -105,11 +106,13 @@ func ec2InstanceToInternalVirtualMachineObject(instance *ec2.Instance, vpcs map[ } labelsMap := map[string]string{ - labels.CloudAccountName: account.Name, - labels.CloudAccountNamespace: account.Namespace, - labels.VpcName: strings.ToLower(cloudNetwork), - labels.CloudVmUID: strings.ToLower(cloudID), - labels.CloudVpcUID: strings.ToLower(cloudNetwork), + labels.CloudAccountName: accountNamespacedName.Name, + labels.CloudAccountNamespace: accountNamespacedName.Namespace, + labels.CloudSelectorName: selectorNamespacedName.Name, + labels.CloudSelectorNamespace: selectorNamespacedName.Namespace, + labels.VpcName: strings.ToLower(cloudNetwork), + labels.CloudVmUID: strings.ToLower(cloudID), + labels.CloudVpcUID: strings.ToLower(cloudNetwork), } vmObj := &runtimev1alpha1.VirtualMachine{ @@ -120,7 +123,7 @@ func ec2InstanceToInternalVirtualMachineObject(instance *ec2.Instance, vpcs map[ ObjectMeta: v1.ObjectMeta{ UID: uuid.NewUUID(), Name: cloudID, - Namespace: namespace, + Namespace: selectorNamespacedName.Namespace, Labels: labelsMap, }, Status: *vmStatus, @@ -172,7 +175,7 @@ func ec2VpcToInternalVpcObject(vpc *ec2.Vpc, accountNamespace, accountName, regi Managed: managed, } - labels := map[string]string{ + labelsMap := map[string]string{ labels.CloudAccountNamespace: accountNamespace, labels.CloudAccountName: accountName, labels.CloudVpcUID: *vpc.VpcId, @@ -182,7 +185,7 @@ func ec2VpcToInternalVpcObject(vpc *ec2.Vpc, accountNamespace, accountName, regi ObjectMeta: v1.ObjectMeta{ Name: *vpc.VpcId, Namespace: accountNamespace, - Labels: labels, + Labels: labelsMap, }, Status: *status, } diff --git a/pkg/cloudprovider/plugins/aws/aws_ec2.go b/pkg/cloudprovider/plugins/aws/aws_ec2.go index a90b7213..07475494 100644 --- a/pkg/cloudprovider/plugins/aws/aws_ec2.go +++ b/pkg/cloudprovider/plugins/aws/aws_ec2.go @@ -28,34 +28,32 @@ import ( crdv1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" "antrea.io/nephe/pkg/cloudprovider/plugins/internal" + nephetypes "antrea.io/nephe/pkg/types" ) type ec2ServiceConfig struct { accountNamespacedName types.NamespacedName apiClient awsEC2Wrapper + credentials *awsAccountConfig resourcesCache *internal.CloudServiceResourcesCache inventoryStats *internal.CloudServiceStats - // instanceFilters has following possible values - // - empty map indicates no selectors configured for this account. NO cloud api call for inventory will be made. - // - non-empty map indicates selectors are configured. Cloud api call for inventory will be made. - // - key with nil value indicates no filters. Get all instances for account. - // - key with "some-filter-string" value indicates some filter. Get instances matching those filters only. - instanceFilters map[string][][]*ec2.Filter - credentials *awsAccountConfig + instanceFilters map[types.NamespacedName][][]*ec2.Filter + // selectors required for updating resource filters on account config update. + selectors map[types.NamespacedName]*crdv1alpha1.CloudEntitySelector } // ec2ResourcesCacheSnapshot holds the results from querying for all instances. type ec2ResourcesCacheSnapshot struct { - instances map[internal.InstanceID]*ec2.Instance - vpcs []*ec2.Vpc - vpcIDs map[string]struct{} - vpcNameToID map[string]string - vpcPeers map[string][]string + vms map[types.NamespacedName][]*ec2.Instance + vpcs []*ec2.Vpc + managedVpcIDs map[string]struct{} + vpcNameToID map[string]string + vpcPeers map[string][]string } func newEC2ServiceConfig(accountNamespacedName types.NamespacedName, service awsServiceClientCreateInterface, credentials *awsAccountConfig) (internal.CloudServiceInterface, error) { - // create ec2 sdk api client + // create ec2 sdk api client. apiClient, err := service.compute() if err != nil { return nil, fmt.Errorf("error creating ec2 sdk api client for account : %v, err: %v", accountNamespacedName.String(), err) @@ -66,9 +64,13 @@ func newEC2ServiceConfig(accountNamespacedName types.NamespacedName, service aws accountNamespacedName: accountNamespacedName, resourcesCache: &internal.CloudServiceResourcesCache{}, inventoryStats: &internal.CloudServiceStats{}, - instanceFilters: make(map[string][][]*ec2.Filter), credentials: credentials, + instanceFilters: make(map[types.NamespacedName][][]*ec2.Filter), + selectors: make(map[types.NamespacedName]*crdv1alpha1.CloudEntitySelector), } + + vmSnapshot := make(map[types.NamespacedName][]*ec2.Instance) + config.resourcesCache.UpdateSnapshot(&ec2ResourcesCacheSnapshot{vmSnapshot, nil, nil, nil, nil}) return config, nil } @@ -98,53 +100,34 @@ func (ec2Cfg *ec2ServiceConfig) waitForInventoryInit(duration time.Duration) err return backoff.Retry(operation, b) } -// getInstanceResourceFilters returns filters to be applied to describeInstances api if filters are configured. -// Otherwise, returns (nil, false). false indicates no selectors configured for the account and hence no cloud api needs -// to be made for instance inventory. -func (ec2Cfg *ec2ServiceConfig) getInstanceResourceFilters() ([][]*ec2.Filter, bool) { - var allFilters [][]*ec2.Filter - - instanceFilters := ec2Cfg.instanceFilters - if len(instanceFilters) == 0 { - return nil, false - } - - for _, filters := range ec2Cfg.instanceFilters { - // if any selector found with nil filter, skip all other selectors. As nil indicates all - if len(filters) == 0 { - return nil, true - } - allFilters = append(allFilters, filters...) - } - return allFilters, true -} - -// getCachedInstances returns instances from the cache for the account. -func (ec2Cfg *ec2ServiceConfig) getCachedInstances() []*ec2.Instance { +// getCachedInstances returns instances from the cache applicable for the given selector. +func (ec2Cfg *ec2ServiceConfig) getCachedInstances(selector *types.NamespacedName) []*ec2.Instance { snapshot := ec2Cfg.resourcesCache.GetSnapshot() if snapshot == nil { - awsPluginLogger().V(4).Info("Cache snapshot nil", "account", ec2Cfg.accountNamespacedName) + awsPluginLogger().V(4).Info("Cache snapshot nil", + "type", providerType, "account", ec2Cfg.accountNamespacedName) return []*ec2.Instance{} } - instances := snapshot.(*ec2ResourcesCacheSnapshot).instances - instancesToReturn := make([]*ec2.Instance, 0, len(instances)) - for _, instance := range instances { - instancesToReturn = append(instancesToReturn, instance) + instances, found := snapshot.(*ec2ResourcesCacheSnapshot).vms[*selector] + if !found { + awsPluginLogger().V(4).Info("Vm cache snapshot not found", + "account", ec2Cfg.accountNamespacedName, "selector", selector) + return []*ec2.Instance{} } - awsPluginLogger().V(1).Info("Cached vm instances", "account", ec2Cfg.accountNamespacedName, - "instances", len(instancesToReturn)) + instancesToReturn := make([]*ec2.Instance, 0, len(instances)) + instancesToReturn = append(instancesToReturn, instances...) return instancesToReturn } -// getManagedVpcIDs returns vpcIDs of vpcs containing managed vms. +// getManagedVpcIDs returns vpcIDs of vpcs containing managed vms from cache. func (ec2Cfg *ec2ServiceConfig) getManagedVpcIDs() map[string]struct{} { vpcIDsCopy := make(map[string]struct{}) snapshot := ec2Cfg.resourcesCache.GetSnapshot() if snapshot == nil { - awsPluginLogger().V(4).Info("Cache snapshot nil", "account", ec2Cfg.accountNamespacedName) + awsPluginLogger().V(4).Info("Cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) return vpcIDsCopy } - vpcIDsSet := snapshot.(*ec2ResourcesCacheSnapshot).vpcIDs + vpcIDsSet := snapshot.(*ec2ResourcesCacheSnapshot).managedVpcIDs for vpcID := range vpcIDsSet { vpcIDsCopy[vpcID] = struct{}{} @@ -153,12 +136,12 @@ func (ec2Cfg *ec2ServiceConfig) getManagedVpcIDs() map[string]struct{} { return vpcIDsCopy } -// getManagedVpcs returns vpcs containing managed vms. -func (ec2Cfg *ec2ServiceConfig) getManagedVpcs() map[string]*ec2.Vpc { +// getCachedVpcsMap returns vpcs from cache in map format. +func (ec2Cfg *ec2ServiceConfig) getCachedVpcsMap() map[string]*ec2.Vpc { vpcCopy := make(map[string]*ec2.Vpc) snapshot := ec2Cfg.resourcesCache.GetSnapshot() if snapshot == nil { - awsPluginLogger().Info("Compute service cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) + awsPluginLogger().V(4).Info("Cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) return vpcCopy } @@ -174,7 +157,7 @@ func (ec2Cfg *ec2ServiceConfig) getCachedVpcNameToID() map[string]string { vpcNameToIDCopy := make(map[string]string) snapshot := ec2Cfg.resourcesCache.GetSnapshot() if snapshot == nil { - awsPluginLogger().V(4).Info("Ec2 service cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) + awsPluginLogger().V(4).Info("Cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) return vpcNameToIDCopy } vpcNameToID := snapshot.(*ec2ResourcesCacheSnapshot).vpcNameToID @@ -187,10 +170,10 @@ func (ec2Cfg *ec2ServiceConfig) getCachedVpcNameToID() map[string]string { } // GetCachedVpcs returns VPCs from cached snapshot for the account. -func (ec2Cfg *ec2ServiceConfig) GetCachedVpcs() []*ec2.Vpc { +func (ec2Cfg *ec2ServiceConfig) getCachedVpcs() []*ec2.Vpc { snapshot := ec2Cfg.resourcesCache.GetSnapshot() if snapshot == nil { - awsPluginLogger().Info("Cache snapshot nil", "account", ec2Cfg.accountNamespacedName) + awsPluginLogger().V(4).Info("Cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) return []*ec2.Vpc{} } vpcs := snapshot.(*ec2ResourcesCacheSnapshot).vpcs @@ -204,7 +187,7 @@ func (ec2Cfg *ec2ServiceConfig) GetCachedVpcs() []*ec2.Vpc { func (ec2Cfg *ec2ServiceConfig) getVpcPeers(vpcID string) []string { snapshot := ec2Cfg.resourcesCache.GetSnapshot() if snapshot == nil { - awsPluginLogger().V(4).Info("Ec2 service cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) + awsPluginLogger().V(4).Info("Cache snapshot nil", "type", providerType, "account", ec2Cfg.accountNamespacedName) return nil } vpcPeersCopy := make([]string, 0) @@ -214,30 +197,14 @@ func (ec2Cfg *ec2ServiceConfig) getVpcPeers(vpcID string) []string { return vpcPeersCopy } -// getInstances gets instance for the account from aws EC2 API. -func (ec2Cfg *ec2ServiceConfig) getInstances() ([]*ec2.Instance, error) { - filters, hasFilters := ec2Cfg.getInstanceResourceFilters() - if !hasFilters { - awsPluginLogger().V(1).Info("Fetching vm resources from cloud skipped", - "account", ec2Cfg.accountNamespacedName, "resource-filters", "not-configured") - return nil, nil - } - - if filters == nil { - awsPluginLogger().V(1).Info("Fetching vm resources from cloud", - "account", ec2Cfg.accountNamespacedName, "resource-filters", "all(nil)") - var validInstanceStateFilters []*ec2.Filter - validInstanceStateFilters = append(validInstanceStateFilters, buildEc2FilterForValidInstanceStates()) - request := &ec2.DescribeInstancesInput{ - MaxResults: aws.Int64(internal.MaxCloudResourceResponse), - Filters: validInstanceStateFilters, - } - return ec2Cfg.apiClient.pagedDescribeInstancesWrapper(request) - } - - awsPluginLogger().V(1).Info("Fetching vm resources from cloud", - "account", ec2Cfg.accountNamespacedName, "resource-filters", "configured") +// getInstances gets instances from cloud matching the given selector configuration. +func (ec2Cfg *ec2ServiceConfig) getInstances(namespacedName *types.NamespacedName) ([]*ec2.Instance, error) { var instances []*ec2.Instance + filters, found := ec2Cfg.instanceFilters[*namespacedName] + if found && len(filters) != 0 { + awsPluginLogger().V(1).Info("Fetching vm resources from cloud", "account", ec2Cfg.accountNamespacedName, + "selector", namespacedName, "resource-filters", "configured") + } for _, filter := range filters { if len(filter) > 0 { if *filter[0].Name == awsCustomFilterKeyVPCName { @@ -248,77 +215,87 @@ func (ec2Cfg *ec2ServiceConfig) getInstances() ([]*ec2.Instance, error) { MaxResults: aws.Int64(internal.MaxCloudResourceResponse), Filters: filter, } - filterInstances, e := ec2Cfg.apiClient.pagedDescribeInstancesWrapper(request) - if e != nil { - return nil, e + filterInstances, err := ec2Cfg.apiClient.pagedDescribeInstancesWrapper(request) + if err != nil { + return nil, err } instances = append(instances, filterInstances...) } - - awsPluginLogger().V(1).Info("Vm instances from cloud", "account", ec2Cfg.accountNamespacedName, - "instances", len(instances)) + awsPluginLogger().Info("Vm instances from cloud", "account", ec2Cfg.accountNamespacedName, + "selector", namespacedName, "instances", len(instances)) return instances, nil } -// DoResourceInventory gets inventory from cloud for given cloud account. +// DoResourceInventory gets inventory from cloud for a given cloud account. func (ec2Cfg *ec2ServiceConfig) DoResourceInventory() error { vpcs, err := ec2Cfg.getVpcs() if err != nil { awsPluginLogger().Error(err, "failed to fetch cloud resources", "account", ec2Cfg.accountNamespacedName) return err } + awsPluginLogger().V(1).Info("Vpcs from cloud", "account", ec2Cfg.accountNamespacedName, + "vpcs", len(vpcs)) + vpcNameToID := ec2Cfg.buildMapVpcNameToID(vpcs) + vpcPeers, _ := ec2Cfg.buildMapVpcPeers() + allInstances := make(map[types.NamespacedName][]*ec2.Instance) + + // Call cloud APIs for the configured CloudEntitySelectors CRs. + if len(ec2Cfg.selectors) == 0 { + awsPluginLogger().V(1).Info("Fetching vm resources from cloud skipped", + "account", ec2Cfg.accountNamespacedName, "resource-filters", "not-configured") + ec2Cfg.resourcesCache.UpdateSnapshot(&ec2ResourcesCacheSnapshot{allInstances, vpcs, nil, vpcNameToID, vpcPeers}) + return nil + } - instances, err := ec2Cfg.getInstances() - if err != nil { - awsPluginLogger().Error(err, "failed to fetch cloud resources", "account", ec2Cfg.accountNamespacedName) - return err - } else { - exists := struct{}{} - vpcIDs := make(map[string]struct{}) - instanceIDs := make(map[internal.InstanceID]*ec2.Instance) - vpcNameToID := ec2Cfg.buildMapVpcNameToID(vpcs) - vpcPeers, _ := ec2Cfg.buildMapVpcPeers() + managedVpcIDs := make(map[string]struct{}) + for namespacedName := range ec2Cfg.selectors { + instances, err := ec2Cfg.getInstances(&namespacedName) + if err != nil { + awsPluginLogger().Error(err, "failed to fetch cloud resources", "account", ec2Cfg.accountNamespacedName) + return err + } for _, instance := range instances { - id := internal.InstanceID(strings.ToLower(aws.StringValue(instance.InstanceId))) - instanceIDs[id] = instance - vpcIDs[strings.ToLower(*instance.VpcId)] = exists + managedVpcIDs[strings.ToLower(*instance.VpcId)] = struct{}{} } - ec2Cfg.resourcesCache.UpdateSnapshot(&ec2ResourcesCacheSnapshot{instanceIDs, vpcs, vpcIDs, vpcNameToID, vpcPeers}) + allInstances[namespacedName] = instances } + ec2Cfg.resourcesCache.UpdateSnapshot(&ec2ResourcesCacheSnapshot{allInstances, vpcs, managedVpcIDs, vpcNameToID, vpcPeers}) return nil } // AddResourceFilters add/updates instances resource filter for the service. func (ec2Cfg *ec2ServiceConfig) AddResourceFilters(selector *crdv1alpha1.CloudEntitySelector) error { + namespacedName := types.NamespacedName{Namespace: selector.Namespace, Name: selector.Name} if filters, ok := convertSelectorToEC2InstanceFilters(selector); ok { - key := selector.GetNamespace() + "/" + selector.GetName() - ec2Cfg.instanceFilters[key] = filters + ec2Cfg.instanceFilters[namespacedName] = filters + ec2Cfg.selectors[namespacedName] = selector.DeepCopy() } else { return fmt.Errorf("error creating resource query filters") } return nil } -func (ec2Cfg *ec2ServiceConfig) RemoveResourceFilters(selectorNamespacedName *types.NamespacedName) { - delete(ec2Cfg.instanceFilters, selectorNamespacedName.String()) +func (ec2Cfg *ec2ServiceConfig) RemoveResourceFilters(namespacedName *types.NamespacedName) { + delete(ec2Cfg.instanceFilters, *namespacedName) + delete(ec2Cfg.selectors, *namespacedName) } -func (ec2Cfg *ec2ServiceConfig) GetInternalResourceObjects(namespace string, - account *types.NamespacedName) map[string]*runtimev1alpha1.VirtualMachine { - instances := ec2Cfg.getCachedInstances() - vpcs := ec2Cfg.getManagedVpcs() +// getVirtualMachineObjects converts cached virtual machines in cloud format to internal runtimev1alpha1.VirtualMachine format. +func (ec2Cfg *ec2ServiceConfig) getVirtualMachineObjects(accountNamespacedName *types.NamespacedName, + selector *types.NamespacedName) map[string]*runtimev1alpha1.VirtualMachine { + instances := ec2Cfg.getCachedInstances(selector) + vpcs := ec2Cfg.getCachedVpcsMap() + vmObjects := map[string]*runtimev1alpha1.VirtualMachine{} for _, instance := range instances { - // build runtimev1alpha1 VirtualMachine object. - vmObject := ec2InstanceToInternalVirtualMachineObject(instance, vpcs, namespace, account, ec2Cfg.credentials.region) + // build runtime.v1alpha1.VirtualMachine object. + vmObject := ec2InstanceToInternalVirtualMachineObject(instance, vpcs, selector, + accountNamespacedName, ec2Cfg.credentials.region) vmObjects[vmObject.Name] = vmObject } - awsPluginLogger().V(1).Info("Internal resource objects", "account", ec2Cfg.accountNamespacedName, - "VirtualMachine objects", len(vmObjects)) - return vmObjects } @@ -381,23 +358,34 @@ func (ec2Cfg *ec2ServiceConfig) getVpcs() ([]*ec2.Vpc, error) { return result.Vpcs, nil } -// GetVpcInventory generates vpc object for the vpcs stored in snapshot(in cloud format) and return a map of vpc runtime objects. -func (ec2Cfg *ec2ServiceConfig) GetVpcInventory() map[string]*runtimev1alpha1.Vpc { - vpcs := ec2Cfg.GetCachedVpcs() - vpcIDs := ec2Cfg.getManagedVpcIDs() +// getVpcObjects generates vpc object for the vpcs stored in snapshot(in cloud format) and return a map of vpc runtime objects. +func (ec2Cfg *ec2ServiceConfig) getVpcObjects() map[string]*runtimev1alpha1.Vpc { + vpcs := ec2Cfg.getCachedVpcs() + managedVpcIDs := ec2Cfg.getManagedVpcIDs() // Convert to kubernetes object and return a map indexed using VPC ID. vpcMap := map[string]*runtimev1alpha1.Vpc{} for _, vpc := range vpcs { managed := false - if _, ok := vpcIDs[*vpc.VpcId]; ok { + if _, ok := managedVpcIDs[*vpc.VpcId]; ok { managed = true } vpcObj := ec2VpcToInternalVpcObject(vpc, ec2Cfg.accountNamespacedName.Namespace, ec2Cfg.accountNamespacedName.Name, strings.ToLower(ec2Cfg.credentials.region), managed) vpcMap[strings.ToLower(*vpc.VpcId)] = vpcObj } + return vpcMap +} - awsPluginLogger().V(1).Info("Cached vpcs", "account", ec2Cfg.accountNamespacedName, "vpc objects", len(vpcMap)) +// GetCloudInventory fetches VM and VPC inventory from stored snapshot and converts from cloud format to internal format. +func (ec2Cfg *ec2ServiceConfig) GetCloudInventory() *nephetypes.CloudInventory { + cloudInventory := nephetypes.CloudInventory{ + VmMap: map[types.NamespacedName]map[string]*runtimev1alpha1.VirtualMachine{}, + VpcMap: map[string]*runtimev1alpha1.Vpc{}, + } + cloudInventory.VpcMap = ec2Cfg.getVpcObjects() + for namespacedName := range ec2Cfg.selectors { + cloudInventory.VmMap[namespacedName] = ec2Cfg.getVirtualMachineObjects(&ec2Cfg.accountNamespacedName, &namespacedName) + } - return vpcMap + return &cloudInventory } diff --git a/pkg/cloudprovider/plugins/aws/aws_security_test.go b/pkg/cloudprovider/plugins/aws/aws_security_test.go index 529f9409..3c18ac4d 100644 --- a/pkg/cloudprovider/plugins/aws/aws_security_test.go +++ b/pkg/cloudprovider/plugins/aws/aws_security_test.go @@ -96,7 +96,8 @@ var _ = Describe("AWS Cloud Security", func() { Namespace: testAccountNamespacedName.Namespace, }, Spec: crdv1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []crdv1alpha1.VirtualMachineSelector{ { VpcMatch: &crdv1alpha1.EntityMatch{ diff --git a/pkg/cloudprovider/plugins/aws/aws_test.go b/pkg/cloudprovider/plugins/aws/aws_test.go index d6e79bf5..cc79e26a 100644 --- a/pkg/cloudprovider/plugins/aws/aws_test.go +++ b/pkg/cloudprovider/plugins/aws/aws_test.go @@ -43,8 +43,9 @@ var ( var _ = Describe("AWS cloud", func() { var ( - testAccountNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "account01"} - credentials = "credentials" + testAccountNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "account01"} + testSelectorNamespacedName = types.NamespacedName{Namespace: "namespace02", Name: "selector01"} + credentials = "credentials" ) Context("AddProviderAccount", func() { @@ -104,12 +105,19 @@ var _ = Describe("AWS cloud", func() { BeforeEach(func() { selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: v1.ObjectMeta{ - Name: "selector-all", + Name: "vpc-match-selector", Namespace: testAccountNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, - VMSelector: []v1alpha1.VirtualMachineSelector{}, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VpcMatch: &v1alpha1.EntityMatch{ + MatchID: "xyz", + }, + }, + }, }, } @@ -186,9 +194,9 @@ var _ = Describe("AWS cloud", func() { errPolAdd := c.DoInventoryPoll(&testAccountNamespacedName) Expect(errPolAdd).Should(BeNil()) - vpcMap, err := c.GetVpcInventory(&testAccountNamespacedName) + cloudInventory, err := c.GetCloudInventory(&testAccountNamespacedName) Expect(err).Should(BeNil()) - Expect(len(vpcMap)).Should(Equal(len(vpcIDs))) + Expect(len(cloudInventory.VpcMap)).Should(Equal(len(vpcIDs))) }) It("StopPoller cloud inventory poll on poller delete", func() { credential := `{"accessKeyId": "keyId","accessKeySecret": "keySecret", "sessionToken": "token"}` @@ -230,7 +238,7 @@ var _ = Describe("AWS cloud", func() { mockawsEC2.EXPECT().describeVpcsWrapper(gomock.Any()).Return(&ec2.DescribeVpcsOutput{}, nil).Times(0) mockawsEC2.EXPECT().describeVpcPeeringConnectionsWrapper(gomock.Any()).Return(&ec2.DescribeVpcPeeringConnectionsOutput{}, nil).Times(0) }) - It("Should discover few instances with get ALL selector using credentials", func() { + It("Should discover instances when selector is in different namespace from account", func() { instanceIds := []string{"i-01", "i-02"} credential := `{"accessKeyId": "keyId","accessKeySecret": "keySecret"}` @@ -244,42 +252,24 @@ var _ = Describe("AWS cloud", func() { }, } - mockawsEC2.EXPECT().pagedDescribeInstancesWrapper(gomock.Any()).Return(getEc2InstanceObject(instanceIds), nil).AnyTimes() - mockawsEC2.EXPECT().pagedDescribeNetworkInterfaces(gomock.Any()).Return([]*ec2.NetworkInterface{}, nil).AnyTimes() - mockawsEC2.EXPECT().describeVpcsWrapper(gomock.Any()).Return(&ec2.DescribeVpcsOutput{}, nil).AnyTimes() - mockawsEC2.EXPECT().describeVpcPeeringConnectionsWrapper(gomock.Any()).Return(&ec2.DescribeVpcPeeringConnectionsOutput{}, - nil).AnyTimes() - - _ = fakeClient.Create(context.Background(), secret) - c := newAWSCloud(mockawsCloudHelper) - err := c.AddProviderAccount(fakeClient, account) - - Expect(err).Should(BeNil()) - accCfg, found := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - Expect(found).To(BeTrue()) - Expect(accCfg).To(Not(BeNil())) - - errSelAdd := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) - Expect(errSelAdd).Should(BeNil()) - - err = c.DoInventoryPoll(&testAccountNamespacedName) - Expect(err).Should(BeNil()) - - err = checkAccountAddSuccessCondition(c, testAccountNamespacedName, instanceIds) - Expect(err).Should(BeNil()) - }) - It("Should discover few instances with get ALL selector using roleArn", func() { - instanceIds := []string{"i-01", "i-02"} - credential := `{"roleArn" : "roleArn","externalID" : "" }` - secret = &corev1.Secret{ + selector = &v1alpha1.CloudEntitySelector{ ObjectMeta: v1.ObjectMeta{ - Name: testAccountNamespacedName.Name, - Namespace: testAccountNamespacedName.Namespace, + Name: testSelectorNamespacedName.Name, + Namespace: testSelectorNamespacedName.Namespace, }, - Data: map[string][]byte{ - "credentials": []byte(credential), + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VpcMatch: &v1alpha1.EntityMatch{ + MatchID: "xyz", + }, + }, + }, }, } + mockawsEC2.EXPECT().pagedDescribeInstancesWrapper(gomock.Any()).Return(getEc2InstanceObject(instanceIds), nil).AnyTimes() mockawsEC2.EXPECT().pagedDescribeNetworkInterfaces(gomock.Any()).Return([]*ec2.NetworkInterface{}, nil).AnyTimes() mockawsEC2.EXPECT().describeVpcsWrapper(gomock.Any()).Return(&ec2.DescribeVpcsOutput{}, nil).AnyTimes() @@ -301,7 +291,7 @@ var _ = Describe("AWS cloud", func() { err = c.DoInventoryPoll(&testAccountNamespacedName) Expect(err).Should(BeNil()) - err = checkAccountAddSuccessCondition(c, testAccountNamespacedName, instanceIds) + err = checkAccountAddSuccessCondition(c, testAccountNamespacedName, testSelectorNamespacedName, instanceIds) Expect(err).Should(BeNil()) }) It("Should discover no instances with get ALL selector", func() { @@ -325,7 +315,7 @@ var _ = Describe("AWS cloud", func() { err = c.DoInventoryPoll(&testAccountNamespacedName) Expect(err).Should(BeNil()) - err = checkAccountAddSuccessCondition(c, testAccountNamespacedName, instanceIds) + err = checkAccountAddSuccessCondition(c, testAccountNamespacedName, testSelectorNamespacedName, instanceIds) Expect(err).Should(BeNil()) }) }) @@ -382,7 +372,8 @@ var _ = Describe("AWS cloud", func() { Namespace: testAccountNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ @@ -454,8 +445,7 @@ var _ = Describe("AWS cloud", func() { err := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - accCfg, _ := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - filters := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[testSelectorNamespacedName.String()] + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedFilters)) }) }) @@ -485,8 +475,7 @@ var _ = Describe("AWS cloud", func() { err := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - accCfg, _ := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - filters := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[testSelectorNamespacedName.String()] + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedFilters)) }) It("Should match expected filter - multiple vpcName only match", func() { @@ -514,9 +503,7 @@ var _ = Describe("AWS cloud", func() { selector.Spec.VMSelector = vmSelector err := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - - accCfg, _ := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - filters := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[testSelectorNamespacedName.String()] + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedFilters)) }) It("Should match expected filter - multiple vpcID & vmName match", func() { @@ -569,8 +556,7 @@ var _ = Describe("AWS cloud", func() { err := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - accCfg, _ := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - filters := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[testSelectorNamespacedName.String()] + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedFilters)) }) It("Should match expected filter - multiple with one all", func() { @@ -594,9 +580,7 @@ var _ = Describe("AWS cloud", func() { selector.Spec.VMSelector = vmSelector err := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - - accCfg, _ := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - filters := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[testSelectorNamespacedName.String()] + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedFilters)) }) It("Should match expected filter - multiple vm names only match", func() { @@ -631,8 +615,7 @@ var _ = Describe("AWS cloud", func() { err := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - accCfg, _ := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - filters := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[testSelectorNamespacedName.String()] + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedFilters)) }) It("Should match expected filter - multiple vm IDs only match", func() { @@ -667,8 +650,7 @@ var _ = Describe("AWS cloud", func() { err := c.AddAccountResourceSelector(&testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - accCfg, _ := c.cloudCommon.GetCloudAccountByName(&testAccountNamespacedName) - filters := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[testSelectorNamespacedName.String()] + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedFilters)) }) }) @@ -712,14 +694,15 @@ func createVpcObject(vpcIDs []string) *ec2.DescribeVpcsOutput { return vpcsOutput } -func checkAccountAddSuccessCondition(c *awsCloud, namespacedName types.NamespacedName, ids []string) error { +func checkAccountAddSuccessCondition(c *awsCloud, namespacedName types.NamespacedName, selectorNamespacedName types.NamespacedName, + ids []string) error { conditionFunc := func() (done bool, e error) { accCfg, found := c.cloudCommon.GetCloudAccountByName(&namespacedName) if !found { return true, errors.New("failed to find account") } - instances := accCfg.GetServiceConfig().(*ec2ServiceConfig).getCachedInstances() + instances := accCfg.GetServiceConfig().(*ec2ServiceConfig).getCachedInstances(&selectorNamespacedName) instanceIds := make([]string, 0, len(instances)) for _, instance := range instances { instanceIds = append(instanceIds, *instance.InstanceId) @@ -744,7 +727,7 @@ func checkVpcPollResult(c *awsCloud, namespacedName types.NamespacedName, ids [] return true, errors.New("failed to find account") } - vpcs := accCfg.GetServiceConfig().(*ec2ServiceConfig).GetCachedVpcs() + vpcs := accCfg.GetServiceConfig().(*ec2ServiceConfig).getCachedVpcs() vpcIDs := make([]string, 0, len(vpcs)) for _, vpc := range vpcs { _, _ = GinkgoWriter.Write([]byte(fmt.Sprintf("vpc id %s", *vpc.VpcId))) @@ -762,3 +745,11 @@ func checkVpcPollResult(c *awsCloud, namespacedName types.NamespacedName, ids [] return wait.PollImmediate(1*time.Second, 5*time.Second, conditionFunc) } + +func getFilters(c *awsCloud, selectorNamespacedName types.NamespacedName) [][]*ec2.Filter { + accCfg, _ := c.cloudCommon.GetCloudAccountByName(&types.NamespacedName{Namespace: "namespace01", Name: "account01"}) + if obj, found := accCfg.GetServiceConfig().(*ec2ServiceConfig).instanceFilters[selectorNamespacedName]; found { + return obj + } + return nil +} diff --git a/pkg/cloudprovider/plugins/azure/azure_account_impl.go b/pkg/cloudprovider/plugins/azure/azure_account_impl.go index 2daf442e..e6d6e4d4 100644 --- a/pkg/cloudprovider/plugins/azure/azure_account_impl.go +++ b/pkg/cloudprovider/plugins/azure/azure_account_impl.go @@ -19,7 +19,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" crdv1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" - runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" ) // AddProviderAccount adds and initializes given account of a cloud provider. @@ -55,8 +54,3 @@ func (c *azureCloud) DoInventoryPoll(accountNamespacedName *types.NamespacedName func (c *azureCloud) ResetInventoryCache(accountNamespacedName *types.NamespacedName) error { return c.cloudCommon.ResetInventoryCache(accountNamespacedName) } - -// GetVpcInventory pulls cloud vpc inventory from internal snapshot. -func (c *azureCloud) GetVpcInventory(accountNamespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.Vpc, error) { - return c.cloudCommon.GetVpcInventory(accountNamespacedName) -} diff --git a/pkg/cloudprovider/plugins/azure/azure_compute.go b/pkg/cloudprovider/plugins/azure/azure_compute.go index aee21a9d..33d30409 100644 --- a/pkg/cloudprovider/plugins/azure/azure_compute.go +++ b/pkg/cloudprovider/plugins/azure/azure_compute.go @@ -28,10 +28,11 @@ import ( crdv1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" "antrea.io/nephe/pkg/cloudprovider/plugins/internal" + nephetypes "antrea.io/nephe/pkg/types" ) type computeServiceConfig struct { - account types.NamespacedName + accountNamespacedName types.NamespacedName nwIntfAPIClient azureNwIntfWrapper nsgAPIClient azureNsgWrapper asgAPIClient azureAsgWrapper @@ -40,16 +41,17 @@ type computeServiceConfig struct { resourcesCache *internal.CloudServiceResourcesCache inventoryStats *internal.CloudServiceStats credentials *azureAccountConfig - computeFilters map[string][]*string + computeFilters map[types.NamespacedName][]*string // selectors required for updating resource filters on account config update. - selectors map[string]*crdv1alpha1.CloudEntitySelector + selectors map[types.NamespacedName]*crdv1alpha1.CloudEntitySelector } type computeResourcesCacheSnapshot struct { - virtualMachines map[internal.InstanceID]*virtualMachineTable - vnets []armnetwork.VirtualNetwork - vnetIDs map[string]struct{} - vnetPeers map[string][][]string + // vm resources for each CloudEntitySelector CR. + vms map[types.NamespacedName][]*virtualMachineTable + vnets []armnetwork.VirtualNetwork + managedVnetIDs map[string]struct{} + vnetPeers map[string][][]string } func newComputeServiceConfig(account types.NamespacedName, service azureServiceClientCreateInterface, @@ -82,7 +84,7 @@ func newComputeServiceConfig(account types.NamespacedName, service azureServiceC } config := &computeServiceConfig{ - account: account, + accountNamespacedName: account, nwIntfAPIClient: nwIntfAPIClient, nsgAPIClient: securityGroupsAPIClient, asgAPIClient: applicationSecurityGroupsAPIClient, @@ -91,9 +93,12 @@ func newComputeServiceConfig(account types.NamespacedName, service azureServiceC resourcesCache: &internal.CloudServiceResourcesCache{}, inventoryStats: &internal.CloudServiceStats{}, credentials: credentials, - computeFilters: make(map[string][]*string), - selectors: make(map[string]*crdv1alpha1.CloudEntitySelector), + computeFilters: make(map[types.NamespacedName][]*string), + selectors: make(map[types.NamespacedName]*crdv1alpha1.CloudEntitySelector), } + + vmSnapshot := make(map[types.NamespacedName][]*virtualMachineTable) + config.resourcesCache.UpdateSnapshot(&computeResourcesCacheSnapshot{vmSnapshot, nil, nil, nil}) return config, nil } @@ -101,7 +106,8 @@ func (computeCfg *computeServiceConfig) waitForInventoryInit(duration time.Durat operation := func() error { done := computeCfg.inventoryStats.IsInventoryInitialized() if !done { - return fmt.Errorf("inventory for account %v not initialized (waited %v duration)", computeCfg.account, duration) + return fmt.Errorf("inventory for account %v not initialized (waited %v duration)", + computeCfg.accountNamespacedName, duration) } return nil } @@ -112,20 +118,41 @@ func (computeCfg *computeServiceConfig) waitForInventoryInit(duration time.Durat return backoff.Retry(operation, b) } -// getCachedVirtualMachines returns virtualMachines from the cache for the subscription. -func (computeCfg *computeServiceConfig) getCachedVirtualMachines() []*virtualMachineTable { +// getCachedVirtualMachines returns virtualMachines specific to a selector from the cache for the subscription. +func (computeCfg *computeServiceConfig) getCachedVirtualMachines(selector *types.NamespacedName) []*virtualMachineTable { snapshot := computeCfg.resourcesCache.GetSnapshot() if snapshot == nil { - azurePluginLogger().V(4).Info("Compute service cache snapshot nil", "type", providerType, "account", computeCfg.account) + azurePluginLogger().V(4).Info("Cache snapshot nil", + "type", providerType, "account", computeCfg.accountNamespacedName) + return []*virtualMachineTable{} + } + + virtualMachines, found := snapshot.(*computeResourcesCacheSnapshot).vms[*selector] + if !found { + azurePluginLogger().V(4).Info("Vm snapshot nil", + "type", providerType, "account", computeCfg.accountNamespacedName) return []*virtualMachineTable{} } - virtualMachines := snapshot.(*computeResourcesCacheSnapshot).virtualMachines + instancesToReturn := make([]*virtualMachineTable, 0, len(virtualMachines)) - for _, virtualMachine := range virtualMachines { - instancesToReturn = append(instancesToReturn, virtualMachine) + instancesToReturn = append(instancesToReturn, virtualMachines...) + return instancesToReturn +} + +// getAllCachedVirtualMachines returns all virtualMachines from the cache for the subscription. +func (computeCfg *computeServiceConfig) getAllCachedVirtualMachines() []*virtualMachineTable { + snapshot := computeCfg.resourcesCache.GetSnapshot() + if snapshot == nil { + azurePluginLogger().V(4).Info("Cache snapshot nil", + "type", providerType, "account", computeCfg.accountNamespacedName) + return []*virtualMachineTable{} } - azurePluginLogger().V(1).Info("Cached vm instances", "account", computeCfg.account, + instancesToReturn := make([]*virtualMachineTable, 0) + for _, virtualMachines := range snapshot.(*computeResourcesCacheSnapshot).vms { + instancesToReturn = append(instancesToReturn, virtualMachines...) + } + azurePluginLogger().V(1).Info("Cached vm instances", "account", computeCfg.accountNamespacedName, "instances", len(instancesToReturn)) return instancesToReturn } @@ -135,10 +162,11 @@ func (computeCfg *computeServiceConfig) getManagedVnetIDs() map[string]struct{} vnetIDsCopy := make(map[string]struct{}) snapshot := computeCfg.resourcesCache.GetSnapshot() if snapshot == nil { - azurePluginLogger().Info("Compute service cache snapshot nil", "type", providerType, "account", computeCfg.account) + azurePluginLogger().Info("Cache snapshot nil", + "type", providerType, "account", computeCfg.accountNamespacedName) return vnetIDsCopy } - vnetIDsSet := snapshot.(*computeResourcesCacheSnapshot).vnetIDs + vnetIDsSet := snapshot.(*computeResourcesCacheSnapshot).managedVnetIDs for vnetID := range vnetIDsSet { vnetIDsCopy[vnetID] = struct{}{} @@ -147,12 +175,13 @@ func (computeCfg *computeServiceConfig) getManagedVnetIDs() map[string]struct{} return vnetIDsCopy } -// getManagedVnets returns vnets containing managed vms. -func (computeCfg *computeServiceConfig) getManagedVnets() map[string]armnetwork.VirtualNetwork { +// getCachedVnetsMap returns vnets from cache in map format. +func (computeCfg *computeServiceConfig) getCachedVnetsMap() map[string]armnetwork.VirtualNetwork { vnetCopy := make(map[string]armnetwork.VirtualNetwork) snapshot := computeCfg.resourcesCache.GetSnapshot() if snapshot == nil { - azurePluginLogger().Info("Compute service cache snapshot nil", "type", providerType, "account", computeCfg.account) + azurePluginLogger().Info("Cache snapshot nil", + "type", providerType, "account", computeCfg.accountNamespacedName) return vnetCopy } @@ -166,9 +195,11 @@ func (computeCfg *computeServiceConfig) getManagedVnets() map[string]armnetwork. func (computeCfg *computeServiceConfig) getVnetPeers(vnetID string) [][]string { snapshot := computeCfg.resourcesCache.GetSnapshot() if snapshot == nil { - azurePluginLogger().V(4).Info("Compute service cache snapshot nil", "type", providerType, "account", computeCfg.account) + azurePluginLogger().Info("Cache snapshot nil", + "type", providerType, "account", computeCfg.accountNamespacedName) return nil } + vnetPeersCopy := make([][]string, 0) if peers, ok := snapshot.(*computeResourcesCacheSnapshot).vnetPeers[vnetID]; ok { vnetPeersCopy = deepcopy.Copy(peers).([][]string) @@ -176,90 +207,63 @@ func (computeCfg *computeServiceConfig) getVnetPeers(vnetID string) [][]string { return vnetPeersCopy } -func (computeCfg *computeServiceConfig) getVirtualMachines() ([]*virtualMachineTable, error) { - filters, hasFilters := computeCfg.getComputeResourceFilters() - if !hasFilters { - azurePluginLogger().V(1).Info("Fetching vm resources from cloud skipped", - "account", computeCfg.account, "resource-filters", "not-configured") - return nil, nil - } - - if filters == nil { - azurePluginLogger().V(1).Info("Fetching vm resources from cloud", - "account", computeCfg.account, "resource-filters", "all(nil)") - } else { +// getVirtualMachines gets virtual machines from cloud matching the given selector configuration. +func (computeCfg *computeServiceConfig) getVirtualMachines(namespacedName *types.NamespacedName) ([]*virtualMachineTable, error) { + filters, found := computeCfg.computeFilters[*namespacedName] + if found && len(filters) != 0 { azurePluginLogger().V(1).Info("Fetching vm resources from cloud", - "account", computeCfg.account, "resource-filters", "configured") + "account", computeCfg.accountNamespacedName, "selector", namespacedName, "resource-filters", "configured") } var subscriptions []*string subscriptions = append(subscriptions, &computeCfg.credentials.SubscriptionID) - var virtualMachines []*virtualMachineTable for _, filter := range filters { virtualMachineRows, _, err := getVirtualMachineTable(computeCfg.resourceGraphAPIClient, filter, subscriptions) if err != nil { + azurePluginLogger().Error(err, "failed to fetch cloud resources", + "account", computeCfg.accountNamespacedName, "selector", namespacedName) return nil, err } virtualMachines = append(virtualMachines, virtualMachineRows...) } - - azurePluginLogger().V(1).Info("Vm instances from cloud", - "account", computeCfg.account, "instances", len(virtualMachines)) + azurePluginLogger().V(1).Info("Vm instances from cloud", "account", computeCfg.accountNamespacedName, + "selector", namespacedName, "instances", len(virtualMachines)) return virtualMachines, nil } -func (computeCfg *computeServiceConfig) getComputeResourceFilters() ([]*string, bool) { - var allFilters []*string - - computeFilters := computeCfg.computeFilters - if len(computeFilters) == 0 { - return nil, false - } - - for _, filters := range computeCfg.computeFilters { - // if any selector found with nil filter, skip all other selectors. As nil indicates all - if len(filters) == 0 { - var queries []*string - subscriptionIDs := []string{computeCfg.credentials.SubscriptionID} - tenantIDs := []string{computeCfg.credentials.TenantID} - locations := []string{computeCfg.credentials.region} - queryStr, err := getVMsBySubscriptionIDsAndTenantIDsAndLocationsMatchQuery(subscriptionIDs, tenantIDs, locations) - if err != nil { - azurePluginLogger().Error(err, "query string creation failed", "account", computeCfg.account) - return nil, false - } - queries = append(queries, queryStr) - return queries, true - } - allFilters = append(allFilters, filters...) - } - return allFilters, true -} - func (computeCfg *computeServiceConfig) DoResourceInventory() error { vnets, err := computeCfg.getVpcs() if err != nil { - azurePluginLogger().Error(err, "failed to fetch cloud resources", "account", computeCfg.account) + azurePluginLogger().Error(err, "failed to fetch cloud resources", "account", computeCfg.accountNamespacedName) return err } + azurePluginLogger().V(1).Info("Vpcs from cloud", "account", computeCfg.accountNamespacedName, + "vpcs", len(vnets)) + vnetPeers := computeCfg.buildMapVpcPeers(vnets) + allVirtualMachines := make(map[types.NamespacedName][]*virtualMachineTable) + + // Make cloud API calls for fetching vm inventory for each configured CES. + if len(computeCfg.selectors) == 0 { + computeCfg.resourcesCache.UpdateSnapshot(&computeResourcesCacheSnapshot{allVirtualMachines, vnets, nil, vnetPeers}) + azurePluginLogger().V(1).Info("Fetching vm resources from cloud skipped", + "account", computeCfg.accountNamespacedName, "resource-filters", "not-configured") + return nil + } - virtualMachines, err := computeCfg.getVirtualMachines() - if err != nil { - azurePluginLogger().Error(err, "failed to fetch cloud resources", "account", computeCfg.account) - return err - } else { - exists := struct{}{} - vnetIDs := make(map[string]struct{}) - vpcPeers := computeCfg.buildMapVpcPeers(vnets) - vmIDToInfoMap := make(map[internal.InstanceID]*virtualMachineTable) + managedVnetIDs := make(map[string]struct{}) + for namespacedName := range computeCfg.selectors { + virtualMachines, err := computeCfg.getVirtualMachines(&namespacedName) + if err != nil { + azurePluginLogger().Error(err, "failed to fetch cloud resources", "account", computeCfg.accountNamespacedName) + return err + } for _, vm := range virtualMachines { - id := internal.InstanceID(strings.ToLower(*vm.ID)) - vmIDToInfoMap[id] = vm - vnetIDs[*vm.VnetID] = exists + managedVnetIDs[*vm.VnetID] = struct{}{} } - computeCfg.resourcesCache.UpdateSnapshot(&computeResourcesCacheSnapshot{vmIDToInfoMap, vnets, vnetIDs, vpcPeers}) + allVirtualMachines[namespacedName] = virtualMachines } + computeCfg.resourcesCache.UpdateSnapshot(&computeResourcesCacheSnapshot{allVirtualMachines, vnets, managedVnetIDs, vnetPeers}) return nil } @@ -267,37 +271,35 @@ func (computeCfg *computeServiceConfig) AddResourceFilters(selector *crdv1alpha1 subscriptionIDs := []string{computeCfg.credentials.SubscriptionID} tenantIDs := []string{computeCfg.credentials.TenantID} locations := []string{computeCfg.credentials.region} - + namespacedName := types.NamespacedName{Namespace: selector.Namespace, Name: selector.Name} if filters, ok := convertSelectorToComputeQuery(selector, subscriptionIDs, tenantIDs, locations); ok { - key := selector.GetNamespace() + "/" + selector.GetName() - computeCfg.computeFilters[key] = filters - computeCfg.selectors[key] = selector.DeepCopy() + computeCfg.computeFilters[namespacedName] = filters + computeCfg.selectors[namespacedName] = selector.DeepCopy() } else { return fmt.Errorf("error creating resource query filters") } + return nil } func (computeCfg *computeServiceConfig) RemoveResourceFilters(selectorNamespacedName *types.NamespacedName) { - delete(computeCfg.computeFilters, selectorNamespacedName.String()) - delete(computeCfg.selectors, selectorNamespacedName.String()) + delete(computeCfg.computeFilters, *selectorNamespacedName) + delete(computeCfg.selectors, *selectorNamespacedName) } -func (computeCfg *computeServiceConfig) GetInternalResourceObjects(namespace string, - account *types.NamespacedName) map[string]*runtimev1alpha1.VirtualMachine { - virtualMachines := computeCfg.getCachedVirtualMachines() - vnets := computeCfg.getManagedVnets() +// getVirtualMachineObjects converts cached virtual machines in cloud format to internal runtimev1alpha1.VirtualMachine format. +func (computeCfg *computeServiceConfig) getVirtualMachineObjects(accountNamespacedName *types.NamespacedName, + selectorNamespacedName *types.NamespacedName) map[string]*runtimev1alpha1.VirtualMachine { + virtualMachines := computeCfg.getCachedVirtualMachines(selectorNamespacedName) + vnets := computeCfg.getCachedVnetsMap() vmObjects := map[string]*runtimev1alpha1.VirtualMachine{} - for _, virtualMachine := range virtualMachines { // build runtimev1alpha1 VirtualMachine object. - vmObject := computeInstanceToInternalVirtualMachineObject(virtualMachine, vnets, namespace, account, computeCfg.credentials.region) + vmObject := computeInstanceToInternalVirtualMachineObject(virtualMachine, vnets, selectorNamespacedName, + accountNamespacedName, computeCfg.credentials.region) vmObjects[vmObject.Name] = vmObject } - azurePluginLogger().V(1).Info("Internal resource objects", "account", computeCfg.account, - "VirtualMachine objects", len(vmObjects)) - return vmObjects } @@ -318,8 +320,8 @@ func (computeCfg *computeServiceConfig) UpdateServiceConfig(newConfig internal.C computeCfg.vnetAPIClient = newComputeServiceConfig.vnetAPIClient computeCfg.resourceGraphAPIClient = newComputeServiceConfig.resourceGraphAPIClient computeCfg.credentials = newComputeServiceConfig.credentials - for _, value := range computeCfg.selectors { - if err := computeCfg.AddResourceFilters(value); err != nil { + for _, selector := range computeCfg.selectors { + if err := computeCfg.AddResourceFilters(selector); err != nil { return err } } @@ -328,7 +330,18 @@ func (computeCfg *computeServiceConfig) UpdateServiceConfig(newConfig internal.C // getVpcs invokes cloud API to fetch the list of vnets. func (computeCfg *computeServiceConfig) getVpcs() ([]armnetwork.VirtualNetwork, error) { - return computeCfg.vnetAPIClient.listAllComplete(context.Background()) + vnets := make([]armnetwork.VirtualNetwork, 0) + allVnets, err := computeCfg.vnetAPIClient.listAllComplete(context.Background()) + if err != nil { + return vnets, err + } + // Store the vnets which are in the configured region, discard the rest. + for _, vnet := range allVnets { + if strings.EqualFold(*vnet.Location, computeCfg.credentials.region) { + vnets = append(vnets, vnet) + } + } + return vnets, nil } func (computeCfg *computeServiceConfig) buildMapVpcPeers(results []armnetwork.VirtualNetwork) map[string][][]string { @@ -363,31 +376,41 @@ func (computeCfg *computeServiceConfig) buildMapVpcPeers(results []armnetwork.Vi return vpcPeers } -// GetVpcInventory generates vpc object for the vpcs stored in snapshot(in cloud format) and return a map of vpc runtime objects. -func (computeCfg *computeServiceConfig) GetVpcInventory() map[string]*runtimev1alpha1.Vpc { +// GetCloudInventory fetches VM and VPC inventory from stored snapshot and converts from cloud format to internal format. +func (computeCfg *computeServiceConfig) GetCloudInventory() *nephetypes.CloudInventory { + cloudInventory := nephetypes.CloudInventory{ + VmMap: map[types.NamespacedName]map[string]*runtimev1alpha1.VirtualMachine{}, + VpcMap: map[string]*runtimev1alpha1.Vpc{}, + } + cloudInventory.VpcMap = computeCfg.getVpcObjects() + for ns := range computeCfg.selectors { + cloudInventory.VmMap[ns] = computeCfg.getVirtualMachineObjects(&computeCfg.accountNamespacedName, &ns) + } + + return &cloudInventory +} + +// getVpcObjects generates vpc object for the vpcs stored in snapshot(in cloud format) and return a map of vpc runtime objects. +func (computeCfg *computeServiceConfig) getVpcObjects() map[string]*runtimev1alpha1.Vpc { + managedVnetIDs := computeCfg.getManagedVnetIDs() snapshot := computeCfg.resourcesCache.GetSnapshot() if snapshot == nil { - azurePluginLogger().Info("Compute service cache snapshot nil", - "type", providerType, "account", computeCfg.account) + azurePluginLogger().Info("Cache snapshot nil", + "type", providerType, "account", computeCfg.accountNamespacedName) return nil } - vnetIDs := computeCfg.getManagedVnetIDs() - // Convert to kubernetes object and return a map indexed using VnetID. vpcMap := map[string]*runtimev1alpha1.Vpc{} for _, vpc := range snapshot.(*computeResourcesCacheSnapshot).vnets { - if strings.EqualFold(*vpc.Location, computeCfg.credentials.region) { - managed := false - if _, ok := vnetIDs[strings.ToLower(*vpc.ID)]; ok { - managed = true - } - vpcObj := ComputeVpcToInternalVpcObject(&vpc, computeCfg.account.Namespace, computeCfg.account.Name, - strings.ToLower(computeCfg.credentials.region), managed) - vpcMap[strings.ToLower(*vpc.ID)] = vpcObj + managed := false + if _, ok := managedVnetIDs[strings.ToLower(*vpc.ID)]; ok { + managed = true } + vpcObj := ComputeVpcToInternalVpcObject(&vpc, computeCfg.accountNamespacedName.Namespace, + computeCfg.accountNamespacedName.Name, strings.ToLower(computeCfg.credentials.region), managed) + vpcMap[strings.ToLower(*vpc.ID)] = vpcObj } - azurePluginLogger().V(1).Info("Cached vpcs", "account", computeCfg.account, "vpc objects", len(vpcMap)) return vpcMap } diff --git a/pkg/cloudprovider/plugins/azure/azure_compute_impl.go b/pkg/cloudprovider/plugins/azure/azure_compute_impl.go index 7058c4bd..68210edb 100644 --- a/pkg/cloudprovider/plugins/azure/azure_compute_impl.go +++ b/pkg/cloudprovider/plugins/azure/azure_compute_impl.go @@ -15,14 +15,12 @@ package azure import ( - runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" "k8s.io/apimachinery/pkg/types" + + nephetypes "antrea.io/nephe/pkg/types" ) -// InstancesGivenProviderAccount returns all VM instances of a given cloud provider account, as a map of -// runtime VirtualMachine objects. -func (c *azureCloud) InstancesGivenProviderAccount(accountNamespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.VirtualMachine, - error) { - vmInternalObjectsMap, err := c.cloudCommon.GetCloudAccountComputeInternalResourceObjects(accountNamespacedName) - return vmInternalObjectsMap, err +// GetCloudInventory pulls cloud vpc and vm inventory from internal snapshot. +func (c *azureCloud) GetCloudInventory(accountNamespacedName *types.NamespacedName) (*nephetypes.CloudInventory, error) { + return c.cloudCommon.GetCloudInventory(accountNamespacedName) } diff --git a/pkg/cloudprovider/plugins/azure/azure_crd_helpers.go b/pkg/cloudprovider/plugins/azure/azure_crd_helpers.go index 883ddcc3..2c26734c 100644 --- a/pkg/cloudprovider/plugins/azure/azure_crd_helpers.go +++ b/pkg/cloudprovider/plugins/azure/azure_crd_helpers.go @@ -41,7 +41,7 @@ var azureStateMap = map[string]runtimev1alpha1.VMState{ // computeInstanceToInternalVirtualMachineObject converts compute instance to VirtualMachine runtime object. func computeInstanceToInternalVirtualMachineObject(instance *virtualMachineTable, - vnets map[string]armnetwork.VirtualNetwork, namespace string, account *types.NamespacedName, + vnets map[string]armnetwork.VirtualNetwork, selectorNamespacedName *types.NamespacedName, accountNamespacedName *types.NamespacedName, region string) *runtimev1alpha1.VirtualMachine { vmTags := make(map[string]string) for key, value := range instance.Tags { @@ -127,11 +127,13 @@ func computeInstanceToInternalVirtualMachineObject(instance *virtualMachineTable } labelsMap := map[string]string{ - labels.CloudAccountName: account.Name, - labels.CloudAccountNamespace: account.Namespace, - labels.VpcName: cloudNetworkShortID, - labels.CloudVmUID: strings.ToLower(vmUid), - labels.CloudVpcUID: strings.ToLower(vnetUid), + labels.CloudAccountName: accountNamespacedName.Name, + labels.CloudAccountNamespace: accountNamespacedName.Namespace, + labels.CloudSelectorName: selectorNamespacedName.Name, + labels.CloudSelectorNamespace: selectorNamespacedName.Namespace, + labels.VpcName: cloudNetworkShortID, + labels.CloudVmUID: strings.ToLower(vmUid), + labels.CloudVpcUID: strings.ToLower(vnetUid), } vmObj := &runtimev1alpha1.VirtualMachine{ @@ -142,7 +144,7 @@ func computeInstanceToInternalVirtualMachineObject(instance *virtualMachineTable ObjectMeta: v1.ObjectMeta{ UID: uuid.NewUUID(), Name: crdName, - Namespace: namespace, + Namespace: selectorNamespacedName.Namespace, Labels: labelsMap, }, Status: *vmStatus, @@ -185,7 +187,7 @@ func ComputeVpcToInternalVpcObject(vnet *armnetwork.VirtualNetwork, accountNames Managed: managed, } - labels := map[string]string{ + labelsMap := map[string]string{ labels.CloudAccountNamespace: accountNamespace, labels.CloudAccountName: accountName, labels.CloudVpcUID: uid, @@ -195,7 +197,7 @@ func ComputeVpcToInternalVpcObject(vnet *armnetwork.VirtualNetwork, accountNames ObjectMeta: v1.ObjectMeta{ Name: crdName, Namespace: accountNamespace, - Labels: labels, + Labels: labelsMap, }, Status: *status, } diff --git a/pkg/cloudprovider/plugins/azure/azure_resourcegraph_vmTable.go b/pkg/cloudprovider/plugins/azure/azure_resourcegraph_vmTable.go index 597a16ac..0d841405 100644 --- a/pkg/cloudprovider/plugins/azure/azure_resourcegraph_vmTable.go +++ b/pkg/cloudprovider/plugins/azure/azure_resourcegraph_vmTable.go @@ -278,36 +278,6 @@ func getVMsByVMIDsMatchQuery(vmIDs []string, subscriptionIDs []string, tenantIDs return queryString, nil } -func getVMsBySubscriptionIDsAndTenantIDsAndLocationsMatchQuery(subscriptionIDs []string, tenantIDs []string, - locations []string) (*string, error) { - commaSeparatedSubscriptionIDs := convertStrSliceToLowercaseCommaSeparatedStr(subscriptionIDs) - if len(commaSeparatedSubscriptionIDs) == 0 { - return nil, fmt.Errorf(subscriptionIDsNotFoundErrorMsg) - } - - commaSeparatedTenantIDs := convertStrSliceToLowercaseCommaSeparatedStr(tenantIDs) - if len(commaSeparatedTenantIDs) == 0 { - return nil, fmt.Errorf(tenantIDsNotFoundErrorMsg) - } - - commaSeparatedLocations := convertStrSliceToLowercaseCommaSeparatedStr(locations) - if len(commaSeparatedLocations) == 0 { - return nil, fmt.Errorf(locationsNotFoundErrorMsg) - } - - queryParams := &vmTableQueryParameters{ - SubscriptionIDs: &commaSeparatedSubscriptionIDs, - TenantIDs: &commaSeparatedTenantIDs, - Locations: &commaSeparatedLocations, - } - - queryString, err := buildVmsTableQueryWithParams("getVMsBySubscriptionIDsAndTenantIDsAndLocationsMatchQuery", queryParams) - if err != nil { - return nil, err - } - return queryString, nil -} - func getVMsByVnetAndOtherMatchesQuery(vnetIDs []string, vmNames []string, vmIDs []string, subscriptionIDs []string, tenantIDs []string, locations []string) (*string, error) { var queryParams *vmTableQueryParameters diff --git a/pkg/cloudprovider/plugins/azure/azure_security.go b/pkg/cloudprovider/plugins/azure/azure_security.go index 92a90e5f..7f919d58 100644 --- a/pkg/cloudprovider/plugins/azure/azure_security.go +++ b/pkg/cloudprovider/plugins/azure/azure_security.go @@ -646,7 +646,7 @@ func (computeCfg *computeServiceConfig) processAndBuildATSgView(networkInterface Name: strings.ToLower(*networkInterface.ID), Vpc: vnetIDLowerCase, }, - AccountID: computeCfg.account.String(), + AccountID: computeCfg.accountNamespacedName.String(), CloudProvider: string(runtimev1alpha1.AzureCloudProvider), } cloudResources := nepheControllerATSgNameToMemberCloudResourcesMap[asgName] @@ -701,7 +701,7 @@ func (computeCfg *computeServiceConfig) getATGroupView(nepheControllerATSGNameTo Name: atSgName, Vpc: vnetIDLowercase, }, - AccountID: computeCfg.account.String(), + AccountID: computeCfg.accountNamespacedName.String(), CloudProvider: string(runtimev1alpha1.AzureCloudProvider), } groupSyncObj := cloudresource.SynchronizationContent{ @@ -784,7 +784,7 @@ func (computeCfg *computeServiceConfig) processAndBuildAGSgView( Name: strings.ToLower(*networkInterface.ID), Vpc: vnetIDLowerCase, }, - AccountID: computeCfg.account.String(), + AccountID: computeCfg.accountNamespacedName.String(), CloudProvider: string(runtimev1alpha1.AzureCloudProvider), } cloudResources := nepheControllerAGSgNameToMemberCloudResourcesMap[sgName] @@ -822,7 +822,7 @@ func (computeCfg *computeServiceConfig) getAGGroupView(nepheControllerAGSgNameTo Name: asgName, Vpc: vnetID, }, - AccountID: computeCfg.account.String(), + AccountID: computeCfg.accountNamespacedName.String(), CloudProvider: string(runtimev1alpha1.AzureCloudProvider), } groupSyncObj := cloudresource.SynchronizationContent{ diff --git a/pkg/cloudprovider/plugins/azure/azure_security_impl.go b/pkg/cloudprovider/plugins/azure/azure_security_impl.go index 171c8a4e..9970b045 100644 --- a/pkg/cloudprovider/plugins/azure/azure_security_impl.go +++ b/pkg/cloudprovider/plugins/azure/azure_security_impl.go @@ -104,7 +104,7 @@ func (c *azureCloud) UpdateSecurityGroupRules(appliedToGroupIdentifier *cloudres vnetPeerPairs := computeService.getVnetPeers(vnetID) vnetCachedIDs := computeService.getManagedVnetIDs() - vnetVMs, _ := computeService.getVirtualMachines() + vnetVMs := computeService.getAllCachedVirtualMachines() // ruleIP := vnetVMs[len(vnetVMs)-1].NetworkInterfaces[0].PrivateIps[0] // AT sg name per vnet is fixed and predefined. Get azure nsg name for it. tokens := strings.Split(appliedToGroupIdentifier.Vpc, "/") @@ -119,7 +119,7 @@ func (c *azureCloud) UpdateSecurityGroupRules(appliedToGroupIdentifier *cloudres if _, ok := vnetCachedIDs[vnetPeerID]; ok { var ruleIP *string for _, vnetVM := range vnetVMs { - azurePluginLogger().Info("Accessing VM network interfaces", vnetVM.Name) + azurePluginLogger().Info("Accessing VM network interfaces", "VM", vnetVM.Name) if *vnetVM.VnetID == vnetID { ruleIP = vnetVM.NetworkInterfaces[0].PrivateIps[0] } diff --git a/pkg/cloudprovider/plugins/azure/azure_security_test.go b/pkg/cloudprovider/plugins/azure/azure_security_test.go index 35c9fc2e..8c80cb9a 100644 --- a/pkg/cloudprovider/plugins/azure/azure_security_test.go +++ b/pkg/cloudprovider/plugins/azure/azure_security_test.go @@ -34,7 +34,6 @@ import ( crdv1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" "antrea.io/nephe/apis/runtime/v1alpha1" "antrea.io/nephe/pkg/cloudprovider/cloudresource" - "antrea.io/nephe/pkg/cloudprovider/plugins/internal" "antrea.io/nephe/pkg/config" ) @@ -86,9 +85,6 @@ var _ = Describe("Azure Cloud Security", func() { testNsgID = fmt.Sprintf("/subscriptions/%v/resourceGroups/%v/providers/Microsoft.Network/applicationSecurityGroups/%v", testSubID, testRG, nsgID) - testVM01 = "testVM01" - testVMID01 = fmt.Sprintf("/subscriptions/%v/resourceGroups/%v/providers/Microsoft.Network/virtualMachines/%v", - testSubID, testRG, testVM01) ) Context("SecurityGroup", func() { @@ -151,7 +147,8 @@ var _ = Describe("Azure Cloud Security", func() { Namespace: testAccountNamespacedName.Namespace, }, Spec: crdv1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []crdv1alpha1.VirtualMachineSelector{ { VpcMatch: &crdv1alpha1.EntityMatch{ @@ -243,9 +240,9 @@ var _ = Describe("Azure Cloud Security", func() { vpcPeers[testVnetPeerID01] = [][]string{ {strings.ToLower(testVnetPeerID01), "destinationID", "sourceID"}, } - vmIDToInfoMap := make(map[internal.InstanceID]*virtualMachineTable) + vmInfo := make([]*virtualMachineTable, 0) - vmIDToInfoMap[internal.InstanceID(testVMID01)] = &virtualMachineTable{ + vmInfo = append(vmInfo, &virtualMachineTable{ VnetID: &testVnetPeerID01, NetworkInterfaces: []*networkInterface{ { @@ -254,7 +251,7 @@ var _ = Describe("Azure Cloud Security", func() { }, }, }, - } + }) cloudresource.SetCloudResourcePrefix(config.DefaultCloudResourcePrefix) @@ -263,8 +260,15 @@ var _ = Describe("Azure Cloud Security", func() { vnet.Name = &testVnet01 vnet.ID = &testVnetID01 vnetList = append(vnetList, *vnet) + vmSnapshot := make(map[types.NamespacedName][]*virtualMachineTable) serviceConfig.(*computeServiceConfig).resourcesCache.UpdateSnapshot(&computeResourcesCacheSnapshot{ - vmIDToInfoMap, vnetList, vnetIDs, vpcPeers}) + vmSnapshot, vnetList, vnetIDs, vpcPeers}) + snapshot := serviceConfig.(*computeServiceConfig).resourcesCache.GetSnapshot() + selectorNamespacedName := types.NamespacedName{Namespace: selector.Namespace, Name: selector.Name} + vmSnapshot[selectorNamespacedName] = vmInfo + serviceConfig.(*computeServiceConfig).resourcesCache.UpdateSnapshot( + &computeResourcesCacheSnapshot{vmSnapshot, snapshot.(*computeResourcesCacheSnapshot).vnets, + snapshot.(*computeResourcesCacheSnapshot).managedVnetIDs, snapshot.(*computeResourcesCacheSnapshot).vnetPeers}) }) AfterEach(func() { @@ -609,8 +613,8 @@ var _ = Describe("Azure Cloud Security", func() { testNetworkInterface := networkInterface{ ID: &nItfID, } - vmToUpdateMap := make(map[internal.InstanceID]*virtualMachineTable) - vmToUpdateMap["vm"] = &virtualMachineTable{ + vmToUpdate := make([]*virtualMachineTable, 0) + vmToUpdate = append(vmToUpdate, &virtualMachineTable{ ID: &vmID, Name: &vmName, Tags: tags, @@ -618,13 +622,18 @@ var _ = Describe("Azure Cloud Security", func() { &testNetworkInterface, }, VnetID: &testVnetID03, - } + }) accCfg, _ := c.cloudCommon.GetCloudAccountByName(testAccountNamespacedName) serviceConfig := accCfg.GetServiceConfig() - serviceConfig.(*computeServiceConfig).resourcesCache.UpdateSnapshot(&computeResourcesCacheSnapshot{vmToUpdateMap, nil, nil, nil}) - - serviceConfig.(*computeServiceConfig).GetInternalResourceObjects(testAccountNamespacedName.Namespace, testAccountNamespacedName) + snapshot := serviceConfig.(*computeServiceConfig).resourcesCache.GetSnapshot() + selectorNamespacedName := types.NamespacedName{Namespace: selector.Namespace, Name: selector.Name} + vmSnapshot := snapshot.(*computeResourcesCacheSnapshot).vms + vmSnapshot[selectorNamespacedName] = vmToUpdate + serviceConfig.(*computeServiceConfig).resourcesCache.UpdateSnapshot( + &computeResourcesCacheSnapshot{vmSnapshot, snapshot.(*computeResourcesCacheSnapshot).vnets, + snapshot.(*computeResourcesCacheSnapshot).managedVnetIDs, snapshot.(*computeResourcesCacheSnapshot).vnetPeers}) + serviceConfig.(*computeServiceConfig).getVirtualMachineObjects(testAccountNamespacedName, &selectorNamespacedName) }) }) diff --git a/pkg/cloudprovider/plugins/azure/azure_test.go b/pkg/cloudprovider/plugins/azure/azure_test.go index db084e43..7c8a7687 100644 --- a/pkg/cloudprovider/plugins/azure/azure_test.go +++ b/pkg/cloudprovider/plugins/azure/azure_test.go @@ -131,7 +131,8 @@ var _ = Describe("Azure", func() { Namespace: testSelectorNamespacedName.Namespace, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, }, } mockCtrl = gomock.NewController(GinkgoT()) @@ -187,9 +188,9 @@ var _ = Describe("Azure", func() { errPolAdd := c.DoInventoryPoll(testAccountNamespacedName) Expect(errPolAdd).Should(BeNil()) - vnetMap, err := c.GetVpcInventory(testAccountNamespacedName) + cloudInventory, err := c.GetCloudInventory(testAccountNamespacedName) Expect(err).Should(BeNil()) - Expect(len(vnetMap)).Should(Equal(len(vnetIDs))) + Expect(len(cloudInventory.VpcMap)).Should(Equal(len(vnetIDs))) }) It("StopPoller cloud inventory poll on poller delete", func() { vnetIDs := []string{"testVnetID01", "testVnetID02"} @@ -247,17 +248,14 @@ var _ = Describe("Azure", func() { err := c.AddAccountResourceSelector(testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - filters := getFilters(c, testSelectorNamespacedName.String()) + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedQueryStrs)) c.RemoveAccountResourcesSelector(testAccountNamespacedName, testSelectorNamespacedName) expectedQueryStrs = expectedQueryStrs[:len(expectedQueryStrs)-1] - filters = getFilters(c, testSelectorNamespacedName.String()) + filters = getFilters(c, testSelectorNamespacedName) Expect(len(filters)).To(Equal(len(expectedQueryStrs))) - _, err = c.InstancesGivenProviderAccount(testAccountNamespacedName) - Expect(err).Should(BeNil()) - _ = c.GetEnforcedSecurity() }) @@ -284,12 +282,12 @@ var _ = Describe("Azure", func() { err := c.AddAccountResourceSelector(testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - filters := getFilters(c, testSelectorNamespacedName.String()) + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedQueryStrs)) c.RemoveAccountResourcesSelector(testAccountNamespacedName, testSelectorNamespacedName) expectedQueryStrs = expectedQueryStrs[:len(expectedQueryStrs)-1] - filters = getFilters(c, testSelectorNamespacedName.String()) + filters = getFilters(c, testSelectorNamespacedName) Expect(len(filters)).To(Equal(len(expectedQueryStrs))) }) @@ -310,7 +308,7 @@ var _ = Describe("Azure", func() { err := c.AddAccountResourceSelector(testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - filters := getFilters(c, testSelectorNamespacedName.String()) + filters := getFilters(c, testSelectorNamespacedName) Expect(len(filters)).To(Equal(len(expectedQueryStrs))) }) @@ -332,12 +330,12 @@ var _ = Describe("Azure", func() { err := c.AddAccountResourceSelector(testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - filters := getFilters(c, testSelectorNamespacedName.String()) + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedQueryStrs)) c.RemoveAccountResourcesSelector(testAccountNamespacedName, testSelectorNamespacedName) expectedQueryStrs = expectedQueryStrs[:len(expectedQueryStrs)-1] - filters = getFilters(c, testSelectorNamespacedName.String()) + filters = getFilters(c, testSelectorNamespacedName) Expect(len(filters)).To(Equal(len(expectedQueryStrs))) }) @@ -360,19 +358,19 @@ var _ = Describe("Azure", func() { err := c.AddAccountResourceSelector(testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - filters := getFilters(c, testSelectorNamespacedName.String()) + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedQueryStrs)) c.RemoveAccountResourcesSelector(testAccountNamespacedName, testSelectorNamespacedName) expectedQueryStrs = expectedQueryStrs[:len(expectedQueryStrs)-1] - filters = getFilters(c, testSelectorNamespacedName.String()) + filters = getFilters(c, testSelectorNamespacedName) Expect(len(filters)).To(Equal(len(expectedQueryStrs))) }) It("Should match expected filter - vpcID with VMID match", func() { vnetIDs = []string{testVnetID01} vmIDs = []string{testVMID01} - vmNames := []string{} + var vmNames []string var expectedQueryStrs []*string expectedQueryStr, _ := getVMsByVnetAndOtherMatchesQuery(vnetIDs, vmNames, vmIDs, subIDs, tenantIDs, locations) @@ -390,12 +388,12 @@ var _ = Describe("Azure", func() { err := c.AddAccountResourceSelector(testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - filters := getFilters(c, testSelectorNamespacedName.String()) + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedQueryStrs)) c.RemoveAccountResourcesSelector(testAccountNamespacedName, testSelectorNamespacedName) expectedQueryStrs = expectedQueryStrs[:len(expectedQueryStrs)-1] - filters = getFilters(c, testSelectorNamespacedName.String()) + filters = getFilters(c, testSelectorNamespacedName) Expect(len(filters)).To(Equal(len(expectedQueryStrs))) }) @@ -421,12 +419,12 @@ var _ = Describe("Azure", func() { err := c.AddAccountResourceSelector(testAccountNamespacedName, selector) Expect(err).Should(BeNil()) - filters := getFilters(c, testSelectorNamespacedName.String()) + filters := getFilters(c, testSelectorNamespacedName) Expect(filters).To(Equal(expectedQueryStrs)) c.RemoveAccountResourcesSelector(testAccountNamespacedName, testSelectorNamespacedName) expectedQueryStrs = expectedQueryStrs[:len(expectedQueryStrs)-1] - filters = getFilters(c, testSelectorNamespacedName.String()) + filters = getFilters(c, testSelectorNamespacedName) Expect(len(filters)).To(Equal(len(expectedQueryStrs))) }) @@ -481,10 +479,13 @@ func getResourceGraphResult() resourcegraph.ClientResourcesResponse { return result } -func getFilters(c *azureCloud, selectorNamespacedName string) []*string { +func getFilters(c *azureCloud, selectorNamespacedName *types.NamespacedName) []*string { accCfg, _ := c.cloudCommon.GetCloudAccountByName(&types.NamespacedName{Namespace: "namespace01", Name: "account01"}) - filters := accCfg.GetServiceConfig().(*computeServiceConfig).computeFilters[selectorNamespacedName] - return filters + serviceConfig := accCfg.GetServiceConfig() + if filters, found := serviceConfig.(*computeServiceConfig).computeFilters[*selectorNamespacedName]; found { + return filters + } + return nil } func setupClientAndCloud(mockAzureServiceHelper *MockazureServicesHelper, account *v1alpha1.CloudProviderAccount, secret *corev1.Secret) ( client.WithWatch, *azureCloud) { diff --git a/pkg/cloudprovider/plugins/internal/cloud_common.go b/pkg/cloudprovider/plugins/internal/cloud_common.go index 47837ced..f9cae697 100644 --- a/pkg/cloudprovider/plugins/internal/cloud_common.go +++ b/pkg/cloudprovider/plugins/internal/cloud_common.go @@ -27,6 +27,7 @@ import ( crdv1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" "antrea.io/nephe/pkg/logging" + nephetypes "antrea.io/nephe/pkg/types" ) var ( @@ -56,9 +57,6 @@ type CloudCommonInterface interface { GetCloudAccountByAccountId(accountID *string) (CloudAccountInterface, bool) GetCloudAccounts() map[types.NamespacedName]CloudAccountInterface - GetCloudAccountComputeInternalResourceObjects(namespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.VirtualMachine, - error) - AddCloudAccount(client client.Client, account *crdv1alpha1.CloudProviderAccount, credentials interface{}) error RemoveCloudAccount(namespacedName *types.NamespacedName) @@ -71,7 +69,7 @@ type CloudCommonInterface interface { ResetInventoryCache(accountNamespacedName *types.NamespacedName) error - GetVpcInventory(accountNamespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.Vpc, error) + GetCloudInventory(accountNamespacedName *types.NamespacedName) (*nephetypes.CloudInventory, error) } type cloudCommon struct { @@ -118,7 +116,6 @@ func (c *cloudCommon) AddCloudAccount(client client.Client, account *crdv1alpha1 } c.accountConfigs[*config.GetNamespacedName()] = config - return nil } @@ -167,17 +164,6 @@ func (c *cloudCommon) GetCloudAccounts() map[types.NamespacedName]CloudAccountIn return accountConfigs } -func (c *cloudCommon) GetCloudAccountComputeInternalResourceObjects(accountNamespacedName *types.NamespacedName) ( - map[string]*runtimev1alpha1.VirtualMachine, error) { - accCfg, found := c.GetCloudAccountByName(accountNamespacedName) - if !found { - return nil, fmt.Errorf("unable to find cloud account config") - } - accCfg.LockMutex() - defer accCfg.UnlockMutex() - return accCfg.GetServiceConfig().GetInternalResourceObjects(accCfg.GetNamespacedName().Namespace, accCfg.GetNamespacedName()), nil -} - func (c *cloudCommon) AddResourceFilters(accountNamespacedName *types.NamespacedName, selector *crdv1alpha1.CloudEntitySelector) error { accCfg, found := c.GetCloudAccountByName(accountNamespacedName) if !found { @@ -233,8 +219,8 @@ func (c *cloudCommon) ResetInventoryCache(accountNamespacedName *types.Namespace return nil } -// GetVpcInventory gets a map of vpcs applicable for the account. -func (c *cloudCommon) GetVpcInventory(accountNamespacedName *types.NamespacedName) (map[string]*runtimev1alpha1.Vpc, error) { +// GetCloudInventory gets VPC and VM inventory from plugin snapshot for a given cloud provider account. +func (c *cloudCommon) GetCloudInventory(accountNamespacedName *types.NamespacedName) (*nephetypes.CloudInventory, error) { accCfg, found := c.GetCloudAccountByName(accountNamespacedName) if !found { return nil, fmt.Errorf("unable to find cloud account config") @@ -242,5 +228,5 @@ func (c *cloudCommon) GetVpcInventory(accountNamespacedName *types.NamespacedNam accCfg.LockMutex() defer accCfg.UnlockMutex() - return accCfg.GetServiceConfig().GetVpcInventory(), nil + return accCfg.GetServiceConfig().GetCloudInventory(), nil } diff --git a/pkg/cloudprovider/plugins/internal/services_common.go b/pkg/cloudprovider/plugins/internal/services_common.go index 5a90b3de..0de38230 100644 --- a/pkg/cloudprovider/plugins/internal/services_common.go +++ b/pkg/cloudprovider/plugins/internal/services_common.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/types" crdv1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" - runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" + nephetypes "antrea.io/nephe/pkg/types" ) // CloudServiceInterface needs to be implemented by every cloud-service to be added for a cloud-plugin. @@ -41,12 +41,10 @@ type CloudServiceInterface interface { DoResourceInventory() error // GetInventoryStats returns Inventory statistics for the service. GetInventoryStats() *CloudServiceStats - // GetInternalResourceObjects returns VM instances saved in CloudServiceResourcesCache in terms of runtimev1alpha1.VirtualMachine. - GetInternalResourceObjects(namespace string, accountId *types.NamespacedName) map[string]*runtimev1alpha1.VirtualMachine // ResetInventoryCache clears any internal state built by the service as part of cloud resource discovery. ResetInventoryCache() - // GetVpcInventory copies VPCs stored in internal snapshot(in cloud specific format) to runtimev1alpha1.Vpc format. - GetVpcInventory() map[string]*runtimev1alpha1.Vpc + // GetCloudInventory copies VPCs and VMs stored in internal snapshot(in cloud specific format) to internal format. + GetCloudInventory() *nephetypes.CloudInventory } // CloudServiceResourcesCache is cache used by all services. Each service can maintain diff --git a/pkg/controllers/cloudentityselector/controller.go b/pkg/controllers/cloudentityselector/controller.go index d1822407..3154ea9f 100644 --- a/pkg/controllers/cloudentityselector/controller.go +++ b/pkg/controllers/cloudentityselector/controller.go @@ -128,8 +128,13 @@ func (r *CloudEntitySelectorReconciler) processCreateOrUpdate(selector *crdv1alp selectorNamespacedName *types.NamespacedName) error { r.Log.Info("Received request", "selector", selectorNamespacedName, "operation", "create/update") + var accountNamespace = selector.Spec.AccountNamespace + // For upgrade purpose, use selector namespace as account namespace when not available, remove later. + if accountNamespace == "" { + accountNamespace = selector.Namespace + } accountNamespacedName := &types.NamespacedName{ - Namespace: selector.Namespace, + Namespace: accountNamespace, Name: selector.Spec.AccountName, } r.selectorToAccountMap[*selectorNamespacedName] = *accountNamespacedName diff --git a/pkg/controllers/cloudentityselector/controller_test.go b/pkg/controllers/cloudentityselector/controller_test.go index 8778e216..ed232374 100644 --- a/pkg/controllers/cloudentityselector/controller_test.go +++ b/pkg/controllers/cloudentityselector/controller_test.go @@ -61,11 +61,12 @@ func TestCloud(t *testing.T) { var _ = Describe("CloudEntitySelector Controller", func() { Context("CES workflow", func() { var ( - testAccountNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "account01"} - testSelectorNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "selector01"} - selector *crdv1alpha1.CloudEntitySelector - reconciler *CloudEntitySelectorReconciler - fakeClient client.WithWatch + testAccountNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "account01"} + testSelectorNamespacedName = types.NamespacedName{Namespace: "namespace01", Name: "selector01"} + testSelectorDifferentNamespace = types.NamespacedName{Namespace: "namespace02", Name: "selector02"} + selector *crdv1alpha1.CloudEntitySelector + reconciler *CloudEntitySelectorReconciler + fakeClient client.WithWatch ) BeforeEach(func() { newScheme := runtime.NewScheme() @@ -87,16 +88,10 @@ var _ = Describe("CloudEntitySelector Controller", func() { ObjectMeta: v1.ObjectMeta{ Name: testSelectorNamespacedName.Name, Namespace: testSelectorNamespacedName.Namespace, - OwnerReferences: []v1.OwnerReference{ - { - APIVersion: "crd.cloud.antrea.io/crdv1alpha1", - Kind: "CloudProviderAccount", - Name: testAccountNamespacedName.Name, - }, - }, }, Spec: crdv1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountNamespacedName.Name, + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, VMSelector: []crdv1alpha1.VirtualMachineSelector{ { VpcMatch: &crdv1alpha1.EntityMatch{ @@ -119,6 +114,34 @@ var _ = Describe("CloudEntitySelector Controller", func() { err = reconciler.processDelete(&testSelectorNamespacedName) Expect(err).ShouldNot(HaveOccurred()) }) + It("CES Add and Delete when CES and CPA are in different namespace", func() { + selector = &crdv1alpha1.CloudEntitySelector{ + ObjectMeta: v1.ObjectMeta{ + Name: testSelectorDifferentNamespace.Name, + Namespace: testSelectorDifferentNamespace.Namespace, + }, + Spec: crdv1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []crdv1alpha1.VirtualMachineSelector{ + { + VpcMatch: &crdv1alpha1.EntityMatch{ + MatchID: "xyz", + }, + }, + }, + }, + } + + mockAccManager.EXPECT().AddResourceFiltersToAccount(&testAccountNamespacedName, &testSelectorDifferentNamespace, + selector, false).Return(true, nil).Times(1) + mockAccManager.EXPECT().RemoveResourceFiltersFromAccount(&testAccountNamespacedName, + &testSelectorDifferentNamespace).Return(nil).Times(1) + err := reconciler.processCreateOrUpdate(selector, &testSelectorDifferentNamespace) + Expect(err).ShouldNot(HaveOccurred()) + err = reconciler.processDelete(&testSelectorDifferentNamespace) + Expect(err).ShouldNot(HaveOccurred()) + }) It("CES Add failure without retry", func() { mockAccManager.EXPECT().AddResourceFiltersToAccount(&testAccountNamespacedName, &testSelectorNamespacedName, selector, false).Return(false, fmt.Errorf("dummy")).Times(1) diff --git a/pkg/controllers/cloudprovideraccount/controller.go b/pkg/controllers/cloudprovideraccount/controller.go index f9532350..28fb65b3 100644 --- a/pkg/controllers/cloudprovideraccount/controller.go +++ b/pkg/controllers/cloudprovideraccount/controller.go @@ -142,8 +142,8 @@ func (r *CloudProviderAccountReconciler) processCreateOrUpdate(namespacedName *t return fmt.Errorf("failed to add or update account: %v", err) } - retry, err := r.AccManager.AddAccount(namespacedName, accountCloudType, account) - if err != nil && retry { + retryAdd, err := r.AccManager.AddAccount(namespacedName, accountCloudType, account) + if err != nil && retryAdd { return err } r.updateStatus(namespacedName, err) @@ -151,7 +151,24 @@ func (r *CloudProviderAccountReconciler) processCreateOrUpdate(namespacedName *t } func (r *CloudProviderAccountReconciler) processDelete(namespacedName *types.NamespacedName) error { - return r.AccManager.RemoveAccount(namespacedName) + if err := r.AccManager.RemoveAccount(namespacedName); err != nil { + return err + } + + // Delete dependent CES. + cesList := &crdv1alpha1.CloudEntitySelectorList{} + if err := r.Client.List(context.TODO(), cesList, &client.ListOptions{}); err != nil { + return err + } + for _, ces := range cesList.Items { + if ces.Spec.AccountName == namespacedName.Name && ces.Spec.AccountNamespace == namespacedName.Namespace { + r.Log.Info("Deleting selector", "selector", types.NamespacedName{Namespace: ces.Namespace, Name: ces.Name}) + if err := r.Client.Delete(context.TODO(), &ces); err != nil { + return fmt.Errorf("failed to delete selector %v/%v err %v", ces.Namespace, ces.Name, err) + } + } + } + return nil } // updatePendingSyncCountAndStatus decrements the pendingSyncCount and when diff --git a/pkg/controllers/cloudprovideraccount/controller_test.go b/pkg/controllers/cloudprovideraccount/controller_test.go index 4379fd31..48734004 100644 --- a/pkg/controllers/cloudprovideraccount/controller_test.go +++ b/pkg/controllers/cloudprovideraccount/controller_test.go @@ -144,6 +144,26 @@ var _ = Describe("CloudProviderAccount Controller", func() { mockAccManager.EXPECT().RemoveAccount(&testAccountNamespacedName).Return(nil).Times(1) err = reconciler.processCreateOrUpdate(&testAccountNamespacedName, account) Expect(err).ShouldNot(HaveOccurred()) + + selector := &v1alpha1.CloudEntitySelector{ + ObjectMeta: v1.ObjectMeta{ + Name: "selector01", + Namespace: testSecretNamespacedName.Namespace, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountNamespacedName.Name, + AccountNamespace: testAccountNamespacedName.Namespace, + VMSelector: []v1alpha1.VirtualMachineSelector{ + { + VpcMatch: &v1alpha1.EntityMatch{ + MatchID: "xyzq", + }, + }, + }, + }, + } + _ = fakeClient.Create(context.Background(), selector) + err = reconciler.processDelete(&testAccountNamespacedName) Expect(err).ShouldNot(HaveOccurred()) }) diff --git a/pkg/inventory/indexer/indexer.go b/pkg/inventory/indexer/indexer.go index 86134cd8..52eb9b2f 100644 --- a/pkg/inventory/indexer/indexer.go +++ b/pkg/inventory/indexer/indexer.go @@ -20,6 +20,7 @@ const ( VpcByNamespacedAccountName = "namespace-cloud-account-name" - VirtualMachineByCloudId = "cloud-assigned-id" - VirtualMachineByNamespacedAccountName = "namespaced-cloud-account-name" + VirtualMachineByCloudId = "cloud-assigned-id" + VirtualMachineByAccountNamespacedName = "namespaced-cloud-account-name" + VirtualMachineBySelectorNamespacedName = "namespaced-cloud-selector-name" ) diff --git a/pkg/inventory/interfaces.go b/pkg/inventory/interfaces.go index 3f186da7..4f544f5a 100644 --- a/pkg/inventory/interfaces.go +++ b/pkg/inventory/interfaces.go @@ -49,10 +49,14 @@ type VPCStore interface { type VMStore interface { // BuildVmCache builds the vm cache using discoveredVmMap. - BuildVmCache(discoveredVmMap map[string]*runtimev1alpha1.VirtualMachine, namespacedName *types.NamespacedName) + BuildVmCache(discoveredVmMap map[string]*runtimev1alpha1.VirtualMachine, accountNamespacedName *types.NamespacedName, + selectorNamespacedName *types.NamespacedName) - // DeleteVmsFromCache deletes all vms from the cache. - DeleteVmsFromCache(namespacedName *types.NamespacedName) error + // DeleteAllVmsFromCache deletes all vms from the cache for a given account. + DeleteAllVmsFromCache(accountNamespacedName *types.NamespacedName) error + + // DeleteVmsFromCache deletes all vms from the cache for a given selector. + DeleteVmsFromCache(accountNamespacedName *types.NamespacedName, selectorNamespacedName *types.NamespacedName) error // GetVmFromIndexer gets all vms from the cache that have a matching index value. GetVmFromIndexer(indexName string, indexedValue string) ([]interface{}, error) diff --git a/pkg/inventory/inventory.go b/pkg/inventory/inventory.go index f70fa1a9..e19aae00 100644 --- a/pkg/inventory/inventory.go +++ b/pkg/inventory/inventory.go @@ -60,7 +60,10 @@ func (i *Inventory) BuildVpcCache(discoveredVpcMap map[string]*runtimev1alpha1.V // Remove vpcs in vpc cache which are not found in vpc list fetched from cloud. for _, object := range vpcsInCache { - vpc := object.(*runtimev1alpha1.Vpc) + vpc, ok := object.(*runtimev1alpha1.Vpc) + if !ok { + continue + } if _, found := discoveredVpcMap[vpc.Status.CloudId]; !found { if err := i.vpcStore.Delete(fmt.Sprintf("%v/%v-%v", vpc.Namespace, vpc.Labels[nephelabels.CloudAccountName], vpc.Status.CloudId)); err != nil { @@ -112,7 +115,10 @@ func (i *Inventory) DeleteVpcsFromCache(namespacedName *types.NamespacedName) er } var numVpcsToDelete int for _, object := range vpcsInCache { - vpc := object.(*runtimev1alpha1.Vpc) + vpc, ok := object.(*runtimev1alpha1.Vpc) + if !ok { + continue + } key := fmt.Sprintf("%v/%v-%v", vpc.Namespace, vpc.Labels[nephelabels.CloudAccountName], vpc.Status.CloudId) if err := i.vpcStore.Delete(key); err != nil { i.log.Error(err, "failed to delete vpc from vpc cache, account: %v", *namespacedName) @@ -144,20 +150,23 @@ func (i *Inventory) WatchVpcs(ctx context.Context, key string, labelSelector lab } // BuildVmCache builds vm cache for given account using vm list fetched from cloud. -func (i *Inventory) BuildVmCache(discoveredVmMap map[string]*runtimev1alpha1.VirtualMachine, - namespacedName *types.NamespacedName) { +func (i *Inventory) BuildVmCache(discoveredVmMap map[string]*runtimev1alpha1.VirtualMachine, accountNamespacedName *types.NamespacedName, + selectorNamespacedName *types.NamespacedName) { var numVmsToAdd, numVmsToUpdate, numVmsToDelete int - // Fetch all vms for a given account from the cache and check if it exists in the discovered vm list. - vmsInCache, _ := i.vmStore.GetByIndex(indexer.VirtualMachineByNamespacedAccountName, namespacedName.String()) + // Fetch all vms specific to a selector from the inventory cache and check if it exists in the discovered vm list. + vmsInCache, _ := i.vmStore.GetByIndex(indexer.VirtualMachineBySelectorNamespacedName, selectorNamespacedName.String()) // Remove vm from vm cache which are not found in vm map fetched from cloud. for _, cachedObject := range vmsInCache { - cachedVm := cachedObject.(*runtimev1alpha1.VirtualMachine) + cachedVm, ok := cachedObject.(*runtimev1alpha1.VirtualMachine) + if !ok { + continue + } if _, found := discoveredVmMap[cachedVm.Name]; !found { key := fmt.Sprintf("%v/%v", cachedVm.Namespace, cachedVm.Name) if err := i.vmStore.Delete(key); err != nil { - i.log.Error(err, "failed to delete vm from vm cache", "vm", cachedVm.Name, "account", - namespacedName.String()) + i.log.Error(err, "failed to delete vm from vm cache, account: %v, selector: %v, vm: %v", + *accountNamespacedName, *selectorNamespacedName, cachedVm.Name) } else { numVmsToDelete++ } @@ -192,35 +201,67 @@ func (i *Inventory) BuildVmCache(discoveredVmMap map[string]*runtimev1alpha1.Vir } if err != nil { i.log.Error(err, "failed to update vm in vm cache", "vm", discoveredVm.Name, - "account", namespacedName.String()) + "account", accountNamespacedName, "selector", selectorNamespacedName) } } if numVmsToAdd != 0 || numVmsToUpdate != 0 || numVmsToDelete != 0 { - i.log.Info("Vm poll statistics", "account", namespacedName, "added", numVmsToAdd, - "update", numVmsToUpdate, "delete", numVmsToDelete) + i.log.Info("Vm poll statistics", "account", accountNamespacedName, "selector", selectorNamespacedName, + "added", numVmsToAdd, "update", numVmsToUpdate, "delete", numVmsToDelete) } } -// DeleteVmsFromCache deletes all entries from vm cache for a given account. -func (i *Inventory) DeleteVmsFromCache(namespacedName *types.NamespacedName) error { - vmsInCache, err := i.vmStore.GetByIndex(indexer.VirtualMachineByNamespacedAccountName, namespacedName.String()) +// DeleteAllVmsFromCache deletes all entries from vm cache for a given account. +func (i *Inventory) DeleteAllVmsFromCache(accountNamespacedName *types.NamespacedName) error { + vmsInCache, err := i.vmStore.GetByIndex(indexer.VirtualMachineByAccountNamespacedName, accountNamespacedName.String()) if err != nil { return err } var numVmsToDelete int for _, cachedObject := range vmsInCache { - cachedVm := cachedObject.(*runtimev1alpha1.VirtualMachine) + cachedVm, ok := cachedObject.(*runtimev1alpha1.VirtualMachine) + if !ok { + continue + } + key := fmt.Sprintf("%v/%v", cachedVm.Namespace, cachedVm.Name) + if err := i.vmStore.Delete(key); err != nil { + i.log.Error(err, "failed to delete vm from vm cache, account: %v, vm: %v", *accountNamespacedName, cachedVm.Name) + } else { + numVmsToDelete++ + } + } + + if numVmsToDelete != 0 { + i.log.Info("Vm poll statistics", "account", accountNamespacedName, "deleted", numVmsToDelete) + } + return nil +} + +// DeleteVmsFromCache deletes all entries from vm cache for a given selector. +func (i *Inventory) DeleteVmsFromCache(accountNamespacedName *types.NamespacedName, + selectorNamespacedName *types.NamespacedName) error { + vmsInCache, err := i.vmStore.GetByIndex(indexer.VirtualMachineBySelectorNamespacedName, selectorNamespacedName.String()) + if err != nil { + return err + } + var numVmsToDelete int + for _, cachedObject := range vmsInCache { + cachedVm, ok := cachedObject.(*runtimev1alpha1.VirtualMachine) + if !ok { + continue + } key := fmt.Sprintf("%v/%v", cachedVm.Namespace, cachedVm.Name) if err := i.vmStore.Delete(key); err != nil { - i.log.Error(err, "failed to delete vm from vm cache, account: %v vm: %v", *namespacedName, cachedVm.Name) + i.log.Error(err, "failed to delete vm from vm cache, account: %v, selector: %v, vm: %v", + *accountNamespacedName, *selectorNamespacedName, cachedVm.Name) } else { numVmsToDelete++ } } if numVmsToDelete != 0 { - i.log.Info("Vm poll statistics", "account", namespacedName, "deleted", numVmsToDelete) + i.log.Info("Vm poll statistics", "account", accountNamespacedName, + "selector", selectorNamespacedName, "deleted", numVmsToDelete) } return nil } diff --git a/pkg/inventory/inventory_test.go b/pkg/inventory/inventory_test.go index 8c127fe7..d4e1044f 100644 --- a/pkg/inventory/inventory_test.go +++ b/pkg/inventory/inventory_test.go @@ -33,24 +33,27 @@ func TestInventory(t *testing.T) { } var ( - testVpcID01 = "testVpcID01" - testVpcName01 = "testVpcName01" - testVpcID02 = "testVpcID02" - testVpcName02 = "testVpcName02" - namespace = "testNS" - accountName = "account01" - namespacedAccountName = types.NamespacedName{Namespace: namespace, Name: accountName} - vpcCacheKey1 = fmt.Sprintf("%s-%s", namespacedAccountName, testVpcID01) - testVmID01 = "testVmID01" - testVmName01 = "testVmName01" - testVmID02 = "testVmID02" - vmCacheKey1 = fmt.Sprintf("%s/%s", namespace, testVmID01) - vmCacheKey2 = fmt.Sprintf("%s/%s", namespace, testVmID02) - networkInterfaceID = "networkInterface01" - macAddress = "00-01-02-03-04-05" - ipAddress = "10.10.10.10" - ipAddressCRDs []runtimev1alpha1.IPAddress - cloudInventory *Inventory + testVpcID01 = "testVpcID01" + testVpcName01 = "testVpcName01" + testVpcID02 = "testVpcID02" + testVpcName02 = "testVpcName02" + namespace = "testNS" + accountName = "account01" + selectorNS = "selectorNS" + namespacedAccountName = types.NamespacedName{Namespace: namespace, Name: accountName} + selectorName = "selector01" + selectorNamespacedName = types.NamespacedName{Namespace: selectorNS, Name: selectorName} + vpcCacheKey1 = fmt.Sprintf("%s-%s", namespacedAccountName, testVpcID01) + testVmID01 = "testVmID01" + testVmName01 = "testVmName01" + testVmID02 = "testVmID02" + vmCacheKey1 = fmt.Sprintf("%s/%s", selectorNS, testVmID01) + vmCacheKey2 = fmt.Sprintf("%s/%s", selectorNS, testVmID02) + networkInterfaceID = "networkInterface01" + macAddress = "00-01-02-03-04-05" + ipAddress = "10.10.10.10" + ipAddressCRDs []runtimev1alpha1.IPAddress + cloudInventory *Inventory ) var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { @@ -130,11 +133,13 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { }) Context("VM Inventory Test", func() { vmLabelsMap := map[string]string{ - labels.CloudAccountName: namespacedAccountName.Name, - labels.CloudAccountNamespace: namespacedAccountName.Namespace, - labels.CloudVmUID: testVmID01, - labels.CloudVpcUID: testVpcID01, - labels.VpcName: testVpcName01, + labels.CloudSelectorName: selectorNamespacedName.Name, + labels.CloudSelectorNamespace: selectorNamespacedName.Namespace, + labels.CloudAccountName: namespacedAccountName.Name, + labels.CloudAccountNamespace: namespacedAccountName.Namespace, + labels.CloudVmUID: testVmID01, + labels.CloudVpcUID: testVpcID01, + labels.VpcName: testVpcName01, } ipAddressCRD := runtimev1alpha1.IPAddress{ @@ -168,18 +173,18 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { vmList := make(map[string]*runtimev1alpha1.VirtualMachine) vmObj := new(runtimev1alpha1.VirtualMachine) vmObj.Name = testVmID01 - vmObj.Namespace = namespace + vmObj.Namespace = selectorNS vmObj.Labels = vmLabelsMap vmObj.Status = *vmStatus vmList[testVmID01] = vmObj It("Add VMs to VM inventory", func() { - cloudInventory.BuildVmCache(vmList, &namespacedAccountName) + cloudInventory.BuildVmCache(vmList, &namespacedAccountName, &selectorNamespacedName) allVmList := cloudInventory.GetAllVms() Expect(allVmList).Should(HaveLen(len(vmList))) - vmListByIndex, err := cloudInventory.GetVmFromIndexer(indexer.VirtualMachineByNamespacedAccountName, - namespacedAccountName.String()) + vmListByIndex, err := cloudInventory.GetVmFromIndexer(indexer.VirtualMachineBySelectorNamespacedName, + selectorNamespacedName.String()) Expect(err).ShouldNot(HaveOccurred()) Expect(vmListByIndex).Should(HaveLen(len(vmList))) for _, i := range vmListByIndex { @@ -188,10 +193,10 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { } }) It("Delete a VM from VM inventory", func() { - cloudInventory.BuildVmCache(vmList, &namespacedAccountName) + cloudInventory.BuildVmCache(vmList, &namespacedAccountName, &selectorNamespacedName) - vmListByIndex, err := cloudInventory.GetVmFromIndexer(indexer.VirtualMachineByNamespacedAccountName, - namespacedAccountName.String()) + vmListByIndex, err := cloudInventory.GetVmFromIndexer(indexer.VirtualMachineBySelectorNamespacedName, + selectorNamespacedName.String()) Expect(err).ShouldNot(HaveOccurred()) Expect(vmListByIndex).Should(HaveLen(len(vmList))) for _, i := range vmListByIndex { @@ -203,11 +208,11 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { vmList2 := make(map[string]*runtimev1alpha1.VirtualMachine) vmObj := new(runtimev1alpha1.VirtualMachine) vmObj.Name = testVmID02 - vmObj.Namespace = namespace + vmObj.Namespace = selectorNS vmObj.Labels = vmLabelsMap vmObj.Status = *vmStatus vmList2[testVmID02] = vmObj - cloudInventory.BuildVmCache(vmList2, &namespacedAccountName) + cloudInventory.BuildVmCache(vmList2, &namespacedAccountName, &selectorNamespacedName) _, exist := cloudInventory.GetVmByKey(vmCacheKey2) Expect(exist).Should(BeTrue()) @@ -216,7 +221,7 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { Expect(exist).Should(BeFalse()) }) It("Update Agented field in Status and add to VM inventory", func() { - cloudInventory.BuildVmCache(vmList, &namespacedAccountName) + cloudInventory.BuildVmCache(vmList, &namespacedAccountName, &selectorNamespacedName) vm, exist := cloudInventory.GetVmByKey(vmCacheKey1) Expect(exist).Should(BeTrue()) @@ -233,11 +238,11 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { vmListUpdate := make(map[string]*runtimev1alpha1.VirtualMachine) vmObjUpdate := new(runtimev1alpha1.VirtualMachine) vmObjUpdate.Name = testVmID01 - vmObjUpdate.Namespace = namespace + vmObjUpdate.Namespace = selectorNS vmObjUpdate.Labels = vmLabelsMap vmObjUpdate.Status = *vmStatusUpdate vmListUpdate[testVmID01] = vmObjUpdate - cloudInventory.BuildVmCache(vmListUpdate, &namespacedAccountName) + cloudInventory.BuildVmCache(vmListUpdate, &namespacedAccountName, &selectorNamespacedName) // Vm object should be updated the latest Status field. vm, exist = cloudInventory.GetVmByKey(vmCacheKey1) @@ -245,7 +250,7 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { Expect(vm.Status.Agented).To(BeTrue()) }) It("Update State field in Status and add to VM inventory", func() { - cloudInventory.BuildVmCache(vmList, &namespacedAccountName) + cloudInventory.BuildVmCache(vmList, &namespacedAccountName, &selectorNamespacedName) vm, exist := cloudInventory.GetVmByKey(vmCacheKey1) Expect(exist).Should(BeTrue()) @@ -262,11 +267,11 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { vmListUpdate := make(map[string]*runtimev1alpha1.VirtualMachine) vmObjUpdate := new(runtimev1alpha1.VirtualMachine) vmObjUpdate.Name = testVmID01 - vmObjUpdate.Namespace = namespace + vmObjUpdate.Namespace = selectorNS vmObjUpdate.Labels = vmLabelsMap vmObjUpdate.Status = *vmStatusUpdate vmListUpdate[testVmID01] = vmObjUpdate - cloudInventory.BuildVmCache(vmListUpdate, &namespacedAccountName) + cloudInventory.BuildVmCache(vmListUpdate, &namespacedAccountName, &namespacedAccountName) // Vm object should be updated with the latest Status field. vm, exist = cloudInventory.GetVmByKey(vmCacheKey1) @@ -274,18 +279,31 @@ var _ = Describe("Validate VPC and Virtual Machine Inventory", func() { Expect(vm.Status.State).To(Equal(runtimev1alpha1.Stopped)) }) It("Delete VM inventory", func() { - cloudInventory.BuildVmCache(vmList, &namespacedAccountName) + cloudInventory.BuildVmCache(vmList, &namespacedAccountName, &selectorNamespacedName) - vmListByIndex, err := cloudInventory.GetVmFromIndexer(indexer.VirtualMachineByNamespacedAccountName, - namespacedAccountName.String()) + vmListByIndex, err := cloudInventory.GetVmFromIndexer(indexer.VirtualMachineBySelectorNamespacedName, + selectorNamespacedName.String()) Expect(err).ShouldNot(HaveOccurred()) Expect(vmListByIndex).Should(HaveLen(len(vmList))) // Delete vm cache. - err = cloudInventory.DeleteVmsFromCache(&namespacedAccountName) + err = cloudInventory.DeleteVmsFromCache(&namespacedAccountName, &selectorNamespacedName) Expect(err).ShouldNot(HaveOccurred()) _, exist := cloudInventory.GetVmByKey(vmCacheKey1) Expect(exist).Should(BeFalse()) + + // Add vm inventory again and delete vm inventory using account namespaced name. + cloudInventory.BuildVmCache(vmList, &namespacedAccountName, &selectorNamespacedName) + vmListByIndex, err = cloudInventory.GetVmFromIndexer(indexer.VirtualMachineBySelectorNamespacedName, + selectorNamespacedName.String()) + Expect(err).ShouldNot(HaveOccurred()) + Expect(vmListByIndex).Should(HaveLen(len(vmList))) + + // Delete vm cache. + err = cloudInventory.DeleteAllVmsFromCache(&namespacedAccountName) + Expect(err).ShouldNot(HaveOccurred()) + _, exist = cloudInventory.GetVmByKey(vmCacheKey1) + Expect(exist).Should(BeFalse()) }) }) }) diff --git a/pkg/inventory/store/vm_inventory.go b/pkg/inventory/store/vm_inventory.go index 02418b64..fa2a141b 100644 --- a/pkg/inventory/store/vm_inventory.go +++ b/pkg/inventory/store/vm_inventory.go @@ -147,7 +147,7 @@ func NewVmInventoryStore() antreastorage.Interface { vm := obj.(*runtimev1alpha1.VirtualMachine) return []string{vm.Namespace + "/" + vm.Name}, nil }, - indexer.VirtualMachineByNamespacedAccountName: func(obj interface{}) ([]string, error) { + indexer.VirtualMachineByAccountNamespacedName: func(obj interface{}) ([]string, error) { vm := obj.(*runtimev1alpha1.VirtualMachine) return []string{vm.Labels[nephelabels.CloudAccountNamespace] + "/" + vm.Labels[nephelabels.CloudAccountName]}, nil @@ -156,6 +156,11 @@ func NewVmInventoryStore() antreastorage.Interface { vm := obj.(*runtimev1alpha1.VirtualMachine) return []string{vm.Status.CloudId}, nil }, + indexer.VirtualMachineBySelectorNamespacedName: func(obj interface{}) ([]string, error) { + vm := obj.(*runtimev1alpha1.VirtualMachine) + return []string{vm.Labels[nephelabels.CloudSelectorNamespace] + "/" + + vm.Labels[nephelabels.CloudSelectorName]}, nil + }, } return ram.NewStore(vmKeyFunc, indexers, genVmEvent, keyAndSpanSelectFuncVm, func() runtime.Object { return new(runtimev1alpha1.VirtualMachine) }) diff --git a/pkg/labels/labels.go b/pkg/labels/labels.go index 63ba3ab6..ceedf228 100644 --- a/pkg/labels/labels.go +++ b/pkg/labels/labels.go @@ -33,9 +33,11 @@ const ( ) const ( - CloudAccountName = LabelPrefixNephe + "cpa-name" - CloudAccountNamespace = LabelPrefixNephe + "cpa-namespace" - VpcName = LabelPrefixNephe + "vpc-name" - CloudVpcUID = LabelPrefixNephe + "cloud-vpc-uid" - CloudVmUID = LabelPrefixNephe + "cloud-vm-uid" + CloudAccountName = LabelPrefixNephe + "cpa-name" + CloudAccountNamespace = LabelPrefixNephe + "cpa-namespace" + CloudSelectorName = LabelPrefixNephe + "ces-name" + CloudSelectorNamespace = LabelPrefixNephe + "ces-namespace" + VpcName = LabelPrefixNephe + "vpc-name" + CloudVpcUID = LabelPrefixNephe + "cloud-vpc-uid" + CloudVmUID = LabelPrefixNephe + "cloud-vm-uid" ) diff --git a/pkg/testing/cloud/mock.go b/pkg/testing/cloud/mock.go index 65220288..31e1bc0d 100644 --- a/pkg/testing/cloud/mock.go +++ b/pkg/testing/cloud/mock.go @@ -25,8 +25,9 @@ import ( v1alpha1 "antrea.io/nephe/apis/crd/v1alpha1" v1alpha10 "antrea.io/nephe/apis/runtime/v1alpha1" cloudresource "antrea.io/nephe/pkg/cloudprovider/cloudresource" + types "antrea.io/nephe/pkg/types" gomock "github.com/golang/mock/gomock" - types "k8s.io/apimachinery/pkg/types" + types0 "k8s.io/apimachinery/pkg/types" client "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -54,7 +55,7 @@ func (m *MockCloudInterface) EXPECT() *MockCloudInterfaceMockRecorder { } // AddAccountResourceSelector mocks base method. -func (m *MockCloudInterface) AddAccountResourceSelector(arg0 *types.NamespacedName, arg1 *v1alpha1.CloudEntitySelector) error { +func (m *MockCloudInterface) AddAccountResourceSelector(arg0 *types0.NamespacedName, arg1 *v1alpha1.CloudEntitySelector) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddAccountResourceSelector", arg0, arg1) ret0, _ := ret[0].(error) @@ -111,7 +112,7 @@ func (mr *MockCloudInterfaceMockRecorder) DeleteSecurityGroup(arg0, arg1 interfa } // DoInventoryPoll mocks base method. -func (m *MockCloudInterface) DoInventoryPoll(arg0 *types.NamespacedName) error { +func (m *MockCloudInterface) DoInventoryPoll(arg0 *types0.NamespacedName) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DoInventoryPoll", arg0) ret0, _ := ret[0].(error) @@ -125,7 +126,7 @@ func (mr *MockCloudInterfaceMockRecorder) DoInventoryPoll(arg0 interface{}) *gom } // GetAccountStatus mocks base method. -func (m *MockCloudInterface) GetAccountStatus(arg0 *types.NamespacedName) (*v1alpha1.CloudProviderAccountStatus, error) { +func (m *MockCloudInterface) GetAccountStatus(arg0 *types0.NamespacedName) (*v1alpha1.CloudProviderAccountStatus, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAccountStatus", arg0) ret0, _ := ret[0].(*v1alpha1.CloudProviderAccountStatus) @@ -139,48 +140,33 @@ func (mr *MockCloudInterfaceMockRecorder) GetAccountStatus(arg0 interface{}) *go return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAccountStatus", reflect.TypeOf((*MockCloudInterface)(nil).GetAccountStatus), arg0) } -// GetEnforcedSecurity mocks base method. -func (m *MockCloudInterface) GetEnforcedSecurity() []cloudresource.SynchronizationContent { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetEnforcedSecurity") - ret0, _ := ret[0].([]cloudresource.SynchronizationContent) - return ret0 -} - -// GetEnforcedSecurity indicates an expected call of GetEnforcedSecurity. -func (mr *MockCloudInterfaceMockRecorder) GetEnforcedSecurity() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnforcedSecurity", reflect.TypeOf((*MockCloudInterface)(nil).GetEnforcedSecurity)) -} - -// GetVpcInventory mocks base method. -func (m *MockCloudInterface) GetVpcInventory(arg0 *types.NamespacedName) (map[string]*v1alpha10.Vpc, error) { +// GetCloudInventory mocks base method. +func (m *MockCloudInterface) GetCloudInventory(arg0 *types0.NamespacedName) (*types.CloudInventory, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetVpcInventory", arg0) - ret0, _ := ret[0].(map[string]*v1alpha10.Vpc) + ret := m.ctrl.Call(m, "GetCloudInventory", arg0) + ret0, _ := ret[0].(*types.CloudInventory) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetVpcInventory indicates an expected call of GetVpcInventory. -func (mr *MockCloudInterfaceMockRecorder) GetVpcInventory(arg0 interface{}) *gomock.Call { +// GetCloudInventory indicates an expected call of GetCloudInventory. +func (mr *MockCloudInterfaceMockRecorder) GetCloudInventory(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVpcInventory", reflect.TypeOf((*MockCloudInterface)(nil).GetVpcInventory), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCloudInventory", reflect.TypeOf((*MockCloudInterface)(nil).GetCloudInventory), arg0) } -// InstancesGivenProviderAccount mocks base method. -func (m *MockCloudInterface) InstancesGivenProviderAccount(arg0 *types.NamespacedName) (map[string]*v1alpha10.VirtualMachine, error) { +// GetEnforcedSecurity mocks base method. +func (m *MockCloudInterface) GetEnforcedSecurity() []cloudresource.SynchronizationContent { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstancesGivenProviderAccount", arg0) - ret0, _ := ret[0].(map[string]*v1alpha10.VirtualMachine) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret := m.ctrl.Call(m, "GetEnforcedSecurity") + ret0, _ := ret[0].([]cloudresource.SynchronizationContent) + return ret0 } -// InstancesGivenProviderAccount indicates an expected call of InstancesGivenProviderAccount. -func (mr *MockCloudInterfaceMockRecorder) InstancesGivenProviderAccount(arg0 interface{}) *gomock.Call { +// GetEnforcedSecurity indicates an expected call of GetEnforcedSecurity. +func (mr *MockCloudInterfaceMockRecorder) GetEnforcedSecurity() *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstancesGivenProviderAccount", reflect.TypeOf((*MockCloudInterface)(nil).InstancesGivenProviderAccount), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetEnforcedSecurity", reflect.TypeOf((*MockCloudInterface)(nil).GetEnforcedSecurity)) } // ProviderType mocks base method. @@ -198,7 +184,7 @@ func (mr *MockCloudInterfaceMockRecorder) ProviderType() *gomock.Call { } // RemoveAccountResourcesSelector mocks base method. -func (m *MockCloudInterface) RemoveAccountResourcesSelector(arg0, arg1 *types.NamespacedName) { +func (m *MockCloudInterface) RemoveAccountResourcesSelector(arg0, arg1 *types0.NamespacedName) { m.ctrl.T.Helper() m.ctrl.Call(m, "RemoveAccountResourcesSelector", arg0, arg1) } @@ -210,7 +196,7 @@ func (mr *MockCloudInterfaceMockRecorder) RemoveAccountResourcesSelector(arg0, a } // RemoveProviderAccount mocks base method. -func (m *MockCloudInterface) RemoveProviderAccount(arg0 *types.NamespacedName) { +func (m *MockCloudInterface) RemoveProviderAccount(arg0 *types0.NamespacedName) { m.ctrl.T.Helper() m.ctrl.Call(m, "RemoveProviderAccount", arg0) } @@ -222,7 +208,7 @@ func (mr *MockCloudInterfaceMockRecorder) RemoveProviderAccount(arg0 interface{} } // ResetInventoryCache mocks base method. -func (m *MockCloudInterface) ResetInventoryCache(arg0 *types.NamespacedName) error { +func (m *MockCloudInterface) ResetInventoryCache(arg0 *types0.NamespacedName) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ResetInventoryCache", arg0) ret0, _ := ret[0].(error) diff --git a/pkg/testing/inventory/mock.go b/pkg/testing/inventory/mock.go index d396b201..133555b8 100644 --- a/pkg/testing/inventory/mock.go +++ b/pkg/testing/inventory/mock.go @@ -55,15 +55,15 @@ func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder { } // BuildVmCache mocks base method. -func (m *MockInterface) BuildVmCache(arg0 map[string]*v1alpha1.VirtualMachine, arg1 *types.NamespacedName) { +func (m *MockInterface) BuildVmCache(arg0 map[string]*v1alpha1.VirtualMachine, arg1, arg2 *types.NamespacedName) { m.ctrl.T.Helper() - m.ctrl.Call(m, "BuildVmCache", arg0, arg1) + m.ctrl.Call(m, "BuildVmCache", arg0, arg1, arg2) } // BuildVmCache indicates an expected call of BuildVmCache. -func (mr *MockInterfaceMockRecorder) BuildVmCache(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockInterfaceMockRecorder) BuildVmCache(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildVmCache", reflect.TypeOf((*MockInterface)(nil).BuildVmCache), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildVmCache", reflect.TypeOf((*MockInterface)(nil).BuildVmCache), arg0, arg1, arg2) } // BuildVpcCache mocks base method. @@ -80,18 +80,32 @@ func (mr *MockInterfaceMockRecorder) BuildVpcCache(arg0, arg1 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildVpcCache", reflect.TypeOf((*MockInterface)(nil).BuildVpcCache), arg0, arg1) } +// DeleteAllVmsFromCache mocks base method. +func (m *MockInterface) DeleteAllVmsFromCache(arg0 *types.NamespacedName) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAllVmsFromCache", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteAllVmsFromCache indicates an expected call of DeleteAllVmsFromCache. +func (mr *MockInterfaceMockRecorder) DeleteAllVmsFromCache(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAllVmsFromCache", reflect.TypeOf((*MockInterface)(nil).DeleteAllVmsFromCache), arg0) +} + // DeleteVmsFromCache mocks base method. -func (m *MockInterface) DeleteVmsFromCache(arg0 *types.NamespacedName) error { +func (m *MockInterface) DeleteVmsFromCache(arg0, arg1 *types.NamespacedName) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteVmsFromCache", arg0) + ret := m.ctrl.Call(m, "DeleteVmsFromCache", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } // DeleteVmsFromCache indicates an expected call of DeleteVmsFromCache. -func (mr *MockInterfaceMockRecorder) DeleteVmsFromCache(arg0 interface{}) *gomock.Call { +func (mr *MockInterfaceMockRecorder) DeleteVmsFromCache(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVmsFromCache", reflect.TypeOf((*MockInterface)(nil).DeleteVmsFromCache), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteVmsFromCache", reflect.TypeOf((*MockInterface)(nil).DeleteVmsFromCache), arg0, arg1) } // DeleteVpcsFromCache mocks base method. diff --git a/pkg/types/types.go b/pkg/types/types.go new file mode 100644 index 00000000..4f074eb9 --- /dev/null +++ b/pkg/types/types.go @@ -0,0 +1,28 @@ +// Copyright 2023 Antrea Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package types + +import ( + "k8s.io/apimachinery/pkg/types" + + runtimev1alpha1 "antrea.io/nephe/apis/runtime/v1alpha1" +) + +type CloudInventory struct { + // VmMap holds Virtual Machine objects indexed per selector. + VmMap map[types.NamespacedName]map[string]*runtimev1alpha1.VirtualMachine + // VpcMap holds VPC objects. + VpcMap map[string]*runtimev1alpha1.Vpc +} diff --git a/test/integration/crd_rw_test.go b/test/integration/crd_rw_test.go index 3479767d..758d0a23 100644 --- a/test/integration/crd_rw_test.go +++ b/test/integration/crd_rw_test.go @@ -54,7 +54,8 @@ var _ = Describe(fmt.Sprintf("%s,%s: Basic CRD Read-Write", focusAws, focusAzure Namespace: nameSpaceName, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountName, + AccountName: testAccountName, + AccountNamespace: nameSpaceName, VMSelector: []v1alpha1.VirtualMachineSelector{ { VpcMatch: &v1alpha1.EntityMatch{ diff --git a/test/integration/entityselector_test.go b/test/integration/entityselector_test.go index b369cee9..60430c1e 100644 --- a/test/integration/entityselector_test.go +++ b/test/integration/entityselector_test.go @@ -38,7 +38,7 @@ import ( var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { const ( - nameSpaceName = "entity-selector-test" + namespaceName = "entity-selector-test" testAccountName = "entity-selector-test-account" ) @@ -50,29 +50,31 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { ) var ( - getVMsCmd string - vpcID string - vpcName string - vmList []string - vmIDList []string - vmNameList []string - pollInterval uint = 30 - nameSpace *v1.Namespace + vpcID string + vpcName string + vmList []string + vmIDList []string + vmNameList []string + pollInterval uint = 30 + numNamespace int + cpaNamespace *v1.Namespace + cesNamespace []v1.Namespace + // CES can be in same namespace as CPA(cpaNamespace) or a different namespace(cesNamespace). account *v1alpha1.CloudProviderAccount - selector *v1alpha1.CloudEntitySelector + selector []v1alpha1.CloudEntitySelector secret *corev1.Secret cloudProvider string ) - createNS := func() { - logf.Log.Info("Create", "namespace", nameSpace.Name) - err := k8sClient.Create(context.TODO(), nameSpace) + createNS := func(namespace *v1.Namespace) { + logf.Log.Info("Create", "namespace", namespace.Name) + err := k8sClient.Create(context.TODO(), namespace) Expect(err).ToNot(HaveOccurred()) } - deleteNS := func() { - logf.Log.Info("Delete", "namespace", nameSpace.Name) - err := k8sClient.Delete(context.TODO(), nameSpace) + deleteNS := func(namespace *v1.Namespace) { + logf.Log.Info("Delete", "namespace", namespace.Name) + err := k8sClient.Delete(context.TODO(), namespace) Expect(err).ToNot(HaveOccurred()) } @@ -93,57 +95,74 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { Expect(err).ToNot(HaveOccurred()) } - applyEntitySelector := func(matchKey string, matchValue string, selectorExists bool) { - logf.Log.Info("Apply entity selector with", matchKey, matchValue) - switch matchKey { - case vpcIDMatch: - if len(selector.Spec.VMSelector) == 0 { - selector.Spec.VMSelector = append(selector.Spec.VMSelector, - v1alpha1.VirtualMachineSelector{VpcMatch: &v1alpha1.EntityMatch{MatchID: matchValue}}) - } else { - selector.Spec.VMSelector[0].VpcMatch.MatchID = matchValue - } - case vpcNameMatch: - if len(selector.Spec.VMSelector) == 0 { - selector.Spec.VMSelector = append(selector.Spec.VMSelector, - v1alpha1.VirtualMachineSelector{VpcMatch: &v1alpha1.EntityMatch{MatchName: matchValue}}) - } else { - selector.Spec.VMSelector[0].VpcMatch.MatchName = matchValue + applyEntitySelector := func(matchKey string, matchValue []string, selectorExists bool, cesNs []v1.Namespace) { + for i := range cesNs { + logf.Log.Info("Apply entity selector with", matchKey, matchValue[i], "namespace", cesNs[i].Name) + // set CES namespace based on the value passed to the function. + if !selectorExists { + selector[i] = v1alpha1.CloudEntitySelector{ + ObjectMeta: v12.ObjectMeta{ + Name: testAccountName, + Namespace: cesNs[i].Name, + }, + Spec: v1alpha1.CloudEntitySelectorSpec{ + AccountName: testAccountName, + AccountNamespace: cpaNamespace.Name, + VMSelector: []v1alpha1.VirtualMachineSelector{}, + }, + } } - case vmIDMatch: - if len(selector.Spec.VMSelector) == 0 { - selector.Spec.VMSelector = append(selector.Spec.VMSelector, - v1alpha1.VirtualMachineSelector{ - VMMatch: []v1alpha1.EntityMatch{ - { - MatchID: matchValue, - }, - }}) - } else { - selector.Spec.VMSelector[0].VMMatch[0].MatchID = matchValue + + switch matchKey { + case vpcIDMatch: + if len(selector[i].Spec.VMSelector) == 0 { + selector[i].Spec.VMSelector = append(selector[i].Spec.VMSelector, + v1alpha1.VirtualMachineSelector{VpcMatch: &v1alpha1.EntityMatch{MatchID: matchValue[i]}}) + } else { + selector[i].Spec.VMSelector[0].VpcMatch.MatchID = matchValue[i] + } + case vpcNameMatch: + if len(selector[i].Spec.VMSelector) == 0 { + selector[i].Spec.VMSelector = append(selector[i].Spec.VMSelector, + v1alpha1.VirtualMachineSelector{VpcMatch: &v1alpha1.EntityMatch{MatchName: matchValue[i]}}) + } else { + selector[i].Spec.VMSelector[0].VpcMatch.MatchName = matchValue[i] + } + case vmIDMatch: + if len(selector[i].Spec.VMSelector) == 0 { + selector[i].Spec.VMSelector = append(selector[i].Spec.VMSelector, + v1alpha1.VirtualMachineSelector{ + VMMatch: []v1alpha1.EntityMatch{ + { + MatchID: matchValue[i], + }, + }}) + } else { + selector[i].Spec.VMSelector[0].VMMatch[0].MatchID = matchValue[i] + } + case vmNameMatch: + if len(selector[i].Spec.VMSelector) == 0 { + selector[i].Spec.VMSelector = append(selector[i].Spec.VMSelector, + v1alpha1.VirtualMachineSelector{ + VMMatch: []v1alpha1.EntityMatch{ + { + MatchName: matchValue[i], + }, + }}) + } else { + selector[i].Spec.VMSelector[0].VMMatch[0].MatchName = matchValue[i] + } + default: + logf.Log.Error(errors.New("invalid matchKey"), "matchKey", matchKey) } - case vmNameMatch: - if len(selector.Spec.VMSelector) == 0 { - selector.Spec.VMSelector = append(selector.Spec.VMSelector, - v1alpha1.VirtualMachineSelector{ - VMMatch: []v1alpha1.EntityMatch{ - { - MatchName: matchValue, - }, - }}) + var err error + if selectorExists { + err = k8sClient.Update(context.TODO(), &selector[i]) } else { - selector.Spec.VMSelector[0].VMMatch[0].MatchName = matchValue + err = k8sClient.Create(context.TODO(), &selector[i]) } - default: - logf.Log.Error(errors.New("invalid matchKey"), "matchKey", matchKey) - } - var err error - if selectorExists { - err = k8sClient.Update(context.TODO(), selector) - } else { - err = k8sClient.Create(context.TODO(), selector) + Expect(err).ToNot(HaveOccurred()) } - Expect(err).ToNot(HaveOccurred()) } removeEmptyStr := func(input []string) []string { @@ -176,40 +195,60 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { return true } - // Check whether all elements in expected is contained in actual - checkContain := func(actual, expected []string) bool { - if len(expected) > len(actual) { - logf.Log.Info("the value is not correct", "actual", actual, "expected", expected) - return false - } - actualSet := make(map[string]int) - for i, v := range actual { - actualSet[v] = i - } - for _, v := range expected { - if _, ok := actualSet[v]; !ok { - logf.Log.Info("actual is not contained in the expected", "actual", actual, "expected", expected) - return false + tester := func(matchKey string, matchValue []string, selectorExists bool, numOfInterval int, cesNs []v1.Namespace, + expectedResult [][]string) { + applyEntitySelector(matchKey, matchValue, selectorExists, cesNs) + time.Sleep(time.Duration(numOfInterval) * time.Duration(pollInterval) * time.Second) + + for i := range cesNs { + var expectedResultValue []string + if len(expectedResult) > 0 { + expectedResultValue = expectedResult[i] } + getVMsCmd := fmt.Sprintf( + "get virtualmachine -n %s -o=jsonpath='{range.items[*]}{.metadata.name}{\"\\n\"}{end}'", cesNs[i].Name) + output, err := kubeCtl.Cmd(getVMsCmd) + Expect(err).ToNot(HaveOccurred()) + VMList := strings.Split(strings.Trim(output, "'"), "\n") + actualResult := removeEmptyStr(VMList) + logf.Log.Info("After test", "Actual Result ", actualResult) + logf.Log.Info("After test", "Expected Result ", expectedResultValue) + Expect(checkEqual(actualResult, expectedResultValue)).To(BeTrue()) } - return true } - tester := func(matchKey string, matchValue string, selectorExists bool, numOfInterval int, expectedResult []string) { - applyEntitySelector(matchKey, matchValue, selectorExists) - time.Sleep(time.Duration(numOfInterval) * time.Duration(pollInterval) * time.Second) - output, err := kubeCtl.Cmd(getVMsCmd) - Expect(err).ToNot(HaveOccurred()) - VMList := strings.Split(strings.Trim(output, "'"), "\n") - // vms in different VPCs might have the same name and all of them will be selected - if cloudProvider == string(runtimev1alpha1.AzureCloudProvider) && matchKey == vmNameMatch { - Expect(checkContain(removeEmptyStr(VMList), expectedResult)).To(BeTrue()) - } else { - actualResult := removeEmptyStr(VMList) - logf.Log.Info("After test", "Actual Result ", actualResult) - logf.Log.Info("After test", "Expected Result ", expectedResult) - Expect(checkEqual(actualResult, expectedResult)).To(BeTrue()) + setParams := func(matchKey string, appendKey string) ([]string, [][]string) { + var matchValue []string + var expectedResult [][]string + + switch matchKey { + case vpcIDMatch: + for i := 0; i < numNamespace; i++ { + matchValue = append(matchValue, vpcID+appendKey) + expectedResult = append(expectedResult, [][]string{vmList}...) + } + case vpcNameMatch: + for i := 0; i < numNamespace; i++ { + matchValue = append(matchValue, vpcName+appendKey) + expectedResult = append(expectedResult, [][]string{vmIDList}...) + } + case vmIDMatch: + for i := 0; i < numNamespace; i++ { + matchValue = append(matchValue, vmIDList[i]+appendKey) + temp := []string{vmList[i]} + expectedResult = append(expectedResult, [][]string{temp}...) + } + case vmNameMatch: + for i := 0; i < numNamespace; i++ { + matchValue = append(matchValue, vmNameList[i]+appendKey) + temp := []string{vmList[i]} + expectedResult = append(expectedResult, [][]string{temp}...) + } + default: + logf.Log.Error(errors.New("invalid matchKey"), "matchKey", matchKey) } + + return matchValue, expectedResult } BeforeEach(func() { @@ -221,18 +260,24 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { vmList = cloudVPC.GetVMs() vmIDList = cloudVPC.GetVMIDs() vmNameList = cloudVPC.GetVMNames() - nameSpace = &v1.Namespace{} - nameSpace.Name = nameSpaceName + "-" + fmt.Sprintf("%x", rand.Int()) - getVMsCmd = fmt.Sprintf( - "get virtualmachine -n %s -o=jsonpath='{range.items[*]}{.metadata.name}{\"\\n\"}{end}'", nameSpace.Name) - accountParameters := cloudVPC.GetCloudAccountParameters(testAccountName, nameSpace.Name, false) + numNamespace = len(vmList) + cpaNamespace = &v1.Namespace{} + cpaNamespace.Name = namespaceName + "-" + fmt.Sprintf("%x", rand.Int()) + // create namespaces for CES to test CES in different namespace from CPA. + cesNamespace = make([]v1.Namespace, numNamespace) + for i := 0; i < numNamespace; i++ { + cesNamespace[i] = v1.Namespace{} + cesNamespace[i].Name = namespaceName + "-" + fmt.Sprintf("%x", rand.Int()) + } + selector = make([]v1alpha1.CloudEntitySelector, numNamespace) + accountParameters := cloudVPC.GetCloudAccountParameters(testAccountName, cpaNamespace.Name, false) cloudProvider = strings.Split(cloudProviders, ",")[0] switch cloudProvider { case string(runtimev1alpha1.AWSCloudProvider): account = &v1alpha1.CloudProviderAccount{ ObjectMeta: v12.ObjectMeta{ Name: testAccountName, - Namespace: nameSpace.Name, + Namespace: cpaNamespace.Name, }, Spec: v1alpha1.CloudProviderAccountSpec{ PollIntervalInSeconds: &pollInterval, @@ -250,7 +295,7 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { account = &v1alpha1.CloudProviderAccount{ ObjectMeta: v12.ObjectMeta{ Name: testAccountName, - Namespace: nameSpace.Name, + Namespace: cpaNamespace.Name, }, Spec: v1alpha1.CloudProviderAccountSpec{ PollIntervalInSeconds: &pollInterval, @@ -267,16 +312,7 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { default: logf.Log.Error(nil, "Invalid provider", "Provider", cloudProvider) } - selector = &v1alpha1.CloudEntitySelector{ - ObjectMeta: v12.ObjectMeta{ - Name: testAccountName, - Namespace: nameSpace.Name, - }, - Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountName, - VMSelector: []v1alpha1.VirtualMachineSelector{}, - }, - } + // SDK call will automatically base64 encode data. secret = &corev1.Secret{ ObjectMeta: v12.ObjectMeta{ @@ -285,7 +321,10 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { }, Data: map[string][]byte{accountParameters.SecretRef.Key: []byte(accountParameters.SecretRef.Credential)}, } - createNS() + createNS(cpaNamespace) + for i := 0; i < numNamespace; i++ { + createNS(&cesNamespace[i]) + } createAccount() }) @@ -304,44 +343,26 @@ var _ = Describe(fmt.Sprintf("%s: Entity selector test", focusAws), func() { } preserveSetup = false deleteAccount() - deleteNS() + deleteNS(cpaNamespace) + for i := 0; i < numNamespace; i++ { + deleteNS(&cesNamespace[i]) + } }) DescribeTable("Testing entity selector", func(matchKey string) { - var matchValue string - var expectedResult []string - - switch matchKey { - case vpcIDMatch: - matchValue = vpcID - expectedResult = vmList - case vpcNameMatch: - matchValue = vpcName - expectedResult = vmIDList - case vmIDMatch: - matchValue = vmIDList[0] - expectedResult = vmList[:1] - case vmNameMatch: - matchValue = vmNameList[0] - expectedResult = vmList[:1] - default: - logf.Log.Error(errors.New("invalid matchKey"), "matchKey", matchKey) - } - By("Apply entity selector with valid match key") - switch matchKey { - case vpcNameMatch: - tester(matchKey, matchValue, false, 3, expectedResult) - default: - tester(matchKey, matchValue, false, 1, expectedResult) - } + matchValue, expectedResult := setParams(matchKey, "") + tester(matchKey, matchValue, false, 2, cesNamespace, expectedResult) By("Change match key to invalid non-empty value") - tester(matchKey, matchValue+"a", true, 2, nil) + matchValue, _ = setParams(matchKey, "xyz") + tester(matchKey, matchValue, true, 2, cesNamespace, nil) By("Change match key back to valid value again") - tester(matchKey, matchValue, true, 2, expectedResult) + matchValue, expectedResult = setParams(matchKey, "") + tester(matchKey, matchValue, true, 2, cesNamespace, expectedResult) + }, Entry(focusAzure+":"+"VPC id match", vpcIDMatch), Entry(focusAzure+":"+"VM id match", vmIDMatch), diff --git a/test/integration/externalnode_test.go b/test/integration/externalnode_test.go index 90551a4c..e5d37d6d 100644 --- a/test/integration/externalnode_test.go +++ b/test/integration/externalnode_test.go @@ -444,8 +444,9 @@ var _ = Describe(fmt.Sprintf("%s,%s: ExternalNode", focusAws, focusAzure), func( Namespace: namespace.Name, }, Spec: v1alpha1.CloudEntitySelectorSpec{ - AccountName: testAccountName, - VMSelector: []v1alpha1.VirtualMachineSelector{}, + AccountName: testAccountName, + AccountNamespace: namespace.Name, + VMSelector: []v1alpha1.VirtualMachineSelector{}, }, } // SDK call will automatically base64 encode data. diff --git a/test/templates/entity_selector.go b/test/templates/entity_selector.go index 6fedc9fc..cf39bf9f 100644 --- a/test/templates/entity_selector.go +++ b/test/templates/entity_selector.go @@ -15,12 +15,13 @@ package templates type CloudEntitySelectorParameters struct { - Name string - Namespace string - CloudAccountName string - Selector *SelectorParameters - Kind string - Agented bool + Name string + Namespace string + CloudAccountName string + CloudAccountNamespace string + Selector *SelectorParameters + Kind string + Agented bool } type SelectorParameters struct { @@ -36,6 +37,7 @@ metadata: namespace: {{.Namespace}} spec: accountName: {{.CloudAccountName}} + accountNamespace: {{.CloudAccountNamespace}} vmSelector: {{- if .Selector.VPC }} - vpcMatch: diff --git a/test/utils/cloud_provider_aws.go b/test/utils/cloud_provider_aws.go index 806ef2a5..e0c9daa0 100644 --- a/test/utils/cloud_provider_aws.go +++ b/test/utils/cloud_provider_aws.go @@ -29,8 +29,9 @@ import ( ) type awsVPC struct { - output map[string]interface{} - currentAccountName string + output map[string]interface{} + currentAccountName string + currentAccountNamespace string } // createAWSVPC creates AWS VPC that contains some VMs. It returns VPC id if successful. @@ -187,6 +188,7 @@ func (p *awsVPC) Reapply(timeout time.Duration, withAgent bool) error { func (p *awsVPC) GetCloudAccountParameters(name, namespace string, useInvalidCred bool) k8stemplates.CloudAccountParameters { p.currentAccountName = name + p.currentAccountNamespace = namespace out := k8stemplates.CloudAccountParameters{ Name: name, Namespace: namespace, @@ -226,11 +228,12 @@ func (p *awsVPC) GetCloudAccountParameters(name, namespace string, useInvalidCre // All VMs in the VPC will be imported if vms is nil. func (p *awsVPC) GetEntitySelectorParameters(name, namespace, kind string, vms []string) k8stemplates.CloudEntitySelectorParameters { out := k8stemplates.CloudEntitySelectorParameters{ - Name: name, - Namespace: namespace, - Selector: &k8stemplates.SelectorParameters{VPC: p.GetVPCID()}, - CloudAccountName: p.currentAccountName, - Kind: kind, + Name: name, + Namespace: namespace, + Selector: &k8stemplates.SelectorParameters{VPC: p.GetVPCID()}, + CloudAccountName: p.currentAccountName, + CloudAccountNamespace: p.currentAccountNamespace, + Kind: kind, } if vms != nil { out.Selector = &k8stemplates.SelectorParameters{VMs: vms} diff --git a/test/utils/cloud_provider_azure.go b/test/utils/cloud_provider_azure.go index 0a2597de..1282086a 100644 --- a/test/utils/cloud_provider_azure.go +++ b/test/utils/cloud_provider_azure.go @@ -31,8 +31,9 @@ import ( ) type azureVPC struct { - output map[string]interface{} - currentAccountName string + output map[string]interface{} + currentAccountName string + currentAccountNamespace string } // createAzureSVPC creates Azure VPC that contains some VMs. It returns VPC id if successful. @@ -219,6 +220,7 @@ func (p *azureVPC) Reapply(timeout time.Duration, withAgent bool) error { func (p *azureVPC) GetCloudAccountParameters(name, namespace string, useInvalidCred bool) k8stemplates.CloudAccountParameters { p.currentAccountName = name + p.currentAccountNamespace = namespace out := k8stemplates.CloudAccountParameters{ Name: name, Namespace: namespace, @@ -252,11 +254,12 @@ func (p *azureVPC) GetCloudAccountParameters(name, namespace string, useInvalidC // All VMs in the VPC will be imported if vms is nil. func (p *azureVPC) GetEntitySelectorParameters(name, namespace, kind string, vms []string) k8stemplates.CloudEntitySelectorParameters { out := k8stemplates.CloudEntitySelectorParameters{ - Name: name, - Namespace: namespace, - Selector: &k8stemplates.SelectorParameters{VPC: p.GetVPCID()}, - CloudAccountName: p.currentAccountName, - Kind: kind, + Name: name, + Namespace: namespace, + Selector: &k8stemplates.SelectorParameters{VPC: p.GetVPCID()}, + CloudAccountName: p.currentAccountName, + CloudAccountNamespace: p.currentAccountNamespace, + Kind: kind, } if vms != nil { out.Selector = &k8stemplates.SelectorParameters{VMs: vms}