From 0d4147f3f63f7a32efebddc29b6d9067a0438891 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Fri, 25 Jul 2025 05:56:42 -0400 Subject: [PATCH] Netris Network Plugin Integration with CloudStack (#10458) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Netris Plugin introduces Netris as a network service provider in CloudStack to be able to create and manage Virtual Private Clouds (VPCs) in CloudStack, being able to orchestrate the following network functionalities: - Network segmentation with Netris-VXLAN isolation method - Routing between "public" IP and network segments with an ACS ROUTED mode offering - SourceNAT, DNAT, 1:1 NAT between "public" IP and network segments with an ACS NATTED mode offering - Routing between VPC network segments (tiers in ACS nomenclature) - Access Lists (ACLs) between VPC tiers and "public" network (TCP, UDP, ICMP) both as global egress rules and "public" IP specific ingress rules. - ACLs between VPC network tiers (TCP, UDP, ICMP) - External load balancing – between VPC network tiers and "public" IP - Internal load balancing – between VPC network tiers - CloudStack Virtual Router services (DHCP, DNS, UserData, Password Injection, etc…) --- .../cloud/agent/api/to/FirewallRuleTO.java | 2 +- .../agent/api/to/PortForwardingRuleTO.java | 4 - .../configuration/ConfigurationService.java | 16 + .../main/java/com/cloud/event/EventTypes.java | 2 + .../java/com/cloud/network/IpAddress.java | 1 + .../main/java/com/cloud/network/Network.java | 1 + .../main/java/com/cloud/network/Networks.java | 3 +- .../cloud/network/SDNProviderNetworkRule.java | 358 +++ .../cloud/network/Site2SiteVpnConnection.java | 2 +- .../cloud/network/element/NetworkElement.java | 9 + .../PortForwardingServiceProvider.java | 28 + .../cloud/network/element/VpcProvider.java | 4 + .../com/cloud/network/guru/NetworkGuru.java | 4 + .../cloud/network/netris/NetrisLbBackend.java | 41 + .../network/netris/NetrisNetworkRule.java | 108 + .../cloud/network/netris/NetrisProvider.java | 30 + .../cloud/network/netris/NetrisService.java | 310 +++ .../com/cloud/network/vpc/StaticRoute.java | 5 +- .../cloud/network/vpc/StaticRouteProfile.java | 22 +- .../com/cloud/network/vpc/VpcOffering.java | 4 +- .../network/vpc/VpcProvisioningService.java | 2 +- .../com/cloud/network/vpc/VpcService.java | 2 +- .../com/cloud/offering/NetworkOffering.java | 6 +- .../apache/cloudstack/api/ApiConstants.java | 11 + .../network/CreateNetworkOfferingCmd.java | 56 +- .../admin/vlan/CreateVlanIpRangeCmd.java | 13 +- .../admin/vpc/CreateVPCOfferingCmd.java | 56 +- .../address/ListPublicIpAddressesCmd.java | 7 + .../user/vpc/CreateStaticRouteCmd.java | 53 +- .../command/user/vpn/CreateVpnGatewayCmd.java | 14 +- .../api/response/AsyncJobResponse.java | 9 - .../ClusterDrsPlanMigrationResponse.java | 12 +- .../api/response/IPAddressResponse.java | 8 + .../api/response/NetworkResponse.java | 16 - .../api/response/StaticRouteResponse.java | 24 +- .../api/response/SystemVmResponse.java | 8 - .../api/response/VlanIpRangeResponse.java | 10 +- .../cloudstack/api/response/ZoneResponse.java | 13 + client/pom.xml | 5 + .../api/CheckS2SVpnConnectionsAnswer.java | 1 - .../agent/api/SetupGuestNetworkCommand.java | 9 + .../facade/SetGuestNetworkConfigItem.java | 1 + .../virtualnetwork/model/GuestNetwork.java | 9 + .../agent/transport/ArrayTypeAdaptor.java | 12 +- .../cloud/agent/transport/ResponseTest.java | 46 + deps/install-non-oss.sh | 3 + .../service/NetworkOrchestrationService.java | 3 + .../configuration/ConfigurationManager.java | 5 +- .../java/com/cloud/network/addr/PublicIp.java | 4 + .../com/cloud/network/rules/RulesManager.java | 2 + .../cloud/network/vpc/NetworkACLManager.java | 2 +- .../com/cloud/network/vpc/VpcManager.java | 16 + .../orchestration/NetworkOrchestrator.java | 70 +- .../main/java/com/cloud/dc/dao/VlanDao.java | 2 + .../java/com/cloud/dc/dao/VlanDaoImpl.java | 27 + .../cloud/network/dao/IPAddressDaoImpl.java | 1 + .../com/cloud/network/dao/IPAddressVO.java | 12 + .../cloud/network/dao/NetrisProviderDao.java | 24 + .../network/dao/NetrisProviderDaoImpl.java | 52 + .../cloud/network/dao/RemoteAccessVpnDao.java | 2 + .../network/dao/RemoteAccessVpnDaoImpl.java | 7 + .../network/dao/Site2SiteVpnGatewayDao.java | 2 + .../dao/Site2SiteVpnGatewayDaoImpl.java | 8 + .../network/element/NetrisProviderVO.java | 265 +++ .../com/cloud/network/vpc/StaticRouteVO.java | 35 +- .../com/cloud/network/vpc/VpcOfferingVO.java | 11 - .../vpc/dao/VpcOfferingServiceMapDao.java | 5 + .../vpc/dao/VpcOfferingServiceMapDaoImpl.java | 19 + .../network/vpc/dao/VpcServiceMapDaoImpl.java | 11 +- .../cloud/offerings/NetworkOfferingVO.java | 24 - .../main/java/com/cloud/vm/dao/NicDao.java | 4 + .../java/com/cloud/vm/dao/NicDaoImpl.java | 20 + ...spring-engine-schema-core-daos-context.xml | 1 + .../META-INF/db/schema-42010to42100.sql | 37 + .../db/views/cloud.network_offering_view.sql | 2 - .../db/views/cloud.vpc_offering_view.sql | 1 - .../kvm/resource/BridgeVifDriver.java | 12 +- .../network/element/CiscoNexusVSMElement.java | 1 - .../cluster/KubernetesClusterManagerImpl.java | 1 - .../metrics/MetricsServiceImpl.java | 2 +- .../response/HostMetricsResponse.java | 10 - .../ManagementServerMetricsResponse.java | 17 - .../management/ContrailManagerImpl.java | 6 +- plugins/network-elements/netris/pom.xml | 44 + .../cloudstack/StartupNetrisCommand.java | 26 + .../AddOrUpdateNetrisStaticRouteCommand.java | 48 + .../agent/api/CreateNetrisACLCommand.java | 119 + .../agent/api/CreateNetrisVnetCommand.java | 84 + .../agent/api/CreateNetrisVpcCommand.java | 31 + .../api/CreateOrUpdateNetrisACLCommand.java | 119 + ...OrUpdateNetrisLoadBalancerRuleCommand.java | 90 + .../api/CreateOrUpdateNetrisNatCommand.java | 148 ++ .../agent/api/DeleteNetrisACLCommand.java | 46 + .../DeleteNetrisLoadBalancerRuleCommand.java | 52 + .../agent/api/DeleteNetrisNatRuleCommand.java | 72 + .../api/DeleteNetrisStaticRouteCommand.java | 23 + .../agent/api/DeleteNetrisVnetCommand.java | 51 + .../agent/api/DeleteNetrisVpcCommand.java | 30 + .../api/ListNetrisStaticRoutesAnswer.java | 36 + .../api/ListNetrisStaticRoutesCommand.java | 23 + .../cloudstack/agent/api/NetrisAnswer.java | 30 + .../cloudstack/agent/api/NetrisCommand.java | 70 + .../agent/api/ReleaseNatIpCommand.java | 30 + .../api/SetupNetrisPublicRangeCommand.java | 37 + .../agent/api/UpdateNetrisVnetCommand.java | 51 + .../agent/api/UpdateNetrisVpcCommand.java | 32 + .../api/command/AddNetrisProviderCmd.java | 126 ++ .../api/command/DeleteNetrisProviderCmd.java | 86 + .../api/command/ListNetrisProvidersCmd.java | 73 + .../api/response/NetrisProviderResponse.java | 135 ++ .../cloudstack/resource/NetrisPortGroup.java | 30 + .../cloudstack/resource/NetrisResource.java | 441 ++++ .../resource/NetrisResourceObjectUtils.java | 103 + .../cloudstack/service/NetrisApiClient.java | 100 + .../service/NetrisApiClientImpl.java | 2000 +++++++++++++++++ .../cloudstack/service/NetrisElement.java | 820 +++++++ .../service/NetrisGuestNetworkGuru.java | 346 +++ .../service/NetrisProviderService.java | 32 + .../service/NetrisProviderServiceImpl.java | 217 ++ .../service/NetrisPublicNetworkGuru.java | 144 ++ .../cloudstack/service/NetrisServiceImpl.java | 556 +++++ .../spring-netris-core-managers-context.xml | 31 + .../cloudstack/netris/module.properties | 21 + .../netris/spring-netris-context.xml | 41 + ...dOrUpdateNetrisStaticRouteCommandTest.java | 91 + .../agent/api/CreateNetrisACLCommandTest.java | 144 ++ .../api/CreateNetrisVnetCommandTest.java | 95 + .../agent/api/CreateNetrisVpcCommandTest.java | 63 + ...dateNetrisLoadBalancerRuleCommandTest.java | 139 ++ .../CreateOrUpdateNetrisNatCommandTest.java | 145 ++ .../agent/api/DeleteNetrisACLCommandTest.java | 103 + ...leteNetrisLoadBalancerRuleCommandTest.java | 98 + .../api/DeleteNetrisNatRuleCommandTest.java | 94 + .../api/DeleteNetrisVnetCommandTest.java | 83 + .../agent/api/DeleteNetrisVpcCommandTest.java | 64 + .../agent/api/ReleaseNatIpCommandTest.java | 80 + .../SetupNetrisPublicRangeCommandTest.java | 63 + .../api/UpdateNetrisVnetCommandTest.java | 105 + .../agent/api/UpdateNetrisVpcCommandTest.java | 93 + .../api/command/AddNetrisProviderCmdTest.java | 122 + .../command/DeleteNetrisProviderCmdTest.java | 101 + .../command/ListNetrisProvidersCmdTest.java | 104 + .../NetrisResourceObjectUtilsTest.java | 109 + .../resource/NetrisResourceTest.java | 141 ++ .../service/NetrisApiClientImplTest.java | 103 + .../cloudstack/service/NetrisElementTest.java | 141 ++ .../service/NetrisGuestNetworkGuruTest.java | 230 ++ .../NetrisProviderServiceImplTest.java | 220 ++ .../service/NetrisPublicNetworkGuruTest.java | 225 ++ .../service/NetrisServiceImplTest.java | 33 + .../api/command/DeleteNsxControllerCmd.java | 3 +- .../cloudstack/resource/NsxNetworkRule.java | 353 +-- .../cloudstack/service/NsxApiClient.java | 13 +- .../apache/cloudstack/service/NsxElement.java | 138 +- .../service/NsxGuestNetworkGuru.java | 9 - .../service/NsxPublicNetworkGuru.java | 18 +- .../cloudstack/service/NsxServiceImpl.java | 17 +- .../cloudstack/service/NsxApiClientTest.java | 6 +- .../cloudstack/service/NsxElementTest.java | 42 +- .../service/NsxPublicNetworkGuruTest.java | 10 +- .../ConfigTungstenFabricServiceCmd.java | 1 - plugins/pom.xml | 1 + pom.xml | 2 +- .../java/com/cloud/api/ApiResponseHelper.java | 92 +- .../api/query/dao/DataCenterJoinDaoImpl.java | 23 +- .../api/query/dao/VpcOfferingJoinDaoImpl.java | 9 +- .../api/query/vo/NetworkOfferingJoinVO.java | 20 - .../cloud/api/query/vo/VpcOfferingJoinVO.java | 8 - .../api/response/ApiResponseSerializer.java | 4 +- .../ConfigurationManagerImpl.java | 97 +- .../deploy/DeploymentPlanningManagerImpl.java | 2 +- .../cloud/network/IpAddressManagerImpl.java | 88 + .../com/cloud/network/NetworkModelImpl.java | 9 +- .../com/cloud/network/NetworkServiceImpl.java | 58 +- .../cloud/network/SDNProviderOpObject.java | 8 +- .../network/as/AutoScaleManagerImpl.java | 14 +- .../network/element/VirtualRouterElement.java | 1 - .../guru/ExternalGuestNetworkGuru.java | 5 +- .../cloud/network/guru/GuestNetworkGuru.java | 20 +- .../cloud/network/guru/PublicNetworkGuru.java | 14 +- .../lb/LoadBalancingRulesManagerImpl.java | 15 + .../network/router/CommandSetupHelper.java | 11 +- .../network/router/NetworkHelperImpl.java | 14 +- .../network/router/NicProfileHelperImpl.java | 4 +- .../VirtualNetworkApplianceManagerImpl.java | 8 + ...VpcVirtualNetworkApplianceManagerImpl.java | 20 +- .../cloud/network/rules/RulesManagerImpl.java | 35 +- .../network/vpc/NetworkACLManagerImpl.java | 11 +- .../network/vpc/NetworkACLServiceImpl.java | 11 +- .../com/cloud/network/vpc/VpcManagerImpl.java | 557 ++++- .../vpn/RemoteAccessVpnManagerImpl.java | 72 +- .../network/vpn/Site2SiteVpnManagerImpl.java | 76 +- .../cloud/server/ConfigurationServerImpl.java | 69 +- .../cloud/server/ManagementServerImpl.java | 36 +- .../RouterDeploymentDefinition.java | 19 +- .../RouterDeploymentDefinitionBuilder.java | 4 + .../VpcRouterDeploymentDefinition.java | 6 +- .../ConfigurationManagerImplTest.java | 4 + .../cloud/network/NetworkModelImplTest.java | 8 +- .../network/as/AutoScaleManagerImplTest.java | 16 +- .../network/lb/UpdateLoadBalancerTest.java | 7 +- .../vpc/MockConfigurationManagerImpl.java | 4 +- .../com/cloud/vpc/NetworkACLServiceTest.java | 6 + .../dao/MockVpcOfferingServiceMapDaoImpl.java | 11 + .../RouterDeploymentDefinitionTest.java | 3 + .../VpcRouterDeploymentDefinitionTest.java | 3 + .../CreateNetworkOfferingTest.java | 20 +- .../service/NetrisServiceMockTest.java | 134 ++ .../test/resources/createNetworkOffering.xml | 2 + systemvm/debian/opt/cloud/bin/configure.py | 38 +- systemvm/debian/opt/cloud/bin/cs/CsAddress.py | 112 +- systemvm/debian/opt/cloud/bin/cs/CsConfig.py | 3 + systemvm/debian/opt/cloud/bin/cs/CsDatabag.py | 7 + systemvm/debian/opt/cloud/bin/cs/CsDhcp.py | 4 +- .../debian/opt/cloud/bin/cs/CsGuestNetwork.py | 10 +- systemvm/debian/opt/cloud/bin/cs/CsRoute.py | 21 + .../opt/cloud/bin/cs/CsVpcGuestNetwork.py | 15 +- .../debian/opt/cloud/bin/passwd_server_ip.py | 13 +- .../component/test_project_usage.py | 25 +- test/integration/component/test_vpn_users.py | 118 +- test/integration/smoke/test_usage.py | 12 +- tools/apidoc/gen_toc.py | 1 + ui/public/locales/en.json | 32 +- ui/src/components/CheckBoxSelectPair.vue | 8 +- ui/src/components/view/InfoCard.vue | 2 +- ui/src/config/section/infra/phynetworks.js | 2 +- ui/src/config/section/network.js | 3 +- ui/src/views/AutogenView.vue | 4 - .../views/infra/network/IpRangesTabPublic.vue | 21 + .../infra/network/ServiceProvidersTab.vue | 45 +- .../views/infra/network/TrafficTypesTab.vue | 2 +- .../views/infra/zone/IpAddressRangeForm.vue | 20 +- .../views/infra/zone/PhysicalNetworksTab.vue | 2 +- ui/src/views/infra/zone/ZoneWizard.vue | 2 +- .../views/infra/zone/ZoneWizardLaunchZone.vue | 73 +- .../infra/zone/ZoneWizardNetworkSetupStep.vue | 90 +- .../ZoneWizardPhysicalNetworkSetupStep.vue | 1 + ui/src/views/network/IpAddressesTab.vue | 22 +- ui/src/views/network/LoadBalancing.vue | 41 +- ui/src/views/network/PublicIpResource.vue | 31 +- ui/src/views/network/StaticRoutesTab.vue | 130 +- ui/src/views/network/VpcTab.vue | 133 +- ui/src/views/network/VpcTiersTab.vue | 6 +- ui/src/views/network/VpnDetails.vue | 164 +- ui/src/views/offering/AddNetworkOffering.vue | 156 +- ui/src/views/offering/AddVpcOffering.vue | 100 +- .../java/com/cloud/utils/net/NetUtils.java | 34 + .../java/com/cloud/utils/LogUtilsTest.java | 2 +- .../com/cloud/utils/net/NetUtilsTest.java | 19 + 249 files changed, 14202 insertions(+), 1259 deletions(-) create mode 100644 api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java create mode 100644 api/src/main/java/com/cloud/network/netris/NetrisLbBackend.java create mode 100644 api/src/main/java/com/cloud/network/netris/NetrisNetworkRule.java create mode 100644 api/src/main/java/com/cloud/network/netris/NetrisProvider.java create mode 100644 api/src/main/java/com/cloud/network/netris/NetrisService.java create mode 100644 core/src/test/java/com/cloud/agent/transport/ResponseTest.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDao.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDaoImpl.java create mode 100644 engine/schema/src/main/java/com/cloud/network/element/NetrisProviderVO.java create mode 100644 plugins/network-elements/netris/pom.xml create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/StartupNetrisCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisACLCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisStaticRouteCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesAnswer.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisAnswer.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommand.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/AddNetrisProviderCmd.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmd.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmd.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/response/NetrisProviderResponse.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisPortGroup.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderService.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderServiceImpl.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java create mode 100644 plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java create mode 100644 plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/core/spring-netris-core-managers-context.xml create mode 100644 plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/module.properties create mode 100644 plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/spring-netris-context.xml create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommandTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/AddNetrisProviderCmdTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmdTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmdTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisApiClientImplTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisElementTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisGuestNetworkGuruTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisProviderServiceImplTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisPublicNetworkGuruTest.java create mode 100644 plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisServiceImplTest.java rename plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java => server/src/main/java/com/cloud/network/SDNProviderOpObject.java (94%) create mode 100644 server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java diff --git a/api/src/main/java/com/cloud/agent/api/to/FirewallRuleTO.java b/api/src/main/java/com/cloud/agent/api/to/FirewallRuleTO.java index 25c75001a3c..69350815be3 100644 --- a/api/src/main/java/com/cloud/agent/api/to/FirewallRuleTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/FirewallRuleTO.java @@ -47,7 +47,7 @@ public class FirewallRuleTO implements InternalIdentity { int[] srcPortRange; boolean revoked; boolean alreadyAdded; - private List sourceCidrList; + protected List sourceCidrList; private List destCidrList; FirewallRule.Purpose purpose; private Integer icmpType; diff --git a/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java b/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java index d43625c09a9..91f337c5f55 100644 --- a/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java +++ b/api/src/main/java/com/cloud/agent/api/to/PortForwardingRuleTO.java @@ -21,8 +21,6 @@ import com.cloud.network.rules.PortForwardingRule; import com.cloud.utils.net.NetUtils; import org.apache.commons.lang3.StringUtils; -import java.util.List; - /** * PortForwardingRuleTO specifies one port forwarding rule. * @@ -32,8 +30,6 @@ public class PortForwardingRuleTO extends FirewallRuleTO { String dstIp; int[] dstPortRange; - List sourceCidrList; - protected PortForwardingRuleTO() { super(); } diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 13a44ef05b0..32e31519ea7 100644 --- a/api/src/main/java/com/cloud/configuration/ConfigurationService.java +++ b/api/src/main/java/com/cloud/configuration/ConfigurationService.java @@ -17,7 +17,11 @@ package com.cloud.configuration; import java.util.List; +import java.util.Map; +import java.util.Objects; +import com.cloud.network.Network; +import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.command.admin.config.ResetCfgCmd; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; @@ -373,4 +377,16 @@ public interface ConfigurationService { List listPortableIps(long id); Boolean isAccountAllowedToCreateOfferingsWithTags(IsAccountAllowedToCreateOfferingsWithTagsCmd cmd); + + public static final Map ProviderDetailKeyMap = Map.of( + Network.Provider.Nsx.getName(), ApiConstants.NSX_DETAIL_KEY, + Network.Provider.Netris.getName(), ApiConstants.NETRIS_DETAIL_KEY + ); + + public static boolean IsIpRangeForProvider(Network.Provider provider) { + if (Objects.isNull(provider)) { + return false; + } + return ProviderDetailKeyMap.containsKey(provider.getName()); + } } diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 27f507d3a75..1eb1998850f 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -499,6 +499,8 @@ public class EventTypes { public static final String EVENT_ZONE_VLAN_ASSIGN = "ZONE.VLAN.ASSIGN"; public static final String EVENT_ZONE_VLAN_RELEASE = "ZONE.VLAN.RELEASE"; + public static final String EVENT_ZONE_VXLAN_ASSIGN = "ZONE.VXLAN.ASSIGN"; + public static final String EVENT_ZONE_VXLAN_RELEASE = "ZONE.VXLAN.RELEASE"; // Projects public static final String EVENT_PROJECT_CREATE = "PROJECT.CREATE"; diff --git a/api/src/main/java/com/cloud/network/IpAddress.java b/api/src/main/java/com/cloud/network/IpAddress.java index ae1af450577..70d652b54e9 100644 --- a/api/src/main/java/com/cloud/network/IpAddress.java +++ b/api/src/main/java/com/cloud/network/IpAddress.java @@ -99,4 +99,5 @@ public interface IpAddress extends ControlledEntity, Identity, InternalIdentity, boolean isForSystemVms(); + boolean isForRouter(); } diff --git a/api/src/main/java/com/cloud/network/Network.java b/api/src/main/java/com/cloud/network/Network.java index d3bc5005cb7..dc94932e31f 100644 --- a/api/src/main/java/com/cloud/network/Network.java +++ b/api/src/main/java/com/cloud/network/Network.java @@ -206,6 +206,7 @@ public interface Network extends ControlledEntity, StateObject, I public static final Provider Tungsten = new Provider("Tungsten", false); public static final Provider Nsx = new Provider("Nsx", false); + public static final Provider Netris = new Provider("Netris", false); private final String name; private final boolean isExternal; diff --git a/api/src/main/java/com/cloud/network/Networks.java b/api/src/main/java/com/cloud/network/Networks.java index dfa0ddb84ca..9f06a044111 100644 --- a/api/src/main/java/com/cloud/network/Networks.java +++ b/api/src/main/java/com/cloud/network/Networks.java @@ -129,7 +129,8 @@ public class Networks { UnDecided(null, null), OpenDaylight("opendaylight", String.class), TUNGSTEN("tf", String.class), - NSX("nsx", String.class); + NSX("nsx", String.class), + Netris("netris", String.class); private final String scheme; private final Class type; diff --git a/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java b/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java new file mode 100644 index 00000000000..a22db4287dc --- /dev/null +++ b/api/src/main/java/com/cloud/network/SDNProviderNetworkRule.java @@ -0,0 +1,358 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network; + +import java.util.List; + +public class SDNProviderNetworkRule { + + protected long domainId; + protected long accountId; + protected long zoneId; + protected Long networkResourceId; + protected String networkResourceName; + protected boolean isVpcResource; + protected long vmId; + protected long ruleId; + protected String publicIp; + protected String vmIp; + protected String publicPort; + protected String privatePort; + protected String protocol; + protected String algorithm; + protected List sourceCidrList; + protected List destinationCidrList; + protected Integer icmpCode; + + protected Integer icmpType; + protected String trafficType; + protected Network.Service service; + + public long getDomainId() { + return domainId; + } + + public void setDomainId(long domainId) { + this.domainId = domainId; + } + + public long getAccountId() { + return accountId; + } + + public void setAccountId(long accountId) { + this.accountId = accountId; + } + + public long getZoneId() { + return zoneId; + } + + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } + + public Long getNetworkResourceId() { + return networkResourceId; + } + + public void setNetworkResourceId(Long networkResourceId) { + this.networkResourceId = networkResourceId; + } + + public String getNetworkResourceName() { + return networkResourceName; + } + + public void setNetworkResourceName(String networkResourceName) { + this.networkResourceName = networkResourceName; + } + + public boolean isVpcResource() { + return isVpcResource; + } + + public void setVpcResource(boolean vpcResource) { + isVpcResource = vpcResource; + } + + public long getVmId() { + return vmId; + } + + public void setVmId(long vmId) { + this.vmId = vmId; + } + + public long getRuleId() { + return ruleId; + } + + public void setRuleId(long ruleId) { + this.ruleId = ruleId; + } + + public String getPublicIp() { + return publicIp; + } + + public void setPublicIp(String publicIp) { + this.publicIp = publicIp; + } + + public String getVmIp() { + return vmIp; + } + + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } + + public String getPublicPort() { + return publicPort; + } + + public void setPublicPort(String publicPort) { + this.publicPort = publicPort; + } + + public String getPrivatePort() { + return privatePort; + } + + public void setPrivatePort(String privatePort) { + this.privatePort = privatePort; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public void setAlgorithm(String algorithm) { + this.algorithm = algorithm; + } + + public String getAlgorithm() { + return algorithm; + } + + public Network.Service getService() { + return service; + } + + public void setService(Network.Service service) { + this.service = service; + } + + public Integer getIcmpCode() { + return icmpCode; + } + + public void setIcmpCode(Integer icmpCode) { + this.icmpCode = icmpCode; + } + + public Integer getIcmpType() { + return icmpType; + } + + public void setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + } + + public List getSourceCidrList() { + return sourceCidrList; + } + + public void setSourceCidrList(List sourceCidrList) { + this.sourceCidrList = sourceCidrList; + } + + public List getDestinationCidrList() { + return destinationCidrList; + } + + public void setDestinationCidrList(List destinationCidrList) { + this.destinationCidrList = destinationCidrList; + } + + public String getTrafficType() { + return trafficType; + } + + public void setTrafficType(String trafficType) { + this.trafficType = trafficType; + } + + public static class Builder { + public long domainId; + public long accountId; + public long zoneId; + public Long networkResourceId; + public String networkResourceName; + public boolean isVpcResource; + public long vmId; + + public long ruleId; + public String publicIp; + public String vmIp; + public String publicPort; + public String privatePort; + public String protocol; + public String algorithm; + public List sourceCidrList; + public List destinationCidrList; + public String trafficType; + public Integer icmpType; + public Integer icmpCode; + public Network.Service service; + + public Builder() { + // Default constructor + } + + public Builder setDomainId(long domainId) { + this.domainId = domainId; + return this; + } + + public Builder setAccountId(long accountId) { + this.accountId = accountId; + return this; + } + + public Builder setZoneId(long zoneId) { + this.zoneId = zoneId; + return this; + } + + public Builder setNetworkResourceId(Long networkResourceId) { + this.networkResourceId = networkResourceId; + return this; + } + + public Builder setNetworkResourceName(String networkResourceName) { + this.networkResourceName = networkResourceName; + return this; + } + + public Builder setVpcResource(boolean isVpcResource) { + this.isVpcResource = isVpcResource; + return this; + } + + + public Builder setVmId(long vmId) { + this.vmId = vmId; + return this; + } + + public Builder setRuleId(long ruleId) { + this.ruleId = ruleId; + return this; + } + + public Builder setPublicIp(String publicIp) { + this.publicIp = publicIp; + return this; + } + + public Builder setVmIp(String vmIp) { + this.vmIp = vmIp; + return this; + } + + public Builder setPublicPort(String publicPort) { + this.publicPort = publicPort; + return this; + } + + public Builder setPrivatePort(String privatePort) { + this.privatePort = privatePort; + return this; + } + + public Builder setProtocol(String protocol) { + this.protocol = protocol; + return this; + } + + public Builder setAlgorithm(String algorithm) { + this.algorithm = algorithm; + return this; + } + + public Builder setTrafficType(String trafficType) { + this.trafficType = trafficType; + return this; + } + + public Builder setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + return this; + } + + public Builder setIcmpCode(Integer icmpCode) { + this.icmpCode = icmpCode; + return this; + } + + public Builder setSourceCidrList(List sourceCidrList) { + this.sourceCidrList = sourceCidrList; + return this; + } + + public Builder setDestinationCidrList(List destinationCidrList) { + this.destinationCidrList = destinationCidrList; + return this; + } + + public Builder setService(Network.Service service) { + this.service = service; + return this; + } + + public SDNProviderNetworkRule build() { + SDNProviderNetworkRule rule = new SDNProviderNetworkRule(); + rule.setDomainId(this.domainId); + rule.setAccountId(this.accountId); + rule.setZoneId(this.zoneId); + rule.setNetworkResourceId(this.networkResourceId); + rule.setNetworkResourceName(this.networkResourceName); + rule.setVpcResource(this.isVpcResource); + rule.setVmId(this.vmId); + rule.setVmIp(this.vmIp); + rule.setPublicIp(this.publicIp); + rule.setPublicPort(this.publicPort); + rule.setPrivatePort(this.privatePort); + rule.setProtocol(this.protocol); + rule.setRuleId(this.ruleId); + rule.setAlgorithm(this.algorithm); + rule.setIcmpType(this.icmpType); + rule.setIcmpCode(this.icmpCode); + rule.setSourceCidrList(this.sourceCidrList); + rule.setDestinationCidrList(this.destinationCidrList); + rule.setTrafficType(this.trafficType); + rule.setService(service); + return rule; + } + } +} diff --git a/api/src/main/java/com/cloud/network/Site2SiteVpnConnection.java b/api/src/main/java/com/cloud/network/Site2SiteVpnConnection.java index 994df875f7d..51036abe060 100644 --- a/api/src/main/java/com/cloud/network/Site2SiteVpnConnection.java +++ b/api/src/main/java/com/cloud/network/Site2SiteVpnConnection.java @@ -24,7 +24,7 @@ import org.apache.cloudstack.api.InternalIdentity; public interface Site2SiteVpnConnection extends ControlledEntity, InternalIdentity, Displayable { enum State { - Pending, Connecting, Connected, Disconnected, Error, + Pending, Connecting, Connected, Disconnected, Error, Removed } @Override diff --git a/api/src/main/java/com/cloud/network/element/NetworkElement.java b/api/src/main/java/com/cloud/network/element/NetworkElement.java index fa67575edd3..cb0fc2fca98 100644 --- a/api/src/main/java/com/cloud/network/element/NetworkElement.java +++ b/api/src/main/java/com/cloud/network/element/NetworkElement.java @@ -23,6 +23,7 @@ import com.cloud.deploy.DeployDestination; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddress; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Provider; @@ -87,6 +88,14 @@ public interface NetworkElement extends Adapter { boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException; + /** + * Release IP from the network provider if reserved + * @param ipAddress + */ + default boolean releaseIp(IpAddress ipAddress) { + return true; + } + /** * The network is being shutdown. * @param network diff --git a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java b/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java index e99bc2fd416..8dcc8b6d0a4 100644 --- a/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java +++ b/api/src/main/java/com/cloud/network/element/PortForwardingServiceProvider.java @@ -17,12 +17,40 @@ package com.cloud.network.element; import java.util.List; +import java.util.Objects; import com.cloud.exception.ResourceUnavailableException; import com.cloud.network.Network; +import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.vpc.NetworkACLItem; public interface PortForwardingServiceProvider extends NetworkElement, IpDeployingRequester { + + static String getPublicPortRange(PortForwardingRule rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + + static String getPrivatePFPortRange(PortForwardingRule rule) { + return rule.getDestinationPortStart() == rule.getDestinationPortEnd() ? + String.valueOf(rule.getDestinationPortStart()) : + String.valueOf(rule.getDestinationPortStart()).concat("-").concat(String.valueOf(rule.getDestinationPortEnd())); + } + + static String getPrivatePortRange(FirewallRule rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + + static String getPrivatePortRangeForACLRule(NetworkACLItem rule) { + return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? + String.valueOf(rule.getSourcePortStart()) : + String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); + } + /** * Apply rules * @param network diff --git a/api/src/main/java/com/cloud/network/element/VpcProvider.java b/api/src/main/java/com/cloud/network/element/VpcProvider.java index 6debd1fbc2d..fe8c8f8612f 100644 --- a/api/src/main/java/com/cloud/network/element/VpcProvider.java +++ b/api/src/main/java/com/cloud/network/element/VpcProvider.java @@ -55,4 +55,8 @@ public interface VpcProvider extends NetworkElement { boolean applyACLItemsToPrivateGw(PrivateGateway gateway, List rules) throws ResourceUnavailableException; boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address); + + default boolean updateVpc(Vpc vpc, String previousVpcName) { + return true; + } } diff --git a/api/src/main/java/com/cloud/network/guru/NetworkGuru.java b/api/src/main/java/com/cloud/network/guru/NetworkGuru.java index 7b81c75ed84..ced664e54a9 100644 --- a/api/src/main/java/com/cloud/network/guru/NetworkGuru.java +++ b/api/src/main/java/com/cloud/network/guru/NetworkGuru.java @@ -215,4 +215,8 @@ public interface NetworkGuru extends Adapter { default boolean isSlaacV6Only() { return true; } + + default boolean update(Network network, String prevNetworkName) { + return true; + } } diff --git a/api/src/main/java/com/cloud/network/netris/NetrisLbBackend.java b/api/src/main/java/com/cloud/network/netris/NetrisLbBackend.java new file mode 100644 index 00000000000..afc21f7f511 --- /dev/null +++ b/api/src/main/java/com/cloud/network/netris/NetrisLbBackend.java @@ -0,0 +1,41 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network.netris; + +public class NetrisLbBackend { + private long vmId; + private String vmIp; + private int port; + + public NetrisLbBackend(long vmId, String vmIp, int port) { + this.vmId = vmId; + this.vmIp = vmIp; + this.port = port; + } + + public long getVmId() { + return vmId; + } + + public String getVmIp() { + return vmIp; + } + + public int getPort() { + return port; + } +} diff --git a/api/src/main/java/com/cloud/network/netris/NetrisNetworkRule.java b/api/src/main/java/com/cloud/network/netris/NetrisNetworkRule.java new file mode 100644 index 00000000000..211517ead49 --- /dev/null +++ b/api/src/main/java/com/cloud/network/netris/NetrisNetworkRule.java @@ -0,0 +1,108 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network.netris; + +import com.cloud.network.SDNProviderNetworkRule; + + +import java.util.List; + +public class NetrisNetworkRule { + public enum NetrisRuleAction { + PERMIT, DENY + } + + private SDNProviderNetworkRule baseRule; + private NetrisRuleAction aclAction; + private List lbBackends; + private String lbRuleName; + private String lbCidrList; + private String reason; + + public NetrisNetworkRule(Builder builder) { + this.baseRule = builder.baseRule; + this.aclAction = builder.aclAction; + this.lbBackends = builder.lbBackends; + this.reason = builder.reason; + this.lbCidrList = builder.lbCidrList; + this.lbRuleName = builder.lbRuleName; + } + + public NetrisRuleAction getAclAction() { + return aclAction; + } + + public List getLbBackends() { + return lbBackends; + } + + public String getReason() { + return reason; + } + + public String getLbCidrList() {return lbCidrList; } + + public String getLbRuleName() { return lbRuleName; } + + public SDNProviderNetworkRule getBaseRule() { + return baseRule; + } + + // Builder class extending the parent builder + public static class Builder { + private SDNProviderNetworkRule baseRule; + private NetrisRuleAction aclAction; + private List lbBackends; + private String reason; + private String lbCidrList; + private String lbRuleName; + + public Builder baseRule(SDNProviderNetworkRule baseRule) { + this.baseRule = baseRule; + return this; + } + + public Builder aclAction(NetrisRuleAction aclAction) { + this.aclAction = aclAction; + return this; + } + + public Builder lbBackends(List lbBackends) { + this.lbBackends = lbBackends; + return this; + } + + public Builder reason(String reason) { + this.reason = reason; + return this; + } + + public Builder lbCidrList(String lbCidrList) { + this.lbCidrList = lbCidrList; + return this; + } + + public Builder lbRuleName(String lbRuleName) { + this.lbRuleName = lbRuleName; + return this; + } + + public NetrisNetworkRule build() { + return new NetrisNetworkRule(this); + } + } +} diff --git a/api/src/main/java/com/cloud/network/netris/NetrisProvider.java b/api/src/main/java/com/cloud/network/netris/NetrisProvider.java new file mode 100644 index 00000000000..fccf2930e97 --- /dev/null +++ b/api/src/main/java/com/cloud/network/netris/NetrisProvider.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network.netris; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface NetrisProvider extends InternalIdentity, Identity { + long getZoneId(); + String getName(); + String getUrl(); + String getUsername(); + String getSiteName(); + String getTenantName(); + String getNetrisTag(); +} diff --git a/api/src/main/java/com/cloud/network/netris/NetrisService.java b/api/src/main/java/com/cloud/network/netris/NetrisService.java new file mode 100644 index 00000000000..110e9f07105 --- /dev/null +++ b/api/src/main/java/com/cloud/network/netris/NetrisService.java @@ -0,0 +1,310 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network.netris; + +import com.cloud.network.IpAddress; +import com.cloud.network.Network; +import com.cloud.network.SDNProviderNetworkRule; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.Vpc; + +import java.util.List; + +/** + * Interface for Netris Services that provides methods to manage VPCs, networks, + * NAT rules, network rules, and static routes in an SDN (Software Defined Networking) environment. + */ + +public interface NetrisService { + + /** + * Creates IPAM (IP Address Management) allocations for zone-level public ranges. + * + * @param zoneId the ID of the zone + * @return true if the operation is successful, false otherwise + */ + boolean createIPAMAllocationsForZoneLevelPublicRanges(long zoneId); + + /** + * Creates a VPC (Virtual Private Cloud) resource. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcId the ID of the VPC + * @param vpcName the name of the VPC + * @param sourceNatEnabled true if source NAT is enabled + * @param cidr the CIDR of the VPC + * @param isVpcNetwork true if it is a VPC network + * @return true if the operation is successful, false otherwise + */ + boolean createVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, boolean sourceNatEnabled, String cidr, boolean isVpcNetwork); + + /** + * Updates an existing VPC resource. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcId the ID of the VPC + * @param vpcName the new name of the VPC + * @param previousVpcName the previous name of the VPC + * @return true if the operation is successful, false otherwise + */ + boolean updateVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, String previousVpcName); + + /** + * Deletes a VPC resource. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpc the VPC to delete + * @return true if the operation is successful, false otherwise + */ + boolean deleteVpcResource(long zoneId, long accountId, long domainId, Vpc vpc); + + /** + * Creates a virtual network (vNet) resource. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcName the name of the VPC + * @param vpcId the ID of the VPC + * @param networkName the name of the network + * @param networkId the ID of the network + * @param cidr the CIDR of the network + * @param globalRouting true if global routing is enabled + * @return true if the operation is successful, false otherwise + */ + boolean createVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr, Boolean globalRouting); + + /** + * Updates an existing vNet resource. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcName the name of the VPC + * @param vpcId the ID of the VPC + * @param networkName the new name of the network + * @param networkId the ID of the network + * @param prevNetworkName the previous name of the network + * @return true if the operation is successful, false otherwise + */ + boolean updateVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String prevNetworkName); + + /** + * Deletes an existing vNet resource. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcName the name of the VPC + * @param vpcId the ID of the VPC + * @param networkName the name of the network + * @param networkId the ID of the network + * @param cidr the CIDR of the network + * @return true if the operation is successful, false otherwise + */ + boolean deleteVnetResource(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr); + + /** + * Creates a source NAT rule for a VPC or network. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcName the name of the VPC + * @param vpcId the ID of the VPC + * @param networkName the name of the network + * @param networkId the ID of the network + * @param isForVpc true if the rule applies to a VPC + * @param vpcCidr the VPC CIDR + * @param sourceNatIp the source NAT IP + * @return true if the operation is successful, false otherwise + */ + boolean createSnatRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, long networkId, boolean isForVpc, String vpcCidr, String sourceNatIp); + + /** + * Creates a port forwarding rule for a VPC or network. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcName the name of the VPC + * @param vpcId the ID of the VPC + * @param networkName the name of the network + * @param networkId the ID of the network + * @param isForVpc true if the rule applies to a VPC + * @param vpcCidr the VPC CIDR + * @param networkRule the network rule to forward + * @return true if the operation is successful, false otherwise + */ + boolean createPortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule); + + /** + * Deletes a port forwarding rule for a VPC or network. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param vpcName the name of the VPC + * @param vpcId the ID of the VPC + * @param networkName the name of the network + * @param networkId the ID of the network + * @param isForVpc true if the rule applies to a VPC + * @param vpcCidr the VPC CIDR + * @param networkRule the network rule to remove + * @return true if the operation is successful, false otherwise + */ + boolean deletePortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule); + + /** + * Updates the source NAT IP for a specified VPC. + * + * @param vpc the VPC to updates + * @param address the new source NAT IP address + * @return true if the operation is successful, false otherwise + */ + boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address); + + /** + * Creates a static NAT rule for a specific VM. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param networkResourceName the name of the network resource + * @param networkResourceId the ID of the network resource + * @param isForVpc true if the rule applies to a VPC + * @param vpcCidr the VPC CIDR + * @param staticNatIp the static NAT IP + * @param vmIp the VM's IP address + * @param vmId the ID of the VM + * @return true if the operation is successful, false otherwise + */ + boolean createStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String vpcCidr, String staticNatIp, String vmIp, long vmId); + + /** + * Deletes a static NAT rule for a specific VM. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param networkResourceName the name of the network resource + * @param networkResourceId the ID of the network resource + * @param isForVpc true if the rule applies to a VPC + * @param staticNatIp the static NAT IP + * @param vmId the ID of the VM + * @return true if the operation is successful, false otherwise + */ + boolean deleteStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String staticNatIp, long vmId); + + /** + * Adds firewall rules to a specific network. + * + * @param network the target network + * @param firewallRules the list of firewall rules to add + * @return true if the operation is successful, false otherwise + */ + boolean addFirewallRules(Network network, List firewallRules); + + /** + * Deletes firewall rules from a specific network. + * + * @param network the target network + * @param firewallRules the list of firewall rules to delete + * @return true if the operation is successful, false otherwise + */ + boolean deleteFirewallRules(Network network, List firewallRules); + + /** + * Adds or updates a static route for a specific network or VPC. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param networkResourceName the name of the network resource + * @param networkResourceId the ID of the network resource + * @param isForVpc true if it is for a VPC + * @param prefix the IP prefix of the route + * @param nextHop the next hop address + * @param routeId the ID of the route + * @param updateRoute true if the route should be updated + * @return true if the operation is successful, false otherwise + */ + boolean addOrUpdateStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId, boolean updateRoute); + + /** + * Deletes a specific static route for a network or VPC. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param networkResourceName the name of the network resource + * @param networkResourceId the ID of the network resource + * @param isForVpc true if it is for a VPC + * @param prefix the IP prefix of the route + * @param nextHop the next hop address + * @param routeId the ID of the route + * @return true if the operation is successful, false otherwise + */ + boolean deleteStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId); + + /** + * Lists static routes for a specific network or VPC. + * + * @param zoneId the ID of the zone + * @param accountId the ID of the account + * @param domainId the ID of the domain + * @param networkResourceName the name of the network resource + * @param networkResourceId the ID of the network resource + * @param isForVpc true if it is for a VPC + * @param prefix the IP prefix of the route + * @param nextHop the next hop address + * @param routeId the ID of the route + * @return a list of static routes + */ + List listStaticRoutes(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId); + + /** + * Releases a NAT IP address. + * + * @param zoneId the ID of the zone + * @param publicIp the public NAT IP to release + * @return true if the operation is successful, false otherwise + */ + boolean releaseNatIp(long zoneId, String publicIp); + + /** + * Creates or updates a load balancer (LB) rule. + * + * @param rule the network rule for the load balancer + * @return true if the operation is successful, false otherwise + */ + boolean createOrUpdateLbRule(NetrisNetworkRule rule); + + /** + * Deletes a load balancer (LB) rule. + * + * @param rule the network rule to delete + * @return true if the operation is successful, false otherwise + */ + boolean deleteLbRule(NetrisNetworkRule rule); +} diff --git a/api/src/main/java/com/cloud/network/vpc/StaticRoute.java b/api/src/main/java/com/cloud/network/vpc/StaticRoute.java index 5707ca14024..739fca328b8 100644 --- a/api/src/main/java/com/cloud/network/vpc/StaticRoute.java +++ b/api/src/main/java/com/cloud/network/vpc/StaticRoute.java @@ -25,6 +25,7 @@ public interface StaticRoute extends ControlledEntity, Identity, InternalIdentit Staged, // route been created but has never got through network rule conflict detection. Routes in this state can not be sent to VPC virtual router. Add, // Add means the route has been created and has gone through network rule conflict detection. Active, // Route has been sent to the VPC router and reported to be active. + Update, Revoke, // Revoke means this route has been revoked. If this route has been sent to the VPC router, the route will be deleted from database. Deleting // rule has been revoked and is scheduled for deletion } @@ -32,7 +33,9 @@ public interface StaticRoute extends ControlledEntity, Identity, InternalIdentit /** * @return */ - long getVpcGatewayId(); + Long getVpcGatewayId(); + + String getNextHop(); /** * @return diff --git a/api/src/main/java/com/cloud/network/vpc/StaticRouteProfile.java b/api/src/main/java/com/cloud/network/vpc/StaticRouteProfile.java index cb4849f1f7b..c8fc073911f 100644 --- a/api/src/main/java/com/cloud/network/vpc/StaticRouteProfile.java +++ b/api/src/main/java/com/cloud/network/vpc/StaticRouteProfile.java @@ -23,7 +23,8 @@ public class StaticRouteProfile implements StaticRoute { private String targetCidr; private long accountId; private long domainId; - private long gatewayId; + private Long gatewayId; + private String nextHop; private StaticRoute.State state; private long vpcId; String vlanTag; @@ -46,6 +47,18 @@ public class StaticRouteProfile implements StaticRoute { ipAddress = gateway.getIp4Address(); } + public StaticRouteProfile(StaticRoute staticRoute) { + id = staticRoute.getId(); + uuid = staticRoute.getUuid(); + targetCidr = staticRoute.getCidr(); + accountId = staticRoute.getAccountId(); + domainId = staticRoute.getDomainId(); + gatewayId = staticRoute.getVpcGatewayId(); + state = staticRoute.getState(); + vpcId = staticRoute.getVpcId(); + gateway = staticRoute.getNextHop(); + } + @Override public long getAccountId() { return accountId; @@ -57,10 +70,15 @@ public class StaticRouteProfile implements StaticRoute { } @Override - public long getVpcGatewayId() { + public Long getVpcGatewayId() { return gatewayId; } + @Override + public String getNextHop() { + return nextHop; + } + @Override public String getCidr() { return targetCidr; diff --git a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java index 38263f59667..17f49bb3652 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java @@ -32,6 +32,8 @@ public interface VpcOffering extends InternalIdentity, Identity { public static final String redundantVPCOfferingName = "Redundant VPC offering"; public static final String DEFAULT_VPC_NAT_NSX_OFFERING_NAME = "VPC offering with NSX - NAT Mode"; public static final String DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME = "VPC offering with NSX - Route Mode"; + public static final String DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME = "VPC offering with Netris - Route Mode"; + public static final String DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME = "VPC offering with Netris - NAT Mode"; /** * @@ -56,8 +58,6 @@ public interface VpcOffering extends InternalIdentity, Identity { */ boolean isDefault(); - boolean isForNsx(); - NetworkOffering.NetworkMode getNetworkMode(); /** diff --git a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java index 10f1ddcc12d..97b95339ecf 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcProvisioningService.java @@ -37,7 +37,7 @@ public interface VpcProvisioningService { VpcOffering createVpcOffering(String name, String displayText, List supportedServices, Map> serviceProviders, Map serviceCapabilitystList, NetUtils.InternetProtocol internetProtocol, - Long serviceOfferingId, Boolean forNsx, NetworkOffering.NetworkMode networkMode, + Long serviceOfferingId, String externalProvider, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, VpcOffering.State state, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber); diff --git a/api/src/main/java/com/cloud/network/vpc/VpcService.java b/api/src/main/java/com/cloud/network/vpc/VpcService.java index 9b7a83c29c1..c1546609d2b 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcService.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcService.java @@ -238,7 +238,7 @@ public interface VpcService { * @param cidr * @return */ - StaticRoute createStaticRoute(long gatewayId, String cidr) throws NetworkRuleConflictException; + StaticRoute createStaticRoute(Long gatewayId, Long vpcId, String nextHop, String cidr) throws NetworkRuleConflictException; /** * Lists static routes based on parameters passed to the call diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index 7011aea679e..5000a4f8c62 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -64,6 +64,8 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, public static final String DEFAULT_NAT_NSX_OFFERING_FOR_VPC = "DefaultNATNSXNetworkOfferingForVpc"; public static final String DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB = "DefaultNATNSXNetworkOfferingForVpcWithInternalLB"; public static final String DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC = "DefaultRoutedNSXNetworkOfferingForVpc"; + public static final String DEFAULT_ROUTED_NETRIS_OFFERING_FOR_VPC = "DefaultRoutedNetrisNetworkOfferingForVpc"; + public static final String DEFAULT_NAT_NETRIS_OFFERING_FOR_VPC = "DefaultNATNetrisNetworkOfferingForVpc"; public static final String DEFAULT_NAT_NSX_OFFERING = "DefaultNATNSXNetworkOffering"; public static final String DEFAULT_ROUTED_NSX_OFFERING = "DefaultRoutedNSXNetworkOffering"; public final static String QuickCloudNoServices = "QuickCloudNoServices"; @@ -102,10 +104,6 @@ public interface NetworkOffering extends InfrastructureEntity, InternalIdentity, boolean isForVpc(); - boolean isForTungsten(); - - boolean isForNsx(); - NetworkMode getNetworkMode(); TrafficType getTrafficType(); diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 607504835c0..71bd5c9addc 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -227,6 +227,7 @@ public class ApiConstants { public static final String FORMAT = "format"; public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork"; public static final String FOR_SYSTEM_VMS = "forsystemvms"; + public static final String FOR_PROVIDER = "forprovider"; public static final String FULL_PATH = "fullpath"; public static final String GATEWAY = "gateway"; public static final String IP6_GATEWAY = "ip6gateway"; @@ -271,6 +272,7 @@ public class ApiConstants { public static final String PREVIOUS_OWNER_ID = "previousownerid"; public static final String PREVIOUS_OWNER_NAME = "previousownername"; public static final String NEXT_ACL_RULE_ID = "nextaclruleid"; + public static final String NEXT_HOP = "nexthop"; public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash"; public static final String IMAGE_PATH = "imagepath"; public static final String INSTANCE_CONVERSION_SUPPORTED = "instanceconversionsupported"; @@ -352,6 +354,8 @@ public class ApiConstants { public static final String MIN_CPU_NUMBER = "mincpunumber"; public static final String MIN_MEMORY = "minmemory"; public static final String MIGRATION_TYPE = "migrationtype"; + public static final String MIGRATION_JOB_ID = "migrationjobid"; + public static final String MIGRATION_JOB_STATUS = "migrationjobstatus"; public static final String MIGRATIONS = "migrations"; public static final String MEMORY = "memory"; public static final String MODE = "mode"; @@ -488,6 +492,7 @@ public class ApiConstants { public static final String SIGNATURE = "signature"; public static final String SIGNATURE_VERSION = "signatureversion"; public static final String SINCE = "since"; + public static final String SITE_NAME = "sitename"; public static final String SIZE = "size"; public static final String SIZEGB = "sizegb"; public static final String SNAPSHOT = "snapshot"; @@ -536,6 +541,7 @@ public class ApiConstants { public static final String TIMEOUT = "timeout"; public static final String TIMEZONE = "timezone"; public static final String TIMEZONEOFFSET = "timezoneoffset"; + public static final String TENANT_NAME = "tenantname"; public static final String TOTAL = "total"; public static final String TOTAL_SUBNETS = "totalsubnets"; public static final String TYPE = "type"; @@ -912,6 +918,8 @@ public class ApiConstants { public static final String NETWORK = "network"; public static final String VPC_ID = "vpcid"; public static final String VPC_NAME = "vpcname"; + public static final String VPC_GATEWAY_ID = "vpcgatewayid"; + public static final String VPC_GATEWAY_IP = "vpcgatewayip"; public static final String GATEWAY_ID = "gatewayid"; public static final String CAN_USE_FOR_DEPLOY = "canusefordeploy"; public static final String RESOURCE_IDS = "resourceids"; @@ -1207,6 +1215,9 @@ public class ApiConstants { public static final String SOURCE_NAT_IP_ID = "sourcenatipaddressid"; public static final String HAS_RULES = "hasrules"; public static final String NSX_DETAIL_KEY = "forNsx"; + public static final String NETRIS_DETAIL_KEY = "forNetris"; + public static final String NETRIS_TAG = "netristag"; + public static final String NETRIS_VXLAN_ID = "netrisvxlanid"; public static final String DISK_PATH = "diskpath"; public static final String IMPORT_SOURCE = "importsource"; public static final String TEMP_PATH = "temppath"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index af3db374a7c..51ba6ec02ea 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.api.command.admin.network; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -140,12 +141,19 @@ public class CreateNetworkOfferingCmd extends BaseCmd { description = "true if network offering is meant to be used for VPC, false otherwise.") private Boolean forVpc; + @Deprecated @Parameter(name = ApiConstants.FOR_NSX, type = CommandType.BOOLEAN, description = "true if network offering is meant to be used for NSX, false otherwise.", since = "4.20.0") private Boolean forNsx; + @Parameter(name = ApiConstants.PROVIDER, + type = CommandType.STRING, + description = "Name of the provider providing the service", + since = "4.21.0") + private String provider; + @Parameter(name = ApiConstants.NSX_SUPPORT_LB, type = CommandType.BOOLEAN, description = "true if network offering for NSX network offering supports Load balancer service.", @@ -257,18 +265,38 @@ public class CreateNetworkOfferingCmd extends BaseCmd { return serviceOfferingId; } + public boolean isExternalNetworkProvider() { + return Arrays.asList("NSX", "Netris").stream() + .anyMatch(s -> provider != null && s.equalsIgnoreCase(provider)); + } + + public boolean isForNsx() { + return provider != null && provider.equalsIgnoreCase("NSX"); + } + + public boolean isForNetris() { + return provider != null && provider.equalsIgnoreCase("Netris"); + } + + public String getProvider() { + return provider; + } + public List getSupportedServices() { - if (!isForNsx()) { + if (!isExternalNetworkProvider()) { return supportedServices == null ? new ArrayList() : supportedServices; } else { List services = new ArrayList<>(List.of( Dhcp.getName(), Dns.getName(), - StaticNat.getName(), - SourceNat.getName(), - PortForwarding.getName(), UserData.getName() )); + if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode())) { + services.addAll(Arrays.asList( + StaticNat.getName(), + SourceNat.getName(), + PortForwarding.getName())); + } if (getNsxSupportsLbService()) { services.add(Lb.getName()); } @@ -308,10 +336,6 @@ public class CreateNetworkOfferingCmd extends BaseCmd { return forVpc; } - public boolean isForNsx() { - return BooleanUtils.isTrue(forNsx); - } - public String getNetworkMode() { return networkMode; } @@ -345,7 +369,7 @@ public class CreateNetworkOfferingCmd extends BaseCmd { public Map> getServiceProviders() { Map> serviceProviderMap = new HashMap<>(); - if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isForNsx()) { + if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isExternalNetworkProvider()) { Collection servicesCollection = serviceProviderList.values(); Iterator iter = servicesCollection.iterator(); while (iter.hasNext()) { @@ -361,17 +385,16 @@ public class CreateNetworkOfferingCmd extends BaseCmd { providerList.add(provider); serviceProviderMap.put(service, providerList); } - } else if (Boolean.TRUE.equals(forNsx)) { - getServiceProviderMapForNsx(serviceProviderMap); + } else if (isExternalNetworkProvider()) { + getServiceProviderMapForExternalProvider(serviceProviderMap, Network.Provider.getProvider(provider).getName()); } return serviceProviderMap; } - private void getServiceProviderMapForNsx(Map> serviceProviderMap) { + private void getServiceProviderMapForExternalProvider(Map> serviceProviderMap, String provider) { String routerProvider = Boolean.TRUE.equals(getForVpc()) ? VirtualRouterProvider.Type.VPCVirtualRouter.name() : VirtualRouterProvider.Type.VirtualRouter.name(); - List unsupportedServices = new ArrayList<>(List.of("Vpn", "SecurityGroup", "Connectivity", - "Gateway", "BaremetalPxeService")); + List unsupportedServices = new ArrayList<>(List.of("Vpn", "Gateway", "SecurityGroup", "Connectivity", "BaremetalPxeService")); List routerSupported = List.of("Dhcp", "Dns", "UserData"); List allServices = Service.listAllServices().stream().map(Service::getName).collect(Collectors.toList()); if (routerProvider.equals(VirtualRouterProvider.Type.VPCVirtualRouter.name())) { @@ -384,8 +407,9 @@ public class CreateNetworkOfferingCmd extends BaseCmd { continue; if (routerSupported.contains(service)) serviceProviderMap.put(service, List.of(routerProvider)); - else - serviceProviderMap.put(service, List.of(Network.Provider.Nsx.getName())); + else if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode()) || NetworkACL.getName().equalsIgnoreCase(service)) { + serviceProviderMap.put(service, List.of(provider)); + } if (!getNsxSupportsLbService()) { serviceProviderMap.remove(Lb.getName()); } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java index c0ba99a8233..5cb384925e8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java @@ -16,6 +16,8 @@ // under the License. package org.apache.cloudstack.api.command.admin.vlan; +import com.cloud.configuration.ConfigurationService; +import com.cloud.network.Network; import com.cloud.utils.net.NetUtils; import org.apache.cloudstack.api.APICommand; @@ -39,7 +41,6 @@ import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.user.Account; -import java.util.Objects; @APICommand(name = "createVlanIpRange", description = "Creates a VLAN IP range.", responseObject = VlanIpRangeResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -114,8 +115,8 @@ public class CreateVlanIpRangeCmd extends BaseCmd { @Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if IP range is set to system vms, false if not") private Boolean forSystemVms; - @Parameter(name = ApiConstants.FOR_NSX, type = CommandType.BOOLEAN, description = "true if the IP range is used for NSX resource", since = "4.20.0") - private boolean forNsx; + @Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, description = "Provider name for which the IP range is reserved for", since = "4.21.0") + private String provider; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -157,12 +158,12 @@ public class CreateVlanIpRangeCmd extends BaseCmd { return startIp; } - public boolean isForNsx() { - return !Objects.isNull(forNsx) && forNsx; + public Network.Provider getProvider() { + return Network.Provider.getProvider(provider); } public String getVlan() { - if ((vlan == null || vlan.isEmpty()) && !isForNsx()) { + if ((vlan == null || vlan.isEmpty()) && !ConfigurationService.IsIpRangeForProvider(getProvider())) { vlan = "untagged"; } return vlan; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java index 73b4f5df196..84f4d451460 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vpc/CreateVPCOfferingCmd.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.api.command.admin.vpc; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -25,10 +26,12 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.Network; import com.cloud.network.VirtualRouterProvider; +import com.cloud.offering.NetworkOffering; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.ZoneResponse; import org.apache.commons.collections.CollectionUtils; @@ -57,6 +60,7 @@ import static com.cloud.network.Network.Service.SourceNat; import static com.cloud.network.Network.Service.PortForwarding; import static com.cloud.network.Network.Service.NetworkACL; import static com.cloud.network.Network.Service.UserData; +import static com.cloud.network.Network.Service.Gateway; @APICommand(name = "createVPCOffering", description = "Creates VPC offering", responseObject = VpcOfferingResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) @@ -112,12 +116,19 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { since = "4.13") private List zoneIds; + @Deprecated @Parameter(name = ApiConstants.FOR_NSX, type = CommandType.BOOLEAN, description = "true if network offering is meant to be used for NSX, false otherwise.", since = "4.20.0") private Boolean forNsx; + @Parameter(name = ApiConstants.PROVIDER, + type = CommandType.STRING, + description = "Name of the provider providing the service", + since = "4.21.0") + private String provider; + @Parameter(name = ApiConstants.NSX_SUPPORT_LB, type = CommandType.BOOLEAN, description = "true if network offering for NSX VPC offering supports Load balancer service.", @@ -158,20 +169,31 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { return StringUtils.isEmpty(displayText) ? vpcOfferingName : displayText; } + public boolean isExternalNetworkProvider() { + return Arrays.asList("NSX", "Netris").stream() + .anyMatch(s -> provider != null && s.equalsIgnoreCase(provider)); + } + public List getSupportedServices() { - if (!isForNsx() && CollectionUtils.isEmpty(supportedServices)) { + if (!isExternalNetworkProvider() && CollectionUtils.isEmpty(supportedServices)) { throw new InvalidParameterValueException("Supported services needs to be provided"); } - if (isForNsx()) { + if (isExternalNetworkProvider()) { supportedServices = new ArrayList<>(List.of( Dhcp.getName(), Dns.getName(), - StaticNat.getName(), - SourceNat.getName(), NetworkACL.getName(), - PortForwarding.getName(), UserData.getName() )); + if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode())) { + supportedServices.addAll(Arrays.asList( + StaticNat.getName(), + SourceNat.getName(), + PortForwarding.getName())); + } + if (NetworkOffering.NetworkMode.ROUTED.name().equalsIgnoreCase(getNetworkMode())) { + supportedServices.add(Gateway.getName()); + } if (getNsxSupportsLbService()) { supportedServices.add(Lb.getName()); } @@ -179,8 +201,8 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { return supportedServices; } - public boolean isForNsx() { - return BooleanUtils.isTrue(forNsx); + public String getProvider() { + return provider; } public String getNetworkMode() { @@ -193,7 +215,7 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { public Map> getServiceProviders() { Map> serviceProviderMap = new HashMap<>(); - if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isForNsx()) { + if (serviceProviderList != null && !serviceProviderList.isEmpty() && !isExternalNetworkProvider()) { Collection> servicesCollection = serviceProviderList.values(); Iterator> iter = servicesCollection.iterator(); while (iter.hasNext()) { @@ -213,16 +235,18 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { providerList.add(provider); serviceProviderMap.put(service, providerList); } - } else if (Boolean.TRUE.equals(forNsx)) { - getServiceProviderMapForNsx(serviceProviderMap); + } else if (isExternalNetworkProvider()) { + getServiceProviderMapForExternalProvider(serviceProviderMap, Network.Provider.getProvider(provider).getName()); } return serviceProviderMap; } - private void getServiceProviderMapForNsx(Map> serviceProviderMap) { - List unsupportedServices = List.of("Vpn", "BaremetalPxeService", "SecurityGroup", "Connectivity", - "Gateway", "Firewall"); + private void getServiceProviderMapForExternalProvider(Map> serviceProviderMap, String provider) { + List unsupportedServices = new ArrayList<>(List.of("Vpn", "BaremetalPxeService", "SecurityGroup", "Connectivity", "Firewall")); + if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode())) { + unsupportedServices.add("Gateway"); + } List routerSupported = List.of("Dhcp", "Dns", "UserData"); List allServices = Network.Service.listAllServices().stream().map(Network.Service::getName).collect(Collectors.toList()); for (String service : allServices) { @@ -230,8 +254,10 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd { continue; if (routerSupported.contains(service)) serviceProviderMap.put(service, List.of(VirtualRouterProvider.Type.VPCVirtualRouter.name())); - else - serviceProviderMap.put(service, List.of(Network.Provider.Nsx.getName())); + else if (NetworkOffering.NetworkMode.NATTED.name().equalsIgnoreCase(getNetworkMode()) || + Stream.of(NetworkACL.getName(), Gateway.getName()).anyMatch(s -> s.equalsIgnoreCase(service))) { + serviceProviderMap.put(service, List.of(provider)); + } } if (!getNsxSupportsLbService()) { serviceProviderMap.remove(Lb.getName()); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java index 5760ca3ba1c..357f0c83ed7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/address/ListPublicIpAddressesCmd.java @@ -108,6 +108,9 @@ public class ListPublicIpAddressesCmd extends BaseListRetrieveOnlyResourceCountC @Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if range is dedicated for system VMs", since = "4.20.0") private Boolean forSystemVMs; + @Parameter(name = ApiConstants.FOR_PROVIDER, type = CommandType.BOOLEAN, description = "true if range is dedicated for external network provider", since = "4.21.0") + private Boolean forProvider; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -183,6 +186,10 @@ public class ListPublicIpAddressesCmd extends BaseListRetrieveOnlyResourceCountC return BooleanUtils.isTrue(forSystemVMs); } + public boolean isForProvider() { + return BooleanUtils.isTrue(forProvider); + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java index b28c02cb800..c4b5e159b5c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateStaticRouteCmd.java @@ -27,6 +27,7 @@ import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; import org.apache.cloudstack.api.response.PrivateGatewayResponse; import org.apache.cloudstack.api.response.StaticRouteResponse; +import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.context.CallContext; import com.cloud.event.EventTypes; @@ -45,20 +46,40 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.GATEWAY_ID, type = CommandType.UUID, entityType = PrivateGatewayResponse.class, - required = true, - description = "the gateway id we are creating static route for") + description = "the gateway id we are creating static route for. Mutually exclusive with the nexthop parameter") private Long gatewayId; + @Parameter(name = ApiConstants.VPC_ID, + type = CommandType.UUID, + entityType = VpcResponse.class, + description = "the vpc id for which the static route is created. This is required for nexthop parameter", + since = "4.21.0") + private Long vpcId; + + @Parameter(name = ApiConstants.NEXT_HOP, + type = CommandType.STRING, + description = "the next hop of static route. Mutually exclusive with the gatewayid parameter", + since = "4.21.0") + private String nextHop; + @Parameter(name = ApiConstants.CIDR, required = true, type = CommandType.STRING, description = "static route cidr") private String cidr; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// - public long getGatewayId() { + public Long getGatewayId() { return gatewayId; } + public Long getVpcId() { + return vpcId; + } + + public String getNextHop() { + return nextHop; + } + public String getCidr() { return cidr; } @@ -69,7 +90,7 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd { @Override public void create() throws ResourceAllocationException { try { - StaticRoute result = _vpcService.createStaticRoute(getGatewayId(), getCidr()); + StaticRoute result = _vpcService.createStaticRoute(getGatewayId(), getVpcId(), getNextHop(), getCidr()); setEntityId(result.getId()); setEntityUuid(result.getUuid()); } catch (NetworkRuleConflictException ex) { @@ -114,11 +135,8 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd { @Override public long getEntityOwnerId() { - VpcGateway gateway = _entityMgr.findById(VpcGateway.class, gatewayId); - if (gateway == null) { - throw new InvalidParameterValueException("Invalid gateway id is specified"); - } - return _entityMgr.findById(Vpc.class, gateway.getVpcId()).getAccountId(); + Long vpcId = getSyncObjId(); + return _entityMgr.findById(Vpc.class, vpcId).getAccountId(); } @Override @@ -128,11 +146,20 @@ public class CreateStaticRouteCmd extends BaseAsyncCreateCmd { @Override public Long getSyncObjId() { - VpcGateway gateway = _entityMgr.findById(VpcGateway.class, gatewayId); - if (gateway == null) { - throw new InvalidParameterValueException("Invalid id is specified for the gateway"); + if (gatewayId != null) { + VpcGateway gateway = _entityMgr.findById(VpcGateway.class, gatewayId); + if (gateway == null) { + throw new InvalidParameterValueException("Invalid id is specified for the gateway"); + } + return gateway.getVpcId(); + } else if (vpcId != null) { + Vpc vpc = _entityMgr.findById(Vpc.class, vpcId); + if (vpc == null) { + throw new InvalidParameterValueException("Invalid vpc id is specified"); + } + return vpc.getId(); } - return gateway.getVpcId(); + throw new InvalidParameterValueException("One of vpcId or gatewayId must be specified"); } @Override diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java index 6f31176c4ff..6c3f57b3dfa 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpn/CreateVpnGatewayCmd.java @@ -28,6 +28,7 @@ import org.apache.cloudstack.api.BaseAsyncCmd; import org.apache.cloudstack.api.BaseAsyncCreateCmd; import org.apache.cloudstack.api.Parameter; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.IPAddressResponse; import org.apache.cloudstack.api.response.Site2SiteVpnGatewayResponse; import org.apache.cloudstack.api.response.VpcResponse; import org.apache.cloudstack.context.CallContext; @@ -44,9 +45,16 @@ public class CreateVpnGatewayCmd extends BaseAsyncCreateCmd { type = CommandType.UUID, entityType = VpcResponse.class, required = true, - description = "public ip address id of the vpn gateway") + description = "id of the vpc") private Long vpcId; + @Parameter(name = ApiConstants.IP_ADDRESS_ID, + type = CommandType.UUID, + entityType = IPAddressResponse.class, + description = "the public IP address ID for which VPN gateway is being enabled. By default the source NAT IP or router IP will be used.", + since = "4.21.0") + private Long ipAddressId; + @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the vpn to the end user or not", since = "4.4", authorized = {RoleType.Admin}) private Boolean display; @@ -58,6 +66,10 @@ public class CreateVpnGatewayCmd extends BaseAsyncCreateCmd { return vpcId; } + public Long getIpAddressId() { + return ipAddressId; + } + @Deprecated public Boolean getDisplay() { return display; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java index 5b47a7a06e4..edbc94bc498 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java @@ -55,10 +55,6 @@ public class AsyncJobResponse extends BaseResponse { @Param(description = "the async command executed") private String cmd; - @SerializedName("jobstatus") - @Param(description = "the current job status-should be 0 for PENDING") - private Integer jobStatus; - @SerializedName("jobprocstatus") @Param(description = "the progress information of the PENDING job") private Integer jobProcStatus; @@ -123,11 +119,6 @@ public class AsyncJobResponse extends BaseResponse { this.cmd = cmd; } - @Override - public void setJobStatus(Integer jobStatus) { - this.jobStatus = jobStatus; - } - public void setJobProcStatus(Integer jobProcStatus) { this.jobProcStatus = jobProcStatus; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ClusterDrsPlanMigrationResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ClusterDrsPlanMigrationResponse.java index 4114c228e26..f399c1260f7 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ClusterDrsPlanMigrationResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ClusterDrsPlanMigrationResponse.java @@ -50,13 +50,13 @@ public class ClusterDrsPlanMigrationResponse extends BaseResponse { @Param(description = "Destination host for VM migration") String destHostName; - @SerializedName(ApiConstants.JOB_ID) + @SerializedName(ApiConstants.MIGRATION_JOB_ID) @Param(description = "id of VM migration async job") - private Long jobId; + private Long migrationJobId; - @SerializedName(ApiConstants.JOB_STATUS) + @SerializedName(ApiConstants.MIGRATION_JOB_STATUS) @Param(description = "Job status of VM migration async job") - private JobInfo.Status jobStatus; + private JobInfo.Status migrationJobStatus; public ClusterDrsPlanMigrationResponse(String vmId, String vmName, String srcHostId, String srcHostName, @@ -68,8 +68,8 @@ public class ClusterDrsPlanMigrationResponse extends BaseResponse { this.srcHostName = srcHostName; this.destHostId = destHostId; this.destHostName = destHostName; - this.jobId = jobId; - this.jobStatus = jobStatus; + this.migrationJobId = jobId; + this.migrationJobStatus = jobStatus; this.setObjectName(ApiConstants.MIGRATIONS); } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java index 0018edc8638..8b0e3cc0201 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/IPAddressResponse.java @@ -175,6 +175,10 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co @Param(description="true if range is dedicated for System VMs") private boolean forSystemVms; + @SerializedName(ApiConstants.FOR_PROVIDER) + @Param(description="true if range is dedicated for external network providers", since = "4.21.0") + private boolean forProvider; + public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; } @@ -332,4 +336,8 @@ public class IPAddressResponse extends BaseResponseWithAnnotations implements Co public void setForSystemVms(boolean forSystemVms) { this.forSystemVms = forSystemVms; } + + public void setForProvider(boolean forProvider) { + this.forProvider = forProvider; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index a1ffda72234..d5db8b4dabb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -211,14 +211,6 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement @Param(description = "Name of the VPC to which this network belongs", since = "4.15") private String vpcName; - @SerializedName(ApiConstants.ASSOCIATED_NETWORK_ID) - @Param(description = "the ID of the Network associated with this network") - private String associatedNetworkId; - - @SerializedName(ApiConstants.ASSOCIATED_NETWORK) - @Param(description = "the name of the Network associated with this network") - private String associatedNetworkName; - @SerializedName(ApiConstants.TUNGSTEN_VIRTUAL_ROUTER_UUID) @Param(description = "Tungsten-Fabric virtual router the network belongs to") private String tungstenVirtualRouterUuid; @@ -619,14 +611,6 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement this.vpcName = vpcName; } - public void setAssociatedNetworkId(String associatedNetworkId) { - this.associatedNetworkId = associatedNetworkId; - } - - public void setAssociatedNetworkName(String associatedNetworkName) { - this.associatedNetworkName = associatedNetworkName; - } - @Override public void setResourceIconResponse(ResourceIconResponse icon) { this.icon = icon; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/StaticRouteResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/StaticRouteResponse.java index 51f8a130383..9008fce2392 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/StaticRouteResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/StaticRouteResponse.java @@ -42,9 +42,17 @@ public class StaticRouteResponse extends BaseResponse implements ControlledEntit @Param(description = "VPC the static route belongs to") private String vpcId; - @SerializedName(ApiConstants.GATEWAY_ID) + @SerializedName(ApiConstants.VPC_GATEWAY_ID) @Param(description = "VPC gateway the route is created for") - private String gatewayId; + private String vpcGatewayId; + + @SerializedName(ApiConstants.VPC_GATEWAY_IP) + @Param(description = "IP of VPC gateway the route is created for", since = "4.21.0") + private String vpcGatewayIp; + + @SerializedName(ApiConstants.NEXT_HOP) + @Param(description = "Next hop of the static route", since = "4.21.0") + private String nextHop; @SerializedName(ApiConstants.CIDR) @Param(description = "static route CIDR") @@ -95,8 +103,16 @@ public class StaticRouteResponse extends BaseResponse implements ControlledEntit this.vpcId = vpcId; } - public void setGatewayId(String gatewayId) { - this.gatewayId = gatewayId; + public void setVpcGatewayId(String vpcGatewayId) { + this.vpcGatewayId = vpcGatewayId; + } + + public void setVpcGatewayIp(String vpcGatewayIp) { + this.vpcGatewayIp = vpcGatewayIp; + } + + public void setNextHop(String nextHop) { + this.nextHop = nextHop; } public void setCidr(String cidr) { diff --git a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java index be9f14f5060..7b1784fc767 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java @@ -38,14 +38,6 @@ public class SystemVmResponse extends BaseResponseWithAnnotations { @Param(description = "the system VM type") private String systemVmType; - @SerializedName("jobid") - @Param(description = "the job ID associated with the system VM. This is only displayed if the router listed is part of a currently running asynchronous job.") - private String jobId; - - @SerializedName("jobstatus") - @Param(description = "the job status associated with the system VM. This is only displayed if the router listed is part of a currently running asynchronous job.") - private Integer jobStatus; - @SerializedName("zoneid") @Param(description = "the Zone ID for the system VM") private String zoneId; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java index 1492c23e882..2be08bb7fcb 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VlanIpRangeResponse.java @@ -127,9 +127,9 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit @Param(description = "indicates whether VLAN IP range is dedicated to system vms or not") private Boolean forSystemVms; - @SerializedName(ApiConstants.FOR_NSX) - @Param(description = "indicates whether IP range is dedicated to NSX resources or not") - private Boolean forNsx; + @SerializedName(ApiConstants.PROVIDER) + @Param(description = "indicates to which provider the IP range is dedicated to", since = "4.21.0") + private String provider; public void setId(String id) { this.id = id; @@ -249,7 +249,7 @@ public class VlanIpRangeResponse extends BaseResponse implements ControlledEntit this.ip6Cidr = ip6Cidr; } - public void setForNsx(Boolean forNsx) { - this.forNsx = forNsx; + public void setProvider(String provider) { + this.provider = provider; } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java index 8e9a993bac6..975d9edcca1 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ZoneResponse.java @@ -145,10 +145,15 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso @Param(description = "the type of the zone - core or edge", since = "4.18.0") String type; + @Deprecated(since = "4.21.0") @SerializedName(ApiConstants.NSX_ENABLED) @Param(description = "true, if zone is NSX enabled", since = "4.20.0") private boolean nsxEnabled = false; + @SerializedName(ApiConstants.PROVIDER) + @Param(description = "External network provider if any", since = "4.21.0") + private String provider = null; + @SerializedName(ApiConstants.MULTI_ARCH) @Param(description = "true, if zone contains clusters and hosts from different CPU architectures", since = "4.20") private boolean multiArch; @@ -381,6 +386,14 @@ public class ZoneResponse extends BaseResponseWithAnnotations implements SetReso return nsxEnabled; } + public String getProvider() { + return provider; + } + + public void setProvider(String provider) { + this.provider = provider; + } + @Override public void setResourceIconResponse(ResourceIconResponse resourceIconResponse) { this.resourceIconResponse = resourceIconResponse; diff --git a/client/pom.xml b/client/pom.xml index 60bd34cc334..38a4c405120 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -1092,6 +1092,11 @@ cloud-plugin-network-nsx ${project.version} + + org.apache.cloudstack + cloud-plugin-network-netris + ${project.version} + org.apache.cloudstack cloud-plugin-network-tungsten diff --git a/core/src/main/java/com/cloud/agent/api/CheckS2SVpnConnectionsAnswer.java b/core/src/main/java/com/cloud/agent/api/CheckS2SVpnConnectionsAnswer.java index b299c602dde..351702a048c 100644 --- a/core/src/main/java/com/cloud/agent/api/CheckS2SVpnConnectionsAnswer.java +++ b/core/src/main/java/com/cloud/agent/api/CheckS2SVpnConnectionsAnswer.java @@ -25,7 +25,6 @@ import java.util.Map; public class CheckS2SVpnConnectionsAnswer extends Answer { Map ipToConnected; Map ipToDetail; - String details; protected CheckS2SVpnConnectionsAnswer() { ipToConnected = new HashMap(); diff --git a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java index 06583f2d0d3..fef0ceed6b8 100644 --- a/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java +++ b/core/src/main/java/com/cloud/agent/api/SetupGuestNetworkCommand.java @@ -36,6 +36,7 @@ public class SetupGuestNetworkCommand extends NetworkElementCommand { String routerIpv6Gateway = null; String routerIpv6Cidr = null; boolean isVrGuestGateway = false; + long networkId; public NicTO getNic() { return nic; @@ -123,4 +124,12 @@ public class SetupGuestNetworkCommand extends NetworkElementCommand { public void setVrGuestGateway(boolean vrGuestGateway) { isVrGuestGateway = vrGuestGateway; } + + public long getNetworkId() { + return networkId; + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java index 1a6824ceb7f..57c96ec4bc9 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/facade/SetGuestNetworkConfigItem.java @@ -76,6 +76,7 @@ public class SetGuestNetworkConfigItem extends AbstractConfigItemFacade { guestNetwork.setRouterIp6Gateway(command.getRouterIpv6Gateway()); guestNetwork.setRouterIp6Cidr(command.getRouterIpv6Cidr()); guestNetwork.setVrGuestGateway(command.isVrGuestGateway()); + guestNetwork.setNetworkId(command.getNetworkId()); return generateConfigItems(guestNetwork); } diff --git a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java index a416b4bc5e4..6bf36d62bf9 100644 --- a/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java +++ b/core/src/main/java/com/cloud/agent/resource/virtualnetwork/model/GuestNetwork.java @@ -38,6 +38,7 @@ public class GuestNetwork extends ConfigBase { private String routerIp6Gateway; private String routerIp6Cidr; private boolean isVrGuestGateway; + long networkId; private Integer mtu; @@ -211,4 +212,12 @@ public class GuestNetwork extends ConfigBase { public void setVrGuestGateway(boolean vrGuestGateway) { isVrGuestGateway = vrGuestGateway; } + + public long getNetworkId() { + return networkId; + } + + public void setNetworkId(long networkId) { + this.networkId = networkId; + } } diff --git a/core/src/main/java/com/cloud/agent/transport/ArrayTypeAdaptor.java b/core/src/main/java/com/cloud/agent/transport/ArrayTypeAdaptor.java index 7229f0903b7..eabcc82040d 100644 --- a/core/src/main/java/com/cloud/agent/transport/ArrayTypeAdaptor.java +++ b/core/src/main/java/com/cloud/agent/transport/ArrayTypeAdaptor.java @@ -75,13 +75,17 @@ public class ArrayTypeAdaptor implements JsonDeserializer, JsonSerialize try { clazz = Class.forName(name); } catch (ClassNotFoundException e) { - throw new CloudRuntimeException("can't find " + name); + throw new JsonParseException("can't find " + name); } T cmd = (T)_gson.fromJson(entry.getValue(), clazz); cmds.add(cmd); } - Class type = ((Class)typeOfT).getComponentType(); - T[] ts = (T[])Array.newInstance(type, cmds.size()); - return cmds.toArray(ts); + try { + Class type = Class.forName(typeOfT.getTypeName().replace("[]", "")); + T[] ts = (T[])Array.newInstance(type, cmds.size()); + return cmds.toArray(ts); + } catch (ClassNotFoundException e) { + throw new CloudRuntimeException("can't find " + typeOfT.getTypeName()); + } } } diff --git a/core/src/test/java/com/cloud/agent/transport/ResponseTest.java b/core/src/test/java/com/cloud/agent/transport/ResponseTest.java new file mode 100644 index 00000000000..06869b42eb9 --- /dev/null +++ b/core/src/test/java/com/cloud/agent/transport/ResponseTest.java @@ -0,0 +1,46 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.agent.transport; + +import junit.framework.TestCase; + +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; +import org.junit.Assert; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer; + +import com.cloud.agent.transport.Request.Version; + +public class ResponseTest extends TestCase { + protected Logger logger = LogManager.getLogger(getClass()); + + public void testCheckS2SVpnConnectionsAnswer() { + logger.info("Testing CheckS2SVpnConnectionsAnswer"); + String content = "[{\"com.cloud.agent.api.CheckS2SVpnConnectionsAnswer\":{\"ipToConnected\":{\"10.0.53.13\":true}," + + "\"ipToDetail\":{\"10.0.53.13\":\"IPsec SA found;Site-to-site VPN have connected\"}," + + "\"details\":\"10.0.53.13:0:IPsec SA found;Site-to-site VPN have connected\\u0026\\n\"," + + "\"result\":true,\"contextMap\":{},\"wait\":0,\"bypassHostMaintenance\":false}}]"; + Response response = new Response(Version.v2, 1L, 2L, 3L, 1L, (short)1, content); + Answer answer = response.getAnswer(); + Assert.assertTrue(answer instanceof CheckS2SVpnConnectionsAnswer); + } + +} diff --git a/deps/install-non-oss.sh b/deps/install-non-oss.sh index 56cfc2cba9c..e40946ce312 100755 --- a/deps/install-non-oss.sh +++ b/deps/install-non-oss.sh @@ -85,4 +85,7 @@ mvn install:install-file -Dfile=juniper-contrail-api-1.0-SNAPSHOT.jar -DgroupId= # From https://github.com/radu-todirica/tungsten-api/raw/master/net/juniper/tungsten/juniper-tungsten-api/2.0/juniper-tungsten-api-2.0.jar mvn install:install-file -Dfile=juniper-tungsten-api-2.0.jar -DgroupId=net.juniper.tungsten -DartifactId=juniper-tungsten-api -Dversion=2.0 -Dpackaging=jar +# Netris Integration +mvn install:install-file -Dfile=netris-java-sdk-1.0.0.jar -DgroupId=io.netris -DartifactId=netris-java-sdk -Dversion=1.0.0 -Dpackaging=jar + exit 0 diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index 8463d9cee98..adce5f2f8b4 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -112,6 +112,9 @@ public interface NetworkOrchestrationService { static final ConfigKey NSX_ENABLED = new ConfigKey<>(Boolean.class, "nsx.plugin.enable", "Advanced", "false", "Indicates whether to enable the NSX plugin", false, ConfigKey.Scope.Zone, null); + ConfigKey NETRIS_ENABLED = new ConfigKey<>(Boolean.class, "netris.plugin.enable", "Advanced", "false", + "Indicates whether to enable the Netris plugin", false, ConfigKey.Scope.Zone, null); + List setupNetwork(Account owner, NetworkOffering offering, DeploymentPlan plan, String name, String displayText, boolean isDefault) throws ConcurrentOperationException; diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 5655a0593c8..eebf764289d 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -223,6 +223,7 @@ public interface ConfigurationManager { * @param forVpc * @param forTungsten * @param forNsx + * @param forNetris * @param domainIds * @param zoneIds * @return network offering object @@ -232,11 +233,11 @@ public interface ConfigurationManager { Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, - Boolean forTungsten, boolean forNsx, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, boolean enableOffering, final NetUtils.InternetProtocol internetProtocol, + Boolean forTungsten, boolean forNsx, boolean forNetris, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, boolean enableOffering, final NetUtils.InternetProtocol internetProtocol, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, - String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr, boolean forNsx) + String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr, Provider provider) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; diff --git a/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java b/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java index d69a72a02c5..7132094ce11 100644 --- a/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java +++ b/engine/components-api/src/main/java/com/cloud/network/addr/PublicIp.java @@ -275,5 +275,9 @@ public class PublicIp implements PublicIpAddress { return false; } + @Override + public boolean isForRouter() { + return _addr.isForRouter(); + } } diff --git a/engine/components-api/src/main/java/com/cloud/network/rules/RulesManager.java b/engine/components-api/src/main/java/com/cloud/network/rules/RulesManager.java index 79ffdfdb973..5ba74402a4c 100644 --- a/engine/components-api/src/main/java/com/cloud/network/rules/RulesManager.java +++ b/engine/components-api/src/main/java/com/cloud/network/rules/RulesManager.java @@ -54,6 +54,8 @@ public interface RulesManager extends RulesService { boolean disableStaticNat(long ipAddressId, Account caller, long callerUserId, boolean releaseIpIfElastic) throws ResourceUnavailableException; + boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke); + /** * @param networkId * @param continueOnError diff --git a/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java b/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java index de69b894183..b192cd8d71c 100644 --- a/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java +++ b/engine/components-api/src/main/java/com/cloud/network/vpc/NetworkACLManager.java @@ -93,5 +93,5 @@ public interface NetworkACLManager { boolean applyACLToPrivateGw(PrivateGateway gateway) throws ResourceUnavailableException; - boolean reorderAclRules(VpcVO vpc, List networks, List networkACLItems); + boolean reorderAclRules(VpcVO vpc, List networks, List networkACLItems, Network.Provider networkProvider); } diff --git a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java index 626c4da1bb1..e7f41d079a7 100644 --- a/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java +++ b/engine/components-api/src/main/java/com/cloud/network/vpc/VpcManager.java @@ -195,4 +195,20 @@ public interface VpcManager { * @return */ boolean isSrcNatIpRequired(long vpcOfferingId); + + boolean isSrcNatIpRequiredForVpcVr(long vpcOfferingId); + + List getVpcStaticRoutes(Long vpcId); + + List getVpcStaticRoutes(List routes); + + boolean isProviderSupportServiceInVpc(long vpcId, Service service, Provider provider); + + IPAddressVO getIpAddressForVpcVr(Vpc vpc, IPAddressVO ipAddress, boolean allocateIpIfNeeded); + + boolean configStaticNatForVpcVr(Vpc vpc, IPAddressVO ipAddress); + + void reconfigStaticNatForVpcVr(Long vpcId); + + boolean applyStaticRouteForVpcVpnIfNeeded(Long vpcId, boolean updateAllVpn) throws ResourceUnavailableException; } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 9f8688af8bf..9d07a5c7df6 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -43,6 +43,8 @@ import com.cloud.bgp.BGPService; import com.cloud.dc.VlanDetailsVO; import com.cloud.dc.dao.ASNumberDao; import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.annotation.AnnotationService; @@ -355,9 +357,13 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra @Inject private NsxProviderDao nsxProviderDao; @Inject + private NetrisProviderDao netrisProviderDao; + @Inject private ASNumberDao asNumberDao; @Inject private BGPService bgpService; + @Inject + private Ipv6GuestPrefixSubnetNetworkMapDao ipv6GuestPrefixSubnetNetworkMapDao; @Override public List getNetworkGurus() { @@ -558,27 +564,27 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, Network.GuestType.Shared, false, null, true, null, true, - false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); } //#2 - SG enabled network offering if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + null, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); } //#3 - shared network offering with no SG service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, - null, true, false, false, false, null,null, null, true, null, null, false); + null, true, false, false, false, false, null, null, null, true, null, null, false); } if (_networkOfferingDao.findByUniqueName(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE, "Offering for Tungsten Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultTungstenSharedSGEnabledNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, true, false, null, null,null, true, null, null, false); + null, true, false, null, false, null, true, false, true, false, false, null, null, null, true, null, null, false); offering.setState(NetworkOffering.State.Enabled); _networkOfferingDao.update(offering.getId(), offering); } @@ -588,15 +594,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, - true, false, false, false, null, null,null, true, null, null, false); + true, false, false, false, false, null, null, null, true, null, null, false); } //#5 - default vpc offering with LB service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, - defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, true, true, false, false, null, null, null,true, null, null, false); - + defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false); } //#6 - default vpc offering with no LB service @@ -605,14 +610,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, - null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null,true, null, null, false); + null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false); } //#7 - isolated offering with source nat disabled if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, - true, null, true, false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + true, null, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); } //#8 - network offering with internal lb service @@ -634,7 +639,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB, "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null, true, null, null, false); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false, null, null, null, true, null, null, false); offering.setInternalLb(true); offering.setPublicLb(false); _networkOfferingDao.update(offering.getId(), offering); @@ -665,7 +670,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, - netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false, null, null, null, true, null, null, false); + netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false, false, false, null, null, null, true, null, null, false); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); } @@ -822,6 +827,11 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (domainId != null && aclType == ACLType.Domain) { _networksDao.addDomainToNetwork(id, domainId, subdomainAccess == null || subdomainAccess); } + String ipv6Cidr = network.getIp6Cidr(); + String ipv6Gateway = network.getIp6Gateway(); + if (StringUtils.isNoneBlank(ipv6Cidr, ipv6Gateway)) { + ipv6Service.assignIpv6SubnetToNetwork(ipv6Cidr, networkPersisted.getId()); + } } }); guru.setup(network, relatedFile); @@ -1056,7 +1066,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return Transaction.execute(new TransactionCallback() { @Override public NicVO doInTransaction(TransactionStatus status) { - NicVO vo = _nicDao.findByIp4AddressAndNetworkId(profile.getIPv4Address(), networkId); + NicVO vo = _nicDao.findNonPlaceHolderByIp4AddressAndNetworkId(profile.getIPv4Address(), networkId); if (vo == null) { applyProfileToNic(nic, profile, deviceId); vo = _nicDao.persist(nic); @@ -1083,10 +1093,14 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return null; } - if (isNicAllocatedForNsxPublicNetworkOnVR(network, profile, vm)) { + if (isNicAllocatedForProviderPublicNetworkOnVR(network, profile, vm, Provider.Nsx)) { String guruName = "NsxPublicNetworkGuru"; NetworkGuru nsxGuru = AdapterBase.getAdapterByName(networkGurus, guruName); nsxGuru.allocate(network, profile, vm); + } else if (isNicAllocatedForProviderPublicNetworkOnVR(network, profile, vm, Provider.Netris)) { + String guruName = "NetrisPublicNetworkGuru"; + NetworkGuru netrisGuru = AdapterBase.getAdapterByName(networkGurus, guruName); + netrisGuru.allocate(network, profile, vm); } if (isDefaultNic != null) { @@ -1149,7 +1163,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return new Pair(vmNic, Integer.valueOf(deviceId)); } - private boolean isNicAllocatedForNsxPublicNetworkOnVR(Network network, NicProfile requested, VirtualMachineProfile vm) { + private boolean isNicAllocatedForProviderPublicNetworkOnVR(Network network, NicProfile requested, VirtualMachineProfile vm, Provider provider) { if (ObjectUtils.anyNull(network, requested, vm)) { return false; } @@ -1159,7 +1173,9 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return false; } long dataCenterId = vm.getVirtualMachine().getDataCenterId(); - if (nsxProviderDao.findByZoneId(dataCenterId) == null) { + if (Provider.Nsx == provider && nsxProviderDao.findByZoneId(dataCenterId) == null) { + return false; + } else if (Provider.Netris == provider && netrisProviderDao.findByZoneId(dataCenterId) == null) { return false; } @@ -1169,14 +1185,16 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra if (CollectionUtils.isEmpty(ips)) { return false; } + ips = ips.stream().filter(x -> !x.getAddress().addr().equals(requested.getIPv4Address())).collect(Collectors.toList()); IPAddressVO ip = ips.get(0); - VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(ip.getVlanId(), ApiConstants.NSX_DETAIL_KEY); + String detailKey = Provider.Nsx == provider ? ApiConstants.NSX_DETAIL_KEY : ApiConstants.NETRIS_DETAIL_KEY; + VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(ip.getVlanId(), detailKey); if (vlanDetail == null) { return false; } - boolean isForNsx = vlanDetail.getValue().equalsIgnoreCase("true"); - return isForNsx && !ip.isForSystemVms(); + boolean isForProvider = vlanDetail.getValue().equalsIgnoreCase("true"); + return isForProvider && !ip.isForSystemVms(); } private void setMtuDetailsInVRNic(final Pair networks, Network network, NicVO vo) { @@ -1694,6 +1712,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } } } + reconfigureAndApplyStaticRouteForVpcVpn(network); } finally { for (final NetworkElement element : networkElements) { if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) { @@ -1703,6 +1722,17 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } } + private void reconfigureAndApplyStaticRouteForVpcVpn(Network network) { + if (network.getVpcId() != null) { + _vpcMgr.reconfigStaticNatForVpcVr(network.getVpcId()); + try { + _vpcMgr.applyStaticRouteForVpcVpnIfNeeded(network.getVpcId(), true); + } catch (ResourceUnavailableException e) { + logger.error("Unable to apply static routes for vpc " + network.getVpcId() + " due to " + e.getMessage()); + } + } + } + private void implementNetworkElements(final DeployDestination dest, final ReservationContext context, final Network network, final NetworkOffering offering, final List providersToImplement) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { for (NetworkElement element : networkElements) { @@ -1939,6 +1969,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra ip.setOneToOneNat(false); ip.setAssociatedWithVmId(null); ip.setVmIp(null); + ip.setForRouter(false); _ipAddressDao.update(ip.getId(), ip); } } @@ -3296,6 +3327,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra } } } + reconfigureAndApplyStaticRouteForVpcVpn(network); return success; } @@ -4877,6 +4909,6 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra return new ConfigKey[]{NetworkGcWait, NetworkGcInterval, NetworkLockTimeout, DeniedRoutes, GuestDomainSuffix, NetworkThrottlingRate, MinVRVersion, PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RollingRestartEnabled, - TUNGSTEN_ENABLED, NSX_ENABLED }; + TUNGSTEN_ENABLED, NSX_ENABLED, NETRIS_ENABLED }; } } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java index 84f38f05441..a6c267bb189 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDao.java @@ -64,4 +64,6 @@ public interface VlanDao extends GenericDao { List listIpv6RangeByZoneIdAndVlanId(long zoneId, String vlanId); List listIpv6SupportingVlansByZone(long zoneId); + + List listVlansForExternalNetworkProvider(long zoneId, String detailKey); } diff --git a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java index 461a9a13b10..d9fad3cad12 100644 --- a/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/dc/dao/VlanDaoImpl.java @@ -26,6 +26,7 @@ import java.util.Map; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.dc.VlanDetailsVO; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -67,6 +68,8 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao protected SearchBuilder ZoneVlanIp6Search; protected SearchBuilder ZoneIp6Search; protected SearchBuilder ZoneVlansSearch; + protected SearchBuilder ProviderVlanSearch; + protected SearchBuilder VlanDetailsProviderSearch; protected SearchBuilder AccountVlanMapSearch; protected SearchBuilder DomainVlanMapSearch; @@ -79,6 +82,8 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao protected DomainVlanMapDao _domainVlanMapDao; @Inject protected IPAddressDao _ipAddressDao; + @Inject + protected VlanDetailsDao vlanDetailsDao; @Override public VlanVO findByZoneAndVlanId(long zoneId, String vlanId) { @@ -277,6 +282,19 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao ZoneVlansSearch.and("zoneId", ZoneVlansSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); ZoneVlansSearch.and("vlan", ZoneVlansSearch.entity().getVlanTag(), SearchCriteria.Op.IN); ZoneVlansSearch.done(); + + ProviderVlanSearch = createSearchBuilder(); + ProviderVlanSearch.and("removed", ProviderVlanSearch.entity().getRemoved(), SearchCriteria.Op.NULL); + ProviderVlanSearch.and("dataCenterId", ProviderVlanSearch.entity().getDataCenterId(), SearchCriteria.Op.EQ); + VlanDetailsProviderSearch = vlanDetailsDao.createSearchBuilder(); + VlanDetailsProviderSearch.and("name", VlanDetailsProviderSearch.entity().getName(), SearchCriteria.Op.EQ); + VlanDetailsProviderSearch.and("value", VlanDetailsProviderSearch.entity().getValue(), SearchCriteria.Op.EQ); + ProviderVlanSearch.join("VlanDetailsProviderSearch", VlanDetailsProviderSearch, ProviderVlanSearch.entity().getId(), + VlanDetailsProviderSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER); + + VlanDetailsProviderSearch.done(); + ProviderVlanSearch.done(); + return result; } @@ -434,4 +452,13 @@ public class VlanDaoImpl extends GenericDaoBase implements VlanDao return listBy(sc); } + @Override + public List listVlansForExternalNetworkProvider(long zoneId, String detailKey) { + SearchCriteria sc = ProviderVlanSearch.create(); + sc.setParameters("dataCenterId", zoneId); + sc.setJoinParameters("VlanDetailsProviderSearch", "name", detailKey); + sc.setJoinParameters("VlanDetailsProviderSearch", "value", "true"); + return search(sc, null); + } + } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java index 5499d04e3a1..0a5ecd25667 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java @@ -197,6 +197,7 @@ public class IPAddressDaoImpl extends GenericDaoBase implemen address.setSourceNat(false); address.setOneToOneNat(false); address.setAssociatedWithVmId(null); + address.setForRouter(false); address.setState(State.Free); address.setAssociatedWithNetworkId(null); address.setVpcId(null); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java index 88e146d2a80..a3a65fdb01b 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/IPAddressVO.java @@ -117,6 +117,9 @@ public class IPAddressVO implements IpAddress { @Column(name = "forsystemvms") private boolean forSystemVms = false; + @Column(name = "for_router") + private boolean forRouter = false; + @Column(name= GenericDao.REMOVED_COLUMN) private Date removed; @@ -388,4 +391,13 @@ public class IPAddressVO implements IpAddress { public boolean isForSystemVms() { return forSystemVms; } + + @Override + public boolean isForRouter() { + return forRouter; + } + + public void setForRouter(boolean forRouter) { + this.forRouter = forRouter; + } } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDao.java b/engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDao.java new file mode 100644 index 00000000000..fe21f72e4db --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDao.java @@ -0,0 +1,24 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network.dao; + +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.utils.db.GenericDao; + +public interface NetrisProviderDao extends GenericDao { + NetrisProviderVO findByZoneId(long zoneId); +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDaoImpl.java new file mode 100644 index 00000000000..86ea04f1db0 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetrisProviderDaoImpl.java @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network.dao; + +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; + +@Component +@DB() +public class NetrisProviderDaoImpl extends GenericDaoBase implements NetrisProviderDao { + + final SearchBuilder allFieldsSearch; + + public NetrisProviderDaoImpl() { + super(); + allFieldsSearch = createSearchBuilder(); + allFieldsSearch.and("id", allFieldsSearch.entity().getId(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("uuid", allFieldsSearch.entity().getUuid(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("hostname", allFieldsSearch.entity().getUrl(), + SearchCriteria.Op.EQ); + allFieldsSearch.and("zone_id", allFieldsSearch.entity().getZoneId(), + SearchCriteria.Op.EQ); + allFieldsSearch.done(); + } + + @Override + public NetrisProviderVO findByZoneId(long zoneId) { + SearchCriteria sc = allFieldsSearch.create(); + sc.setParameters("zone_id", zoneId); + return findOneBy(sc); + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDao.java b/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDao.java index 8113c06c866..f4120a138ac 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDao.java @@ -33,4 +33,6 @@ public interface RemoteAccessVpnDao extends GenericDao List findByAccount(Long accountId); List listByNetworkId(Long networkId); + + List listByVpcId(Long vpcId); } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java index 484aa6f6631..ccbc60a5562 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/RemoteAccessVpnDaoImpl.java @@ -85,4 +85,11 @@ public class RemoteAccessVpnDaoImpl extends GenericDaoBase listByVpcId(Long vpcId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vpcId", vpcId); + return listBy(sc); + } } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDao.java b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDao.java index d3fef252f50..3475003c269 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDao.java @@ -20,4 +20,6 @@ import com.cloud.utils.db.GenericDao; public interface Site2SiteVpnGatewayDao extends GenericDao { Site2SiteVpnGatewayVO findByVpcId(long vpcId); + + Site2SiteVpnGatewayVO findByPublicIpAddress(long ipAddressId); } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java index d1fde963217..0aeefe90c29 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/Site2SiteVpnGatewayDaoImpl.java @@ -35,6 +35,7 @@ public class Site2SiteVpnGatewayDaoImpl extends GenericDaoBase sc = AllFieldsSearch.create(); + sc.setParameters("ipAddressId", ipAddressId); + return findOneBy(sc); + } } diff --git a/engine/schema/src/main/java/com/cloud/network/element/NetrisProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/NetrisProviderVO.java new file mode 100644 index 00000000000..113678f7b01 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/element/NetrisProviderVO.java @@ -0,0 +1,265 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 com.cloud.network.element; + +import com.cloud.network.netris.NetrisProvider; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.Date; +import java.util.UUID; + +@Entity +@Table(name = "netris_providers") +public class NetrisProviderVO implements NetrisProvider { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "name") + private String name; + + @Column(name = "zone_id") + private long zoneId; + + @Column(name = "host_id") + private long hostId; + + @Column(name = "url") + private String url; + + @Column(name = "username") + private String username; + + @Column(name = "password") + private String password; + + @Column(name = "site_name") + private String siteName; + + @Column(name = "tenant_name") + private String tenantName; + + @Column(name = "netris_tag") + private String netrisTag; + + @Column(name = "created") + private Date created; + + @Column(name = "removed") + private Date removed; + + public NetrisProviderVO() { + this.uuid = UUID.randomUUID().toString(); + } + + @Override + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @Override + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + @Override + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public long getZoneId() { + return zoneId; + } + + public void setZoneId(long zoneId) { + this.zoneId = zoneId; + } + + public long getHostId() { + return hostId; + } + + public void setHostId(long hostId) { + this.hostId = hostId; + } + + @Override + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @Override + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getSiteName() { + return siteName; + } + + public void setSiteName(String siteName) { + this.siteName = siteName; + } + + public String getTenantName() { + return tenantName; + } + + public void setTenantName(String tenantName) { + this.tenantName = tenantName; + } + + public String getNetrisTag() { + return netrisTag; + } + + public void setNetrisTag(String netrisTag) { + this.netrisTag = netrisTag; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getRemoved() { + return removed; + } + + public void setRemoved(Date removed) { + this.removed = removed; + } + + public static final class Builder { + private long zoneId; + private long hostId; + private String name; + private String url; + private String username; + private String password; + private String siteName; + private String tenantName; + private String netrisTag; + + public Builder() { + // Default constructor + } + + public Builder setZoneId(long zoneId) { + this.zoneId = zoneId; + return this; + } + + public Builder setHostId(long hostId) { + this.hostId = hostId; + return this; + } + + public Builder setName(String name) { + this.name = name; + return this; + } + + public Builder setUrl(String url) { + this.url = url; + return this; + } + + public Builder setUsername(String username) { + this.username = username; + return this; + } + + public Builder setPassword(String password) { + this.password = password; + return this; + } + + public Builder setSiteName(String siteName) { + this.siteName = siteName; + return this; + } + + public Builder setTenantName(String tenantName) { + this.tenantName = tenantName; + return this; + } + + public Builder setNetrisTag(String netrisTag) { + this.netrisTag = netrisTag; + return this; + } + + public NetrisProviderVO build() { + NetrisProviderVO provider = new NetrisProviderVO(); + provider.setZoneId(this.zoneId); + provider.setHostId(this.hostId); + provider.setUuid(UUID.randomUUID().toString()); + provider.setName(this.name); + provider.setUrl(this.url); + provider.setUsername(this.username); + provider.setPassword(this.password); + provider.setSiteName(this.siteName); + provider.setTenantName(this.tenantName); + provider.setNetrisTag(this.netrisTag); + provider.setCreated(new Date()); + return provider; + } + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/StaticRouteVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/StaticRouteVO.java index 2246bd6eed2..632d96819cd 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/StaticRouteVO.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/StaticRouteVO.java @@ -27,6 +27,7 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; +import javax.persistence.Transient; import com.cloud.utils.db.GenericDao; @@ -42,7 +43,10 @@ public class StaticRouteVO implements StaticRoute { String uuid; @Column(name = "vpc_gateway_id", updatable = false) - long vpcGatewayId; + Long vpcGatewayId; + + @Column(name = "next_hop") + private String nextHop; @Column(name = "cidr") private String cidr; @@ -67,6 +71,9 @@ public class StaticRouteVO implements StaticRoute { uuid = UUID.randomUUID().toString(); } + @Transient + boolean forVpn = false; + /** * @param vpcGatewayId * @param cidr @@ -74,7 +81,7 @@ public class StaticRouteVO implements StaticRoute { * @param accountId TODO * @param domainId TODO */ - public StaticRouteVO(long vpcGatewayId, String cidr, Long vpcId, long accountId, long domainId) { + public StaticRouteVO(Long vpcGatewayId, String cidr, Long vpcId, long accountId, long domainId, String nextHop) { super(); this.vpcGatewayId = vpcGatewayId; this.cidr = cidr; @@ -82,14 +89,32 @@ public class StaticRouteVO implements StaticRoute { this.vpcId = vpcId; this.accountId = accountId; this.domainId = domainId; + this.nextHop = nextHop; uuid = UUID.randomUUID().toString(); } + public StaticRouteVO(String cidr, Long vpcId, long accountId, long domainId, String nextHop, State state, boolean forVpn) { + super(); + this.cidr = cidr; + this.state = state; + this.vpcId = vpcId; + this.accountId = accountId; + this.domainId = domainId; + this.nextHop = nextHop; + uuid = UUID.randomUUID().toString(); + this.forVpn = forVpn; + } + @Override - public long getVpcGatewayId() { + public Long getVpcGatewayId() { return vpcGatewayId; } + @Override + public String getNextHop() { + return nextHop; + } + @Override public String getCidr() { return cidr; @@ -145,4 +170,8 @@ public class StaticRouteVO implements StaticRoute { public String getName() { return null; } + + public boolean isForVpn() { + return forVpn; + } } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java index 274b9fedecc..9320a37bc96 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/VpcOfferingVO.java @@ -60,9 +60,6 @@ public class VpcOfferingVO implements VpcOffering { @Column(name = "default") boolean isDefault = false; - @Column(name = "for_nsx") - boolean forNsx = false; - @Column(name = "network_mode") NetworkOffering.NetworkMode networkMode; @@ -159,14 +156,6 @@ public class VpcOfferingVO implements VpcOffering { return isDefault; } - public boolean isForNsx() { - return forNsx; - } - - public void setForNsx(boolean forNsx) { - this.forNsx = forNsx; - } - public NetworkOffering.NetworkMode getNetworkMode() { return networkMode; } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java index 06cfd25e670..020536e97ec 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDao.java @@ -18,6 +18,7 @@ package com.cloud.network.vpc.dao; import java.util.List; +import com.cloud.network.Network; import com.cloud.network.Network.Service; import com.cloud.network.vpc.VpcOfferingServiceMapVO; import com.cloud.utils.db.GenericDao; @@ -37,4 +38,8 @@ public interface VpcOfferingServiceMapDao extends GenericDao listProvidersForServiceForVpcOffering(long vpcOfferingId, Service service); + } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java index c7400f6edfd..dcb1becf9e8 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcOfferingServiceMapDaoImpl.java @@ -19,6 +19,7 @@ package com.cloud.network.vpc.dao; import java.util.List; +import com.cloud.network.Network; import org.springframework.stereotype.Component; import com.cloud.network.Network.Service; @@ -110,4 +111,22 @@ public class VpcOfferingServiceMapDaoImpl extends GenericDaoBase sc = AllFieldsSearch.create(); + sc.setParameters("vpcOffId", vpcOfferingId); + sc.setParameters("provider", provider.getName()); + return findOneBy(sc) != null; + } + + @Override + public List listProvidersForServiceForVpcOffering(long vpcOfferingId, Service service) { + SearchCriteria sc = AllFieldsSearch.create(); + + sc.setParameters("vpcOffId", vpcOfferingId); + sc.setParameters("service", service.getName()); + + return customSearch(sc, null); + } } diff --git a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java index 753c45fcc78..a5c4c83ff0f 100644 --- a/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/vpc/dao/VpcServiceMapDaoImpl.java @@ -68,8 +68,15 @@ public class VpcServiceMapDaoImpl extends GenericDaoBase @Override public boolean canProviderSupportServiceInVpc(long vpcId, Service service, Provider provider) { - // TODO Auto-generated method stub - return false; + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("vpcId", vpcId); + sc.setParameters("service", service.getName()); + sc.setParameters("provider", provider.getName()); + if (findOneBy(sc) != null) { + return true; + } else { + return false; + } } @Override diff --git a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java index 5cad366945f..904c8e646eb 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java @@ -134,12 +134,6 @@ public class NetworkOfferingVO implements NetworkOffering { @Column(name = "for_vpc") boolean forVpc; - @Column(name = "for_tungsten") - boolean forTungsten = false; - - @Column(name = "for_nsx") - boolean forNsx = false; - @Column(name = "network_mode") NetworkMode networkMode; @@ -200,24 +194,6 @@ public class NetworkOfferingVO implements NetworkOffering { this.forVpc = isForVpc; } - @Override - public boolean isForTungsten() { - return forTungsten; - } - - public void setForTungsten(boolean forTungsten) { - this.forTungsten = forTungsten; - } - - @Override - public boolean isForNsx() { - return forNsx; - } - - public void setForNsx(boolean forNsx) { - this.forNsx = forNsx; - } - @Override public NetworkMode getNetworkMode() { return networkMode; diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java index d34b03c4cb0..70a2558e2d4 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java @@ -46,8 +46,12 @@ public interface NicDao extends GenericDao { NicVO findByNetworkIdAndTypeIncludingRemoved(long networkId, VirtualMachine.Type vmType); + NicVO findNonPlaceHolderByNetworkIdAndType(long networkId, VirtualMachine.Type vmType); + NicVO findByIp4AddressAndNetworkId(String ip4Address, long networkId); + NicVO findNonPlaceHolderByIp4AddressAndNetworkId(String ip4Address, long networkId); + NicVO findByNetworkIdAndMacAddress(long networkId, String mac); NicVO findDefaultNicForVM(long instanceId); diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java index 7d1af1982ae..3618785c1b8 100644 --- a/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java @@ -69,6 +69,7 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { AllFieldsSearch.and("secondaryip", AllFieldsSearch.entity().getSecondaryIp(), Op.EQ); AllFieldsSearch.and("nicid", AllFieldsSearch.entity().getId(), Op.EQ); AllFieldsSearch.and("strategy", AllFieldsSearch.entity().getReservationStrategy(), Op.EQ); + AllFieldsSearch.and("strategyNEQ", AllFieldsSearch.entity().getReservationStrategy(), Op.NEQ); AllFieldsSearch.and("reserverName",AllFieldsSearch.entity().getReserver(),Op.EQ); AllFieldsSearch.and("macAddress", AllFieldsSearch.entity().getMacAddress(), Op.EQ); AllFieldsSearch.and("deviceid", AllFieldsSearch.entity().getDeviceId(), Op.EQ); @@ -195,6 +196,15 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { return findByNetworkIdAndTypeInternal(networkId, vmType, true); } + @Override + public NicVO findNonPlaceHolderByNetworkIdAndType(long networkId, VirtualMachine.Type vmType) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("network", networkId); + sc.setParameters("vmType", vmType); + sc.setParameters("strategyNEQ", Nic.ReservationStrategy.PlaceHolder.toString()); + return findOneBy(sc); + } + @Override public NicVO findByNetworkIdTypeAndGateway(long networkId, VirtualMachine.Type vmType, String gateway) { SearchCriteria sc = AllFieldsSearch.create(); @@ -222,6 +232,16 @@ public class NicDaoImpl extends GenericDaoBase implements NicDao { return findOneBy(sc); } + @Override + public NicVO findNonPlaceHolderByIp4AddressAndNetworkId(String ip4Address, long networkId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("address", ip4Address); + sc.setParameters("network", networkId); + sc.setParameters("strategyNEQ", Nic.ReservationStrategy.PlaceHolder.toString()); + return findOneBy(sc); + } + + @Override public NicVO findByNetworkIdAndMacAddress(long networkId, String mac) { SearchCriteria sc = AllFieldsSearch.create(); diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index 474569f4924..1e144dde8f1 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -138,6 +138,7 @@ + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql b/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql index cc6c4c6ae05..e2389dc9250 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42010to42100.sql @@ -238,6 +238,43 @@ CREATE TABLE IF NOT EXISTS `cloud`.`gui_themes_details` ( CONSTRAINT `fk_gui_themes_details__gui_theme_id` FOREIGN KEY (`gui_theme_id`) REFERENCES `gui_themes`(`id`) ); +-- Netris Plugin +CREATE TABLE `cloud`.`netris_providers` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `uuid` varchar(40), + `zone_id` bigint unsigned NOT NULL COMMENT 'Zone ID', + `host_id` bigint unsigned NOT NULL COMMENT 'Host ID', + `name` varchar(40), + `url` varchar(255) NOT NULL, + `username` varchar(255) NOT NULL, + `password` varchar(255) NOT NULL, + `site_name` varchar(255) NOT NULL, + `tenant_name` varchar(255) NOT NULL, + `netris_tag` varchar(255) NOT NULL, + `created` datetime NOT NULL COMMENT 'created date', + `removed` datetime COMMENT 'removed date if not null', + PRIMARY KEY (`id`), + CONSTRAINT `fk_netris_providers__zone_id` FOREIGN KEY `fk_netris_providers__zone_id` (`zone_id`) REFERENCES `data_center`(`id`) ON DELETE CASCADE, + INDEX `i_netris_providers__zone_id`(`zone_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Drop the Tungsten and NSX columns from the network offerings (replaced by checking the provider on the ntwk_offering_service_map table) +ALTER TABLE `cloud`.`network_offerings` DROP COLUMN `for_tungsten`; +ALTER TABLE `cloud`.`network_offerings` DROP COLUMN `for_nsx`; + +-- Drop the Tungsten and NSX columns from the VPC offerings (replaced by checking the provider on the vpc_offering_service_map table) +ALTER TABLE `cloud`.`vpc_offerings` DROP COLUMN `for_nsx`; + +-- Add next_hop to the static_routes table +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.static_routes', 'next_hop', 'varchar(50) COMMENT "next hop of the static route" AFTER `vpc_gateway_id`'); + +-- Add `for_router` to `user_ip_address` table +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.user_ip_address', 'for_router', 'tinyint(1) DEFAULT 0 COMMENT "True if the ip address is used by Domain Router to expose services"'); + +-- Add Netris Autoscaling rules +INSERT IGNORE INTO `cloud`.`counter` (uuid, provider, source, name, value, created) VALUES (UUID(), 'Netris', 'cpu', 'VM CPU - average percentage', 'vm.cpu.average.percentage', NOW()); +INSERT IGNORE INTO `cloud`.`counter` (uuid, provider, source, name, value, created) VALUES (UUID(), 'Netris', 'memory', 'VM Memory - average percentage', 'vm.memory.average.percentage', NOW()); + -- Rename user_vm_details to vm_instance_details ALTER TABLE `cloud`.`user_vm_details` RENAME TO `cloud`.`vm_instance_details`; ALTER TABLE `cloud`.`vm_instance_details` DROP FOREIGN KEY `fk_user_vm_details__vm_id`; diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql index 640b2397a46..368566c32b3 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.network_offering_view.sql @@ -59,8 +59,6 @@ SELECT `network_offerings`.`supports_public_access` AS `supports_public_access`, `network_offerings`.`supports_vm_autoscaling` AS `supports_vm_autoscaling`, `network_offerings`.`for_vpc` AS `for_vpc`, - `network_offerings`.`for_tungsten` AS `for_tungsten`, - `network_offerings`.`for_nsx` AS `for_nsx`, `network_offerings`.`network_mode` AS `network_mode`, `network_offerings`.`service_package_id` AS `service_package_id`, `network_offerings`.`routing_mode` AS `routing_mode`, diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql index c74d50590de..751d8f91a25 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.vpc_offering_view.sql @@ -28,7 +28,6 @@ select `vpc_offerings`.`display_text` AS `display_text`, `vpc_offerings`.`state` AS `state`, `vpc_offerings`.`default` AS `default`, - `vpc_offerings`.`for_nsx` AS `for_nsx`, `vpc_offerings`.`network_mode` AS `network_mode`, `vpc_offerings`.`created` AS `created`, `vpc_offerings`.`removed` AS `removed`, diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java index 26b8de53083..52c3de88d93 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/BridgeVifDriver.java @@ -51,6 +51,10 @@ public class BridgeVifDriver extends VifDriverBase { private String _controlCidr = NetUtils.getLinkLocalCIDR(); private Long libvirtVersion; + private static boolean isVxlanOrNetris(String protocol) { + return protocol.equals(Networks.BroadcastDomainType.Vxlan.scheme()) || protocol.equals(Networks.BroadcastDomainType.Netris.scheme()); + } + @Override public void configure(Map params) throws ConfigurationException { @@ -177,7 +181,7 @@ public class BridgeVifDriver extends VifDriverBase { protected boolean isBroadcastTypeVlanOrVxlan(final NicTO nic) { return nic != null && (nic.getBroadcastType() == Networks.BroadcastDomainType.Vlan - || nic.getBroadcastType() == Networks.BroadcastDomainType.Vxlan); + || nic.getBroadcastType() == Networks.BroadcastDomainType.Vxlan || nic.getBroadcastType() == Networks.BroadcastDomainType.Netris); } protected boolean isValidProtocolAndVnetId(final String vNetId, final String protocol) { @@ -284,7 +288,7 @@ public class BridgeVifDriver extends VifDriverBase { private String createVnetBr(String vNetId, String pifKey, String protocol) throws InternalErrorException { String nic = _pifs.get(pifKey); - if (nic == null || protocol.equals(Networks.BroadcastDomainType.Vxlan.scheme())) { + if (nic == null || isVxlanOrNetris(protocol)) { // if not found in bridge map, maybe traffic label refers to pif already? File pif = new File("/sys/class/net/" + pifKey); if (pif.isDirectory()) { @@ -292,7 +296,7 @@ public class BridgeVifDriver extends VifDriverBase { } } String brName = ""; - if (protocol.equals(Networks.BroadcastDomainType.Vxlan.scheme())) { + if (isVxlanOrNetris(protocol)) { brName = generateVxnetBrName(nic, vNetId); } else { brName = generateVnetBrName(nic, vNetId); @@ -304,7 +308,7 @@ public class BridgeVifDriver extends VifDriverBase { private void createVnet(String vnetId, String pif, String brName, String protocol) throws InternalErrorException { synchronized (_vnetBridgeMonitor) { String script = _modifyVlanPath; - if (protocol.equals(Networks.BroadcastDomainType.Vxlan.scheme())) { + if (isVxlanOrNetris(protocol)) { script = _modifyVxlanPath; } final Script command = new Script(script, _timeout, logger); diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java index 2503e0ac7fd..193270cc156 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/network/element/CiscoNexusVSMElement.java @@ -24,7 +24,6 @@ import java.util.Set; import javax.inject.Inject; - import com.cloud.api.commands.DeleteCiscoNexusVSMCmd; import com.cloud.api.commands.DisableCiscoNexusVSMCmd; import com.cloud.api.commands.EnableCiscoNexusVSMCmd; diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java index 82e486cd103..d95bc0b9784 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/KubernetesClusterManagerImpl.java @@ -2646,7 +2646,6 @@ public class KubernetesClusterManagerImpl extends ManagerBase implements Kuberne forVpc, true, false, false); if (forNsx) { defaultKubernetesServiceNetworkOffering.setNetworkMode(NetworkOffering.NetworkMode.NATTED); - defaultKubernetesServiceNetworkOffering.setForNsx(true); } defaultKubernetesServiceNetworkOffering.setSupportsVmAutoScaling(true); defaultKubernetesServiceNetworkOffering.setState(NetworkOffering.State.Enabled); diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java index 5d88acaa411..93d6afc1df8 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/metrics/MetricsServiceImpl.java @@ -701,7 +701,7 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements metricsResponse.setCpuTotal(hostResponse.getCpuNumber(), hostResponse.getCpuSpeed()); metricsResponse.setCpuUsed(hostResponse.getCpuUsed(), hostResponse.getCpuNumber(), hostResponse.getCpuSpeed()); metricsResponse.setCpuAllocated(hostResponse.getCpuAllocated(), hostResponse.getCpuNumber(), hostResponse.getCpuSpeed()); - metricsResponse.setLoadAverage(hostResponse.getAverageLoad()); + metricsResponse.setCpuAverageLoad(hostResponse.getAverageLoad()); metricsResponse.setMemTotal(hostResponse.getMemoryTotal()); metricsResponse.setMemAllocated(hostResponse.getMemoryAllocated()); metricsResponse.setMemUsed(hostResponse.getMemoryUsed()); diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/HostMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/HostMetricsResponse.java index 8e12d2cbb6d..39d759f333f 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/response/HostMetricsResponse.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/HostMetricsResponse.java @@ -52,10 +52,6 @@ public class HostMetricsResponse extends HostResponse { @Param(description = "the total cpu allocated in Ghz") private String cpuAllocated; - @SerializedName("cpuloadaverage") - @Param(description = "the average cpu load the last minute") - private Double loadAverage; - @SerializedName("memorytotalgb") @Param(description = "the total memory capacity in GiB") private String memTotal; @@ -132,12 +128,6 @@ public class HostMetricsResponse extends HostResponse { } } - public void setLoadAverage(final Double loadAverage) { - if (loadAverage != null) { - this.loadAverage = loadAverage; - } - } - public void setCpuAllocated(final String cpuAllocated, final Integer cpuNumber, final Long cpuSpeed) { if (cpuAllocated != null && cpuNumber != null && cpuSpeed != null) { this.cpuAllocated = String.format("%.2f Ghz", parseCPU(cpuAllocated) * cpuNumber * cpuSpeed / (100.0 * 1000.0)); diff --git a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java index 83c6f3dc7d4..95c3fd09c07 100644 --- a/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java +++ b/plugins/metrics/src/main/java/org/apache/cloudstack/response/ManagementServerMetricsResponse.java @@ -22,7 +22,6 @@ import org.apache.cloudstack.api.MetricConstants; import org.apache.cloudstack.api.response.ManagementServerResponse; import java.util.Date; -import java.util.List; public class ManagementServerMetricsResponse extends ManagementServerResponse { @@ -30,14 +29,6 @@ public class ManagementServerMetricsResponse extends ManagementServerResponse { @Param(description = "the number of processors available to the JVM") private Integer availableProcessors; - @SerializedName(MetricConstants.LAST_AGENTS) - @Param(description = "the last agents this Management Server is responsible for, before shutdown or preparing for maintenance", since = "4.21.0.0") - private List lastAgents; - - @SerializedName(MetricConstants.AGENTS) - @Param(description = "the agents this Management Server is responsible for", since = "4.21.0.0") - private List agents; - @SerializedName(MetricConstants.AGENT_COUNT) @Param(description = "the number of agents this Management Server is responsible for") private Integer agentCount; @@ -130,14 +121,6 @@ public class ManagementServerMetricsResponse extends ManagementServerResponse { this.availableProcessors = availableProcessors; } - public void setLastAgents(List lastAgents) { - this.lastAgents = lastAgents; - } - - public void setAgents(List agents) { - this.agents = agents; - } - public void setAgentCount(int agentCount) { this.agentCount = agentCount; } diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 6da2e216ff8..f360fab0112 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -217,7 +217,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager) _configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, null, null, null, true, null, null, false); + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false, false, false, null, null, null, true, null, null, false); long id = voffer.getId(); _networkOfferingDao.update(id, voffer); return _networkOfferingDao.findById(id); @@ -252,7 +252,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager ConfigurationManager configMgr = (ConfigurationManager)_configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, null, null, null, true, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false, false, false, null, null, null, true, null, null, false); if (offeringName.equals(vpcRouterOfferingName)) { voffer.setInternalLb(true); } @@ -293,7 +293,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager } serviceProviderMap.put(svc, providerSet); } - vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, false, null, null, null, VpcOffering.State.Enabled, null, false); + vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null, null, null, null, VpcOffering.State.Enabled, null, false); long id = vpcOffer.getId(); _vpcOffDao.update(id, (VpcOfferingVO)vpcOffer); return _vpcOffDao.findById(id); diff --git a/plugins/network-elements/netris/pom.xml b/plugins/network-elements/netris/pom.xml new file mode 100644 index 00000000000..b49a92d9c54 --- /dev/null +++ b/plugins/network-elements/netris/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + cloud-plugin-network-netris + Apache CloudStack Plugin - Netris + + + org.apache.cloudstack + cloudstack-plugins + 4.21.0.0-SNAPSHOT + ../../pom.xml + + + + io.netris + netris-java-sdk + 1.0.0 + + + com.github.seancfoley + ipaddress + 5.5.1 + + + diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/StartupNetrisCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/StartupNetrisCommand.java new file mode 100644 index 00000000000..04be93067a6 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/StartupNetrisCommand.java @@ -0,0 +1,26 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack; + +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.Host; + +public class StartupNetrisCommand extends StartupCommand { + public StartupNetrisCommand() { + super(Host.Type.L2Networking); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommand.java new file mode 100644 index 00000000000..392016fc238 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommand.java @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class AddOrUpdateNetrisStaticRouteCommand extends NetrisCommand { + private String prefix; + private String nextHop; + private Long routeId; + private boolean updateRoute; + + public AddOrUpdateNetrisStaticRouteCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, String prefix, String nextHop, Long routeId, boolean updateRoute) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.prefix = prefix; + this.nextHop = nextHop; + this.routeId = routeId; + this.updateRoute = updateRoute; + } + + public String getPrefix() { + return prefix; + } + + public String getNextHop() { + return nextHop; + } + + public Long getRouteId() { + return routeId; + } + + public boolean isUpdateRoute() { + return updateRoute; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommand.java new file mode 100644 index 00000000000..26c36f696ed --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommand.java @@ -0,0 +1,119 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.apache.cloudstack.resource.NetrisPortGroup; + +public class CreateNetrisACLCommand extends NetrisCommand { + private String vpcName; + private Long vpcId; + private String action; + private String destPrefix; + private String sourcePrefix; + private Integer destPortStart; + private Integer destPortEnd; + private Integer icmpType; + private String protocol; + private NetrisPortGroup portGroup; + private String netrisAclName; + private String reason; + + public CreateNetrisACLCommand(long zoneId, Long accountId, Long domainId, String name, Long id, String vpcName, Long vpcId, boolean isVpc, String action, + String sourcePrefix, String destPrefix, Integer destPortStart, Integer destPortEnd, String protocol) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.vpcName = vpcName; + this.vpcId = vpcId; + this.action = action; + this.sourcePrefix = sourcePrefix; + this.destPrefix = destPrefix; + this.destPortStart = destPortStart; + this.destPortEnd = destPortEnd; + this.protocol = protocol; + } + + public String getVpcName() { + return vpcName; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + public String getAction() { + return action; + } + + public String getDestPrefix() { + return destPrefix; + } + + public String getSourcePrefix() { + return sourcePrefix; + } + + public Integer getDestPortStart() { + return destPortStart; + } + + public Integer getDestPortEnd() { + return destPortEnd; + } + + public String getProtocol() { + return protocol; + } + + public NetrisPortGroup getPortGroup() { + return portGroup; + } + + public void setPortGroup(NetrisPortGroup portGroup) { + this.portGroup = portGroup; + } + + public Integer getIcmpType() { + return icmpType; + } + + public void setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + } + + public String getNetrisAclName() { + return netrisAclName; + } + + public void setNetrisAclName(String netrisAclName) { + this.netrisAclName = netrisAclName; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java new file mode 100644 index 00000000000..e700b3b9d2d --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java @@ -0,0 +1,84 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class CreateNetrisVnetCommand extends NetrisCommand { + private String vpcName; + private Long vpcId; + private String cidr; + private Integer vxlanId; + private String gateway; + private String netrisTag; + private String ipv6Cidr; + private Boolean globalRouting; + + public CreateNetrisVnetCommand(Long zoneId, Long accountId, Long domainId, String vpcName, Long vpcId, String vNetName, Long networkId, String cidr, String gateway, boolean isVpc) { + super(zoneId, accountId, domainId, vNetName, networkId, isVpc); + this.vpcId = vpcId; + this.vpcName = vpcName; + this.cidr = cidr; + this.gateway = gateway; + } + + public Long getVpcId() { + return vpcId; + } + + public String getVpcName() { + return vpcName; + } + + public String getCidr() { + return cidr; + } + + public Integer getVxlanId() { + return vxlanId; + } + + public void setVxlanId(Integer vxlanId) { + this.vxlanId = vxlanId; + } + + public String getGateway() { + return gateway; + } + + public String getNetrisTag() { + return netrisTag; + } + + public void setNetrisTag(String netrisTag) { + this.netrisTag = netrisTag; + } + + public String getIpv6Cidr() { + return ipv6Cidr; + } + + public void setIpv6Cidr(String ipv6Cidr) { + this.ipv6Cidr = ipv6Cidr; + } + + public Boolean isGlobalRouting() { + return globalRouting; + } + + public void setGlobalRouting(Boolean globalRouting) { + this.globalRouting = globalRouting; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommand.java new file mode 100644 index 00000000000..cff25f78287 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommand.java @@ -0,0 +1,31 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class CreateNetrisVpcCommand extends NetrisCommand { + + private final String cidr; + + public CreateNetrisVpcCommand(long zoneId, long accountId, long domainId, String name, String cidr, long vpcId, boolean isVpc) { + super(zoneId, accountId, domainId, name, vpcId, isVpc); + this.cidr = cidr; + } + + public String getCidr() { + return cidr; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisACLCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisACLCommand.java new file mode 100644 index 00000000000..d3b782de6fb --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisACLCommand.java @@ -0,0 +1,119 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.apache.cloudstack.resource.NetrisPortGroup; + +public class CreateOrUpdateNetrisACLCommand extends NetrisCommand { + private String vpcName; + private Long vpcId; + private String action; + private String destPrefix; + private String sourcePrefix; + private Integer destPortStart; + private Integer destPortEnd; + private Integer icmpType; + private String protocol; + private NetrisPortGroup portGroup; + private String netrisAclName; + private String reason; + + public CreateOrUpdateNetrisACLCommand(long zoneId, Long accountId, Long domainId, String name, Long id, String vpcName, Long vpcId, boolean isVpc, String action, + String sourcePrefix, String destPrefix, Integer destPortStart, Integer destPortEnd, String protocol) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.vpcName = vpcName; + this.vpcId = vpcId; + this.action = action; + this.sourcePrefix = sourcePrefix; + this.destPrefix = destPrefix; + this.destPortStart = destPortStart; + this.destPortEnd = destPortEnd; + this.protocol = protocol; + } + + public String getVpcName() { + return vpcName; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + public String getAction() { + return action; + } + + public String getDestPrefix() { + return destPrefix; + } + + public String getSourcePrefix() { + return sourcePrefix; + } + + public Integer getDestPortStart() { + return destPortStart; + } + + public Integer getDestPortEnd() { + return destPortEnd; + } + + public String getProtocol() { + return protocol; + } + + public NetrisPortGroup getPortGroup() { + return portGroup; + } + + public void setPortGroup(NetrisPortGroup portGroup) { + this.portGroup = portGroup; + } + + public Integer getIcmpType() { + return icmpType; + } + + public void setIcmpType(Integer icmpType) { + this.icmpType = icmpType; + } + + public String getNetrisAclName() { + return netrisAclName; + } + + public void setNetrisAclName(String netrisAclName) { + this.netrisAclName = netrisAclName; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommand.java new file mode 100644 index 00000000000..a2a080b33d9 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommand.java @@ -0,0 +1,90 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import com.cloud.network.netris.NetrisLbBackend; + +import java.util.List; + +public class CreateOrUpdateNetrisLoadBalancerRuleCommand extends NetrisCommand { + private final String publicPort; + private final String privatePort; + private final String algorithm; + private final String protocol; + List lbBackends; + private String publicIp; + private final Long lbId; + private String cidrList; + private String ruleName; + + public CreateOrUpdateNetrisLoadBalancerRuleCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, + List lbBackends, long lbId, String publicIp, String publicPort, + String privatePort, String algorithm, String protocol) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.lbId = lbId; + this.publicIp = publicIp; + this.publicPort = publicPort; + this.privatePort = privatePort; + this.algorithm = algorithm; + this.protocol = protocol; + this.lbBackends = lbBackends; + } + + public String getPublicPort() { + return publicPort; + } + + public String getPrivatePort() { + return privatePort; + } + + public String getAlgorithm() { + return algorithm; + } + + public String getProtocol() { + return protocol; + } + + public List getLbBackends() { + return lbBackends; + } + + public Long getLbId() { + return lbId; + } + + public String getPublicIp() { + return publicIp; + } + + public String getCidrList() { + return cidrList; + } + + public void setCidrList(String cidrList) { + this.cidrList = cidrList; + } + + public String getRuleName() { + return ruleName; + } + + public void setRuleName(String ruleName) { + this.ruleName = ruleName; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java new file mode 100644 index 00000000000..ad1b150be3a --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommand.java @@ -0,0 +1,148 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class CreateOrUpdateNetrisNatCommand extends NetrisCommand { + private String vpcName; + private Long vpcId; + private String vpcCidr; + private String natRuleName; + private String natIp; + private String natRuleType; + + // Parameters for DNAT + private String protocol; + private String sourceAddress; + private String sourcePort; + private String destinationAddress; + private String destinationPort; + private String state; + + // Parameters for SNAT (Static NAT) + private String vmIp; + + public CreateOrUpdateNetrisNatCommand(long zoneId, Long accountId, Long domainId, String vpcName, Long vpcId, String vNetName, Long networkId, boolean isVpc, String vpcCidr) { + super(zoneId, accountId, domainId, vNetName, networkId, isVpc); + this.vpcName = vpcName; + this.vpcId = vpcId; + this.vpcCidr = vpcCidr; + } + + public String getVpcName() { + return vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public String getNatIp() { + return natIp; + } + + public void setNatRuleName(String natRuleName) { + this.natRuleName = natRuleName; + } + + public String getNatRuleName() { + return natRuleName; + } + + public String getVpcCidr() { + return vpcCidr; + } + + public void setNatIp(String natIp) { + this.natIp = natIp; + } + + public String getVmIp() { + return vmIp; + } + + public void setVmIp(String vmIp) { + this.vmIp = vmIp; + } + + public String getNatRuleType() { + return natRuleType; + } + + public void setNatRuleType(String natRuleType) { + this.natRuleType = natRuleType; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + public void setVpcCidr(String vpcCidr) { + this.vpcCidr = vpcCidr; + } + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getSourceAddress() { + return sourceAddress; + } + + public void setSourceAddress(String sourceAddress) { + this.sourceAddress = sourceAddress; + } + + public String getSourcePort() { + return sourcePort; + } + + public void setSourcePort(String sourcePort) { + this.sourcePort = sourcePort; + } + + public String getDestinationAddress() { + return destinationAddress; + } + + public void setDestinationAddress(String destinationAddress) { + this.destinationAddress = destinationAddress; + } + + public String getDestinationPort() { + return destinationPort; + } + + public void setDestinationPort(String destinationPort) { + this.destinationPort = destinationPort; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommand.java new file mode 100644 index 00000000000..e4a4993a257 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommand.java @@ -0,0 +1,46 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import java.util.List; + +public class DeleteNetrisACLCommand extends NetrisCommand { + Long vpcId; + String vpcName; + List aclRuleNames; + public DeleteNetrisACLCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, Long vpcId, String vpcName) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.vpcId = vpcId; + this.vpcName = vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public String getVpcName() { + return vpcName; + } + + public List getAclRuleNames() { + return aclRuleNames; + } + + public void setAclRuleNames(List aclRuleNames) { + this.aclRuleNames = aclRuleNames; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommand.java new file mode 100644 index 00000000000..3ca32c8112c --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommand.java @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class DeleteNetrisLoadBalancerRuleCommand extends NetrisCommand { + private Long lbId; + private String ruleName; + private String cidrList; + + public DeleteNetrisLoadBalancerRuleCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, Long lbId) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.lbId = lbId; + } + + public Long getLbId() { + return lbId; + } + + public void setLbId(Long lbId) { + this.lbId = lbId; + } + + public String getRuleName() { + return ruleName; + } + + public void setRuleName(String ruleName) { + this.ruleName = ruleName; + } + + public String getCidrList() { + return cidrList; + } + + public void setCidrList(String cidrList) { + this.cidrList = cidrList; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java new file mode 100644 index 00000000000..b01b2f45192 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommand.java @@ -0,0 +1,72 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class DeleteNetrisNatRuleCommand extends NetrisCommand { + + private String vpcName; + private Long vpcId; + private String natRuleType; + private String natRuleName; + private String natIp; + + public DeleteNetrisNatRuleCommand(long zoneId, Long accountId, Long domainId, String vpcName, Long vpcId, String vNetName, Long networkId, boolean isVpc) { + super(zoneId, accountId, domainId, vNetName, networkId, isVpc); + this.vpcName = vpcName; + this.vpcId = vpcId; + } + + public String getVpcName() { + return vpcName; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } + + public String getNatRuleType() { + return natRuleType; + } + + public void setNatRuleType(String natRuleType) { + this.natRuleType = natRuleType; + } + + public String getNatRuleName() { + return natRuleName; + } + + public void setNatRuleName(String natRuleName) { + this.natRuleName = natRuleName; + } + + public String getNatIp() { + return natIp; + } + + public void setNatIp(String natIp) { + this.natIp = natIp; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisStaticRouteCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisStaticRouteCommand.java new file mode 100644 index 00000000000..b531a049b0f --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisStaticRouteCommand.java @@ -0,0 +1,23 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class DeleteNetrisStaticRouteCommand extends AddOrUpdateNetrisStaticRouteCommand { + public DeleteNetrisStaticRouteCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, String prefix, String nextHop, Long routeId) { + super(zoneId, accountId, domainId, name, id, isVpc, prefix, nextHop, routeId, false); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommand.java new file mode 100644 index 00000000000..240c6c5417c --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommand.java @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class DeleteNetrisVnetCommand extends NetrisCommand { + private String vpcName; + private Long vpcId; + private final String vNetCidr; + private String vNetV6Cidr; + + public DeleteNetrisVnetCommand(long zoneId, long accountId, long domainId, String name, long id, String vpcName, Long vpcId, String vNetCidr, boolean isVpc) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.vpcName = vpcName; + this.vpcId = vpcId; + this.vNetCidr = vNetCidr; + } + + public String getVpcName() { + return vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public String getVNetCidr() { + return vNetCidr; + } + + public String getvNetV6Cidr() { + return vNetV6Cidr; + } + + public void setvNetV6Cidr(String vNetV6Cidr) { + this.vNetV6Cidr = vNetV6Cidr; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommand.java new file mode 100644 index 00000000000..d560f0b8cd9 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommand.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class DeleteNetrisVpcCommand extends NetrisCommand { + private final String cidr; + + public DeleteNetrisVpcCommand(long zoneId, long accountId, long domainId, String name, String cidr, long vpcId, boolean isVpc) { + super(zoneId, accountId, domainId, name, vpcId, isVpc); + this.cidr = cidr; + } + + public String getCidr() { + return cidr; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesAnswer.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesAnswer.java new file mode 100644 index 00000000000..421dc3359b6 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesAnswer.java @@ -0,0 +1,36 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import com.cloud.agent.api.Command; +import com.cloud.network.vpc.StaticRoute; + +import java.util.List; + +public class ListNetrisStaticRoutesAnswer extends NetrisAnswer { + + List staticRoutes; + + public ListNetrisStaticRoutesAnswer(final Command command, final List staticRoutes) { + super(command, true, "OK"); + this.staticRoutes = staticRoutes; + } + + public List getStaticRoutes() { + return staticRoutes; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesCommand.java new file mode 100644 index 00000000000..e116a2386cb --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ListNetrisStaticRoutesCommand.java @@ -0,0 +1,23 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class ListNetrisStaticRoutesCommand extends AddOrUpdateNetrisStaticRouteCommand { + public ListNetrisStaticRoutesCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, String prefix, String nextHop, Long routeId) { + super(zoneId, accountId, domainId, name, id, isVpc, prefix, nextHop, routeId, false); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisAnswer.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisAnswer.java new file mode 100644 index 00000000000..197500a3cce --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisAnswer.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class NetrisAnswer extends Answer { + public NetrisAnswer(final Command command, final boolean success, final String details) { + super(command, success, details); + } + + public NetrisAnswer(final Command command, final Exception e) { + super(command, e); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java new file mode 100644 index 00000000000..280c7de32d1 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java @@ -0,0 +1,70 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import com.cloud.agent.api.Command; + +public class NetrisCommand extends Command { + private final long zoneId; + private final Long accountId; + private final Long domainId; + private String name; + private final Long id; + private final boolean isVpc; + + public NetrisCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc) { + this.zoneId = zoneId; + this.accountId = accountId; + this.domainId = domainId; + this.name = name; + this.id = id; + this.isVpc = isVpc; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public long getZoneId() { + return zoneId; + } + + public Long getAccountId() { + return accountId; + } + + public Long getDomainId() { + return domainId; + } + + public boolean isVpc() { + return isVpc; + } + + @Override + public boolean executeInSequence() { + return false; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommand.java new file mode 100644 index 00000000000..ac3a4faba4d --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommand.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class ReleaseNatIpCommand extends NetrisCommand { + private String natIp; + + public ReleaseNatIpCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc, String natIp) { + super(zoneId, accountId, domainId, name, id, isVpc); + this.natIp = natIp; + } + + public String getNatIp() { + return natIp; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommand.java new file mode 100644 index 00000000000..5cbdd96e76a --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommand.java @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class SetupNetrisPublicRangeCommand extends NetrisCommand { + + private final String superCidr; + private final String exactCidr; + + public SetupNetrisPublicRangeCommand(long zoneId, String superCidr, String exactCidr) { + super(zoneId, null, null, null, zoneId, false); + this.superCidr = superCidr; + this.exactCidr = exactCidr; + } + + public String getSuperCidr() { + return superCidr; + } + + public String getExactCidr() { + return exactCidr; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommand.java new file mode 100644 index 00000000000..99a266e15ad --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommand.java @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class UpdateNetrisVnetCommand extends NetrisCommand{ + private String prevNetworkName; + private String vpcName; + private Long vpcId; + + public UpdateNetrisVnetCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc) { + super(zoneId, accountId, domainId, name, id, isVpc); + } + + public String getPrevNetworkName() { + return prevNetworkName; + } + + public void setPrevNetworkName(String prevNetworkName) { + this.prevNetworkName = prevNetworkName; + } + + public String getVpcName() { + return vpcName; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } + + public Long getVpcId() { + return vpcId; + } + + public void setVpcId(Long vpcId) { + this.vpcId = vpcId; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommand.java new file mode 100644 index 00000000000..764d9155a02 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommand.java @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +public class UpdateNetrisVpcCommand extends NetrisCommand { + private String previousVpcName; + public UpdateNetrisVpcCommand(long zoneId, Long accountId, Long domainId, String name, Long id, boolean isVpc) { + super(zoneId, accountId, domainId, name, id, isVpc); + } + + public String getPreviousVpcName() { + return previousVpcName; + } + + public void setPreviousVpcName(String previousVpcName) { + this.previousVpcName = previousVpcName; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/AddNetrisProviderCmd.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/AddNetrisProviderCmd.java new file mode 100644 index 00000000000..5cdecc77d3b --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/AddNetrisProviderCmd.java @@ -0,0 +1,126 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.network.netris.NetrisProvider; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NetrisProviderResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.service.NetrisProviderService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.inject.Inject; + +@APICommand(name = AddNetrisProviderCmd.APINAME, description = "Add Netris Provider to CloudStack", + responseObject = NetrisProviderResponse.class, requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin}, + since = "4.21.0") +public class AddNetrisProviderCmd extends BaseCmd { + public static final String APINAME = "addNetrisProvider"; + public static final Logger LOGGER = LoggerFactory.getLogger(AddNetrisProviderCmd.class.getName()); + + @Inject + NetrisProviderService netrisProviderService; + + @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, + description = "the ID of zone") + private Long zoneId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Netris provider name") + private String name; + + @Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "Netris provider URL") + private String url; + + @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "Username to login into Netris") + private String username; + + @Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, required = true, description = "Password to login into Netris") + private String password; + + @Parameter(name = ApiConstants.SITE_NAME, type = CommandType.STRING, required = true, description = "Netris Site name") + private String siteName; + + @Parameter(name = ApiConstants.TENANT_NAME, type = CommandType.STRING, required = true, description = "Netris Tenant name") + private String tenantName; + + @Parameter(name = ApiConstants.NETRIS_TAG, type = CommandType.STRING, required = true, description = "Netris tag for vNets") + private String netrisTag; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getZoneId() { + return zoneId; + } + + public String getName() { + return name; + } + + public String getUrl() { + return url; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getSiteName() { + return siteName; + } + + public String getTenantName() { + return tenantName; + } + + public String getNetrisTag() { + return netrisTag; + } + + @Override + public void execute() throws ServerApiException, ConcurrentOperationException { + NetrisProvider provider = netrisProviderService.addProvider(this); + NetrisProviderResponse response = netrisProviderService.createNetrisProviderResponse(provider); + if (response == null) + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Netris provider"); + else { + response.setResponseName(getCommandName()); + setResponseObject(response); + } + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmd.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmd.java new file mode 100644 index 00000000000..6865e113361 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmd.java @@ -0,0 +1,86 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NetrisProviderResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.service.NetrisProviderService; + +import javax.inject.Inject; + +import static org.apache.cloudstack.api.command.DeleteNetrisProviderCmd.APINAME; + +@APICommand(name = APINAME, description = "delete Netris Provider to CloudStack", + responseObject = NetrisProviderResponse.class, requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, + authorized = {RoleType.Admin}, since = "4.21.0") +public class DeleteNetrisProviderCmd extends BaseCmd { + public static final String APINAME = "deleteNetrisProvider"; + + @Inject + private NetrisProviderService netrisProviderService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = NetrisProviderResponse.class, + required = true, description = "Netris Provider ID") + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { return id; } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ServerApiException, ConcurrentOperationException { + try { + boolean deleted = netrisProviderService.deleteNetrisProvider(getId()); + if (deleted) { + SuccessResponse response = new SuccessResponse(getCommandName()); + response.setResponseName(getCommandName()); + setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to Netris provider from zone"); + } + } catch (InvalidParameterValueException e) { + throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage()); + } catch (CloudRuntimeException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); + } + } + + @Override + public long getEntityOwnerId() { + return 0; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmd.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmd.java new file mode 100644 index 00000000000..c2f572a46bc --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmd.java @@ -0,0 +1,73 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.utils.StringUtils; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetrisProviderResponse; +import org.apache.cloudstack.api.response.ZoneResponse; +import org.apache.cloudstack.service.NetrisProviderService; + +import javax.inject.Inject; +import java.util.List; + +@APICommand(name = ListNetrisProvidersCmd.APINAME, description = "list all Netris providers added to CloudStack", + responseObject = NetrisProviderResponse.class, requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false, since = "4.21.0") +public class ListNetrisProvidersCmd extends BaseListCmd { + public static final String APINAME = "listNetrisProviders"; + + @Inject + NetrisProviderService netrisProviderService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + /// + @Parameter(name = ApiConstants.ZONE_ID, description = "ID of the zone", + type = CommandType.UUID, entityType = ZoneResponse.class) + Long zoneId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getZoneId() { + return zoneId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ServerApiException, ConcurrentOperationException { + List baseResponseList = netrisProviderService.listNetrisProviders(zoneId); + List pagingList = StringUtils.applyPagination(baseResponseList, this.getStartIndex(), this.getPageSizeVal()); + ListResponse listResponse = new ListResponse<>(); + listResponse.setResponses(pagingList); + listResponse.setResponseName(getCommandName()); + setResponseObject(listResponse); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/response/NetrisProviderResponse.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/response/NetrisProviderResponse.java new file mode 100644 index 00000000000..d130c3a7372 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/response/NetrisProviderResponse.java @@ -0,0 +1,135 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.api.response; + +import com.cloud.network.netris.NetrisProvider; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = {NetrisProvider.class}) +public class NetrisProviderResponse extends BaseResponse { + @SerializedName(ApiConstants.NAME) + @Param(description = "Netris Provider name") + private String name; + + @SerializedName(ApiConstants.UUID) + @Param(description = "Netris provider uuid") + private String uuid; + + @SerializedName(ApiConstants.ZONE_ID) + @Param(description = "Zone ID to which the Netris Provider is associated with") + private String zoneId; + + @SerializedName(ApiConstants.ZONE_NAME) + @Param(description = "Zone name to which the Netris Provider is associated with") + private String zoneName; + + @SerializedName(ApiConstants.HOST_NAME) + @Param(description = "Netris Provider hostname or IP address") + private String hostname; + + @SerializedName(ApiConstants.PORT) + @Param(description = "Netris Provider port") + private String port; + + @SerializedName(ApiConstants.SITE_NAME) + @Param(description = "Netris Provider site") + private String siteName; + + @SerializedName(ApiConstants.TENANT_NAME) + @Param(description = "Netris Admin tenant name") + private String tenantName; + + @SerializedName(ApiConstants.NETRIS_TAG) + @Param(description = "Netris Tag for vNets") + private String netrisTag; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getZoneId() { + return zoneId; + } + + public void setZoneId(String zoneId) { + this.zoneId = zoneId; + } + + public String getZoneName() { + return zoneName; + } + + public void setZoneName(String zoneName) { + this.zoneName = zoneName; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getSiteName() { + return siteName; + } + + public void setSiteName(String siteName) { + this.siteName = siteName; + } + + public String getTenantName() { + return tenantName; + } + + public void setTenantName(String tenantName) { + this.tenantName = tenantName; + } + + public String getNetrisTag() { + return netrisTag; + } + + public void setNetrisTag(String netrisTag) { + this.netrisTag = netrisTag; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisPortGroup.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisPortGroup.java new file mode 100644 index 00000000000..0f533e011e4 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisPortGroup.java @@ -0,0 +1,30 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.resource; + +public class NetrisPortGroup { + private String ports; + + public NetrisPortGroup() { + } + + public NetrisPortGroup(String ports) { + this.ports = ports; + } + + public String getPorts() { return ports; } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java new file mode 100644 index 00000000000..4aef6d2d80a --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java @@ -0,0 +1,441 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.resource; + +import com.cloud.agent.IAgentControl; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.CheckHealthAnswer; +import com.cloud.agent.api.CheckHealthCommand; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.PingCommand; +import com.cloud.agent.api.ReadyAnswer; +import com.cloud.agent.api.ReadyCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.Host; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.resource.ServerResource; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisACLCommand; +import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisACLCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.ListNetrisStaticRoutesAnswer; +import org.apache.cloudstack.agent.api.ListNetrisStaticRoutesCommand; +import org.apache.cloudstack.agent.api.NetrisAnswer; +import org.apache.cloudstack.StartupNetrisCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; +import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVpcCommand; +import org.apache.cloudstack.service.NetrisApiClient; +import org.apache.cloudstack.service.NetrisApiClientImpl; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.naming.ConfigurationException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NetrisResource implements ServerResource { + protected Logger logger = LogManager.getLogger(getClass()); + + private String name; + protected String endpointUrl; + protected String username; + protected String password; + protected String guid; + protected String zoneId; + protected String siteName; + protected String adminTenantName; + + protected NetrisApiClient netrisApiClient; + + @Override + public Host.Type getType() { + return Host.Type.Routing; + } + + @Override + public StartupCommand[] initialize() { + StartupNetrisCommand sc = new StartupNetrisCommand(); + sc.setGuid(guid); + sc.setName(name); + sc.setDataCenter(zoneId); + sc.setPod(""); + sc.setPrivateIpAddress(""); + sc.setStorageIpAddress(""); + sc.setVersion(""); + return new StartupCommand[] {sc}; + } + + @Override + public PingCommand getCurrentStatus(long id) { + return null; + } + + @Override + public Answer executeRequest(Command cmd) { + if (cmd instanceof ReadyCommand) { + return executeRequest((ReadyCommand) cmd); + } else if (cmd instanceof CheckHealthCommand) { + return executeRequest((CheckHealthCommand) cmd); + } else if (cmd instanceof CreateNetrisVpcCommand) { + return executeRequest((CreateNetrisVpcCommand) cmd); + } else if (cmd instanceof UpdateNetrisVpcCommand) { + return executeRequest((UpdateNetrisVpcCommand) cmd); + } else if (cmd instanceof DeleteNetrisVpcCommand) { + return executeRequest((DeleteNetrisVpcCommand) cmd); + } else if (cmd instanceof CreateNetrisVnetCommand) { + return executeRequest((CreateNetrisVnetCommand) cmd); + } else if (cmd instanceof UpdateNetrisVnetCommand) { + return executeRequest((UpdateNetrisVnetCommand) cmd); + } else if (cmd instanceof DeleteNetrisVnetCommand) { + return executeRequest((DeleteNetrisVnetCommand) cmd); + } else if (cmd instanceof SetupNetrisPublicRangeCommand) { + return executeRequest((SetupNetrisPublicRangeCommand) cmd); + } else if (cmd instanceof DeleteNetrisNatRuleCommand) { + return executeRequest((DeleteNetrisNatRuleCommand) cmd); + } else if (cmd instanceof CreateOrUpdateNetrisNatCommand) { + return executeRequest((CreateOrUpdateNetrisNatCommand) cmd); + } else if (cmd instanceof CreateOrUpdateNetrisACLCommand) { + return executeRequest((CreateOrUpdateNetrisACLCommand) cmd); + } else if (cmd instanceof DeleteNetrisACLCommand) { + return executeRequest((DeleteNetrisACLCommand) cmd); + } else if (cmd instanceof ListNetrisStaticRoutesCommand) { + return executeRequest((ListNetrisStaticRoutesCommand) cmd); + } else if (cmd instanceof DeleteNetrisStaticRouteCommand) { + return executeRequest((DeleteNetrisStaticRouteCommand) cmd); + } else if (cmd instanceof AddOrUpdateNetrisStaticRouteCommand) { + return executeRequest((AddOrUpdateNetrisStaticRouteCommand) cmd); + } else if (cmd instanceof ReleaseNatIpCommand) { + return executeRequest((ReleaseNatIpCommand) cmd); + } else if (cmd instanceof CreateOrUpdateNetrisLoadBalancerRuleCommand) { + return executeRequest((CreateOrUpdateNetrisLoadBalancerRuleCommand) cmd); + } else if (cmd instanceof DeleteNetrisLoadBalancerRuleCommand) { + return executeRequest((DeleteNetrisLoadBalancerRuleCommand) cmd); + } else { + return Answer.createUnsupportedCommandAnswer(cmd); + } + } + + @Override + public void disconnected() { + // Do nothing + } + + @Override + public IAgentControl getAgentControl() { + return null; + } + + @Override + public void setAgentControl(IAgentControl agentControl) { + // Do nothing + } + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + this.name = name; + } + + @Override + public void setConfigParams(Map params) { + // Do nothing + } + + @Override + public Map getConfigParams() { + return new HashMap<>(); + } + + @Override + public int getRunLevel() { + return 0; + } + + @Override + public void setRunLevel(int level) { + + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + endpointUrl = (String) params.get("url"); + if (endpointUrl == null) { + throw new ConfigurationException("Missing Netris provider URL from params: " + params); + } + + username = (String) params.get("username"); + if (username == null) { + throw new ConfigurationException("Missing Netris username from params: " + params); + } + + password = (String) params.get("password"); + if (password == null) { + throw new ConfigurationException("Missing Netris password from params: " + params); + } + + this.name = (String) params.get("name"); + if (this.name == null) { + throw new ConfigurationException("Unable to find name"); + } + + guid = (String) params.get("guid"); + if (guid == null) { + throw new ConfigurationException("Unable to find the guid"); + } + + zoneId = (String) params.get("zoneId"); + if (zoneId == null) { + throw new ConfigurationException("Unable to find zone"); + } + + siteName = (String) params.get("siteName"); + if (siteName == null) { + throw new ConfigurationException("Unable to find the Netris site name"); + } + + adminTenantName = (String) params.get("tenantName"); + if (adminTenantName == null) { + throw new ConfigurationException("Unable to find the Netris admin tenant name"); + } + + netrisApiClient = new NetrisApiClientImpl(endpointUrl, username, password, siteName, adminTenantName); + return netrisApiClient.isSessionAlive(); + } + + private Answer executeRequest(ReadyCommand cmd) { + return new ReadyAnswer(cmd); + } + + private Answer executeRequest(CheckHealthCommand cmd) { + return new CheckHealthAnswer(cmd, netrisApiClient.isSessionAlive()); + } + + private Answer executeRequest(CreateNetrisVpcCommand cmd) { + try { + boolean result = netrisApiClient.createVpc(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Netris VPC %s creation failed", cmd.getName())); + } + return new NetrisAnswer(cmd, true, "OK"); + } catch (CloudRuntimeException e) { + String msg = String.format("Error creating Netris VPC: %s", e.getMessage()); + logger.error(msg, e); + return new NetrisAnswer(cmd, new CloudRuntimeException(msg)); + } + } + + private Answer executeRequest(UpdateNetrisVpcCommand cmd) { + try { + boolean result = netrisApiClient.updateVpc(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Netris VPC %s creation failed", cmd.getName())); + } + return new NetrisAnswer(cmd, true, "OK"); + } catch (CloudRuntimeException e) { + String msg = String.format("Error creating Netris VPC: %s", e.getMessage()); + logger.error(msg, e); + return new NetrisAnswer(cmd, new CloudRuntimeException(msg)); + } + } + + private Answer executeRequest(CreateNetrisVnetCommand cmd) { + try { + String vpcName = cmd.getVpcName(); + boolean result = netrisApiClient.createVnet(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Netris VPC %s creation failed", vpcName)); + } + return new NetrisAnswer(cmd, true, "OK"); + } catch (CloudRuntimeException e) { + String msg = String.format("Error creating Netris VPC: %s", e.getMessage()); + logger.error(msg, e); + return new NetrisAnswer(cmd, new CloudRuntimeException(msg)); + } + } + + private Answer executeRequest(UpdateNetrisVnetCommand cmd) { + try { + String networkName = cmd.getName(); + String prevNetworkName = cmd.getPrevNetworkName(); + boolean result = netrisApiClient.updateVnet(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to update network name from %s to %s", prevNetworkName, networkName)); + } + return new NetrisAnswer(cmd, true, "OK"); + } catch (CloudRuntimeException e) { + String msg = String.format("Error updating Netris vNet: %s", e.getMessage()); + logger.error(msg, e); + return new NetrisAnswer(cmd, new CloudRuntimeException(msg)); + } + } + + private Answer executeRequest(DeleteNetrisVnetCommand cmd) { + try { + String networkName = cmd.getName(); + boolean result = netrisApiClient.deleteVnet(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Netris vNet: %s deletion failed", networkName)); + } + return new NetrisAnswer(cmd, true, "OK"); + } catch (CloudRuntimeException e) { + String msg = String.format("Error deleting Netris vNet: %s", e.getMessage()); + logger.error(msg, e); + return new NetrisAnswer(cmd, new CloudRuntimeException(msg)); + } + } + + private Answer executeRequest(DeleteNetrisVpcCommand cmd) { + boolean result = netrisApiClient.deleteVpc(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Netris VPC %s deletion failed", cmd.getName())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(SetupNetrisPublicRangeCommand cmd) { + boolean result = netrisApiClient.setupZoneLevelPublicRange(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, "Netris Setup for Public Range failed"); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(CreateOrUpdateNetrisNatCommand cmd) { + String natRuleType = cmd.getNatRuleType(); + if ("SNAT".equals(natRuleType)) { + boolean result = netrisApiClient.createOrUpdateSNATRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to create SNAT rule on Netris for network %s", cmd.getName())); + } + } else if ("DNAT".equals(natRuleType)) { + boolean result = netrisApiClient.createOrUpdateDNATRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to create DNAT rule on Netris for network %s", cmd.getName())); + } + } else if ("STATICNAT".equals(natRuleType)) { + boolean result = netrisApiClient.createStaticNatRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to create SNAT rule on Netris for network %s", cmd.getName())); + } + } + + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(DeleteNetrisNatRuleCommand cmd) { + boolean result = netrisApiClient.deleteNatRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Netris NAT rule: %s deletion failed", cmd.getNatRuleName())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(CreateOrUpdateNetrisACLCommand cmd) { + boolean result = netrisApiClient.addOrUpdateAclRule(cmd, false); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Creation of Netris ACL rule: %s failed", cmd.getNetrisAclName())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(DeleteNetrisACLCommand cmd) { + boolean result = netrisApiClient.deleteAclRule(cmd, false); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to delete Netris ACLs: %s", String.join("'", cmd.getAclRuleNames()))); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(ListNetrisStaticRoutesCommand cmd) { + List staticRoutes = netrisApiClient.listStaticRoutes(cmd); + return new ListNetrisStaticRoutesAnswer(cmd, staticRoutes); + } + + private Answer executeRequest(AddOrUpdateNetrisStaticRouteCommand cmd) { + boolean result = netrisApiClient.addOrUpdateStaticRoute(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to add static route for VPC: %s, prefix: %s, nextHop: %s ", cmd.getName(), cmd.getPrefix(), cmd.getNextHop())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(DeleteNetrisStaticRouteCommand cmd) { + boolean result = netrisApiClient.deleteStaticRoute(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to add static route for VPC: %s, prefix: %s, nextHop: %s ", cmd.getName(), cmd.getPrefix(), cmd.getNextHop())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(ReleaseNatIpCommand cmd) { + boolean result = netrisApiClient.releaseNatIp(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to release NAT IP: %s", cmd.getNatIp())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(CreateOrUpdateNetrisLoadBalancerRuleCommand cmd) { + boolean result = netrisApiClient.createOrUpdateLbRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to create Netris LB rule for %s: %s, " + + "for private port: %s and public port: %s", getNetworkType(cmd.isVpc()), cmd.getName(), cmd.getPrivatePort(), cmd.getPublicPort())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private Answer executeRequest(DeleteNetrisLoadBalancerRuleCommand cmd) { + boolean result = netrisApiClient.deleteLbRule(cmd); + if (!result) { + return new NetrisAnswer(cmd, false, String.format("Failed to delete Netris LB rule for %s: %s", getNetworkType(cmd.isVpc()), cmd.getName())); + } + return new NetrisAnswer(cmd, true, "OK"); + } + + private String getNetworkType(Boolean isVpc) { + if (isVpc) { + return "VPC"; + } + return "Network"; + } + + @Override + public boolean start() { + return true; + } + + @Override + public boolean stop() { + return true; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java new file mode 100644 index 00000000000..164c56cd763 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.resource; + +import org.apache.cloudstack.agent.api.NetrisCommand; +import org.apache.commons.lang3.ArrayUtils; + +import java.util.Objects; + +public class NetrisResourceObjectUtils { + + public enum NetrisObjectType { + VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET, SNAT, STATICNAT, DNAT, STATICROUTE, ACL, LB + } + + public static String retrieveNetrisResourceObjectName(NetrisCommand cmd, NetrisObjectType netrisObjectType, String... suffixes) { + long zoneId = cmd.getZoneId(); + Long accountId = cmd.getAccountId(); + Long domainId = cmd.getDomainId(); + Long objectId = cmd.getId(); + String objectName = cmd.getName(); + boolean isVpc = cmd.isVpc(); + boolean isZoneLevel = accountId == null && domainId == null; + + StringBuilder stringBuilder = new StringBuilder(); + if (isZoneLevel) { + stringBuilder.append(String.format("Z%s", zoneId)); + } else { + stringBuilder.append(String.format("D%s-A%s-Z%s", domainId, accountId, zoneId)); + } + String prefix = isVpc ? "-V" : "-N"; + switch (netrisObjectType) { + case VPC: + if (ArrayUtils.isEmpty(suffixes)) { + stringBuilder.append(String.format("%s%s-%s", prefix, objectId, objectName)); + } else { + stringBuilder.append(String.format("%s%s", prefix, suffixes[0])); + suffixes = new String[0]; + } + break; + case IPAM_ALLOCATION: + if (!isZoneLevel) { + stringBuilder.append(String.format("%s%s", prefix, objectId)); + } + break; + case IPAM_SUBNET: + if (!isZoneLevel) { + if (Objects.nonNull(objectId) && Objects.nonNull(objectName) && !isVpc) { + stringBuilder.append(String.format("-N%s", objectId)); + } else { + stringBuilder.append(String.format("-V%s-%s", suffixes[0], suffixes[1])); + return stringBuilder.toString(); + } + } + break; + case SNAT: + stringBuilder.append(String.format("%s%s-%s", prefix, suffixes[0], "SNAT")); + suffixes = new String[0]; + break; + case STATICNAT: + stringBuilder.append(String.format("%s%s-VM%s-%s", prefix, suffixes[0], suffixes[1], "STATICNAT")); + suffixes = new String[0]; + break; + case DNAT: + stringBuilder.append(String.format("%s%s-%s", prefix, suffixes[0], "DNAT")); + suffixes = ArrayUtils.subarray(suffixes, 1, suffixes.length); + break; + case STATICROUTE: + stringBuilder.append(String.format("%s%s-%s%s", prefix, suffixes[0], "ROUTE", suffixes[1])); + suffixes = new String[0]; + break; + case VNET: + case ACL: + break; + case LB: + stringBuilder.append(String.format("%s%s", prefix, objectId)); + break; + default: + stringBuilder.append(String.format("-%s", objectName)); + break; + } + if (ArrayUtils.isNotEmpty(suffixes)) { + for (String suffix : suffixes) { + stringBuilder.append(String.format("-%s", suffix)); + } + } + return stringBuilder.toString(); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java new file mode 100644 index 00000000000..4261c6dc961 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClient.java @@ -0,0 +1,100 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.network.vpc.StaticRoute; +import io.netris.ApiException; +import io.netris.model.GetSiteBody; +import io.netris.model.VPCListing; +import io.netris.model.response.TenantResponse; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisACLCommand; +import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisACLCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.ListNetrisStaticRoutesCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; +import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVpcCommand; + +import java.util.List; + +public interface NetrisApiClient { + boolean isSessionAlive(); + List listSites(); + List listVPCs(); + List listTenants() throws ApiException; + + /** + * Create a VPC on CloudStack creates the following Netris resources: + * - Create a Netris VPC with the VPC name + * - Create an IPAM Allocation for the created Netris VPC using the Prefix = VPC CIDR + */ + boolean createVpc(CreateNetrisVpcCommand cmd); + + boolean updateVpc(UpdateNetrisVpcCommand cmd); + + /** + * Delete a VPC on CloudStack removes the following Netris resources: + * - Delete the IPAM Allocation for the VPC using the Prefix = VPC CIDR + * - Delete a Netris VPC with the VPC name + */ + boolean deleteVpc(DeleteNetrisVpcCommand cmd); + + /** + * Creation of a VPC network tier creates the following Netris resources: + * - Creates a Netris IPAM Subnet for the specified network tier's CIDR + * - Creates a Netris vNet + */ + boolean createVnet(CreateNetrisVnetCommand cmd); + + boolean updateVnet(UpdateNetrisVnetCommand cmd); + + /** + * Deletion of a VPC network tier deletes the following Netris resources: + * - Deletes the Netris IPAM Subnet for the specified network tier's CIDR + * - Deletes the Netris vNet + */ + boolean deleteVnet(DeleteNetrisVnetCommand cmd); + + /** + * Check and create zone level Netris Public range in the following manner: + * - Check the IPAM allocation for the zone super CIDR. In case it doesn't exist, create it + * - Check the IPAM subnet for NAT purpose for the range start-end. In case it doesn't exist, create it + */ + boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd); + boolean createOrUpdateSNATRule(CreateOrUpdateNetrisNatCommand cmd); + boolean createOrUpdateDNATRule(CreateOrUpdateNetrisNatCommand cmd); + boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd); + boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd); + boolean addOrUpdateAclRule(CreateOrUpdateNetrisACLCommand cmd, boolean forLb); + boolean deleteAclRule(DeleteNetrisACLCommand cmd, boolean forLb); + boolean addOrUpdateStaticRoute(AddOrUpdateNetrisStaticRouteCommand cmd); + boolean deleteStaticRoute(DeleteNetrisStaticRouteCommand cmd); + List listStaticRoutes(ListNetrisStaticRoutesCommand cmd); + boolean releaseNatIp(ReleaseNatIpCommand cmd); + boolean createOrUpdateLbRule(CreateOrUpdateNetrisLoadBalancerRuleCommand cmd); + boolean deleteLbRule(DeleteNetrisLoadBalancerRuleCommand cmd); +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java new file mode 100644 index 00000000000..e54006d2f1c --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisApiClientImpl.java @@ -0,0 +1,2000 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.domain.Domain; +import com.cloud.network.netris.NetrisLbBackend; +import com.cloud.network.netris.NetrisNetworkRule; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.StaticRouteVO; +import com.cloud.user.Account; +import com.cloud.utils.Pair; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; +import io.netris.ApiClient; +import io.netris.ApiException; +import io.netris.ApiResponse; +import io.netris.api.v1.AclApi; +import io.netris.api.v1.AuthenticationApi; +import io.netris.api.v1.RoutesApi; +import io.netris.api.v1.SitesApi; +import io.netris.api.v1.TenantsApi; +import io.netris.api.v2.IpamApi; +import io.netris.api.v2.L4LoadBalancerApi; +import io.netris.api.v2.NatApi; +import io.netris.api.v2.VNetApi; +import io.netris.api.v2.VpcApi; +import io.netris.model.AclAddItem; +import io.netris.model.AclBodyVpc; +import io.netris.model.AclDeleteItem; +import io.netris.model.AclEditItem; +import io.netris.model.AclGetBody; +import io.netris.model.AclResponseGetOk; +import io.netris.model.AllocationBody; +import io.netris.model.AllocationBodyVpc; +import io.netris.model.FilterBySites; +import io.netris.model.FilterByVpc; +import io.netris.model.GetSiteBody; + +import io.netris.model.InlineResponse20015; +import io.netris.model.InlineResponse20016; +import io.netris.model.InlineResponse2003; +import io.netris.model.InlineResponse2004; +import io.netris.model.InlineResponse2004Data; +import io.netris.model.IpTree; +import io.netris.model.IpTreeAllocation; +import io.netris.model.IpTreeAllocationTenant; +import io.netris.model.IpTreeSubnet; +import io.netris.model.IpTreeSubnetSites; +import io.netris.model.L4LBSite; +import io.netris.model.L4LbAddItem; +import io.netris.model.L4LbEditItem; +import io.netris.model.L4LbTenant; +import io.netris.model.L4LbVpc; +import io.netris.model.L4LoadBalancerBackendItem; +import io.netris.model.L4LoadBalancerItem; +import io.netris.model.L4lbAddOrUpdateItem; +import io.netris.model.L4lbresBody; +import io.netris.model.NatBodySiteSite; +import io.netris.model.NatBodyVpcVpc; +import io.netris.model.NatGetBody; +import io.netris.model.NatPostBody; +import io.netris.model.NatPutBody; +import io.netris.model.NatResponseGetOk; +import io.netris.model.ResAddEditBody; +import io.netris.model.RoutesBody; +import io.netris.model.RoutesBodyId; +import io.netris.model.RoutesBodyVpcVpc; +import io.netris.model.RoutesGetBody; +import io.netris.model.RoutesPostBody; +import io.netris.model.RoutesPutBody; +import io.netris.model.RoutesResponseGetOk; +import io.netris.model.SitesResponseOK; +import io.netris.model.SubnetBody; +import io.netris.model.SubnetResBody; +import io.netris.model.VPCAdminTenant; +import io.netris.model.VPCCreate; +import io.netris.model.VPCListing; +import io.netris.model.VPCResource; +import io.netris.model.VPCResourceIpam; +import io.netris.model.VPCResponseOK; +import io.netris.model.VPCResponseObjectOK; +import io.netris.model.VPCResponseResourceOK; +import io.netris.model.VnetAddBody; +import io.netris.model.VnetAddBodyDhcp; +import io.netris.model.VnetAddBodyDhcpOptionSet; +import io.netris.model.VnetAddBodyGateways; +import io.netris.model.VnetAddBodyVpc; +import io.netris.model.VnetEditBody; +import io.netris.model.VnetEditBodyDhcp; +import io.netris.model.VnetEditBodyGateways; +import io.netris.model.VnetResAddBody; +import io.netris.model.VnetResDeleteBody; +import io.netris.model.VnetResListBody; +import io.netris.model.VnetsBody; +import io.netris.model.VpcEditResponseOK; +import io.netris.model.VpcVpcIdBody; +import io.netris.model.response.AuthResponse; +import io.netris.model.response.L4LbEditResponse; +import io.netris.model.response.TenantResponse; +import io.netris.model.response.TenantsResponse; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisACLCommand; +import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisACLCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.ListNetrisStaticRoutesCommand; +import org.apache.cloudstack.agent.api.NetrisCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; +import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVpcCommand; +import org.apache.cloudstack.resource.NetrisResourceObjectUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +public class NetrisApiClientImpl implements NetrisApiClient { + + private final Logger logger = LogManager.getLogger(getClass()); + private static final String ANY_IP = "0.0.0.0/0"; + private static final String[] PROTOCOL_LIST = new String[]{"TCP", "UDP", "ICMP", "ALL"}; + + protected ApiClient apiClient; + + protected final int siteId; + private final String siteName; + protected final int tenantId; + private final String tenantName; + + public NetrisApiClientImpl(String endpointBaseUrl, String username, String password, String siteName, String adminTenantName) { + try { + apiClient = new ApiClient(endpointBaseUrl, username, password, 1L); + } catch (ApiException e) { + logAndThrowException(String.format("Error creating the Netris API Client for %s", endpointBaseUrl), e); + } + Pair sitePair = getNetrisSitePair(siteName); + Pair tenantPair = getNetrisTenantPair(adminTenantName); + this.siteId = sitePair.first(); + this.siteName = sitePair.second(); + this.tenantId = tenantPair.first(); + this.tenantName = tenantPair.second(); + } + + private Pair getNetrisSitePair(String siteName) { + List sites = listSites(); + if (CollectionUtils.isEmpty(sites)) { + throw new CloudRuntimeException("There are no Netris sites, please check the Netris endpoint"); + } + List filteredSites = sites.stream().filter(x -> x.getName().equals(siteName)).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(filteredSites)) { + throw new CloudRuntimeException(String.format("Cannot find a site matching name %s on Netris, please check the Netris endpoint", siteName)); + } + return new Pair<>(filteredSites.get(0).getId(), siteName); + } + + private Pair getNetrisTenantPair(String adminTenantName) { + List tenants = listTenants(); + if (CollectionUtils.isEmpty(tenants)) { + throw new CloudRuntimeException("There are no Netris tenants, please check the Netris endpoint"); + } + List filteredTenants = tenants.stream().filter(x -> x.getName().equals(adminTenantName)).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(filteredTenants)) { + throw new CloudRuntimeException(String.format("Cannot find a site matching name %s on Netris, please check the Netris endpoint", adminTenantName)); + } + return new Pair<>(filteredTenants.get(0).getId().intValue(), adminTenantName); + } + + protected void logAndThrowException(String prefix, ApiException e) throws CloudRuntimeException { + String msg = String.format("%s: (%s, %s, %s)", prefix, e.getCode(), e.getMessage(), e.getResponseBody()); + logger.error(msg, e); + throw new CloudRuntimeException(msg); + } + + @Override + public boolean isSessionAlive() { + ApiResponse response = null; + try { + AuthenticationApi api = apiClient.getApiStubForMethod(AuthenticationApi.class); + response = api.apiAuthGet(); + } catch (ApiException e) { + logAndThrowException("Error checking the Netris API session is alive", e); + } + return response != null && response.getStatusCode() == 200; + } + + @Override + public List listSites() { + SitesResponseOK response = null; + try { + SitesApi api = apiClient.getApiStubForMethod(SitesApi.class); + response = api.apiSitesGet(); + } catch (ApiException e) { + logAndThrowException("Error listing Netris Sites", e); + } + return response != null ? response.getData() : null; + } + + @Override + public List listVPCs() { + VPCResponseOK response = null; + try { + VpcApi api = apiClient.getApiStubForMethod(VpcApi.class); + response = api.apiV2VpcGet(); + } catch (ApiException e) { + logAndThrowException("Error listing Netris VPCs", e); + } + return response != null ? response.getData() : null; + } + + @Override + public List listTenants() { + ApiResponse response = null; + try { + TenantsApi api = apiClient.getApiStubForMethod(TenantsApi.class); + response = api.apiTenantsGet(); + } catch (ApiException e) { + logAndThrowException("Error listing Netris Tenants", e); + } + return (response != null && response.getData() != null) ? response.getData().getData() : null; + } + + private VPCResponseObjectOK createVpcInternal(String vpcName, int adminTenantId, String adminTenantName) { + VPCResponseObjectOK response; + logger.debug(String.format("Creating Netris VPC %s", vpcName)); + try { + VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class); + VPCCreate body = new VPCCreate(); + body.setName(vpcName); + VPCAdminTenant vpcAdminTenant = new VPCAdminTenant(); + vpcAdminTenant.setId(adminTenantId); + vpcAdminTenant.name(adminTenantName); + body.setAdminTenant(vpcAdminTenant); + response = vpcApi.apiV2VpcPost(body); + } catch (ApiException e) { + logAndThrowException("Error creating Netris VPC", e); + return null; + } + return response; + } + + private VpcEditResponseOK updateVpcInternal(String vpcName, String prevVpcName, int adminTenantId, String adminTenantName) { + VpcEditResponseOK response; + logger.debug(String.format("Updating Netris VPC name from %s to %s", prevVpcName, vpcName)); + try { + VPCListing vpcResource = getVpcByNameAndTenant(prevVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", prevVpcName, tenantId); + return null; + } + VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class); + VpcVpcIdBody body = new VpcVpcIdBody(); + body.setName(vpcName); + VPCAdminTenant vpcAdminTenant = new VPCAdminTenant(); + vpcAdminTenant.setId(adminTenantId); + vpcAdminTenant.name(adminTenantName); + body.setAdminTenant(vpcAdminTenant); + response = vpcApi.apiV2VpcVpcIdPut(body, vpcResource.getId()); + } catch (ApiException e) { + logAndThrowException("Error updating Netris VPC", e); + return null; + } + return response; + } + + private InlineResponse2004Data createIpamAllocationInternal(String ipamName, String ipamPrefix, VPCListing vpc) { + logger.debug(String.format("Creating Netris IPAM Allocation %s for VPC %s", ipamPrefix, vpc.getName())); + try { + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + AllocationBody body = new AllocationBody(); + AllocationBodyVpc allocationBodyVpc = new AllocationBodyVpc(); + allocationBodyVpc.setId(vpc.getId()); + allocationBodyVpc.setName(vpc.getName()); + body.setVpc(allocationBodyVpc); + body.setName(ipamName); + body.setPrefix(ipamPrefix); + IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant(); + allocationTenant.setId(new BigDecimal(tenantId)); + allocationTenant.setName(tenantName); + body.setTenant(allocationTenant); + InlineResponse2004 ipamResponse = ipamApi.apiV2IpamAllocationPost(body); + if (ipamResponse == null || !ipamResponse.isIsSuccess()) { + String reason = ipamResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris Allocation {} for VPC {} creation failed: {}", ipamPrefix, vpc.getName(), reason); + return null; + } + logger.debug(String.format("Successfully created VPC %s and its IPAM Allocation %s on Netris", vpc.getName(), ipamPrefix)); + return ipamResponse.getData(); + } catch (ApiException e) { + logAndThrowException(String.format("Error creating Netris IPAM Allocation %s for VPC %s", ipamPrefix, vpc.getName()), e); + return null; + } + } + + @Override + public boolean createVpc(CreateNetrisVpcCommand cmd) { + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC); + VPCResponseObjectOK createdVpc = createVpcInternal(netrisVpcName, tenantId, tenantName); + if (createdVpc == null || !createdVpc.isIsSuccess()) { + String reason = createdVpc == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris VPC {} creation failed: {}", cmd.getName(), reason); + return false; + } + + String netrisIpamAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, cmd.getCidr()); + String vpcCidr = cmd.getCidr(); + InlineResponse2004Data createdIpamAllocation = createIpamAllocationInternal(netrisIpamAllocationName, vpcCidr, createdVpc.getData()); + return createdIpamAllocation != null; + } + + @Override + public boolean updateVpc(UpdateNetrisVpcCommand cmd) { + Long domainId = cmd.getDomainId(); + Long zoneId = cmd.getZoneId(); + Long accountId = cmd.getAccountId(); + Long vpcId = cmd.getId(); + String prevVpcName = cmd.getPreviousVpcName(); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC); + String netrisPrevVpcName = String.format("D%s-A%s-Z%s-V%s-%s", domainId, accountId, zoneId, vpcId, prevVpcName); + VpcEditResponseOK updatedVpc = updateVpcInternal(netrisVpcName, netrisPrevVpcName, tenantId, tenantName); + if (updatedVpc == null || !updatedVpc.isIsSuccess()) { + String reason = updatedVpc == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The update of Netris VPC {} failed: {}", cmd.getPreviousVpcName(), reason); + return false; + } + return true; + } + + @Override + public boolean deleteNatRule(DeleteNetrisNatRuleCommand cmd) { + try { + String suffix = getNetrisVpcNameSuffix(cmd.getVpcId(), cmd.getVpcName(), cmd.getId(), cmd.getName(), cmd.isVpc()); + String vpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix); + VPCListing vpcResource = getVpcByNameAndTenant(vpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId); + return false; + } + String natRuleName = cmd.getNatRuleName(); + NatGetBody existingNatRule = netrisNatRuleExists(natRuleName); + boolean ruleExists = Objects.nonNull(existingNatRule); + if (ruleExists) { + deleteNatRule(natRuleName, existingNatRule.getId(), vpcResource.getName()); + if (cmd.getNatRuleType().equals("STATICNAT")) { + String natIp = cmd.getNatIp(); + String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, String.valueOf(cmd.getVpcId()), natIp); + deleteNatSubnet(netrisSubnetName, vpcResource.getId(), natIp); + } + } + } catch (Exception e) { + throw new CloudRuntimeException("Error deleting Netris NAT Rule", e); + } + return true; + } + + @Override + public boolean addOrUpdateAclRule(CreateOrUpdateNetrisACLCommand cmd, boolean forLb) { + String aclName = cmd.getNetrisAclName(); + try { + AclApi aclApi = apiClient.getApiStubForMethod(AclApi.class); + VPCListing vpcResource; + String netrisVpcName; + if (forLb) { + vpcResource = getSystemVpc(); + netrisVpcName = vpcResource.getName(); + + } else { + netrisVpcName = getNetrisVpcName(cmd, cmd.getVpcId(), cmd.getVpcName()); + vpcResource = getNetrisVpcResource(netrisVpcName); + if (Objects.isNull(vpcResource)) { + return false; + } + } + AclBodyVpc vpc = new AclBodyVpc().id(vpcResource.getId()); + List aclNames = List.of(aclName); + Pair> resultAndMatchingAclIds = getMatchingAclIds(aclNames, netrisVpcName); + List aclIdList = resultAndMatchingAclIds.second(); + if (!aclIdList.isEmpty()) { + logger.debug("Netris ACL rule: {} already exists, updating it...", aclName); + AclEditItem aclEditItem = getAclEditItem(cmd, aclName, aclIdList.get(0)); + aclEditItem.setVpc(vpc); + try { + aclApi.apiAclPut(aclEditItem); + } catch (ApiException e) { + if (e.getResponseBody().contains("This kind of acl already exists")) { + logger.info("Netris ACL rule: {} already exists and doesn't need to be updated", aclName); + return true; + } + throw new CloudRuntimeException("Error updating Netris ACL rule", e); + } + return true; + } + AclAddItem aclAddItem = getAclAddItem(cmd, aclName); + aclAddItem.setVpc(vpc); + aclApi.apiAclPost(aclAddItem); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to create Netris ACL: %s", cmd.getNetrisAclName()), e); + } + return true; + } + + AclAddItem getAclAddItem(CreateOrUpdateNetrisACLCommand cmd, String aclName) throws ApiException { + AclAddItem aclAddItem = new AclAddItem(); + aclAddItem.setAction(cmd.getAction()); + aclAddItem.setComment(String.format("ACL rule: %s. %s", cmd.getNetrisAclName(), cmd.getReason())); + aclAddItem.setName(aclName); + String protocol = cmd.getProtocol(); + if ("TCP".equals(protocol)) { + aclAddItem.setEstablished(new BigDecimal(1)); + } else { + aclAddItem.setReverse("yes"); + } + if (!Arrays.asList(PROTOCOL_LIST).contains(protocol)) { + aclAddItem.setProto("ip"); + aclAddItem.setSrcPortTo(cmd.getIcmpType()); + // TODO: set proto number: where should the protocol number be set - API sets the protocol number to Src-from & to and Dest-from & to fields + } else if ("ICMP".equals(protocol)) { + aclAddItem.setProto("icmp"); + if (cmd.getIcmpType() != -1) { + aclAddItem.setIcmpType(cmd.getIcmpType()); + } + } else { + aclAddItem.setProto(protocol.toLowerCase(Locale.ROOT)); + } + + aclAddItem.setDstPortFrom(cmd.getDestPortStart()); + aclAddItem.setDstPortTo(cmd.getDestPortEnd()); + aclAddItem.setDstPrefix(cmd.getDestPrefix()); + aclAddItem.setSrcPrefix(cmd.getSourcePrefix()); + aclAddItem.setSrcPortFrom(1); + aclAddItem.setSrcPortTo(65535); + if (NatPutBody.ProtocolEnum.ICMP.name().equalsIgnoreCase(protocol)) { + aclAddItem.setIcmpType(cmd.getIcmpType()); + } + + return aclAddItem; + } + + AclEditItem getAclEditItem(CreateOrUpdateNetrisACLCommand cmd, String aclName, BigDecimal aclId) throws ApiException { + AclEditItem aclEditItem = new AclEditItem(); + aclEditItem.setId(aclId); + aclEditItem.setAction(cmd.getAction()); + aclEditItem.setComment(String.format("ACL rule: %s. %s", cmd.getNetrisAclName(), cmd.getReason())); + aclEditItem.setName(aclName); + String protocol = cmd.getProtocol(); + if ("TCP".equals(protocol)) { + aclEditItem.setEstablished(new BigDecimal(1)); + } else { + aclEditItem.setReverse("yes"); + } + if (!Arrays.asList(PROTOCOL_LIST).contains(protocol)) { + aclEditItem.setProto("ip"); + aclEditItem.setSrcPortTo(cmd.getIcmpType()); + // TODO: set proto number: where should the protocol number be set - API sets the protocol number to Src-from & to and Dest-from & to fields + } else if ("ICMP".equals(protocol)) { + aclEditItem.setProto("icmp"); + if (cmd.getIcmpType() != -1) { + aclEditItem.setIcmpType(cmd.getIcmpType()); + } + } else { + aclEditItem.setProto(protocol.toLowerCase(Locale.ROOT)); + } + + aclEditItem.setDstPortFrom(cmd.getDestPortStart()); + aclEditItem.setDstPortTo(cmd.getDestPortEnd()); + aclEditItem.setDstPrefix(cmd.getDestPrefix()); + aclEditItem.setSrcPrefix(cmd.getSourcePrefix()); + aclEditItem.setSrcPortFrom(1); + aclEditItem.setSrcPortTo(65535); + if (NatPutBody.ProtocolEnum.ICMP.name().equalsIgnoreCase(protocol)) { + aclEditItem.setIcmpType(cmd.getIcmpType()); + } + + return aclEditItem; + } + + @Override + public boolean deleteAclRule(DeleteNetrisACLCommand cmd, boolean forLb) { + List aclNames = cmd.getAclRuleNames(); + try { + AclApi aclApi = apiClient.getApiStubForMethod(AclApi.class); + + String vpcName; + if (!forLb) { + String suffix = getNetrisVpcNameSuffix(cmd.getVpcId(), cmd.getVpcName(), cmd.getId(), cmd.getName(), cmd.isVpc()); + vpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix); + } else { + VPCListing vpcResource = getSystemVpc(); + vpcName = vpcResource.getName(); + } + Pair> resultAndMatchingAclIds = getMatchingAclIds(aclNames, vpcName); + Boolean result = resultAndMatchingAclIds.first(); + List matchingAclIds = resultAndMatchingAclIds.second(); + if (!result) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId); + return false; + } + if (matchingAclIds.isEmpty()) { + logger.warn("There doesn't seem to be any ACLs on Netris matching {}", aclNames.size() > 1 ? String.join(",", aclNames) : aclNames); + return true; + } + AclDeleteItem aclDeleteItem = new AclDeleteItem(); + aclDeleteItem.setId(matchingAclIds); + aclDeleteItem.setTenantsID(String.valueOf(tenantId)); + aclApi.apiAclDelete(aclDeleteItem); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to delete Netris ACLs: %s", String.join(",", cmd.getAclRuleNames())), e); + } + return true; + } + + Pair> getMatchingAclIds(List aclNames, String vpcName) { + try { + AclApi aclApi = apiClient.getApiStubForMethod(AclApi.class); + VPCListing vpcResource = getVpcByNameAndTenant(vpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId); + return new Pair<>(false, Collections.emptyList()); + } + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(vpcResource.getId()); + FilterBySites siteFilter = new FilterBySites(); + siteFilter.add(siteId); + AclResponseGetOk aclGetResponse = aclApi.apiAclGet(siteFilter, vpcFilter); + if (aclGetResponse == null || !aclGetResponse.isIsSuccess()) { + logger.warn("No ACLs were found to be present for the specific Netris VPC resource {}." + + " Netris ACLs may have been deleted out of band.", vpcName); + return new Pair<>(true, Collections.emptyList()); + } + List aclList = aclGetResponse.getData(); + return new Pair<>(true, aclList.stream() + .filter(acl -> aclNames.contains(acl.getName())) + .map(acl -> BigDecimal.valueOf(acl.getId())) + .collect(Collectors.toList())); + } catch (ApiException e) { + logAndThrowException("Failed to retrieve Netris ACLs", e); + } + return new Pair<>(true, Collections.emptyList()); + } + + public boolean addOrUpdateStaticRoute(AddOrUpdateNetrisStaticRouteCommand cmd) { + String prefix = cmd.getPrefix(); + String nextHop = cmd.getNextHop(); + Long vpcId = cmd.getId(); + String vpcName = cmd.getName(); + boolean updateRoute = cmd.isUpdateRoute(); + try { + String vpcSuffix = getNetrisVpcNameSuffix(vpcId, vpcName, null, null, true); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, vpcSuffix); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + + String[] suffixes = new String[2]; + suffixes[0] = vpcId.toString(); + suffixes[1] = cmd.getRouteId().toString(); + String staticRouteId = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffixes); + + Pair existingStaticRoute = staticRouteExists(vpcResource.getId(), prefix, null, staticRouteId); + if (updateRoute) { + if (!existingStaticRoute.first()) { + logger.error("The Netris static route {} does not exist for VPC {}, adding it", prefix, netrisVpcName); + return addStaticRouteInternal(vpcResource, netrisVpcName, prefix, nextHop, staticRouteId); + } + return updateStaticRouteInternal(existingStaticRoute.second().getId(), netrisVpcName, prefix, nextHop, staticRouteId); + } else { + if (existingStaticRoute.first()) { + String existingNextHop = existingStaticRoute.second().getNextHop(); + if (existingNextHop != null && existingNextHop.equals(nextHop)) { + logger.debug("The Netris static route {} already exists for VPC {}", prefix, netrisVpcName); + return true; + } else { + logger.debug("The Netris static route {} already exists but has different next hop {} for VPC {}", prefix, nextHop, netrisVpcName); + return false; + } + } + return addStaticRouteInternal(vpcResource, netrisVpcName, prefix, nextHop, staticRouteId); + } + } catch (Exception e) { + throw new CloudRuntimeException("Error adding Netris static route", e); + } + } + + private boolean addStaticRouteInternal(VPCListing vpcResource, String netrisVpcName, String prefix, String nextHop, String staticRouteId) { + try { + RoutesApi routesApi = apiClient.getApiStubForMethod(RoutesApi.class); + RoutesPostBody routesPostBody = new RoutesPostBody(); + routesPostBody.setPrefix(prefix); + routesPostBody.setNextHop(nextHop); + routesPostBody.setSiteId(new BigDecimal(siteId)); + routesPostBody.setStateStatus(RoutesBody.StateStatusEnum.ACTIVE); + + RoutesBodyVpcVpc vpcBody = new RoutesBodyVpcVpc(); + vpcBody.setId(vpcResource.getId()); + vpcBody.setName(vpcResource.getName()); + vpcBody.setIsDefault(vpcResource.isIsDefault()); + vpcBody.setIsSystem(vpcResource.isIsSystem()); + routesPostBody.setVpc(vpcBody); + + routesPostBody.setDescription(staticRouteId); + routesPostBody.setStateStatus(RoutesBody.StateStatusEnum.ACTIVE); + routesPostBody.setSwitches(Collections.emptyList()); + + InlineResponse2004 routeResponse = routesApi.apiRoutesPost(routesPostBody); + if (routeResponse == null || !routeResponse.isIsSuccess()) { + String reason = routeResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris static route creation failed for netris VPC - {}: {}", netrisVpcName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException("Error adding Netris static route", e); + return false; + } + return true; + } + + private boolean updateStaticRouteInternal(Integer id, String netrisVpcName, String prefix, String nextHop, String staticRouteId) { + try { + RoutesApi routesApi = apiClient.getApiStubForMethod(RoutesApi.class); + RoutesPutBody routesPutBody = new RoutesPutBody(); + routesPutBody.setId(id); + routesPutBody.setPrefix(prefix); + routesPutBody.setNextHop(nextHop); + routesPutBody.setSiteId(new BigDecimal(siteId)); + routesPutBody.setStateStatus(RoutesPutBody.StateStatusEnum.ACTIVE); + + routesPutBody.setDescription(staticRouteId); + routesPutBody.setSwitches(Collections.emptyList()); + + InlineResponse2003 routeResponse = routesApi.apiRoutesPut(routesPutBody); + if (routeResponse == null || !routeResponse.isIsSuccess()) { + String reason = routeResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("Failed to update Netris static route for netris VPC - {}: {}", netrisVpcName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException("Error updating Netris static route", e); + return false; + } + return true; + } + + @Override + public boolean deleteStaticRoute(DeleteNetrisStaticRouteCommand cmd) { + Long vpcId = cmd.getId(); + String vpcName = cmd.getName(); + String prefix = cmd.getPrefix(); + String nextHop = cmd.getNextHop(); + try { + String vpcSuffix = getNetrisVpcNameSuffix(vpcId, vpcName, null, null, true); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, vpcSuffix); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + + String[] suffixes = new String[2]; + suffixes[0] = vpcId.toString(); + suffixes[1] = cmd.getRouteId().toString(); + String staticRouteId = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffixes); + Pair existingStaticRoute = staticRouteExists(vpcResource.getId(), prefix, nextHop, staticRouteId); + + if (Boolean.FALSE.equals(existingStaticRoute.first())) { + logger.debug("The Netris static route {} does not exist for VPC {}", prefix, netrisVpcName); + return true; + } + RoutesGetBody existingRoute = existingStaticRoute.second(); + RoutesApi routesApi = apiClient.getApiStubForMethod(RoutesApi.class); + RoutesBodyId id = new RoutesBodyId(); + id.setId(existingRoute.getId()); + InlineResponse2003 routeDeleteResponse = routesApi.apiRoutesDelete(id); + if (routeDeleteResponse == null || !routeDeleteResponse.isIsSuccess()) { + String reason = routeDeleteResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris static route deletion failed for netris VPC - {}: {}", netrisVpcName, reason); + throw new CloudRuntimeException(reason); + } + return true; + } catch (ApiException e) { + logAndThrowException("Error deleting Netris static route", e); + } + return false; + } + + @Override + public List listStaticRoutes(ListNetrisStaticRoutesCommand cmd) { + Long vpcId = cmd.getId(); + String vpcName = cmd.getName(); + String prefix = cmd.getPrefix(); + String nextHop = cmd.getNextHop(); + String vpcSuffix = getNetrisVpcNameSuffix(vpcId, vpcName, null, null, true); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, vpcSuffix); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return new ArrayList<>(); + } + + List staticRoutes = listStaticRoutes(vpcResource.getId(), prefix, nextHop); + if (CollectionUtils.isEmpty(staticRoutes)) { + return new ArrayList<>(); + } + List result = new ArrayList<>(); + for (RoutesGetBody staticRoute : staticRoutes) { + // All static routes belong the SYSTEM account, which does not matter + result.add(new StaticRouteVO(null, staticRoute.getName(), vpcId, Account.ACCOUNT_ID_SYSTEM, Domain.ROOT_DOMAIN, staticRoute.getNextHop())); + } + return result; + } + + @Override + public boolean releaseNatIp(ReleaseNatIpCommand cmd) { + String natIp = cmd.getNatIp() + "/32"; + try { + VPCListing systemVpc = getSystemVpc(); + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(systemVpc.getId()); + SubnetResBody subnetResponse = ipamApi.apiV2IpamSubnetsGet(vpcFilter); + if (subnetResponse == null || !subnetResponse.isIsSuccess()) { + String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("Failed to retrieve Netris Public NAT IPs due to {}", reason); + throw new CloudRuntimeException(reason); + } + List natIps = subnetResponse.getData().stream().filter(ip -> ip.getPrefix().equals(natIp)).collect(Collectors.toList()); + if (!natIps.isEmpty()) { + ipamApi.apiV2IpamTypeIdDelete("subnet", natIps.get(0).getId().intValue()); + } + + } catch (ApiException e) { + logAndThrowException("Failed to release Netris IP", e); + } + return true; + } + + @Override + public boolean createOrUpdateLbRule(CreateOrUpdateNetrisLoadBalancerRuleCommand cmd) { + boolean isVpc = cmd.isVpc(); + Long networkResourceId = cmd.getId(); + String networkResourceName = cmd.getName(); + Long domainId = cmd.getDomainId(); + Long accountId = cmd.getAccountId(); + Long zoneId = cmd.getZoneId(); + Long lbId = cmd.getLbId(); + String publicIp = cmd.getPublicIp(); + List lbBackends = cmd.getLbBackends(); + + try { + String resourcePrefix = isVpc ? "V" : "N"; + String netrisResourceName = String.format("D%s-A%s-Z%s-%s%s-%s", domainId, accountId, zoneId, resourcePrefix, networkResourceId, networkResourceName); + VPCListing vpcResource = getNetrisVpcResource(netrisResourceName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisResourceName, tenantId); + return false; + } + createLBSubnet(cmd, publicIp + "/32", vpcResource.getId()); + + String suffix = String.format("LB%s", lbId); + String lbName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.LB, suffix); + Pair> resultAndMatchingLbId = getMatchingLbRule(lbName, vpcResource.getName()); + Boolean result = resultAndMatchingLbId.first(); + List matchingLbId = resultAndMatchingLbId.second(); + if (Boolean.FALSE.equals(result)) { + logger.warn("Could not find the Netris LB rule with name {}", lbName); + } + boolean updateRule = !matchingLbId.isEmpty(); + L4lbAddOrUpdateItem l4lbAddItem = getL4LbRule(cmd, vpcResource, lbName, publicIp, lbBackends, updateRule); + L4LoadBalancerApi loadBalancerApi = apiClient.getApiStubForMethod(L4LoadBalancerApi.class); + boolean success; + L4LbEditResponse editResponse = null; + ResAddEditBody createResponse = null; + if (updateRule) { + editResponse = loadBalancerApi.apiV2L4lbIdPut((L4LbEditItem) l4lbAddItem, matchingLbId.get(0).intValue()); + success = editResponse.isIsSuccess(); + } else { + createResponse = loadBalancerApi.apiV2L4lbPost((L4LbAddItem) l4lbAddItem); + success = createResponse.isIsSuccess(); + } + if (ObjectUtils.allNull(editResponse, createResponse) || Boolean.FALSE.equals(success)) { + throw new CloudRuntimeException(String.format("Failed to %s Netris LB rule", updateRule ? "update" : "create")); + } + if (Objects.nonNull(cmd.getCidrList()) && !cmd.getCidrList().isEmpty()) { + applyAclRulesForLb(cmd, lbName); + } + } catch (ApiException e) { + logAndThrowException("Failed to create Netris load balancer rule", e); + } + return true; + } + + private void applyAclRulesForLb(CreateOrUpdateNetrisLoadBalancerRuleCommand cmd, String lbName) { + // Add deny all rule first + addOrUpdateAclRule(createNetrisACLRuleCommand(cmd, lbName, "ANY", + NetrisNetworkRule.NetrisRuleAction.DENY.name().toLowerCase(Locale.ROOT), 0), true); + AtomicInteger cidrIndex = new AtomicInteger(1); + for (String cidr : cmd.getCidrList().split(" ")) { + try { + addOrUpdateAclRule(createNetrisACLRuleCommand(cmd, lbName, cidr, + NetrisNetworkRule.NetrisRuleAction.PERMIT.name().toLowerCase(Locale.ROOT), + cidrIndex.getAndIncrement()), true); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to add Netris ACL rule for LB CIDR %s", cidr), e); + } + } + } + + private CreateOrUpdateNetrisACLCommand createNetrisACLRuleCommand(CreateOrUpdateNetrisLoadBalancerRuleCommand cmd, String netrisLbName, String cidr, String action, int index) { + Long zoneId = cmd.getZoneId(); + Long accountId = cmd.getAccountId(); + Long domainId = cmd.getDomainId(); + String networkName = null; + Long networkId = null; + String vpcName = null; + Long vpcId = null; + boolean isVpc = cmd.isVpc(); + if (isVpc) { + vpcId = cmd.getId(); + vpcName = cmd.getName(); + } else { + networkName = cmd.getName(); + networkId = cmd.getId(); + } + String destinationPrefix = cmd.getPublicIp() + "/32"; + String srcPort = cmd.getPublicPort(); + String dstPort = cmd.getPublicPort(); + CreateOrUpdateNetrisACLCommand aclCommand = new CreateOrUpdateNetrisACLCommand(zoneId, accountId, domainId, networkName, networkId, + vpcName, vpcId, Objects.nonNull(vpcId), action, NetrisServiceImpl.getPrefix(cidr), NetrisServiceImpl.getPrefix(destinationPrefix), + Integer.parseInt(srcPort), Integer.parseInt(dstPort), cmd.getProtocol()); + String aclName; + if (isVpc) { + aclName = String.format("V%s-LBACL%s-%s", vpcId, index, cmd.getRuleName()); + } else { + aclName = String.format("N%s-LBACL%s-%s", networkId, index, cmd.getRuleName()); + } + String netrisAclName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.ACL, aclName); + aclCommand.setNetrisAclName(netrisAclName); + aclCommand.setReason(String.format("ACL Rule for CIDR %s of LB %s ", aclName, netrisLbName)); + return aclCommand; + } + + private L4lbAddOrUpdateItem getL4LbRule(CreateOrUpdateNetrisLoadBalancerRuleCommand cmd, VPCListing vpcResource, String lbName, + String publicIp, List lbBackends, boolean updateRule) { + L4lbAddOrUpdateItem l4lbAddItem = updateRule ? new L4LbEditItem() : new L4LbAddItem(); + try { + l4lbAddItem.setName(lbName); + + String protocol = cmd.getProtocol().toUpperCase(Locale.ROOT); + if (!Arrays.asList("TCP", "UDP").contains(protocol)) { + throw new CloudRuntimeException("Invalid protocol " + protocol); + } + l4lbAddItem.setProtocol(cmd.getProtocol().toUpperCase(Locale.ROOT)); + L4LBSite site = new L4LBSite(); + site.setId(siteId); + site.setName(siteName); + l4lbAddItem.setSite(site); + l4lbAddItem.setSiteID(new BigDecimal(siteId)); + + L4LbTenant tenant = new L4LbTenant(); + tenant.setId(tenantId); + tenant.setName(tenantName); + l4lbAddItem.setTenant(tenant); + + L4LbVpc vpc = new L4LbVpc(); + vpc.setId(vpcResource.getId()); + l4lbAddItem.setVpc(vpc); + + l4lbAddItem.setAutomatic(false); + l4lbAddItem.setIpFamily(NetUtils.isIpv4(publicIp) ? L4lbAddOrUpdateItem.IpFamilyEnum.IPv4 : L4lbAddOrUpdateItem.IpFamilyEnum.IPv6); + l4lbAddItem.setIp(publicIp); + l4lbAddItem.setStatus("enable"); + + List backends = new ArrayList<>(); + for (NetrisLbBackend backend : lbBackends) { + L4LoadBalancerBackendItem backendItem = new L4LoadBalancerBackendItem(); + backendItem.setIp(backend.getVmIp()); + backendItem.setPort(backend.getPort()); + backends.add(backendItem); + } + l4lbAddItem.setBackend(backends); + l4lbAddItem.setPort(Integer.valueOf(cmd.getPublicPort())); + l4lbAddItem.setHealthCheck(L4lbAddOrUpdateItem.HealthCheckEnum.NONE); + } catch (Exception e) { + throw new CloudRuntimeException("Failed to create Netris load balancer rule", e); + } + return l4lbAddItem; + } + + @Override + public boolean deleteLbRule(DeleteNetrisLoadBalancerRuleCommand cmd) { + boolean isVpc = cmd.isVpc(); + String vpcName = null; + String networkName = null; + Long vpcId = null; + Long networkId = null; + if (isVpc) { + vpcName = cmd.getName(); + vpcId = cmd.getId(); + } else { + networkName = cmd.getName(); + networkId = cmd.getId(); + } + Long lbId = cmd.getLbId(); + String cidrList = cmd.getCidrList(); + try { + String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, networkId, networkName, isVpc); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix); + suffix = String.format("LB%s", lbId); + String lbName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.LB, suffix); + Pair> resultAndMatchingLbId = getMatchingLbRule(lbName, netrisVpcName); + Boolean result = resultAndMatchingLbId.first(); + List matchingLbId = resultAndMatchingLbId.second(); + if (!result) { + logger.error("Could not find the Netris LB rule with name {}", lbName); + return false; + } + if (matchingLbId.isEmpty()) { + logger.warn("There doesn't seem to be any LB rule on Netris matching {}", lbName); + return true; + } + + L4LoadBalancerApi lbApi = apiClient.getApiStubForMethod(L4LoadBalancerApi.class); + lbApi.apiV2L4lbIdDelete(matchingLbId.get(0).intValue()); + if (Objects.nonNull(cidrList)) { + deleteAclRulesForLb(cmd); + } + } catch (ApiException e) { + logAndThrowException("Failed to delete Netris load balancer rule", e); + } + return true; + } + + private void deleteAclRulesForLb(DeleteNetrisLoadBalancerRuleCommand cmd) { + // delete the deny rule + deleteAclRule(deleteNetrisACLCommand(cmd, 0), true); + AtomicInteger cidrIndex = new AtomicInteger(1); + for (String cidr : cmd.getCidrList().split(" ")) { + try { + deleteAclRule(deleteNetrisACLCommand(cmd, cidrIndex.getAndIncrement()), true); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to delete Netris ACL rule for LB CIDR %s", cidr), e); + } + } + } + + private DeleteNetrisACLCommand deleteNetrisACLCommand(DeleteNetrisLoadBalancerRuleCommand cmd, int index) { + Long zoneId = cmd.getZoneId(); + Long accountId = cmd.getAccountId(); + Long domainId = cmd.getDomainId(); + String networkName = null; + Long networkId = null; + String vpcName = null; + Long vpcId = null; + boolean isVpc = cmd.isVpc(); + if (isVpc) { + vpcId = cmd.getId(); + vpcName = cmd.getName(); + } else { + networkName = cmd.getName(); + networkId = cmd.getId(); + } + DeleteNetrisACLCommand deleteAclCommand = new DeleteNetrisACLCommand(zoneId, accountId, domainId, networkName, networkId, isVpc, vpcId, vpcName); + String aclName; + if (isVpc) { + aclName = String.format("V%s-LBACL%s-%s", vpcId, index, cmd.getRuleName()); + } else { + aclName = String.format("N%s-LBACL%s-%s", networkId, index, cmd.getRuleName()); + } + String netrisAclName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.ACL, aclName); + deleteAclCommand.setAclRuleNames(Collections.singletonList(netrisAclName)); + return deleteAclCommand; + } + + private Pair> getMatchingLbRule(String lbName, String vpcName) { + try { + VPCListing vpcResource = getVpcByNameAndTenant(vpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId); + return new Pair<>(false, Collections.emptyList()); + } + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(vpcResource.getId()); + FilterBySites siteFilter = new FilterBySites(); + siteFilter.add(siteId); + L4LoadBalancerApi lbApi = apiClient.getApiStubForMethod(L4LoadBalancerApi.class); + L4lbresBody lbGetResponse = lbApi.apiV2L4lbGet(siteFilter, vpcFilter); + if (lbGetResponse == null || !lbGetResponse.isIsSuccess()) { + logger.warn("No LB rules were found to be present for the specific Netris VPC resource {}." + + " Netris LB rules may have been deleted out of band.", vpcName); + return new Pair<>(true, Collections.emptyList()); + } + List lbList = lbGetResponse.getData(); + return new Pair<>(true, lbList.stream() + .filter(lb -> lbName.equals(lb.getName())) + .map(acl -> BigDecimal.valueOf(acl.getId())) + .collect(Collectors.toList())); + } catch (ApiException e) { + logAndThrowException("Failed to retrieve Netris LB rules", e); + } + return new Pair<>(true, Collections.emptyList()); + } + + private List listStaticRoutes(Integer netrisVpcId, String prefix, String nextHop) { + try { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(netrisVpcId); + FilterBySites sitesFilter = new FilterBySites(); + sitesFilter.add(siteId); + RoutesApi routesApi = apiClient.getApiStubForMethod(RoutesApi.class); + RoutesResponseGetOk routesResponseGetOk = routesApi.apiRoutesGet(sitesFilter, vpcFilter); + if (Objects.isNull(routesResponseGetOk) || Boolean.FALSE.equals(routesResponseGetOk.isIsSuccess())) { + logger.warn("Failed to retrieve static routes"); + return null; + } + List routesList = routesResponseGetOk.getData(); + return routesList.stream() + .filter(x -> (Objects.isNull(prefix) || x.getName().equals(prefix)) && + (Objects.isNull(nextHop) || x.getNextHop().equals(nextHop))) + .collect(Collectors.toList()); + } catch (ApiException e) { + logAndThrowException("Error listing Netris static routes", e); + } + return null; + } + + private Pair staticRouteExists(Integer netrisVpcId, String prefix, String nextHop, String description) { + List staticRoutes = listStaticRoutes(netrisVpcId, prefix, nextHop); + if (staticRoutes == null) { + return new Pair<>(false, null); + } + return new Pair<>(!staticRoutes.isEmpty(), staticRoutes.isEmpty() ? null : staticRoutes.get(0)); + } + + public void deleteNatRule(String natRuleName, Integer snatRuleId, String netrisVpcName) { + logger.debug("Deleting NAT rule on Netris: {} for VPC {}", natRuleName, netrisVpcName); + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + natApi.apiV2NatIdDelete(snatRuleId); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to delete NAT rule: %s for VPC: %s", natRuleName, netrisVpcName), e); + } + } + + private void deleteVpcIpamAllocationInternal(VPCListing vpcResource, String allocationName) { + logger.debug("Deleting Netris VPC IPAM Allocation {} for VPC {}", allocationName, vpcResource.getName()); + try { + VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class); + VPCResponseResourceOK vpcResourcesResponse = vpcApi.apiV2VpcVpcIdResourcesGet(vpcResource.getId()); + VPCResourceIpam vpcAllocationResource = getVpcAllocationResource(vpcResourcesResponse, allocationName); + if (Objects.isNull(vpcAllocationResource)) { + logger.info("No VPC IPAM Allocation found for VPC {}", allocationName); + return; + } + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + logger.debug("Removing the IPAM allocation {} with ID {}", vpcAllocationResource.getName(), vpcAllocationResource.getId()); + ipamApi.apiV2IpamTypeIdDelete("allocation", vpcAllocationResource.getId()); + } catch (ApiException e) { + logAndThrowException(String.format("Error removing IPAM Allocation %s for VPC %s", allocationName, vpcResource.getName()), e); + } + } + + private VPCResourceIpam getVpcAllocationResource(VPCResponseResourceOK vpcResourcesResponse, String allocationName) { + VPCResource resource = vpcResourcesResponse.getData().get(0); + List vpcAllocations = resource.getAllocation(); + if (CollectionUtils.isNotEmpty(vpcAllocations)) { + vpcAllocations = vpcAllocations.stream().filter(x -> x.getName().equalsIgnoreCase(allocationName)).collect(Collectors.toList()); + return CollectionUtils.isNotEmpty(vpcAllocations) ? vpcAllocations.get(0) : null; + } + return null; + } + + private VPCListing getVpcByNameAndTenant(String vpcName) { + try { + List vpcListings = listVPCs(); + List vpcs = vpcListings.stream() + .filter(x -> x.getName().equals(vpcName) && x.getAdminTenant().getId().equals(tenantId)) + .collect(Collectors.toList()); + return vpcs.isEmpty() ? null : vpcs.get(0); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Error getting VPC %s information: %s", vpcName, e.getMessage()), e); + } + } + + private VPCResponseObjectOK deleteVpcInternal(VPCListing vpcResource) { + try { + VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class); + logger.debug("Removing the VPC {} with ID {}", vpcResource.getName(), vpcResource.getId()); + return vpcApi.apiV2VpcVpcIdDelete(vpcResource.getId()); + } catch (ApiException e) { + logAndThrowException(String.format("Error deleting VPC %s: %s", vpcResource.getName(), e.getResponseBody()), e); + return null; + } + } + + @Override + public boolean deleteVpc(DeleteNetrisVpcCommand cmd) { + String suffix = String.valueOf(cmd.getId()); + String vpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC); + VPCListing vpcResource = getVpcByNameAndTenant(vpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", vpcName, tenantId); + return false; + } + String snatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.SNAT, suffix); + NatGetBody existingNatRule = netrisNatRuleExists(snatRuleName); + boolean ruleExists = Objects.nonNull(existingNatRule); + if (ruleExists) { + deleteNatRule(snatRuleName, existingNatRule.getId(), vpcResource.getName()); + } + + String vpcAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, cmd.getCidr()); + deleteVpcIpamAllocationInternal(vpcResource, vpcAllocationName); + VPCResponseObjectOK response = deleteVpcInternal(vpcResource); + return response != null && response.isIsSuccess(); + } + + @Override + public boolean createVnet(CreateNetrisVnetCommand cmd) { + String vpcName = cmd.getVpcName(); + Long vpcId = cmd.getVpcId(); + String networkName = cmd.getName(); + Long networkId = cmd.getId(); + String vnetCidr = cmd.getCidr(); + Integer vxlanId = cmd.getVxlanId(); + String netrisTag = cmd.getNetrisTag(); + String netmask = vnetCidr.split("/")[1]; + String netrisGateway = cmd.getGateway() + "/" + netmask; + String netrisV6Cidr = cmd.getIpv6Cidr(); + boolean isVpc = cmd.isVpc(); + Boolean isGlobalRouting = cmd.isGlobalRouting(); + + try { + String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName); + VPCListing associatedVpc = getNetrisVpcResource(netrisVpcName); + if (associatedVpc == null) { + logger.error("Failed to find Netris VPC with name: {}, to create the corresponding vNet for network {}", netrisVpcName, networkName); + return false; + } + + String vNetName; + if (isVpc) { + vNetName = String.format("V%s-N%s-%s", vpcId, networkId, networkName); + } else { + vNetName = String.format("N%s-%s", networkId, networkName); + } + String netrisVnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VNET, vNetName) ; + String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, String.valueOf(cmd.getVpcId()), vnetCidr) ; + + createIpamSubnetInternal(netrisSubnetName, vnetCidr, SubnetBody.PurposeEnum.COMMON, associatedVpc, isGlobalRouting); + if (Objects.nonNull(netrisV6Cidr)) { + String netrisV6IpamAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, netrisV6Cidr); + String netrisV6SubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, String.valueOf(cmd.getVpcId()), netrisV6Cidr) ; + BigDecimal ipamAllocationId = getIpamAllocationIdByPrefixAndVpc(netrisV6Cidr, associatedVpc); + if (ipamAllocationId == null) { + InlineResponse2004Data createdIpamAllocation = createIpamAllocationInternal(netrisV6IpamAllocationName, netrisV6Cidr, associatedVpc); + if (Objects.isNull(createdIpamAllocation)) { + throw new CloudRuntimeException(String.format("Failed to create Netris IPAM Allocation %s for VPC %s", netrisV6IpamAllocationName, netrisVpcName)); + } + } + createIpamSubnetInternal(netrisV6SubnetName, netrisV6Cidr, SubnetBody.PurposeEnum.COMMON, associatedVpc, isGlobalRouting); + } + logger.debug("Successfully created IPAM Subnet {} for network {} on Netris", netrisSubnetName, networkName); + + VnetResAddBody vnetResponse = createVnetInternal(associatedVpc, netrisVnetName, netrisGateway, netrisV6Cidr, vxlanId, netrisTag); + if (vnetResponse == null || !vnetResponse.isIsSuccess()) { + String reason = vnetResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris vNet creation {} failed: {}", vNetName, reason); + return false; + } + } catch (ApiException e) { + throw new CloudRuntimeException(String.format("Failed to create Netris vNet %s", networkName), e); + } + return true; + } + + @Override + public boolean updateVnet(UpdateNetrisVnetCommand cmd) { + String networkName = cmd.getName(); + Long networkId = cmd.getId(); + String prevNetworkName = cmd.getPrevNetworkName(); + String vpcName = cmd.getVpcName(); + Long vpcId = cmd.getVpcId(); + boolean isVpc = cmd.isVpc(); + + String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName); + VPCListing associatedVpc = getNetrisVpcResource(netrisVpcName); + if (associatedVpc == null) { + logger.error("Failed to find Netris VPC with name: {}, to create the corresponding vNet for network {}", netrisVpcName, networkName); + return false; + } + + String vNetName; + String prevVnetName; + if (isVpc) { + vNetName = String.format("V%s-N%s-%s", vpcId, networkId, networkName); + prevVnetName = String.format("V%s-N%s-%s", vpcId, networkId, prevNetworkName); + } else { + vNetName = String.format("N%s-%s", networkId, networkName); + prevVnetName = String.format("N%s-%s", networkId, prevNetworkName); + } + String netrisVnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VNET, vNetName) ; + String prevNetrisVnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VNET, prevVnetName) ; + + VnetResAddBody response = updateVnetInternal(associatedVpc, netrisVnetName, prevNetrisVnetName); + if (response == null || !response.isIsSuccess()) { + String reason = response == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("Netris vNet: {} update failed: {}", vNetName, reason); + return false; + } + return true; + } + + private VnetResAddBody updateVnetInternal(VPCListing associatedVpc, String netrisVnetName, String prevVnetName) { + logger.debug("Updating Netris vNet name from {} to {} ", netrisVnetName, prevVnetName); + try { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(associatedVpc.getId()); + FilterBySites siteFilter = new FilterBySites(); + siteFilter.add(siteId); + List vnetsList = getVnets(associatedVpc, prevVnetName, siteFilter, vpcFilter); + if (CollectionUtils.isEmpty(vnetsList)) { + String errorMsg = String.format("Could not find vNet with name: %s", prevVnetName); + logger.error(errorMsg); + throw new CloudRuntimeException(errorMsg); + } + VnetsBody vnetsBody = vnetsList.get(0); + + VnetEditBody vnetBody = new VnetEditBody(); + + vnetBody.setCustomAnycastMac(vnetBody.getCustomAnycastMac()); + + VnetEditBodyGateways gatewayV4 = new VnetEditBodyGateways(); + gatewayV4.prefix(vnetsBody.getGateways().get(0).getPrefix()); + gatewayV4.setDhcpEnabled(false); + VnetEditBodyDhcp dhcp = new VnetEditBodyDhcp(); + dhcp.setEnd(""); + dhcp.setStart(""); + dhcp.setOptionSet(new VnetAddBodyDhcpOptionSet()); + gatewayV4.setDhcp(dhcp); + List gatewaysList = new ArrayList<>(); + gatewaysList.add(gatewayV4); + + if (vnetsBody.getGateways().size() > 1 && Objects.nonNull(vnetsBody.getGateways().get(1))) { + String netrisV6Gateway = vnetsBody.getGateways().get(1).getPrefix(); + VnetEditBodyGateways gatewayV6 = new VnetEditBodyGateways(); + gatewayV6.prefix(netrisV6Gateway); + gatewayV6.setDhcpEnabled(false); + gatewayV6.setDhcp(dhcp); + gatewaysList.add(gatewayV6); + } + + vnetBody.setGateways(gatewaysList); + vnetBody.setGuestTenants(new ArrayList<>()); + vnetBody.setL3vpn(false); + vnetBody.setName(netrisVnetName); + vnetBody.setNativeVlan(0); + vnetBody.setVxlanID(vnetsBody.getVxlanID()); + vnetBody.setPorts(new ArrayList<>()); + + IpTreeSubnetSites subnetSites = new IpTreeSubnetSites(); + subnetSites.setId(new BigDecimal(siteId)); + subnetSites.setName(siteName); + List subnetSitesList = new ArrayList<>(); + subnetSitesList.add(subnetSites); + vnetBody.setSites(subnetSitesList); + + vnetBody.setState(VnetEditBody.StateEnum.ACTIVE); + + vnetBody.setTags(new ArrayList<>()); + + IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant(); + allocationTenant.setId(new BigDecimal(tenantId)); + allocationTenant.setName(tenantName); + vnetBody.setTenant(allocationTenant); + + vnetBody.setVlan(0); + vnetBody.setVlanAware(false); + vnetBody.setVlans(""); + + VnetAddBodyVpc vpc = new VnetAddBodyVpc(); + vpc.setName(associatedVpc.getName()); + vpc.setId(associatedVpc.getId()); + vnetBody.setVpc(vpc); + + vnetBody.setTags(vnetsBody.getTags()); + + VNetApi vnetApi = apiClient.getApiStubForMethod(VNetApi.class); + return vnetApi.apiV2VnetIdPut(vnetBody, vnetsBody.getId().intValue()); + } catch (ApiException e) { + logAndThrowException(String.format("Error creating Netris vNet %s for VPC %s", netrisVnetName, associatedVpc.getName()), e); + return null; + } + } + + @Override + public boolean deleteVnet(DeleteNetrisVnetCommand cmd) { + String vpcName = cmd.getVpcName(); + Long vpcId = cmd.getVpcId(); + String networkName = cmd.getName(); + Long networkId = cmd.getId(); + boolean isVpc = cmd.isVpc(); + String vnetCidr = cmd.getVNetCidr(); + String vnetV6Cidr = cmd.getvNetV6Cidr(); + try { + String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName); + VPCListing associatedVpc = getNetrisVpcResource(netrisVpcName); + if (associatedVpc == null) { + logger.error("Failed to find Netris VPC with name: {}, to create the corresponding vNet for network {}", netrisVpcName, networkName); + return false; + } + + String vNetName; + if (isVpc) { + vNetName = String.format("V%s-N%s-%s", vpcId, networkId, networkName); + } else { + vNetName = String.format("N%s-%s", networkId, networkName); + } + + String netrisVnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VNET, vNetName) ; + String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, String.valueOf(cmd.getVpcId()), vnetCidr); + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(associatedVpc.getId()); + FilterBySites siteFilter = new FilterBySites(); + siteFilter.add(siteId); + deleteVnetInternal(associatedVpc, siteFilter, vpcFilter, netrisVnetName, vNetName); + + logger.debug("Successfully deleted vNet {}", vNetName); + deleteSubnetInternal(vpcFilter, netrisVnetName, netrisSubnetName); + if (Objects.nonNull(vnetV6Cidr)) { + String netrisV6IpamAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, vnetV6Cidr); + String netrisV6SubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, String.valueOf(cmd.getVpcId()), vnetV6Cidr); + deleteSubnetInternal(vpcFilter, netrisVnetName, netrisV6SubnetName); + deleteVpcIpamAllocationInternal(associatedVpc, netrisV6IpamAllocationName); + } + + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to delete Netris vNet %s", networkName), e); + } + return true; + } + + protected VPCListing getSystemVpc() throws ApiException { + List systemVpcList = listVPCs().stream().filter(VPCListing::isIsSystem).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(systemVpcList)) { + String msg = "Cannot find any system VPC"; + logger.error(msg); + throw new CloudRuntimeException(msg); + } + return systemVpcList.get(0); + } + + private BigDecimal getIpamAllocationIdByPrefixAndVpc(String superCidrPrefix, VPCListing vpc) throws ApiException { + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + FilterBySites filterBySites = new FilterBySites(); + filterBySites.add(siteId); + FilterByVpc filterByVpc = new FilterByVpc(); + filterByVpc.add(vpc.getId()); + IpTree ipamTree = ipamApi.apiV2IpamGet(filterBySites, filterByVpc); + List superCidrList = ipamTree.getData().stream() + .filter(x -> x.getPrefix().equals(superCidrPrefix) || isAllocationPartOfBiggerAllocation(x.getPrefix(), superCidrPrefix)) + .collect(Collectors.toList()); + return CollectionUtils.isEmpty(superCidrList) ? null : superCidrList.get(0).getId(); + } + + private boolean isAllocationPartOfBiggerAllocation(String netrisAllocation, String providedAllocation) { + IPAddress biggerAllocation = new IPAddressString(netrisAllocation).getAddress(); + IPAddress smallerAllocation = new IPAddressString(providedAllocation).getAddress(); + + return biggerAllocation.contains(smallerAllocation); + + } + + private IpTreeSubnet getIpamSubnetByAllocationAndPrefixAndPurposeAndVpc(BigDecimal ipamAllocationId, String exactCidr, IpTreeSubnet.PurposeEnum purpose, VPCListing vpc) throws ApiException { + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + FilterByVpc filterByVpc = new FilterByVpc(); + filterByVpc.add(vpc.getId()); + SubnetResBody subnetResBody = ipamApi.apiV2IpamSubnetsGet(filterByVpc); + List exactSubnetList = subnetResBody.getData().stream() + .filter(x -> ipamAllocationId != null ? + x.getAllocationID().equals(ipamAllocationId) && x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose : + x.getPrefix().equals(exactCidr) && x.getPurpose() == purpose) + .collect(Collectors.toList()); + return CollectionUtils.isEmpty(exactSubnetList) ? null : exactSubnetList.get(0); + } + + @Override + public boolean setupZoneLevelPublicRange(SetupNetrisPublicRangeCommand cmd) { + String superCidr = cmd.getSuperCidr(); + String exactCidr = cmd.getExactCidr(); + try { + VPCListing systemVpc = getSystemVpc(); + logger.debug("Checking if the Netris Public Super CIDR {} exists", superCidr); + BigDecimal ipamAllocationId = getIpamAllocationIdByPrefixAndVpc(superCidr, systemVpc); + if (ipamAllocationId == null) { + String ipamName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, superCidr); + InlineResponse2004Data ipamAllocation = createIpamAllocationInternal(ipamName, superCidr, systemVpc); + if (ipamAllocation == null) { + String msg = String.format("Could not create the zone level super CIDR %s for the system VPC", superCidr); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + ipamAllocationId = new BigDecimal(ipamAllocation.getId()); + } + IpTreeSubnet exactSubnet = getIpamSubnetByAllocationAndPrefixAndPurposeAndVpc(ipamAllocationId, exactCidr, IpTreeSubnet.PurposeEnum.COMMON, systemVpc); + if (exactSubnet == null) { + String ipamSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, exactCidr); + createIpamSubnetInternal(ipamSubnetName, exactCidr, SubnetBody.PurposeEnum.COMMON, systemVpc, null); + } + } catch (ApiException e) { + String msg = String.format("Error setting up the Netris Public Range %s on super CIDR %s", exactCidr, superCidr); + logAndThrowException(msg, e); + return false; + } + return true; + } + + private boolean createOrUpdateNatRuleInternal(CreateOrUpdateNetrisNatCommand cmd) { + String ruleName = cmd.getNatRuleName(); + long vpcId = cmd.getVpcId(); + Long networkId = cmd.getId(); + String networkName = cmd.getName(); + String vpcName = cmd.getVpcName(); + String vpcCidr = cmd.getVpcCidr(); + boolean isVpc = cmd.isVpc(); + NatPostBody.ActionEnum action = getNatActionFromRuleType(cmd.getNatRuleType()); + NatPostBody.ProtocolEnum protocol = getProtocolFromString(cmd.getProtocol()); + NatPostBody.StateEnum state = getStateFromString(cmd.getState()); + + String vNetName = isVpc ? + String.format("V%s-N%s-%s", vpcId, networkId, networkName) : + String.format("N%s-%s", networkId, networkName); + String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName); + VPCListing vpcResource = getNetrisVpcResource(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + + String targetIpSubnet = null; + if (NatPostBody.ActionEnum.SNAT == action) { + targetIpSubnet = cmd.getNatIp() + "/32"; + } else if (NatPostBody.ActionEnum.DNAT == action) { + targetIpSubnet = cmd.getDestinationAddress() + "/32"; + } + + if (StringUtils.isNotBlank(targetIpSubnet) && existsDestinationSubnet(targetIpSubnet)) { + logger.debug("Creating subnet with NAT purpose for {}}", targetIpSubnet); + createNatSubnet(cmd, targetIpSubnet, vpcResource.getId()); + } + + NatGetBody existingNatRule = netrisNatRuleExists(ruleName); + boolean ruleExists = Objects.nonNull(existingNatRule); + if (!ruleExists) { + String destinationAddress = action == NatPostBody.ActionEnum.SNAT ? ANY_IP : cmd.getDestinationAddress() + "/32"; + String destinationPort = cmd.getDestinationPort(); + String sourceAddress = action == NatPostBody.ActionEnum.SNAT ? vpcCidr : ANY_IP; + String sourcePort = "1-65535"; + String snatToIp = action == NatPostBody.ActionEnum.SNAT ? targetIpSubnet : null; + String dnatToIp = action == NatPostBody.ActionEnum.DNAT ? cmd.getSourceAddress() + "/32" : null; + String dnatToPort = action == NatPostBody.ActionEnum.DNAT ? cmd.getSourcePort() : null; + return createNatRuleInternal(ruleName, action, protocol, state, destinationAddress, destinationPort, + sourceAddress, sourcePort, snatToIp, dnatToIp, dnatToPort, netrisVpcName, networkName, vNetName); + } else if (NatPostBody.ActionEnum.SNAT == action) { + return updateSnatRuleInternal(ruleName, targetIpSubnet, netrisVpcName, networkName, vNetName, existingNatRule.getId(), vpcCidr); + } + return true; + } + + private NatPostBody.StateEnum getStateFromString(String state) { + return NatPostBody.StateEnum.fromValue(state); + } + + private NatPostBody.ActionEnum getNatActionFromRuleType(String natRuleType) { + return NatPostBody.ActionEnum.fromValue(natRuleType); + } + + @Override + public boolean createOrUpdateSNATRule(CreateOrUpdateNetrisNatCommand cmd) { + return createOrUpdateNatRuleInternal(cmd); + } + + private boolean existsDestinationSubnet(String destinationSubnet) { + try { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(getSystemVpc().getId()); + List targetSubnetList = getSubnet(vpcFilter, destinationSubnet); + return targetSubnetList != null; + } catch (ApiException e) { + logAndThrowException(String.format("Error checking if subnet %s exists: %s", destinationSubnet, e.getMessage()), e); + return false; + } + } + + @Override + public boolean createStaticNatRule(CreateOrUpdateNetrisNatCommand cmd) { + String staticNatRuleName = cmd.getNatRuleName(); + String natIP = cmd.getNatIp() + "/32"; + String vmIp = cmd.getVmIp() + "/32"; + String vpcName = cmd.getVpcName(); + String vpcCidr = cmd.getVpcCidr(); + Long vpcId = cmd.getVpcId(); + Long networkId = cmd.getId(); + String networkName = cmd.getName(); + boolean isVpc = cmd.isVpc(); + + try { + String netrisVpcName = getNetrisVpcName(cmd, vpcId, vpcName); + VPCListing vpcResource = getNetrisVpcResource(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + // Create a /32 subnet for the DNAT IP + createNatSubnet(cmd, natIP, vpcResource.getId()); + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + NatPostBody natBody = new NatPostBody(); + natBody.setAction(NatPostBody.ActionEnum.DNAT); + natBody.setDestinationAddress(natIP); + natBody.setName(staticNatRuleName); + natBody.setProtocol(NatPostBody.ProtocolEnum.ALL); + natBody.setState(NatPostBody.StateEnum.ENABLED); + natBody.setComment(String.format("Static NAT rule for %s", netrisVpcName)); + + NatBodySiteSite site = new NatBodySiteSite(); + site.setId(siteId); + site.setName(siteName); + natBody.setSite(site); + natBody.setSourceAddress(ANY_IP); + natBody.setDnatToIP(vmIp); + + NatBodyVpcVpc vpc = new NatBodyVpcVpc(); + vpc.setId(vpcResource.getId()); + vpc.setName(vpcResource.getName()); + natBody.setVpc(vpc); + + InlineResponse20015 natResponse = natApi.apiV2NatPost(natBody); + if (natResponse == null || !natResponse.isIsSuccess()) { + String reason = natResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris static NAT (DNAT) rule creation failed for netris VPC - {}: {}", netrisVpcName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException(String.format("Failed to create Static NAT (DNAT) rule for network : %s", Objects.nonNull(vpcName) ? vpcName : networkName), e); + } + return true; + } + + private void createNatSubnet(NetrisCommand cmd, String natIp, Integer netrisVpcId) { + try { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(netrisVpcId); + String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, String.valueOf(((CreateOrUpdateNetrisNatCommand)cmd).getVpcId()), natIp); + List matchedSubnets = getSubnet(vpcFilter, netrisSubnetName); + if (matchedSubnets.isEmpty()) { + VPCListing systemVpc = getSystemVpc(); + createIpamSubnetInternal(netrisSubnetName, natIp, SubnetBody.PurposeEnum.NAT, systemVpc, null); + } else { + IpTreeSubnet existingSubnet = matchedSubnets.stream().filter(x -> x.getPrefix().equals(natIp)).collect(Collectors.toList()).get(0); + if (existingSubnet.getPurpose() != IpTreeSubnet.PurposeEnum.NAT) { + VPCListing systemVpc = getSystemVpc(); + logger.debug("Subnet: {} already exists, but purpose is not NAT, updating its purpose to 'nat'", natIp); + updateIpamSubnetInternal(existingSubnet.getId().intValue(), netrisSubnetName, natIp, SubnetBody.PurposeEnum.NAT, systemVpc, null); + } + } + } catch (ApiException e) { + throw new CloudRuntimeException(String.format("Failed to create subnet for %s with NAT purpose", natIp)); + } + } + + private void createLBSubnet(NetrisCommand cmd, String lbIp, Integer netrisVpcId) { + try { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(netrisVpcId); + String netrisSubnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, + NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, + String.valueOf(cmd.getId()), lbIp); + List matchedSubnets = getSubnet(vpcFilter, netrisSubnetName); + VPCListing systemVpc = getSystemVpc(); + if (matchedSubnets.isEmpty()) { + createIpamSubnetInternal(netrisSubnetName, lbIp, SubnetBody.PurposeEnum.LOAD_BALANCER, systemVpc, null); + } else if (IpTreeSubnet.PurposeEnum.LOAD_BALANCER != matchedSubnets.get(0).getPurpose()){ + logger.debug("Updating existing NAT subnet {} to have load balancer purpose", netrisSubnetName); + updateIpamSubnetInternal(matchedSubnets.get(0).getId().intValue(), netrisSubnetName, lbIp, SubnetBody.PurposeEnum.LOAD_BALANCER, systemVpc, null); + } + logger.debug("LB subnet: {} already exists", netrisSubnetName); + } catch (ApiException e) { + throw new CloudRuntimeException(String.format("Failed to create subnet for %s with LB purpose", lbIp)); + } + } + + private NatPostBody.ProtocolEnum getProtocolFromString(String protocol) { + return NatPostBody.ProtocolEnum.fromValue(protocol); + } + + private NatPostBody createNatRulePostBody(String ruleName, NatPostBody.ActionEnum action, NatPostBody.ProtocolEnum protocol, NatPostBody.StateEnum state, + String destinationAddress, String destinationPort, + String sourceAddress, String sourcePort, + String dnatToIp, String dnatToPort, + String netrisVpcName, String snatIP, String comment) { + NatPostBody natBody = new NatPostBody(); + natBody.setAction(action); + natBody.setName(ruleName); + natBody.setProtocol(protocol); + natBody.setState(state); + if (StringUtils.isNotBlank(comment)) { + natBody.setComment(comment); + } + + natBody.setDestinationAddress(destinationAddress); + if (StringUtils.isNotBlank(destinationPort)) { + natBody.setDestinationPort(destinationPort); + } + + if (StringUtils.isNotBlank(sourceAddress)) { + natBody.setSourceAddress(sourceAddress); + } + if (StringUtils.isNotBlank(sourcePort)) { + natBody.setSourcePort(sourcePort); + } + + NatBodySiteSite site = new NatBodySiteSite(); + site.setId(siteId); + site.setName(siteName); + natBody.setSite(site); + + if (StringUtils.isNotBlank(snatIP)) { + natBody.setSnatToIP(snatIP); + } + + if (StringUtils.isNotBlank(dnatToIp)) { + natBody.setDnatToIP(dnatToIp); + } + if (StringUtils.isNotBlank(dnatToPort)) { + natBody.setDnatToPort(Integer.valueOf(dnatToPort)); + } + + NatBodyVpcVpc vpc = new NatBodyVpcVpc(); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return null; + } + vpc.setId(vpcResource.getId()); + vpc.setName(vpcResource.getName()); + natBody.setVpc(vpc); + return natBody; + } + + @Override + public boolean createOrUpdateDNATRule(CreateOrUpdateNetrisNatCommand cmd) { + return createOrUpdateNatRuleInternal(cmd); + } + + private boolean createNatRuleInternal(String ruleName, NatPostBody.ActionEnum action, NatPostBody.ProtocolEnum protocol, NatPostBody.StateEnum state, + String destinationAddress, String destinationPort, String sourceAddress, String sourcePort, + String sNatToIp, String dNatToIp, String dNatToPort, + String netrisVpcName, String networkName, String vNetName) { + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + String comment = String.format("NAT rule for %s with action %s", netrisVpcName, action.name()); + NatPostBody natBody = createNatRulePostBody(ruleName, action, protocol, state, + destinationAddress, destinationPort, sourceAddress, sourcePort, + dNatToIp, dNatToPort, netrisVpcName, sNatToIp, comment); + if (natBody == null) { + return false; + } + InlineResponse20015 natResponse = natApi.apiV2NatPost(natBody); + if (natResponse == null || !natResponse.isIsSuccess()) { + String reason = natResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris NAT rule {} creation failed for network(vNet) - {}({}): {}", action.name(), networkName, vNetName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException(String.format("Failed to create NAT rule %s for network(vNet): %s(%s)", action.name(), networkName, vNetName), e); + } + return true; + } + + private boolean updateSnatRuleInternal(String snatRuleName, String snatIP, String netrisVpcName, String networkName, + String vNetName, Integer netisSnatId, String vpcCidr) { + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + NatPutBody natBody = new NatPutBody(); + natBody.setAction(NatPutBody.ActionEnum.SNAT); + natBody.setDestinationAddress(ANY_IP); + natBody.setName(snatRuleName); + natBody.setProtocol(NatPutBody.ProtocolEnum.ALL); + + NatBodySiteSite site = new NatBodySiteSite(); + site.setId(siteId); + site.setName(siteName); + natBody.setSite(site); + natBody.setSourceAddress(vpcCidr); + natBody.setSnatToIP(snatIP); + + NatBodyVpcVpc vpc = new NatBodyVpcVpc(); + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + return false; + } + vpc.setId(vpcResource.getId()); + vpc.setName(vpcResource.getName()); + natBody.setVpc(vpc); + + InlineResponse20016 natUpdateResponse = natApi.apiV2NatIdPut(natBody, netisSnatId); + if (natUpdateResponse == null || !natUpdateResponse.isIsSuccess()) { + String reason = natUpdateResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("Update of Netris SNAT rule failed for network(vNet) - {}({}): {}", networkName, vNetName, reason); + throw new CloudRuntimeException(reason); + } + } catch (ApiException e) { + logAndThrowException(String.format("Failed to create SNAT rule for network(vNet): %s(%s)", networkName, vNetName), e); + } + return true; + } + + private List getVnets(VPCListing associatedVpc, String netrisVnetName, FilterBySites siteFilter, FilterByVpc vpcFilter) { + try { + VNetApi vNetApi = apiClient.getApiStubForMethod(VNetApi.class); + VnetResListBody vnetList = vNetApi.apiV2VnetGet(siteFilter, vpcFilter); + if (vnetList == null || !vnetList.isIsSuccess()) { + throw new CloudRuntimeException(String.format("Failed to list vNets for the given VPC: %s and site: %s", associatedVpc.getName(), siteName)); + } + return vnetList.getData().stream().filter(vnet -> vnet.getName().equals(netrisVnetName)).collect(Collectors.toList()); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to get vNets: %s", netrisVnetName), e); + } + return Collections.emptyList(); + } + + private void deleteVnetInternal(VPCListing associatedVpc, FilterBySites siteFilter, FilterByVpc vpcFilter, String netrisVnetName, String vNetName) { + try { + VNetApi vNetApi = apiClient.getApiStubForMethod(VNetApi.class); + List vnetsList = getVnets(associatedVpc, netrisVnetName, siteFilter, vpcFilter); + if (CollectionUtils.isEmpty(vnetsList)) { + logger.debug("vNet: {} for the given VPC: {} appears to already be deleted on Netris", vNetName, associatedVpc.getName()); + return; + } + VnetsBody vnetsBody = vnetsList.get(0); + + VnetResDeleteBody deleteVnetResponse = vNetApi.apiV2VnetIdDelete(vnetsBody.getId().intValue()); + if (deleteVnetResponse == null || !deleteVnetResponse.isIsSuccess()) { + throw new CloudRuntimeException(String.format("Failed to delete vNet: %s", vNetName)); + } + } catch (ApiException e) { + logAndThrowException(String.format("Failed to delete vNet: %s", netrisVnetName), e); + } + } + + private List getSubnet(FilterByVpc vpcFilter, String netrisSubnetName) { + try { + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + SubnetResBody subnetsResponse = ipamApi.apiV2IpamSubnetsGet(vpcFilter); + List subnets = subnetsResponse.getData(); + return subnets.stream().filter(subnet -> subnet.getName().equals(netrisSubnetName)).collect(Collectors.toList()); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to get IPAM subnet: %s", netrisSubnetName), e); + } + return new ArrayList<>(); + } + + private void deleteSubnetInternal(FilterByVpc vpcFilter, String netrisVnetName, String netrisSubnetName) { + try { + String logString = ""; + if (Objects.nonNull(netrisVnetName)) { + logString = String.format("for vNet: %s ", netrisVnetName); + } + logger.debug("Deleting Netris VPC IPAM Subnet {} {}", netrisSubnetName, logString); + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + List matchedSubnets = getSubnet(vpcFilter, netrisSubnetName); + if (CollectionUtils.isEmpty(matchedSubnets)) { + logger.debug("IPAM subnet: {} {} appears to already be deleted on Netris", netrisSubnetName, logString); + return; + } + + ipamApi.apiV2IpamTypeIdDelete("subnet", matchedSubnets.get(0).getId().intValue()); + } catch (ApiException e) { + logAndThrowException(String.format("Failed to delete subnet: %s", netrisSubnetName), e); + } + } + + private SubnetBody getIpamSubnetBody(VPCListing vpc, SubnetBody.PurposeEnum purpose, String subnetName, String subnetPrefix, Boolean isGlobalRouting) { + SubnetBody subnetBody = new SubnetBody(); + subnetBody.setName(subnetName); + + AllocationBodyVpc vpcAllocationBody = new AllocationBodyVpc(); + vpcAllocationBody.setName(vpc.getName()); + vpcAllocationBody.setId(vpc.getId()); + subnetBody.setVpc(vpcAllocationBody); + + IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant(); + allocationTenant.setId(new BigDecimal(tenantId)); + allocationTenant.setName(tenantName); + subnetBody.setTenant(allocationTenant); + + IpTreeSubnetSites subnetSites = new IpTreeSubnetSites(); + subnetSites.setId(new BigDecimal(siteId)); + subnetSites.setName(siteName); + subnetBody.setSites(List.of(subnetSites)); + + subnetBody.setPurpose(purpose); + subnetBody.setPrefix(subnetPrefix); + if (isGlobalRouting != null) { + subnetBody.setGlobalRouting(isGlobalRouting); + } + return subnetBody; + } + + private InlineResponse2004Data createIpamSubnetInternal(String subnetName, String subnetPrefix, SubnetBody.PurposeEnum purpose, VPCListing vpc, Boolean isGlobalRouting) { + logger.debug("Creating Netris IPAM Subnet {} for VPC {}", subnetPrefix, vpc.getName()); + try { + + SubnetBody subnetBody = getIpamSubnetBody(vpc, purpose, subnetName, subnetPrefix, isGlobalRouting); + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + InlineResponse2004 subnetResponse = ipamApi.apiV2IpamSubnetPost(subnetBody); + if (subnetResponse == null || !subnetResponse.isIsSuccess()) { + String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris IPAM Subnet {} creation failed: {}", subnetName, reason); + throw new CloudRuntimeException(reason); + } + return subnetResponse.getData(); + } catch (ApiException e) { + logAndThrowException(String.format("Error creating Netris IPAM Subnet %s for VPC %s", subnetPrefix, vpc.getName()), e); + return null; + } + } + + private InlineResponse2004Data updateIpamSubnetInternal(Integer netrisSubnetId, String subnetName, String subnetPrefix, + SubnetBody.PurposeEnum purpose, VPCListing vpc, Boolean isGlobalRouting) { + logger.debug("Updating Netris IPAM Subnet {} for VPC {}", subnetPrefix, vpc.getName()); + try { + + SubnetBody subnetBody = getIpamSubnetBody(vpc, purpose, subnetName, subnetPrefix, isGlobalRouting); + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + InlineResponse2004 subnetResponse = ipamApi.apiV2IpamSubnetIdPut(subnetBody, netrisSubnetId); + if (subnetResponse == null || !subnetResponse.isIsSuccess()) { + String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris IPAM Subnet {} update failed: {}", subnetName, reason); + throw new CloudRuntimeException(reason); + } + return subnetResponse.getData(); + } catch (ApiException e) { + logAndThrowException(String.format("Error Updating Netris IPAM Subnet %s for VPC %s", subnetPrefix, vpc.getName()), e); + return null; + } + } + + VnetResAddBody createVnetInternal(VPCListing associatedVpc, String netrisVnetName, String netrisGateway, String netrisV6Cidr, Integer vxlanId, String netrisTag) { + logger.debug("Creating Netris VPC vNet {} for CIDR {}", netrisVnetName, netrisGateway); + try { + VnetAddBody vnetBody = new VnetAddBody(); + + vnetBody.setCustomAnycastMac(""); + + VnetAddBodyGateways gatewayV4 = new VnetAddBodyGateways(); + gatewayV4.prefix(netrisGateway); + gatewayV4.setDhcpEnabled(false); + VnetAddBodyDhcp dhcp = new VnetAddBodyDhcp(); + dhcp.setEnd(""); + dhcp.setStart(""); + dhcp.setOptionSet(new VnetAddBodyDhcpOptionSet()); + gatewayV4.setDhcp(dhcp); + List gatewaysList = new ArrayList<>(); + gatewaysList.add(gatewayV4); + + if (Objects.nonNull(netrisV6Cidr)) { + VnetAddBodyGateways gatewayV6 = new VnetAddBodyGateways(); + gatewayV6.prefix(NetUtils.getIpv6Gateway(netrisV6Cidr)); + gatewayV6.setDhcpEnabled(false); + gatewayV6.setDhcp(dhcp); + gatewaysList.add(gatewayV6); + } + + vnetBody.setGateways(gatewaysList); + vnetBody.setGuestTenants(new ArrayList<>()); + vnetBody.setL3vpn(false); + vnetBody.setName(netrisVnetName); + vnetBody.setNativeVlan(0); + vnetBody.setVxlanID(vxlanId); + vnetBody.setPorts(new ArrayList<>()); + + IpTreeSubnetSites subnetSites = new IpTreeSubnetSites(); + subnetSites.setId(new BigDecimal(siteId)); + subnetSites.setName(siteName); + List subnetSitesList = new ArrayList<>(); + subnetSitesList.add(subnetSites); + vnetBody.setSites(subnetSitesList); + + vnetBody.setState(VnetAddBody.StateEnum.ACTIVE); + + vnetBody.setTags(new ArrayList<>()); + + IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant(); + allocationTenant.setId(new BigDecimal(tenantId)); + allocationTenant.setName(tenantName); + vnetBody.setTenant(allocationTenant); + + vnetBody.setVlan(0); + vnetBody.setVlanAware(false); + vnetBody.setVlans(""); + + VnetAddBodyVpc vpc = new VnetAddBodyVpc(); + vpc.setName(associatedVpc.getName()); + vpc.setId(associatedVpc.getId()); + vnetBody.setVpc(vpc); + + vnetBody.setTags(Collections.singletonList(netrisTag)); + + VNetApi vnetApi = apiClient.getApiStubForMethod(VNetApi.class); + return vnetApi.apiV2VnetPost(vnetBody); + } catch (ApiException e) { + logAndThrowException(String.format("Error creating Netris vNet %s for VPC %s", netrisVnetName, associatedVpc.getName()), e); + return null; + } + } + + private String getNetrisVpcNameSuffix(Long vpcId, String vpcName, Long networkId, String networkName, boolean isVpc) { + String suffix = null; + if (isVpc) { + suffix = String.format("%s-%s", vpcId, vpcName); + } else { + suffix = String.format("%s-%s", networkId, networkName); + } + return suffix; + } + + private NatGetBody netrisNatRuleExists(String netrisNatRule) { + try { + NatApi natApi = apiClient.getApiStubForMethod(NatApi.class); + //NatResponseGetOk response = natApi.apiV2NatGet(null, Arrays.asList(new BigDecimal(vpcId))); + NatResponseGetOk response = natApi.apiV2NatGet(null, null); + if (Objects.isNull(response) || !response.isIsSuccess()) { + throw new CloudRuntimeException("Failed to list Netris NAT rules"); + } + List data = response.getData().stream().filter(natData -> natData.getName().equals(netrisNatRule)).collect(Collectors.toList()); + if (data.isEmpty()) { + return null; + } + return data.get(0); + + } catch (ApiException e) { + throw new CloudRuntimeException("Failed to list Netris NAT rules"); + } + } + + private VPCListing getNetrisVpcResource(String netrisVpcName) { + VPCListing vpcResource = getVpcByNameAndTenant(netrisVpcName); + if (vpcResource == null) { + logger.error("Could not find the Netris VPC resource with name {} and tenant ID {}", netrisVpcName, tenantId); + } + return vpcResource; + } + + private String getNetrisVpcName(NetrisCommand cmd, Long vpcId, String vpcName) { + String suffix = getNetrisVpcNameSuffix(vpcId, vpcName, cmd.getId(), cmd.getName(), cmd.isVpc()); + return NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix); + } + + private void deleteNatSubnet(String netrisSubnetName, Integer netrisVpcId, String natIp) { + FilterByVpc vpcFilter = new FilterByVpc(); + vpcFilter.add(netrisVpcId); + deleteSubnetInternal(vpcFilter, null, netrisSubnetName); + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java new file mode 100644 index 00000000000..0e798ebb6be --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java @@ -0,0 +1,820 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.amazonaws.util.CollectionUtils; +import com.cloud.agent.AgentManager; +import com.cloud.agent.Listener; +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.AgentControlCommand; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.to.LoadBalancerTO; +import com.cloud.api.ApiDBUtils; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.ConnectionException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.network.IpAddress; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.SDNProviderNetworkRule; +import com.cloud.network.SDNProviderOpObject; +import com.cloud.network.as.AutoScaleCounter; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.LoadBalancerVMMapDao; +import com.cloud.network.dao.LoadBalancerVMMapVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.element.DhcpServiceProvider; +import com.cloud.network.element.DnsServiceProvider; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.LoadBalancingServiceProvider; +import com.cloud.network.element.NetworkACLServiceProvider; +import com.cloud.network.element.PortForwardingServiceProvider; +import com.cloud.network.element.StaticNatServiceProvider; +import com.cloud.network.element.VirtualRouterElement; +import com.cloud.network.element.VpcProvider; +import com.cloud.network.lb.LoadBalancingRule; +import com.cloud.network.netris.NetrisLbBackend; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.network.rules.PortForwardingRule; +import com.cloud.network.rules.StaticNat; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceStateAdapter; +import com.cloud.resource.ServerResource; +import com.cloud.resource.UnableDeleteHostException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.uservm.UserVm; +import com.cloud.utils.Pair; +import com.cloud.utils.component.AdapterBase; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.dao.VMInstanceDao; +import com.google.gson.Gson; +import org.apache.cloudstack.StartupNetrisCommand; +import org.apache.cloudstack.api.ApiConstants; +import com.cloud.network.netris.NetrisNetworkRule; +import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO; +import org.apache.cloudstack.resourcedetail.dao.FirewallRuleDetailsDao; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +@Component +public class NetrisElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, VpcProvider, + StaticNatServiceProvider, IpDeployer, PortForwardingServiceProvider, NetworkACLServiceProvider, + LoadBalancingServiceProvider, ResourceStateAdapter, Listener { + + @Inject + NetworkModel networkModel; + @Inject + AgentManager agentManager; + @Inject + ResourceManager resourceManager; + @Inject + private NetrisService netrisService; + @Inject + private AccountManager accountManager; + @Inject + private DataCenterDao dataCenterDao; + @Inject + private NetworkDao networkDao; + @Inject + private DomainDao domainDao; + @Inject + private VpcDao vpcDao; + @Inject + private FirewallRuleDetailsDao firewallRuleDetailsDao; + @Inject + private IPAddressDao ipAddressDao; + @Inject + private VMInstanceDao vmInstanceDao; + @Inject + LoadBalancerVMMapDao lbVmMapDao; + + protected Logger logger = LogManager.getLogger(getClass()); + + private final Map> capabilities = initCapabilities(); + + protected static List getNetrisAutoScaleCounters() { + AutoScaleCounter counter; + final List counterList = new ArrayList<>(); + counter = new AutoScaleCounter(AutoScaleCounter.AutoScaleCounterType.Cpu); + counterList.add(counter); + counter = new AutoScaleCounter(AutoScaleCounter.AutoScaleCounterType.Memory); + counterList.add(counter); + return counterList; + } + + protected static Map> initCapabilities() { + Map> capabilities = new HashMap<>(); + + Map dhcpCapabilities = Map.of(Network.Capability.DhcpAccrossMultipleSubnets, "true"); + capabilities.put(Network.Service.Dhcp, dhcpCapabilities); + + Map dnsCapabilities = new HashMap<>(); + dnsCapabilities.put(Network.Capability.AllowDnsSuffixModification, "true"); + capabilities.put(Network.Service.Dns, dnsCapabilities); + + capabilities.put(Network.Service.StaticNat, null); + + // Set capabilities for LB service + Map lbCapabilities = new HashMap(); + lbCapabilities.put(Network.Capability.SupportedLBAlgorithms, "roundrobin,leastconn"); + lbCapabilities.put(Network.Capability.SupportedLBIsolation, "dedicated"); + lbCapabilities.put(Network.Capability.SupportedProtocols, "tcp, udp"); + lbCapabilities.put(Network.Capability.SupportedStickinessMethods, VirtualRouterElement.getHAProxyStickinessCapability()); + lbCapabilities.put(Network.Capability.LbSchemes, String.join(",", LoadBalancerContainer.Scheme.Internal.name(), LoadBalancerContainer.Scheme.Public.name())); + final Gson gson = new Gson(); + final String autoScaleCounterList = gson.toJson(getNetrisAutoScaleCounters()); + lbCapabilities.put(Network.Capability.AutoScaleCounters, autoScaleCounterList); + lbCapabilities.put(Network.Capability.VmAutoScaling, "true"); + + capabilities.put(Network.Service.Lb, lbCapabilities); + capabilities.put(Network.Service.PortForwarding, null); + capabilities.put(Network.Service.NetworkACL, null); + + Map firewallCapabilities = new HashMap<>(); + firewallCapabilities.put(Network.Capability.SupportedProtocols, "tcp,udp,icmp"); + firewallCapabilities.put(Network.Capability.SupportedEgressProtocols, "tcp,udp,icmp,all"); + firewallCapabilities.put(Network.Capability.MultipleIps, "true"); + firewallCapabilities.put(Network.Capability.TrafficStatistics, "per public ip"); + firewallCapabilities.put(Network.Capability.SupportedTrafficDirection, "ingress, egress"); + capabilities.put(Network.Service.Firewall, firewallCapabilities); + + Map sourceNatCapabilities = new HashMap<>(); + sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true"); + sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount"); + capabilities.put(Network.Service.Gateway, null); + capabilities.put(Network.Service.SourceNat, sourceNatCapabilities); + return capabilities; + } + + @Override + public boolean processAnswers(long agentId, long seq, Answer[] answers) { + return false; + } + + @Override + public boolean processCommands(long agentId, long seq, Command[] commands) { + return false; + } + + @Override + public AgentControlAnswer processControlCommand(long agentId, AgentControlCommand cmd) { + return null; + } + + @Override + public void processHostAdded(long hostId) { + // Do nothing + } + + @Override + public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException { + // Do nothing + } + + @Override + public boolean processDisconnect(long agentId, Status state) { + return false; + } + + @Override + public void processHostAboutToBeRemoved(long hostId) { + // Do nothing + } + + @Override + public void processHostRemoved(long hostId, long clusterId) { + // Do nothing + } + + @Override + public boolean isRecurring() { + return false; + } + + @Override + public int getTimeout() { + return 0; + } + + @Override + public boolean processTimeout(long agentId, long seq) { + return false; + } + + protected boolean canHandle(Network network, Network.Service service) { + logger.debug("Checking if Netris Element can handle service " + service.getName() + " on network " + + network.getDisplayText()); + + if (!networkModel.isProviderForNetwork(getProvider(), network.getId())) { + logger.debug("Netris Element is not a provider for network " + network.getDisplayText()); + return false; + } + + return true; + } + + @Override + public boolean addDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean configDhcpSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean removeDhcpSupportForSubnet(Network network) throws ResourceUnavailableException { + return true; + } + + @Override + public boolean setExtraDhcpOptions(Network network, long nicId, Map dhcpOptions) { + return true; + } + + @Override + public boolean removeDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile vmProfile) throws ResourceUnavailableException { + return true; + } + + @Override + public boolean addDnsEntry(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean configDnsSupportForSubnet(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + return true; + } + + @Override + public boolean removeDnsSupportForSubnet(Network network) throws ResourceUnavailableException { + return true; + } + + @Override + public Map> getCapabilities() { + return capabilities; + } + + @Override + public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { + return true; + } + + @Override + public Network.Provider getProvider() { + return Network.Provider.Netris; + } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + agentManager.registerForHostEvents(this, true, true, true); + resourceManager.registerResourceStateAdapter(this.getClass().getSimpleName(), this); + return true; + } + + @Override + public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + return true; + } + + @Override + public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + return false; + } + + @Override + public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean releaseIp(IpAddress ipAddress) { + return netrisService.releaseNatIp(ipAddress.getDataCenterId(), ipAddress.getAddress().addr()); + } + + @Override + public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { + return canHandle(network, Network.Service.Connectivity); + } + + @Override + public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + Account account = accountManager.getAccount(network.getAccountId()); + NetworkVO networkVO = networkDao.findById(network.getId()); + DataCenterVO zone = dataCenterDao.findById(network.getDataCenterId()); + DomainVO domain = domainDao.findById(account.getDomainId()); + if (Objects.isNull(zone)) { + String msg = String.format("Cannot find zone with ID %s", network.getDataCenterId()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + String vpcName = null; + Long vpcId = network.getVpcId(); + if (Objects.nonNull(vpcId)) { + VpcVO vpc = vpcDao.findById(vpcId); + if (Objects.nonNull(vpc)) { + vpcName = vpc.getName(); + } + } + netrisService.deleteVnetResource(zone.getId(), account.getId(), domain.getId(), vpcName, vpcId, networkVO.getName(), network.getId(), network.getCidr()); + return true; + } + + @Override + public boolean isReady(PhysicalNetworkServiceProvider provider) { + return true; + } + + @Override + public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean canEnableIndividualServices() { + return true; + } + + @Override + public boolean verifyServicesCombination(Set services) { + return true; + } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { + return null; + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map details, List hostTags) { + if (!(startup[0] instanceof StartupNetrisCommand)) { + return null; + } + host.setType(Host.Type.L2Networking); + return host; + } + + @Override + public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException { + return null; + } + + @Override + public boolean implementVpc(Vpc vpc, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + return true; + } + + @Override + public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + long zoneId = vpc.getZoneId(); + long accountId = vpc.getAccountId(); + long domainId = vpc.getDomainId(); + return netrisService.deleteVpcResource(zoneId, accountId, domainId, vpc); + } + + @Override + public boolean createPrivateGateway(PrivateGateway gateway) throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + @Override + public boolean deletePrivateGateway(PrivateGateway privateGateway) throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + @Override + public boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException { + List existingStaticRoutes = netrisService.listStaticRoutes(vpc.getZoneId(), vpc.getAccountId(), vpc.getDomainId(), vpc.getName(), vpc.getId(), true, null, null, null); + List staticRouteCidrs = new ArrayList<>(); + for(StaticRouteProfile staticRoute : routes) { + if (StaticRoute.State.Add == staticRoute.getState()) { + netrisService.addOrUpdateStaticRoute(vpc.getZoneId(), vpc.getAccountId(), vpc.getDomainId(), vpc.getName(), vpc.getId(), true, staticRoute.getCidr(), staticRoute.getGateway(), staticRoute.getId(), false); + } else if (StaticRoute.State.Revoke == staticRoute.getState()) { + netrisService.deleteStaticRoute(vpc.getZoneId(), vpc.getAccountId(), vpc.getDomainId(), vpc.getName(), vpc.getId(), true, staticRoute.getCidr(), staticRoute.getGateway(), staticRoute.getId()); + } else if (StaticRoute.State.Update == staticRoute.getState()) { + netrisService.addOrUpdateStaticRoute(vpc.getZoneId(), vpc.getAccountId(), vpc.getDomainId(), vpc.getName(), vpc.getId(), true, staticRoute.getCidr(), staticRoute.getGateway(), staticRoute.getId(), true); + } + staticRouteCidrs.add(staticRoute.getCidr()); + } + for (StaticRoute staticRoute : existingStaticRoutes) { + if (!staticRouteCidrs.contains(staticRoute.getCidr())) { + logger.info("Revoking static route with cidr {} which are not used by VPC {}", staticRoute.getCidr(), vpc); + netrisService.deleteStaticRoute(vpc.getZoneId(), vpc.getAccountId(), vpc.getDomainId(), vpc.getName(), vpc.getId(), true, staticRoute.getCidr(), null, staticRoute.getId()); + } + } + return true; + } + + @Override + public boolean applyACLItemsToPrivateGw(PrivateGateway gateway, List rules) throws ResourceUnavailableException { + return true; + } + + @Override + public boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address) { + return netrisService.updateVpcSourceNatIp(vpc, address); + } + + @Override + public boolean updateVpc(Vpc vpc, String previousVpcName) { + return netrisService.updateVpcResource(vpc.getZoneId(), vpc.getAccountId(), vpc.getDomainId(), vpc.getId(), vpc.getName(), previousVpcName); + } + + @Override + public boolean applyNetworkACLs(Network network, List rules) throws ResourceUnavailableException { + if (!canHandle(network, Network.Service.NetworkACL)) { + return false; + } + + List nsxDelNetworkRules = new ArrayList<>(); + boolean success = true; + for (NetworkACLItem rule : rules) { + String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule); + NetrisNetworkRule networkRule = getNetrisNetworkRuleForAcl(rule, privatePort); + if (Arrays.asList(NetworkACLItem.State.Active, NetworkACLItem.State.Add).contains(rule.getState())) { + success = success && netrisService.addFirewallRules(network, List.of(networkRule)); + } else if (NetworkACLItem.State.Revoke == rule.getState()) { + nsxDelNetworkRules.add(networkRule); + } + } + + if (!nsxDelNetworkRules.isEmpty()) { + success = netrisService.deleteFirewallRules(network, nsxDelNetworkRules); + if (!success) { + logger.warn("Not all firewall rules were successfully deleted"); + } + } + return success; + } + + private NetrisNetworkRule getNetrisNetworkRuleForAcl(NetworkACLItem rule, String privatePort) { + SDNProviderNetworkRule baseNetworkRule = new SDNProviderNetworkRule.Builder() + .setRuleId(rule.getId()) + .setSourceCidrList(!CollectionUtils.isNullOrEmpty(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) + .setTrafficType(rule.getTrafficType().toString()) + .setProtocol(rule.getProtocol().toUpperCase()) + .setPublicPort(String.valueOf(rule.getSourcePortStart())) + .setPrivatePort(String.valueOf(privatePort)) + .setIcmpCode(rule.getIcmpCode()) + .setIcmpType(rule.getIcmpType()) + .setService(Network.Service.NetworkACL) + .build(); + return new NetrisNetworkRule.Builder() + .baseRule(baseNetworkRule) + .aclAction(transformActionValue(rule.getAction())) + .reason(rule.getReason()) + .build(); + } + + protected List transformCidrListValues(List sourceCidrList) { + List list = new ArrayList<>(); + if (org.apache.commons.collections.CollectionUtils.isNotEmpty(sourceCidrList)) { + for (String cidr : sourceCidrList) { + if (cidr.equals("0.0.0.0/0")) { + list.add("ANY"); + } else { + list.add(cidr); + } + } + } + return list; + } + + protected NetrisNetworkRule.NetrisRuleAction transformActionValue(NetworkACLItem.Action action) { + if (action == NetworkACLItem.Action.Allow) { + return NetrisNetworkRule.NetrisRuleAction.PERMIT; + } else if (action == NetworkACLItem.Action.Deny) { + return NetrisNetworkRule.NetrisRuleAction.DENY; + } + String err = String.format("Unsupported action %s", action.toString()); + logger.error(err); + throw new CloudRuntimeException(err); + } + + @Override + public boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems) { + List aclRulesList = new ArrayList<>(); + for (NetworkACLItem rule : networkACLItems) { + String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule); + aclRulesList.add(getNetrisNetworkRuleForAcl(rule, privatePort)); + } + for (Network network: networks) { + netrisService.deleteFirewallRules(network, aclRulesList); + } + boolean success = true; + for (Network network : networks) { + for (NetrisNetworkRule aclRule : aclRulesList) { + success = success && netrisService.addFirewallRules(network, List.of(aclRule)); + } + } + return success; + } + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + + @Override + public boolean applyPFRules(Network network, List rules) throws ResourceUnavailableException { + if (!canHandle(network, Network.Service.PortForwarding)) { + return false; + } + return applyPFRulesInternal(network, rules); + } + + private boolean addOrRemovePFRuleOnNetris(UserVm vm, PortForwardingRule rule, NetrisNetworkRule networkRule, SDNProviderOpObject netrisObject, boolean create) { + logger.debug("{} port forwarding rule on Netris for VM {} to ports {} - {}", + create ? "Creating" : "Deleting", vm.getUuid(), rule.getDestinationPortStart(), rule.getDestinationPortEnd()); + Long vpcId = netrisObject.getVpcVO() != null ? netrisObject.getVpcVO().getId() : null; + String vpcName = netrisObject.getVpcVO() != null ? netrisObject.getVpcVO().getName() : null; + Long networkId = netrisObject.getNetworkVO() != null ? netrisObject.getNetworkVO().getId() : null; + String networkName = netrisObject.getNetworkVO() != null ? netrisObject.getNetworkVO().getName() : null; + String vpcCidr = netrisObject.getVpcVO() != null ? netrisObject.getVpcVO().getCidr() : null; + SDNProviderNetworkRule baseNetRule = networkRule.getBaseRule(); + return create ? + netrisService.createPortForwardingRule(baseNetRule.getZoneId(), baseNetRule.getAccountId(), baseNetRule.getDomainId(), + vpcName, vpcId, networkName, networkId, netrisObject.isVpcResource(), vpcCidr, baseNetRule) : + netrisService.deletePortForwardingRule(baseNetRule.getZoneId(), baseNetRule.getAccountId(), baseNetRule.getDomainId(), + vpcName, vpcId, networkName, networkId, netrisObject.isVpcResource(), vpcCidr, baseNetRule); + } + + private boolean applyPFRulesInternal(Network network, List rules) { + return Transaction.execute((TransactionCallback) status -> { + boolean result = true; + for (PortForwardingRule rule : rules) { + IPAddressVO publicIp = ApiDBUtils.findIpAddressById(rule.getSourceIpAddressId()); + UserVm vm = ApiDBUtils.findUserVmById(rule.getVirtualMachineId()); + if (vm == null && rule.getState() != FirewallRule.State.Revoke) { + continue; + } + SDNProviderOpObject netrisObject = getNetrisOpObject(network); + String publicPort = PortForwardingServiceProvider.getPublicPortRange(rule); + String privatePort = PortForwardingServiceProvider.getPrivatePFPortRange(rule); + FirewallRuleDetailVO ruleDetail = firewallRuleDetailsDao.findDetail(rule.getId(), ApiConstants.NETRIS_DETAIL_KEY); + + SDNProviderNetworkRule baseNetworkRule = new SDNProviderNetworkRule.Builder() + .setDomainId(netrisObject.getDomainId()) + .setAccountId(netrisObject.getAccountId()) + .setZoneId(netrisObject.getZoneId()) + .setNetworkResourceId(netrisObject.getNetworkResourceId()) + .setNetworkResourceName(netrisObject.getNetworkResourceName()) + .setVpcResource(netrisObject.isVpcResource()) + .setVmId(Objects.nonNull(vm) ? vm.getId() : 0) + .setVmIp(Objects.nonNull(vm) ? vm.getPrivateIpAddress() : null) + .setPublicIp(publicIp.getAddress().addr()) + .setPrivatePort(privatePort) + .setPublicPort(publicPort) + .setRuleId(rule.getId()) + .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)) + .build(); + + NetrisNetworkRule networkRule = new NetrisNetworkRule.Builder().baseRule(baseNetworkRule).build(); + + if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(rule.getState())) { + boolean pfRuleResult = addOrRemovePFRuleOnNetris(vm, rule, networkRule, netrisObject, true); + if (pfRuleResult) { + logger.debug("Port forwarding rule {} created on Netris, adding detail on firewall rules details", rule.getId()); + if (ruleDetail == null && FirewallRule.State.Add == rule.getState()) { + logger.debug("Adding new firewall detail for rule {}", rule.getId()); + firewallRuleDetailsDao.addDetail(rule.getId(), ApiConstants.NETRIS_DETAIL_KEY, "true", false); + } else if (ruleDetail != null) { + logger.debug("Updating firewall detail for rule {}", rule.getId()); + ruleDetail.setValue("true"); + firewallRuleDetailsDao.update(ruleDetail.getId(), ruleDetail); + } + } + result &= pfRuleResult; + } else if (rule.getState() == FirewallRule.State.Revoke) { + boolean pfRuleResult = addOrRemovePFRuleOnNetris(vm, rule, networkRule, netrisObject, false); + if (pfRuleResult && ruleDetail != null) { + logger.debug("Updating firewall rule detail {} for rule {}, set to false", ruleDetail.getId(), rule.getId()); + ruleDetail.setValue("false"); + firewallRuleDetailsDao.update(ruleDetail.getId(), ruleDetail); + } + result &= pfRuleResult; + } + } + return result; + }); + } + + private SDNProviderOpObject getNetrisOpObject(Network network) { + Pair vpcOrNetwork = getVpcOrNetwork(network.getVpcId(), network.getId()); + VpcVO vpc = vpcOrNetwork.first(); + NetworkVO networkVO = vpcOrNetwork.second(); + long domainId = getResourceId("domain", vpc, networkVO); + long accountId = getResourceId("account", vpc, networkVO); + long zoneId = getResourceId("zone", vpc, networkVO); + + return new SDNProviderOpObject.Builder() + .vpcVO(vpc) + .networkVO(networkVO) + .domainId(domainId) + .accountId(accountId) + .zoneId(zoneId) + .build(); + } + + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + for(StaticNat staticNat : rules) { + long sourceIpAddressId = staticNat.getSourceIpAddressId(); + IPAddressVO ipAddressVO = ipAddressDao.findByIdIncludingRemoved(sourceIpAddressId); + VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(ipAddressVO.getAssociatedWithVmId()); + // floating ip is released when nic was deleted + if (vm == null || networkModel.getNicInNetworkIncludingRemoved(vm.getId(), config.getId()) == null) { + continue; + } + long vmId = vm.getId(); + Pair vpcOrNetwork = getVpcOrNetwork(config.getVpcId(), config.getId()); + VpcVO vpc = vpcOrNetwork.first(); + NetworkVO network = vpcOrNetwork.second(); + Long networkResourceId = Objects.nonNull(vpc) ? vpc.getId() : network.getId(); + String networkResourceName = Objects.nonNull(vpc) ? vpc.getName() : network.getName(); + boolean isVpcResource = Objects.nonNull(vpc); + if (!staticNat.isForRevoke()) { + return netrisService.createStaticNatRule(config.getDataCenterId(), config.getAccountId(), config.getDomainId(), + networkResourceName, networkResourceId, isVpcResource, vpc.getCidr(), + ipAddressVO.getAddress().addr(), staticNat.getDestIpAddress(), vmId); + } else { + return netrisService.deleteStaticNatRule(config.getDataCenterId(), config.getAccountId(), config.getDomainId(), + networkResourceName, networkResourceId, isVpcResource, ipAddressVO.getAddress().addr(), vmId); + } + } + return false; + } + + public Pair getVpcOrNetwork(Long vpcId, long networkId) { + VpcVO vpc = null; + NetworkVO network = null; + if (Objects.nonNull(vpcId)) { + vpc = vpcDao.findById(vpcId); + if (Objects.isNull(vpc)) { + throw new CloudRuntimeException(String.format("Failed to find VPC with id: %s", vpcId)); + } + } else { + network = networkDao.findById(networkId); + if (Objects.isNull(network)) { + throw new CloudRuntimeException(String.format("Failed to find network with id: %s", networkId)); + } + } + return new Pair<>(vpc, network); + } + + private long getResourceId(String resource, VpcVO vpc, NetworkVO network) { + switch (resource) { + case "domain": + return Objects.nonNull(vpc) ? vpc.getDomainId() : network.getDomainId(); + case "account": + return Objects.nonNull(vpc) ? vpc.getAccountId() : network.getAccountId(); + case "zone": + return Objects.nonNull(vpc) ? vpc.getZoneId() : network.getDataCenterId(); + default: + return 0; + } + } + + private SDNProviderOpObject getNetrisObject(Network network) { + Pair vpcOrNetwork = getVpcOrNetwork(network.getVpcId(), network.getId()); + VpcVO vpc = vpcOrNetwork.first(); + NetworkVO networkVO = vpcOrNetwork.second(); + long domainId = getResourceId("domain", vpc, networkVO); + long accountId = getResourceId("account", vpc, networkVO); + long zoneId = getResourceId("zone", vpc, networkVO); + + return new SDNProviderOpObject.Builder() + .vpcVO(vpc) + .networkVO(networkVO) + .domainId(domainId) + .accountId(accountId) + .zoneId(zoneId) + .build(); + } + + @Override + public boolean applyLBRules(Network network, List rules) throws ResourceUnavailableException { + boolean result = true; + for (LoadBalancingRule loadBalancingRule : rules) { + IPAddressVO publicIp = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), + loadBalancingRule.getSourceIp().addr()); + + List lbBackends = getLoadBalancerBackends(loadBalancingRule); + SDNProviderOpObject netrisObject = getNetrisObject(network); + SDNProviderNetworkRule baseNetworkRule = new SDNProviderNetworkRule.Builder() + .setDomainId(netrisObject.getDomainId()) + .setAccountId(netrisObject.getAccountId()) + .setZoneId(netrisObject.getZoneId()) + .setNetworkResourceId(netrisObject.getNetworkResourceId()) + .setNetworkResourceName(netrisObject.getNetworkResourceName()) + .setVpcResource(netrisObject.isVpcResource()) + .setPublicIp(LoadBalancerContainer.Scheme.Public == loadBalancingRule.getScheme() ? + publicIp.getAddress().addr() : loadBalancingRule.getSourceIp().addr()) + .setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart())) + .setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart())) + .setRuleId(loadBalancingRule.getId()) + .setProtocol(loadBalancingRule.getProtocol().toUpperCase(Locale.ROOT)) + .setAlgorithm(loadBalancingRule.getAlgorithm()) + .build(); + + NetrisNetworkRule networkRule = new NetrisNetworkRule.Builder() + .baseRule(baseNetworkRule) + .lbBackends(lbBackends) + .lbCidrList(loadBalancingRule.getCidrList()) + .lbRuleName(loadBalancingRule.getName()) + .build(); + if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(loadBalancingRule.getState())) { + result &= netrisService.createOrUpdateLbRule(networkRule); + } else if (loadBalancingRule.getState() == FirewallRule.State.Revoke) { + result &= netrisService.deleteLbRule(networkRule); + } + } + return result; + } + + private List getLoadBalancerBackends(LoadBalancingRule lbRule) { + List lbVms = lbVmMapDao.listByLoadBalancerId(lbRule.getId(), false); + List lbMembers = new ArrayList<>(); + + for (LoadBalancerVMMapVO lbVm : lbVms) { + NetrisLbBackend member = new NetrisLbBackend(lbVm.getInstanceId(), lbVm.getInstanceIp(), lbRule.getDefaultPortStart()); + lbMembers.add(member); + } + return lbMembers; + } + + @Override + public boolean validateLBRule(Network network, LoadBalancingRule rule) { + return true; + } + + @Override + public List updateHealthChecks(Network network, List lbrules) { + return List.of(); + } + + @Override + public boolean handlesOnlyRulesInTransitionState() { + return false; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java new file mode 100644 index 00000000000..df566e90b67 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java @@ -0,0 +1,346 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.dc.DataCenter; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.domain.DomainVO; +import com.cloud.event.ActionEventUtils; +import com.cloud.event.EventTypes; +import com.cloud.event.EventVO; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.NetworkMigrationResponder; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.dao.NetworkDetailVO; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.guru.GuestNetworkGuru; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.vpc.VpcVO; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.user.Account; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.api.ApiCommandResourceType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.context.CallContext; + +import javax.inject.Inject; +import java.util.Objects; + +import static java.util.Objects.isNull; +import static java.util.Objects.nonNull; + +public class NetrisGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigrationResponder { + + @Inject + private NetrisService netrisService; + @Inject + NetworkModel networkModel; + @Inject + NetworkDetailsDao networkDetailsDao; + + public NetrisGuestNetworkGuru() { + super(); + _isolationMethods = new PhysicalNetwork.IsolationMethod[] {new PhysicalNetwork.IsolationMethod("Netris")}; + } + + @Override + public boolean canHandle(NetworkOffering offering, DataCenter.NetworkType networkType, + PhysicalNetwork physicalNetwork) { + return networkType == DataCenter.NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) + && isMyIsolationMethod(physicalNetwork) && (NetworkOffering.NetworkMode.ROUTED.equals(offering.getNetworkMode()) + || (networkOfferingServiceMapDao.isProviderForNetworkOffering( + offering.getId(), Network.Provider.Netris) && NetworkOffering.NetworkMode.NATTED.equals(offering.getNetworkMode()))); + } + + @Override + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, String name, Long vpcId, Account owner) { + PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); + DataCenter dc = _dcDao.findById(plan.getDataCenterId()); + + if (!canHandle(offering, dc.getNetworkType(), physnet)) { + logger.debug("Refusing to design this network"); + return null; + } + + NetworkVO network = (NetworkVO) super.design(offering, plan, userSpecified, name, vpcId, owner); + if (network == null) { + return null; + } + network.setBroadcastDomainType(Networks.BroadcastDomainType.Netris); + + if (userSpecified != null) { + if ((userSpecified.getIp6Cidr() == null && userSpecified.getIp6Gateway() != null) || ( + userSpecified.getIp6Cidr() != null && userSpecified.getIp6Gateway() == null)) { + throw new InvalidParameterValueException("cidrv6 and gatewayv6 must be specified together."); + } + + if (userSpecified.getIp6Cidr() != null) { + network.setIp6Cidr(userSpecified.getIp6Cidr()); + network.setIp6Gateway(userSpecified.getIp6Gateway()); + } + } + + network.setBroadcastDomainType(Networks.BroadcastDomainType.Netris); + network.setState(Network.State.Allocated); + + NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), + network.getBroadcastDomainType(), network.getNetworkOfferingId(), Network.State.Implemented, + network.getDataCenterId(), network.getPhysicalNetworkId(), offering.isRedundantRouter()); + implemented.setAccountId(owner.getAccountId()); + + if (network.getGateway() != null) { + implemented.setGateway(network.getGateway()); + } + + if (network.getCidr() != null) { + implemented.setCidr(network.getCidr()); + } + + if (vpcId != null) { + implemented.setVpcId(vpcId); + } + + if (name != null) { + implemented.setName(name); + } + implemented.setBroadcastUri(Networks.BroadcastDomainType.Netris.toUri("netris")); + + return network; + } + + @Override + public void setup(Network network, long networkId) { + try { + NetworkVO designedNetwork = _networkDao.findById(networkId); + long zoneId = network.getDataCenterId(); + DataCenter zone = _dcDao.findById(zoneId); + if (isNull(zone)) { + throw new CloudRuntimeException(String.format("Failed to find zone with id: %s", zoneId)); + } + try { + allocateVnet(network, designedNetwork, network.getDataCenterId(), network.getPhysicalNetworkId(), network.getReservationId()); + } catch (Exception e) { + throw new CloudRuntimeException(String.format("Failed to allocate VXLAN for Netris guest Network %s", network.getName())); + } + _networkDao.update(designedNetwork.getId(), designedNetwork); + createNetrisVnet(designedNetwork, zone); + } catch (Exception ex) { + throw new CloudRuntimeException("unable to create Netris network " + network.getUuid() + "due to: " + ex.getMessage()); + } + } + + @Override + @DB + public void deallocate(Network config, NicProfile nic, VirtualMachineProfile vm) { + // Do nothing + } + + @Override + public boolean update(Network network, String prevNetworkName) { + Long vpcId = network.getVpcId(); + String vpcName = null; + if (Objects.nonNull(vpcId)) { + VpcVO vpc = _vpcDao.findById(vpcId); + if (Objects.nonNull(vpc)) { + vpcName = vpc.getName(); + } + } + return netrisService.updateVnetResource(network.getDataCenterId(), network.getAccountId(), network.getDomainId(), + vpcName, vpcId, network.getName(), network.getId(), prevNetworkName); + } + + @Override + public Network implement(Network network, NetworkOffering offering, DeployDestination dest, + ReservationContext context) throws InsufficientVirtualNetworkCapacityException { + NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), + network.getBroadcastDomainType(), network.getNetworkOfferingId(), Network.State.Implemented, + network.getDataCenterId(), network.getPhysicalNetworkId(), offering.isRedundantRouter()); + implemented.setAccountId(network.getAccountId()); + + if (network.getGateway() != null) { + implemented.setGateway(network.getGateway()); + } + + if (network.getCidr() != null) { + implemented.setCidr(network.getCidr()); + } + + if (network.getVpcId() != null) { + implemented.setVpcId(network.getVpcId()); + } + + if (network.getName() != null) { + implemented.setName(network.getName()); + } + allocateVnet(network, implemented, network.getDataCenterId(), network.getPhysicalNetworkId(), network.getReservationId()); + return implemented; + } + + @Override + protected void allocateVnet(Network network, NetworkVO implemented, long dcId, long physicalNetworkId, String reservationId) + throws InsufficientVirtualNetworkCapacityException { + String vnet = null; + Long networkId = implemented.getId() > 0 ? implemented.getId() : network.getId(); + if (network.getBroadcastUri() == null) { + NetworkDetailVO netrisVnetDetail = networkDetailsDao.findDetail(networkId, ApiConstants.NETRIS_VXLAN_ID); + if (nonNull(netrisVnetDetail)) { + vnet = netrisVnetDetail.getValue(); + } else { + vnet = _dcDao.allocateVnet(dcId, physicalNetworkId, network.getAccountId(), reservationId, UseSystemGuestVlans.valueIn(network.getAccountId())); + if (vnet == null) { + throw new InsufficientVirtualNetworkCapacityException("Unable to allocate vnet as a " + "part of network " + network + " implement ", DataCenter.class, + dcId); + } + networkDetailsDao.addDetail(networkId, ApiConstants.NETRIS_VXLAN_ID, vnet, true); + } + implemented.setBroadcastUri(Networks.BroadcastDomainType.Netris.toUri(vnet)); + ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(), network.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VXLAN_ASSIGN, + "Assigned Zone vNet: " + vnet + " Network Id: " + networkId, networkId, ApiCommandResourceType.Network.toString(), 0); + } else { + implemented.setBroadcastUri(network.getBroadcastUri()); + } + } + + @Override + public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + NicProfile nicProfile = super.allocate(network, nic, vm); + if (vm.getType() != VirtualMachine.Type.DomainRouter) { + return nicProfile; + } + + final DataCenter zone = _dcDao.findById(network.getDataCenterId()); + long zoneId = network.getDataCenterId(); + if (Objects.isNull(zone)) { + String msg = String.format("Unable to find zone with id: %s", zoneId); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + Account account = accountDao.findById(network.getAccountId()); + if (Objects.isNull(account)) { + String msg = String.format("Unable to find account with id: %s", network.getAccountId()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + VpcVO vpc = _vpcDao.findById(network.getVpcId()); + if (Objects.isNull(vpc)) { + String msg = String.format("Unable to find VPC with id: %s, allocating for network %s", network.getVpcId(), network.getName()); + logger.debug(msg); + } + + DomainVO domain = domainDao.findById(account.getDomainId()); + if (Objects.isNull(domain)) { + String msg = String.format("Unable to find domain with id: %s", account.getDomainId()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + + NetworkOfferingVO networkOfferingVO = networkOfferingDao.findById(network.getNetworkOfferingId()); + + if (isNull(network.getVpcId()) && networkOfferingVO.getNetworkMode().equals(NetworkOffering.NetworkMode.NATTED)) { + // Netris Natted mode + long domainId = domain.getId(); + long accountId = account.getId(); + long dataCenterId = zone.getId(); + long resourceId = network.getId(); + PublicIpAddress ipAddress = networkModel.getSourceNatIpAddressForGuestNetwork(account, network); + String snatIP = ipAddress.getAddress().addr(); + boolean result = netrisService.createSnatRule(dataCenterId, accountId, domainId, vpc.getName(), vpc.getId(), network.getName(), resourceId, nonNull(network.getVpcId()), vpc.getCidr(), snatIP); + if (!result) { + String msg = String.format("Could not create Netris Nat Rule for IP %s", snatIP); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + + return nicProfile; + } + + @Override + public boolean prepareMigration(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) { + return false; + } + + @Override + public void rollbackMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) { + // Do nothing + } + + @Override + public void commitMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) { + // Do nothing + } + + public void createNetrisVnet(NetworkVO networkVO, DataCenter zone) { + Account account = accountDao.findById(networkVO.getAccountId()); + if (isNull(account)) { + throw new CloudRuntimeException(String.format("Unable to find account with id: %s", networkVO.getAccountId())); + } + DomainVO domain = domainDao.findById(account.getDomainId()); + if (Objects.isNull(domain)) { + String msg = String.format("Unable to find domain with id: %s", account.getDomainId()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + String vpcName = null; + Long vpcId = null; + Boolean globalRouting = null; + long networkOfferingId = networkVO.getNetworkOfferingId(); + NetworkOfferingVO networkOfferingVO = networkOfferingDao.findById(networkOfferingId); + if (NetworkOffering.NetworkMode.ROUTED.equals(networkOfferingVO.getNetworkMode())) { + globalRouting = true; + } + if (nonNull(networkVO.getVpcId())) { + VpcVO vpc = _vpcDao.findById(networkVO.getVpcId()); + if (isNull(vpc)) { + throw new CloudRuntimeException(String.format("Failed to find VPC network with id: %s", networkVO.getVpcId())); + } + vpcName = vpc.getName(); + vpcId = vpc.getId(); + } else { + logger.debug(String.format("Creating IPAM Allocation before creating IPAM Subnet", networkVO.getName())); + boolean isSourceNatSupported = !NetworkOffering.NetworkMode.ROUTED.equals(networkOfferingVO.getNetworkMode()) && + networkOfferingServiceMapDao.areServicesSupportedByNetworkOffering(networkVO.getNetworkOfferingId(), Network.Service.SourceNat); + boolean result = netrisService.createVpcResource(zone.getId(), networkVO.getAccountId(), networkVO.getDomainId(), + networkVO.getId(), networkVO.getName(), isSourceNatSupported, networkVO.getCidr(), false); + if (!result) { + String msg = String.format("Error creating Netris VPC for the network: %s", networkVO.getName()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + boolean result = netrisService.createVnetResource(zone.getId(), account.getId(), domain.getId(), vpcName, vpcId, + networkVO.getName(), networkVO.getId(), networkVO.getCidr(), globalRouting); + if (!result) { + throw new CloudRuntimeException("Failed to create Netris vNet resource for network: " + networkVO.getName()); + } + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderService.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderService.java new file mode 100644 index 00000000000..7d5f4146ab1 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderService.java @@ -0,0 +1,32 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.network.netris.NetrisProvider; +import com.cloud.utils.component.PluggableService; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.command.AddNetrisProviderCmd; +import org.apache.cloudstack.api.response.NetrisProviderResponse; + +import java.util.List; + +public interface NetrisProviderService extends PluggableService { + NetrisProvider addProvider(AddNetrisProviderCmd cmd); + List listNetrisProviders(Long zoneId); + boolean deleteNetrisProvider(Long providerId); + NetrisProviderResponse createNetrisProviderResponse(NetrisProvider provider); +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderServiceImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderServiceImpl.java new file mode 100644 index 00000000000..14a845e1c3a --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisProviderServiceImpl.java @@ -0,0 +1,217 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.DetailVO; +import com.cloud.host.Host; +import com.cloud.host.dao.HostDetailsDao; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.dao.NetrisProviderDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.network.netris.NetrisProvider; +import com.cloud.network.netris.NetrisService; +import com.cloud.resource.ResourceManager; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.db.TransactionCallback; +import com.cloud.utils.exception.CloudRuntimeException; +import com.google.common.annotations.VisibleForTesting; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.command.AddNetrisProviderCmd; +import org.apache.cloudstack.api.command.DeleteNetrisProviderCmd; +import org.apache.cloudstack.api.command.ListNetrisProvidersCmd; +import org.apache.cloudstack.api.response.NetrisProviderResponse; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.cloudstack.resource.NetrisResource; +import org.apache.commons.collections.CollectionUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +public class NetrisProviderServiceImpl implements NetrisProviderService { + + protected Logger logger = LogManager.getLogger(getClass()); + + @Inject + DataCenterDao dataCenterDao; + @Inject + ResourceManager resourceManager; + @Inject + NetrisProviderDao netrisProviderDao; + @Inject + HostDetailsDao hostDetailsDao; + @Inject + PhysicalNetworkDao physicalNetworkDao; + @Inject + NetworkDao networkDao; + @Inject + private NetrisService netrisService; + + @Override + public NetrisProvider addProvider(AddNetrisProviderCmd cmd) { + final Long zoneId = cmd.getZoneId(); + final String name = cmd.getName(); + final String url = cmd.getUrl(); + final String username = cmd.getUsername(); + final String password = cmd.getPassword(); + final String tenantName = cmd.getTenantName(); + final String siteName = cmd.getSiteName(); + final String netrisTag = cmd.getNetrisTag(); + + Map params = new HashMap<>(); + params.put("guid", UUID.randomUUID().toString()); + params.put("zoneId", zoneId.toString()); + params.put("name", name); + params.put("url", url); + params.put("username", username); + params.put("password", password); + params.put("siteName", siteName); + params.put("tenantName", tenantName); + params.put("netrisTag", netrisTag); + + Map hostdetails = new HashMap<>(params); + NetrisProvider netrisProvider; + + NetrisResource netrisResource = new NetrisResource(); + try { + netrisResource.configure(url, hostdetails); + final Host host = resourceManager.addHost(zoneId, netrisResource, netrisResource.getType(), params); + if (host != null) { + netrisProvider = Transaction.execute((TransactionCallback) status -> { + NetrisProviderVO netrisProviderVO = new NetrisProviderVO.Builder() + .setZoneId(zoneId) + .setHostId(host.getId()) + .setName(name) + .setUrl(url) + .setUsername(username) + .setPassword(password) + .setSiteName(siteName) + .setTenantName(tenantName) + .setNetrisTag(netrisTag) + .build(); + + netrisProviderDao.persist(netrisProviderVO); + + DetailVO detail = new DetailVO(host.getId(), "netriscontrollerid", + String.valueOf(netrisProviderVO.getId())); + hostDetailsDao.persist(detail); + + return netrisProviderVO; + }); + } else { + throw new CloudRuntimeException("Failed to add Netris controller due to internal error."); + } + netrisService.createIPAMAllocationsForZoneLevelPublicRanges(zoneId); + } catch (ConfigurationException e) { + throw new CloudRuntimeException(e.getMessage()); + } + return netrisProvider; + } + + @Override + public List listNetrisProviders(Long zoneId) { + List netrisControllersResponseList = new ArrayList<>(); + if (zoneId != null) { + NetrisProviderVO netrisProviderVO = netrisProviderDao.findByZoneId(zoneId); + if (Objects.nonNull(netrisProviderVO)) { + netrisControllersResponseList.add(createNetrisProviderResponse(netrisProviderVO)); + } + } else { + List netrisProviderVOList = netrisProviderDao.listAll(); + for (NetrisProviderVO nsxProviderVO : netrisProviderVOList) { + netrisControllersResponseList.add(createNetrisProviderResponse(nsxProviderVO)); + } + } + + return netrisControllersResponseList; + } + + @Override + public boolean deleteNetrisProvider(Long providerId) { + NetrisProviderVO netrisProvider = netrisProviderDao.findById(providerId); + if (Objects.isNull(netrisProvider)) { + throw new InvalidParameterValueException(String.format("Failed to find Netris provider with id: %s", providerId)); + } + Long zoneId = netrisProvider.getZoneId(); + // Find the physical network we work for + List physicalNetworks = physicalNetworkDao.listByZone(zoneId); + for (PhysicalNetworkVO physicalNetwork : physicalNetworks) { + List networkList = networkDao.listByPhysicalNetwork(physicalNetwork.getId()); + if (!CollectionUtils.isEmpty(networkList)) { + validateNetworkState(networkList); + } + } + netrisProviderDao.remove(providerId); + return true; + } + + @Override + public NetrisProviderResponse createNetrisProviderResponse(NetrisProvider provider) { + DataCenterVO zone = dataCenterDao.findById(provider.getZoneId()); + if (Objects.isNull(zone)) { + throw new CloudRuntimeException(String.format("Failed to find zone with id %s", provider.getZoneId())); + } + + NetrisProviderResponse response = new NetrisProviderResponse(); + response.setName(provider.getName()); + response.setUuid(provider.getUuid()); + response.setHostname(provider.getUrl()); + response.setZoneId(zone.getUuid()); + response.setZoneName(zone.getName()); + response.setSiteName(provider.getSiteName()); + response.setTenantName(provider.getTenantName()); + response.setNetrisTag(provider.getNetrisTag()); + response.setObjectName("netrisProvider"); + return response; + } + + @VisibleForTesting + void validateNetworkState(List networkList) { + for (NetworkVO network : networkList) { + if (network.getBroadcastDomainType() == Networks.BroadcastDomainType.Netris && + ((network.getState() != Network.State.Shutdown) && (network.getState() != Network.State.Destroy))) { + throw new CloudRuntimeException("This Netris provider cannot be deleted as there are one or more logical networks provisioned by CloudStack on it."); + } + } + } + + @Override + public List> getCommands() { + List> cmdList = new ArrayList<>(); + if (Boolean.TRUE.equals(NetworkOrchestrationService.NETRIS_ENABLED.value())) { + cmdList.add(AddNetrisProviderCmd.class); + cmdList.add(ListNetrisProvidersCmd.class); + cmdList.add(DeleteNetrisProviderCmd.class); + } + return cmdList; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java new file mode 100644 index 00000000000..f1cc49b7125 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.java @@ -0,0 +1,144 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.dc.VlanDetailsVO; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.guru.PublicNetworkGuru; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.vpc.VpcOffering; +import com.cloud.network.vpc.VpcOfferingVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.NicProfile; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.commons.collections.CollectionUtils; + +import javax.inject.Inject; +import java.util.List; +import java.util.stream.Collectors; + +public class NetrisPublicNetworkGuru extends PublicNetworkGuru { + + @Inject + private NetrisService netrisService; + + public NetrisPublicNetworkGuru() { + super(); + } + + @Override + protected boolean canHandle(NetworkOffering offering) { + boolean isForNetris = networkModel.isProviderForNetworkOffering(Network.Provider.Netris, offering.getId()); + return isMyTrafficType(offering.getTrafficType()) && offering.isSystemOnly() && isForNetris; + } + + @Override + public Network design(NetworkOffering offering, DeploymentPlan plan, Network network, String name, Long vpcId, Account owner) { + if (!canHandle(offering)) { + return null; + } + + if (offering.getTrafficType() == Networks.TrafficType.Public) { + return new NetworkVO(offering.getTrafficType(), Networks.Mode.Static, network.getBroadcastDomainType(), offering.getId(), Network.State.Setup, plan.getDataCenterId(), + plan.getPhysicalNetworkId(), offering.isRedundantRouter()); + } + return null; + } + + @Override + public NicProfile allocate(Network network, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException { + logger.debug("Netris Public network guru: allocate"); + + IPAddressVO ipAddress = _ipAddressDao.findByIp(nic.getIPv4Address()); + if (ipAddress == null) { + String err = String.format("Cannot find the IP address %s", nic.getIPv4Address()); + logger.error(err); + throw new CloudRuntimeException(err); + } + Long vpcId = ipAddress.getVpcId(); + boolean isForVpc = vpcId != null; + VpcVO vpc = vpcDao.findById(vpcId); + if (vpc == null) { + String err = String.format("Cannot find a VPC with ID %s", vpcId); + logger.error(err); + throw new CloudRuntimeException(err); + } + + // For NSX, use VR Public IP != Source NAT + List ips = _ipAddressDao.listByAssociatedVpc(vpc.getId(), true); + if (CollectionUtils.isEmpty(ips)) { + String err = String.format("Cannot find a source NAT IP for the VPC %s", vpc.getName()); + logger.error(err); + throw new CloudRuntimeException(err); + } + + ips = ips.stream().filter(x -> !x.getAddress().addr().equals(nic.getIPv4Address())).collect(Collectors.toList()); + // Use Source NAT IP address from the Netris Public Range. Do not Use the VR Public IP address + ipAddress = ips.get(0); + if (ipAddress.isSourceNat() && !ipAddress.isForSystemVms()) { + VlanDetailsVO detail = vlanDetailsDao.findDetail(ipAddress.getVlanId(), ApiConstants.NETRIS_DETAIL_KEY); + if (detail != null && detail.getValue().equalsIgnoreCase("true")) { + long accountId = vpc.getAccountId(); + long domainId = vpc.getDomainId(); + long dataCenterId = vpc.getZoneId(); + long resourceId = vpc.getId(); + Network.Service[] services = { Network.Service.SourceNat }; + long networkOfferingId = vpc.getVpcOfferingId(); + VpcOfferingVO vpcVO = vpcOfferingDao.findById(networkOfferingId); + boolean sourceNatEnabled = !NetworkOffering.NetworkMode.ROUTED.equals(vpcVO.getNetworkMode()) && + vpcOfferingServiceMapDao.areServicesSupportedByVpcOffering(vpc.getVpcOfferingId(), services); + + logger.info(String.format("Creating Netris VPC %s", vpc.getName())); + boolean result = netrisService.createVpcResource(dataCenterId, accountId, domainId, resourceId, vpc.getName(), sourceNatEnabled, vpc.getCidr(), true); + if (!result) { + String msg = String.format("Error creating Netris VPC %s", vpc.getName()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + + boolean hasNatSupport = false; + VpcOffering vpcOffering = vpcOfferingDao.findById(vpc.getVpcOfferingId()); + hasNatSupport = NetworkOffering.NetworkMode.NATTED.equals(vpcOffering.getNetworkMode()); + + if (!hasNatSupport) { + return nic; + } + + String snatIP = ipAddress.getAddress().addr(); + result = netrisService.createSnatRule(dataCenterId, accountId, domainId, vpc.getName(), vpc.getId(), network.getName(), network.getId(), isForVpc, vpc.getCidr(), snatIP); + if (!result) { + String msg = String.format("Could not create Netris Nat Rule for IP %s", snatIP); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + + } + } + return nic; + } +} diff --git a/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java new file mode 100644 index 00000000000..6cd944c4678 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java @@ -0,0 +1,556 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.agent.AgentManager; +import com.cloud.agent.api.Answer; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.VlanDao; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.IpAddress; +import com.cloud.network.Ipv6GuestPrefixSubnetNetworkMapVO; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.SDNProviderNetworkRule; +import com.cloud.network.dao.Ipv6GuestPrefixSubnetNetworkMapDao; +import com.cloud.network.dao.NetrisProviderDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.rules.FirewallRule; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.dao.VpcDao; +import io.netris.model.NatPostBody; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisACLCommand; +import com.cloud.utils.Pair; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; +import inet.ipaddr.IPAddress; +import inet.ipaddr.IPAddressString; +import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisACLCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.ListNetrisStaticRoutesAnswer; +import org.apache.cloudstack.agent.api.ListNetrisStaticRoutesCommand; +import org.apache.cloudstack.agent.api.NetrisAnswer; +import org.apache.cloudstack.agent.api.NetrisCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; +import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.UpdateNetrisVpcCommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import com.cloud.network.netris.NetrisNetworkRule; +import org.apache.cloudstack.resource.NetrisResourceObjectUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Objects; +import java.util.stream.Collectors; + +public class NetrisServiceImpl implements NetrisService, Configurable { + + protected Logger logger = LogManager.getLogger(getClass()); + + @Inject + private NetrisProviderDao netrisProviderDao; + @Inject + private NetworkDao networkDao; + @Inject + private VpcDao vpcDao; + @Inject + private AgentManager agentMgr; + @Inject + private PhysicalNetworkDao physicalNetworkDao; + @Inject + private VlanDao vlanDao; + @Inject + private Ipv6GuestPrefixSubnetNetworkMapDao ipv6PrefixNetworkMapDao; + + @Override + public String getConfigComponentName() { + return NetrisService.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[0]; + } + + private NetrisProviderVO getZoneNetrisProvider(long zoneId) { + NetrisProviderVO netrisProviderVO = netrisProviderDao.findByZoneId(zoneId); + if (netrisProviderVO == null) { + logger.error("No Netris controller was found!"); + throw new InvalidParameterValueException("Failed to find a Netris controller"); + } + return netrisProviderVO; + } + + private NetrisAnswer sendNetrisCommand(NetrisCommand cmd, long zoneId) { + NetrisProviderVO netrisProviderVO = getZoneNetrisProvider(zoneId); + Answer answer = agentMgr.easySend(netrisProviderVO.getHostId(), cmd); + if (answer == null || !answer.getResult()) { + logger.error("Netris API Command failed"); + throw new InvalidParameterValueException("Failed API call to Netris controller"); + } + return (NetrisAnswer) answer; + } + + /** + * Calculate the minimum CIDR subnet containing the IP range (using the library: IPAddress) + * From: Example + * @param ipRange format: startIP-endIP + * @return the minimum CIDR containing the IP range + */ + protected String calculateSubnetCidrFromIpRange(String ipRange) { + if (StringUtils.isBlank(ipRange) || !ipRange.contains("-")) { + return null; + } + String[] rangeArray = ipRange.split("-"); + String startIp = rangeArray[0]; + String endIp = rangeArray[1]; + IPAddress startIpAddress = new IPAddressString(startIp).getAddress(); + IPAddress endIpAddress = new IPAddressString(endIp).getAddress(); + return startIpAddress.coverWithPrefixBlock(endIpAddress).toPrefixLengthString(); + } + + /** + * Prepare the Netris Public Range to be used by CloudStack after the zone is created and the Netris provider is added + */ + private Pair getAllocationAndSubnet(String gateway, String netmask, String ipRange) { + String superCidr = NetUtils.getCidrFromGatewayAndNetmask(gateway, netmask); + String subnetNatCidr = calculateSubnetCidrFromIpRange(ipRange); + return new Pair<>(superCidr, subnetNatCidr); + } + + @Override + public boolean createIPAMAllocationsForZoneLevelPublicRanges(long zoneId) { + List physicalNetworks = physicalNetworkDao.listByZoneAndTrafficType(zoneId, Networks.TrafficType.Public); + physicalNetworks = physicalNetworks.stream().filter(x -> x.getIsolationMethods().contains(Network.Provider.Netris.getName())).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(physicalNetworks)) { + return false; + } + + List providerVlanIds = vlanDao.listVlansForExternalNetworkProvider(zoneId, ApiConstants.NETRIS_DETAIL_KEY); + List vlanDbIds = providerVlanIds.stream().map(VlanVO::getId).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(vlanDbIds)) { + String msg = "Cannot find a public IP range VLAN range for the Netris Public traffic"; + logger.error(msg); + throw new CloudRuntimeException(msg); + } + for (Long vlanDbId : vlanDbIds) { + VlanVO vlanRecord = vlanDao.findById(vlanDbId); + + String gateway = Objects.nonNull(vlanRecord.getVlanGateway()) ? vlanRecord.getVlanGateway() : vlanRecord.getIp6Gateway(); + String netmask = vlanRecord.getVlanNetmask(); + String ipRange = vlanRecord.getIpRange(); + String ip6Cidr = vlanRecord.getIp6Cidr(); + SetupNetrisPublicRangeCommand cmd = null; + if (NetUtils.isValidIp4(gateway)) { + Pair allocationAndSubnet = getAllocationAndSubnet(gateway, netmask, ipRange); + cmd = new SetupNetrisPublicRangeCommand(zoneId, allocationAndSubnet.first(), allocationAndSubnet.second()); + } else if (NetUtils.isValidIp6(gateway)) { + cmd = new SetupNetrisPublicRangeCommand(zoneId, ip6Cidr, ip6Cidr); + } + + if (cmd == null) { + throw new CloudRuntimeException("Incorrect gateway and netmask details provided for the Netris Public IP range setup"); + } + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + if (!answer.getResult()) { + throw new CloudRuntimeException("Netris Public IP Range setup failed, please check the logs"); + } + } + + return true; + } + + @Override + public boolean createVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, boolean sourceNatEnabled, String cidr, boolean isVpc) { + CreateNetrisVpcCommand cmd = new CreateNetrisVpcCommand(zoneId, accountId, domainId, vpcName, cidr, vpcId, isVpc); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean updateVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, String previousVpcName) { + UpdateNetrisVpcCommand cmd = new UpdateNetrisVpcCommand(zoneId, accountId, domainId, vpcName, vpcId, true); + cmd.setPreviousVpcName(previousVpcName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean deleteVpcResource(long zoneId, long accountId, long domainId, Vpc vpc) { + DeleteNetrisVpcCommand cmd = new DeleteNetrisVpcCommand(zoneId, accountId, domainId, vpc.getName(), vpc.getCidr(), vpc.getId(), true); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean createVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr, Boolean globalRouting) { + NetworkVO network = networkDao.findById(networkId); + String vxlanId = Networks.BroadcastDomainType.getValue(network.getBroadcastUri()); + CreateNetrisVnetCommand cmd = new CreateNetrisVnetCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, cidr, network.getGateway(), !Objects.isNull(vpcId)); + cmd.setVxlanId(Integer.parseInt(vxlanId)); + NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(zoneId); + cmd.setNetrisTag(netrisProvider.getNetrisTag()); + cmd.setGlobalRouting(globalRouting); + if (Objects.nonNull(networkId)) { + Ipv6GuestPrefixSubnetNetworkMapVO ipv6PrefixNetworkMapVO = ipv6PrefixNetworkMapDao.findByNetworkId(networkId); + if (Objects.nonNull(ipv6PrefixNetworkMapVO)) { + cmd.setIpv6Cidr(ipv6PrefixNetworkMapVO.getSubnet()); + } + } + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean updateVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String prevNetworkName) { + UpdateNetrisVnetCommand cmd = new UpdateNetrisVnetCommand(zoneId, accountId, domainId, networkName, networkId, Objects.nonNull(vpcId)); + cmd.setPrevNetworkName(prevNetworkName); + cmd.setVpcId(vpcId); + cmd.setVpcName(vpcName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean deleteVnetResource(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr) { + DeleteNetrisVnetCommand cmd = new DeleteNetrisVnetCommand(zoneId, accountId, domainId, networkName, networkId, vpcName, vpcId, cidr, Objects.nonNull(vpcName)); + Ipv6GuestPrefixSubnetNetworkMapVO ipv6PrefixNetworkMapVO = ipv6PrefixNetworkMapDao.findByNetworkId(networkId); + if (Objects.nonNull(ipv6PrefixNetworkMapVO)) { + cmd.setvNetV6Cidr(ipv6PrefixNetworkMapVO.getSubnet()); + } + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean createSnatRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, long networkId, boolean isForVpc, String vpcCidr, String snatIP) { + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc, vpcCidr); + cmd.setNatIp(snatIP); + cmd.setNatRuleType("SNAT"); + String suffix; + if (isForVpc) { + suffix = String.valueOf(vpcId); // D1-A1-Z1-V25-SNAT + } else { + suffix = String.valueOf(networkId); // D1-A1-Z1-N25-SNAT + } + cmd.setProtocol(NatPostBody.ProtocolEnum.ALL.getValue()); + cmd.setState(NatPostBody.StateEnum.ENABLED.getValue()); + String snatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.SNAT, suffix); + cmd.setNatRuleName(snatRuleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean createPortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, + Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule) { + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, + networkName, networkId, isForVpc, vpcCidr); + cmd.setProtocol(networkRule.getProtocol().toLowerCase(Locale.ROOT)); + cmd.setDestinationAddress(networkRule.getPublicIp()); + cmd.setDestinationPort(networkRule.getPublicPort()); + cmd.setSourceAddress(networkRule.getVmIp()); + cmd.setSourcePort(networkRule.getPrivatePort()); + cmd.setState(NatPostBody.StateEnum.ENABLED.getValue()); + String ruleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.DNAT, + String.valueOf(vpcId), String.format("R%s", networkRule.getRuleId())); + cmd.setNatRuleName(ruleName); + cmd.setNatRuleType("DNAT"); + + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean deletePortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule) { + DeleteNetrisNatRuleCommand cmd = new DeleteNetrisNatRuleCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc); + String ruleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.DNAT, + String.valueOf(vpcId), String.format("R%s", networkRule.getRuleId())); + cmd.setNatRuleType("DNAT"); + cmd.setNatRuleName(ruleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address) { + if (vpc == null || address == null) { + return false; + } + long accountId = vpc.getAccountId(); + long domainId = vpc.getDomainId(); + long zoneId = vpc.getZoneId(); + long vpcId = vpc.getId(); + String vpcName = vpc.getName(); + + logger.debug("Updating the source NAT IP for Netris VPC {} to IP: {}", vpc.getName(), address.getAddress().addr()); + + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, null, null, true, vpc.getCidr()); + cmd.setNatIp(address.getAddress().addr()); + cmd.setNatRuleType("SNAT"); + String snatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.SNAT, String.valueOf(vpcId)); + cmd.setNatRuleName(snatRuleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + if (!answer.getResult()) { + logger.error("Could not update the source NAT IP address for VPC {}: {}", vpc.getName(), answer.getDetails()); + return false; + } + return answer.getResult(); + } + + @Override + public boolean createStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String vpcCidr, String staticNatIp, String vmIp, long vmId) { + String vpcName = null; + String networkName = null; + Long vpcId = null; + Long networkId = null; + if (isForVpc) { + vpcName = networkResourceName; + vpcId = networkResourceId; + } else { + networkName = networkResourceName; + networkId = networkResourceId; + } + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc, vpcCidr); + cmd.setNatRuleType("STATICNAT"); + cmd.setNatIp(staticNatIp); + cmd.setVmIp(vmIp); + String[] suffixes = getStaticNatResourceSuffixes(vpcId, networkId, isForVpc, vmId); + String dnatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.STATICNAT, suffixes); + cmd.setNatRuleName(dnatRuleName); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean deleteStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String staticNatIp, long vmId) { + String vpcName = null; + String networkName = null; + Long vpcId = null; + Long networkId = null; + if (isForVpc) { + vpcName = networkResourceName; + vpcId = networkResourceId; + } else { + networkName = networkResourceName; + networkId = networkResourceId; + } + DeleteNetrisNatRuleCommand cmd = new DeleteNetrisNatRuleCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, isForVpc); + String suffixes[] = getStaticNatResourceSuffixes(vpcId, networkId, isForVpc, vmId); + String dnatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.STATICNAT, suffixes); + cmd.setNatRuleName(dnatRuleName); + cmd.setNatRuleType("STATICNAT"); + cmd.setNatIp(staticNatIp); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean addFirewallRules(Network network, List firewallRules) { + Long zoneId = network.getDataCenterId(); + Long accountId = network.getAccountId(); + Long domainId = network.getDomainId(); + Long vpcId = network.getVpcId(); + Long networkId = network.getId(); + String vpcName = null; + Vpc vpc = null; + if (Objects.nonNull(vpcId)) { + vpc = vpcDao.findById(vpcId); + if (Objects.nonNull(vpc)) { + vpcName = vpc.getName(); + } + } + String networkName = network.getName(); + NetrisNetworkRule rule = firewallRules.get(0); + SDNProviderNetworkRule baseNetworkRule = rule.getBaseRule(); + String trafficType = baseNetworkRule.getTrafficType(); + String sourcePrefix; + String destinationPrefix; + boolean result = true; + List sourceCidrs = baseNetworkRule.getSourceCidrList(); + int index = 1; + for (String sourceCidr : sourceCidrs) { + if (FirewallRule.TrafficType.Ingress.name().equalsIgnoreCase(trafficType)) { + sourcePrefix = sourceCidr; + destinationPrefix = NetUtils.isValidIp4Cidr(sourcePrefix) || + NetUtils.ANY_PROTO.equalsIgnoreCase(sourceCidr) ? + network.getCidr() : network.getIp6Cidr(); + } else { + destinationPrefix = sourceCidr; + sourcePrefix = NetUtils.isValidIp4Cidr(destinationPrefix) || + NetUtils.ANY_PROTO.equalsIgnoreCase(sourceCidr) ? + network.getCidr() : network.getIp6Cidr(); + } + String srcPort; + String dstPort; + if (baseNetworkRule.getPrivatePort().contains("-")) { + srcPort = baseNetworkRule.getPrivatePort().split("-")[0]; + dstPort = baseNetworkRule.getPrivatePort().split("-")[1]; + } else { + srcPort = dstPort = baseNetworkRule.getPrivatePort(); + } + CreateOrUpdateNetrisACLCommand cmd = new CreateOrUpdateNetrisACLCommand(zoneId, accountId, domainId, networkName, networkId, + vpcName, vpcId, Objects.nonNull(vpcId), rule.getAclAction().name().toLowerCase(Locale.ROOT), getPrefix(sourcePrefix), getPrefix(destinationPrefix), + "null".equals(srcPort) ? 1 : Integer.parseInt(srcPort), + "null".equals(dstPort) ? 65535 : Integer.parseInt(dstPort), baseNetworkRule.getProtocol()); + String aclName = String.format("V%s-N%s-ACL%s", vpcId, networkId, rule.getBaseRule().getRuleId()); + if (sourceCidrs.size() > 1) { + aclName = aclName + "-" + index++; + } + String netrisAclName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.ACL, aclName); + cmd.setNetrisAclName(netrisAclName); + cmd.setReason(rule.getReason()); + if (NetUtils.ICMP_PROTO.equals(baseNetworkRule.getProtocol().toLowerCase(Locale.ROOT))) { + cmd.setIcmpType(baseNetworkRule.getIcmpType()); + } + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + result = result && answer.getResult(); + } + return result; + } + + public static String getPrefix(String prefix) { + if ("ANY".equals(prefix)) { + return NetUtils.ALL_IP4_CIDRS; + } + return prefix; + } + + @Override + public boolean deleteFirewallRules(Network network, List firewallRules) { + long zoneId = network.getDataCenterId(); + Long accountId = network.getAccountId(); + Long domainId = network.getDomainId(); + String networkName = network.getName(); + Long networkId = network.getId(); + String vpcName = null; + Long vpcId = network.getVpcId(); + if (Objects.nonNull(vpcId)) { + vpcName = vpcDao.findById(vpcId).getName(); + } + DeleteNetrisACLCommand cmd = new DeleteNetrisACLCommand(zoneId, accountId, domainId, networkName, networkId, Objects.nonNull(network.getVpcId()), vpcId, vpcName); + List aclRuleNames = new ArrayList<>(); + for (NetrisNetworkRule rule : firewallRules) { + List sourceCidrs = rule.getBaseRule().getSourceCidrList(); + int cidrCount = sourceCidrs.size(); + if (cidrCount > 1) { + for (int i = 0; i < cidrCount; i++) { + String aclName = String.format("V%s-N%s-ACL%s-%d", vpcId, networkId, rule.getBaseRule().getRuleId(), (i + 1)); + aclRuleNames.add(NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.ACL, aclName)); + } + } else { + String aclName = String.format("V%s-N%s-ACL%s", vpcId, networkId, rule.getBaseRule().getRuleId()); + aclRuleNames.add(NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.ACL, aclName)); + } + } + cmd.setAclRuleNames(aclRuleNames); + + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + public boolean addOrUpdateStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId, boolean updateRoute) { + AddOrUpdateNetrisStaticRouteCommand cmd = new AddOrUpdateNetrisStaticRouteCommand(zoneId, accountId, domainId, networkResourceName, networkResourceId, isForVpc, prefix, nextHop, routeId, updateRoute); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean deleteStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId) { + DeleteNetrisStaticRouteCommand cmd = new DeleteNetrisStaticRouteCommand(zoneId, accountId, domainId, networkResourceName, networkResourceId, isForVpc, prefix, nextHop, routeId); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public List listStaticRoutes(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId) { + ListNetrisStaticRoutesCommand cmd = new ListNetrisStaticRoutesCommand(zoneId, accountId, domainId, networkResourceName, networkResourceId, isForVpc, prefix, nextHop, routeId); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + if (answer instanceof ListNetrisStaticRoutesAnswer) { + return ((ListNetrisStaticRoutesAnswer) answer).getStaticRoutes(); + } + return List.of(); + } + + @Override + public boolean releaseNatIp(long zoneId, String publicIp) { + ReleaseNatIpCommand cmd = new ReleaseNatIpCommand(zoneId, null, null, null, null, false, publicIp); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } + + @Override + public boolean createOrUpdateLbRule(NetrisNetworkRule rule) { + SDNProviderNetworkRule baseRule = rule.getBaseRule(); + CreateOrUpdateNetrisLoadBalancerRuleCommand cmd = new CreateOrUpdateNetrisLoadBalancerRuleCommand(baseRule.getZoneId(), baseRule.getAccountId(), + baseRule.getDomainId(), baseRule.getNetworkResourceName(), baseRule.getNetworkResourceId(), baseRule.isVpcResource(), + rule.getLbBackends(), baseRule.getRuleId(), baseRule.getPublicIp(), baseRule.getPublicPort(), + baseRule.getPrivatePort(), baseRule.getAlgorithm(), baseRule.getProtocol()); + if (Objects.nonNull(rule.getLbCidrList())) { + cmd.setCidrList(rule.getLbCidrList()); + } + cmd.setRuleName(rule.getLbRuleName()); + NetrisAnswer answer = sendNetrisCommand(cmd, baseRule.getZoneId()); + return answer.getResult(); + } + + @Override + public boolean deleteLbRule(NetrisNetworkRule rule) { + SDNProviderNetworkRule baseRule = rule.getBaseRule(); + DeleteNetrisLoadBalancerRuleCommand cmd = new DeleteNetrisLoadBalancerRuleCommand(baseRule.getZoneId(), baseRule.getAccountId(), + baseRule.getDomainId(), baseRule.getNetworkResourceName(), baseRule.getNetworkResourceId(), baseRule.isVpcResource(), + baseRule.getRuleId()); + if (Objects.nonNull(rule.getLbCidrList())) { + cmd.setCidrList(rule.getLbCidrList()); + } + cmd.setRuleName(rule.getLbRuleName()); + NetrisAnswer answer = sendNetrisCommand(cmd, baseRule.getZoneId()); + return answer.getResult(); + } + + public static String[] getStaticNatResourceSuffixes(Long vpcId, Long networkId, boolean isForVpc, long vmId) { + String[] suffixes = new String[2]; + suffixes[0] = isForVpc ? String.valueOf(vpcId) : String.valueOf(networkId); + suffixes[1] = String.valueOf(vmId); + return suffixes; + } +} diff --git a/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/core/spring-netris-core-managers-context.xml b/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/core/spring-netris-core-managers-context.xml new file mode 100644 index 00000000000..397460dc7f8 --- /dev/null +++ b/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/core/spring-netris-core-managers-context.xml @@ -0,0 +1,31 @@ + + + + + + diff --git a/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/module.properties b/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/module.properties new file mode 100644 index 00000000000..0670b1629f4 --- /dev/null +++ b/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/module.properties @@ -0,0 +1,21 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +name=netris +parent=network diff --git a/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/spring-netris-context.xml b/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/spring-netris-context.xml new file mode 100644 index 00000000000..a0551b7804a --- /dev/null +++ b/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/spring-netris-context.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommandTest.java new file mode 100644 index 00000000000..bd9c7433f66 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/AddOrUpdateNetrisStaticRouteCommandTest.java @@ -0,0 +1,91 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Assert; +import org.junit.Test; + +public class AddOrUpdateNetrisStaticRouteCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-vpc"; + private static final Long ID = 4L; + private static final boolean IS_VPC = true; + private static final String PREFIX = "10.0.0.0/24"; + private static final String NEXT_HOP = "10.0.0.1"; + private static final Long ROUTE_ID = 5L; + private static final boolean UPDATE_ROUTE = true; + + @Test + public void testConstructorAndGetters() { + // Act + AddOrUpdateNetrisStaticRouteCommand command = new AddOrUpdateNetrisStaticRouteCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, PREFIX, NEXT_HOP, ROUTE_ID, UPDATE_ROUTE); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(PREFIX, command.getPrefix()); + Assert.assertEquals(NEXT_HOP, command.getNextHop()); + Assert.assertEquals(ROUTE_ID, command.getRouteId()); + Assert.assertEquals(UPDATE_ROUTE, command.isUpdateRoute()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + AddOrUpdateNetrisStaticRouteCommand command = new AddOrUpdateNetrisStaticRouteCommand( + ZONE_ID, null, null, NAME, null, IS_VPC, PREFIX, NEXT_HOP, null, UPDATE_ROUTE); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertNull(command.getAccountId()); + Assert.assertNull(command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertNull(command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(PREFIX, command.getPrefix()); + Assert.assertEquals(NEXT_HOP, command.getNextHop()); + Assert.assertNull(command.getRouteId()); + Assert.assertEquals(UPDATE_ROUTE, command.isUpdateRoute()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + AddOrUpdateNetrisStaticRouteCommand command = new AddOrUpdateNetrisStaticRouteCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, IS_VPC, "", "", ROUTE_ID, UPDATE_ROUTE); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals("", command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals("", command.getPrefix()); + Assert.assertEquals("", command.getNextHop()); + Assert.assertEquals(ROUTE_ID, command.getRouteId()); + Assert.assertEquals(UPDATE_ROUTE, command.isUpdateRoute()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommandTest.java new file mode 100644 index 00000000000..aed9a921c36 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisACLCommandTest.java @@ -0,0 +1,144 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.apache.cloudstack.resource.NetrisPortGroup; +import org.junit.Assert; +import org.junit.Test; + +public class CreateNetrisACLCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-network"; + private static final Long ID = 4L; + private static final String VPC_NAME = "test-vpc"; + private static final Long VPC_ID = 5L; + private static final boolean IS_VPC = true; + private static final String ACTION = "allow"; + private static final String SOURCE_PREFIX = "10.0.0.0/24"; + private static final String DEST_PREFIX = "10.0.1.0/24"; + private static final Integer DEST_PORT_START = 80; + private static final Integer DEST_PORT_END = 80; + private static final String PROTOCOL = "tcp"; + private static final Integer ICMP_TYPE = 8; + private static final String NETRIS_ACL_NAME = "test-acl"; + private static final String REASON = "test reason"; + private static final String PORTS = "80,443"; + + @Test + public void testConstructorAndGetters() { + // Act + CreateNetrisACLCommand command = new CreateNetrisACLCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, VPC_NAME, VPC_ID, IS_VPC, ACTION, + SOURCE_PREFIX, DEST_PREFIX, DEST_PORT_START, DEST_PORT_END, PROTOCOL); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(VPC_NAME, command.getVpcName()); + Assert.assertEquals(VPC_ID, command.getVpcId()); + Assert.assertEquals(ACTION, command.getAction()); + Assert.assertEquals(SOURCE_PREFIX, command.getSourcePrefix()); + Assert.assertEquals(DEST_PREFIX, command.getDestPrefix()); + Assert.assertEquals(DEST_PORT_START, command.getDestPortStart()); + Assert.assertEquals(DEST_PORT_END, command.getDestPortEnd()); + Assert.assertEquals(PROTOCOL, command.getProtocol()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + CreateNetrisACLCommand command = new CreateNetrisACLCommand( + ZONE_ID, null, null, NAME, null, VPC_NAME, null, IS_VPC, ACTION, + SOURCE_PREFIX, DEST_PREFIX, null, null, PROTOCOL); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertNull(command.getAccountId()); + Assert.assertNull(command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertNull(command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(VPC_NAME, command.getVpcName()); + Assert.assertNull(command.getVpcId()); + Assert.assertEquals(ACTION, command.getAction()); + Assert.assertEquals(SOURCE_PREFIX, command.getSourcePrefix()); + Assert.assertEquals(DEST_PREFIX, command.getDestPrefix()); + Assert.assertNull(command.getDestPortStart()); + Assert.assertNull(command.getDestPortEnd()); + Assert.assertEquals(PROTOCOL, command.getProtocol()); + } + + @Test + public void testSetters() { + // Arrange + CreateNetrisACLCommand command = new CreateNetrisACLCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, VPC_NAME, VPC_ID, IS_VPC, ACTION, + SOURCE_PREFIX, DEST_PREFIX, DEST_PORT_START, DEST_PORT_END, PROTOCOL); + + NetrisPortGroup portGroup = new NetrisPortGroup(PORTS); + String newVpcName = "new-vpc"; + Long newVpcId = 6L; + + // Act + command.setVpcName(newVpcName); + command.setVpcId(newVpcId); + command.setPortGroup(portGroup); + command.setIcmpType(ICMP_TYPE); + command.setNetrisAclName(NETRIS_ACL_NAME); + command.setReason(REASON); + + // Assert + Assert.assertEquals(newVpcName, command.getVpcName()); + Assert.assertEquals(newVpcId, command.getVpcId()); + Assert.assertEquals(portGroup, command.getPortGroup()); + Assert.assertEquals(ICMP_TYPE, command.getIcmpType()); + Assert.assertEquals(NETRIS_ACL_NAME, command.getNetrisAclName()); + Assert.assertEquals(REASON, command.getReason()); + Assert.assertEquals(PORTS, command.getPortGroup().getPorts()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + CreateNetrisACLCommand command = new CreateNetrisACLCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, "", VPC_ID, IS_VPC, "", + "", "", DEST_PORT_START, DEST_PORT_END, ""); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals("", command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals("", command.getVpcName()); + Assert.assertEquals(VPC_ID, command.getVpcId()); + Assert.assertEquals("", command.getAction()); + Assert.assertEquals("", command.getSourcePrefix()); + Assert.assertEquals("", command.getDestPrefix()); + Assert.assertEquals(DEST_PORT_START, command.getDestPortStart()); + Assert.assertEquals(DEST_PORT_END, command.getDestPortEnd()); + Assert.assertEquals("", command.getProtocol()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommandTest.java new file mode 100644 index 00000000000..cc367d181e3 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommandTest.java @@ -0,0 +1,95 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Assert; +import org.junit.Test; + +public class CreateNetrisVnetCommandTest { + + private static final Long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String VPC_NAME = "test-vpc"; + private static final Long VPC_ID = 4L; + private static final String VNET_NAME = "test-vnet"; + private static final Long NETWORK_ID = 5L; + private static final String CIDR = "10.0.0.0/24"; + private static final String GATEWAY = "10.0.0.1"; + private static final boolean IS_VPC = true; + private static final Integer VXLAN_ID = 100; + private static final String NETRIS_TAG = "test-tag"; + private static final String IPV6_CIDR = "2001:db8::/64"; + private static final Boolean GLOBAL_ROUTING = true; + + @Test + public void testConstructorAndGetters() { + // Act + CreateNetrisVnetCommand command = new CreateNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, VPC_NAME, VPC_ID, VNET_NAME, NETWORK_ID, CIDR, GATEWAY, IS_VPC); + + // Assert + Assert.assertEquals(ZONE_ID.longValue(), command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals(VNET_NAME, command.getName()); + Assert.assertEquals(NETWORK_ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(VPC_NAME, command.getVpcName()); + Assert.assertEquals(VPC_ID, command.getVpcId()); + Assert.assertEquals(CIDR, command.getCidr()); + Assert.assertEquals(GATEWAY, command.getGateway()); + } + + @Test + public void testSetters() { + // Arrange + CreateNetrisVnetCommand command = new CreateNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, VPC_NAME, VPC_ID, VNET_NAME, NETWORK_ID, CIDR, GATEWAY, IS_VPC); + + // Act + command.setVxlanId(VXLAN_ID); + command.setNetrisTag(NETRIS_TAG); + command.setIpv6Cidr(IPV6_CIDR); + command.setGlobalRouting(GLOBAL_ROUTING); + + // Assert + Assert.assertEquals(VXLAN_ID, command.getVxlanId()); + Assert.assertEquals(NETRIS_TAG, command.getNetrisTag()); + Assert.assertEquals(IPV6_CIDR, command.getIpv6Cidr()); + Assert.assertEquals(GLOBAL_ROUTING, command.isGlobalRouting()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + CreateNetrisVnetCommand command = new CreateNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", VPC_ID, "", NETWORK_ID, "", "", IS_VPC); + + // Assert + Assert.assertEquals(ZONE_ID.longValue(), command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals("", command.getName()); + Assert.assertEquals(NETWORK_ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals("", command.getVpcName()); + Assert.assertEquals(VPC_ID, command.getVpcId()); + Assert.assertEquals("", command.getCidr()); + Assert.assertEquals("", command.getGateway()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommandTest.java new file mode 100644 index 00000000000..666ff8d2ee8 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateNetrisVpcCommandTest.java @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Assert; +import org.junit.Test; + +public class CreateNetrisVpcCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-vpc"; + private static final String CIDR = "10.0.0.0/24"; + private static final Long VPC_ID = 4L; + private static final boolean IS_VPC = true; + + @Test + public void testConstructorAndGetters() { + // Act + CreateNetrisVpcCommand command = new CreateNetrisVpcCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, CIDR, VPC_ID, IS_VPC); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertEquals(VPC_ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(CIDR, command.getCidr()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + CreateNetrisVpcCommand command = new CreateNetrisVpcCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", "", VPC_ID, IS_VPC); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals("", command.getName()); + Assert.assertEquals(VPC_ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals("", command.getCidr()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommandTest.java new file mode 100644 index 00000000000..d8b2b8e7ae2 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisLoadBalancerRuleCommandTest.java @@ -0,0 +1,139 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import com.cloud.network.netris.NetrisLbBackend; +import org.junit.Assert; +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +public class CreateOrUpdateNetrisLoadBalancerRuleCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-lb"; + private static final Long ID = 4L; + private static final boolean IS_VPC = true; + private static final Long LB_ID = 5L; + private static final String PUBLIC_IP = "10.0.0.1"; + private static final String PUBLIC_PORT = "80"; + private static final String PRIVATE_PORT = "8080"; + private static final String ALGORITHM = "roundrobin"; + private static final String PROTOCOL = "tcp"; + private static final String CIDR_LIST = "0.0.0.0/0"; + private static final String RULE_NAME = "test-rule"; + private static final Long INSTANCE_ID = 6L; + private static final String BACKEND_IP = "10.0.0.2"; + private static final Integer BACKEND_PORT = 8080; + + @Test + public void testConstructorAndGetters() { + // Arrange + List lbBackends = Arrays.asList( + new NetrisLbBackend(INSTANCE_ID, BACKEND_IP, BACKEND_PORT) + ); + + // Act + CreateOrUpdateNetrisLoadBalancerRuleCommand command = new CreateOrUpdateNetrisLoadBalancerRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, + lbBackends, LB_ID, PUBLIC_IP, PUBLIC_PORT, + PRIVATE_PORT, ALGORITHM, PROTOCOL); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(LB_ID, command.getLbId()); + Assert.assertEquals(PUBLIC_IP, command.getPublicIp()); + Assert.assertEquals(PUBLIC_PORT, command.getPublicPort()); + Assert.assertEquals(PRIVATE_PORT, command.getPrivatePort()); + Assert.assertEquals(ALGORITHM, command.getAlgorithm()); + Assert.assertEquals(PROTOCOL, command.getProtocol()); + Assert.assertEquals(lbBackends, command.getLbBackends()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + CreateOrUpdateNetrisLoadBalancerRuleCommand command = new CreateOrUpdateNetrisLoadBalancerRuleCommand( + ZONE_ID, null, null, NAME, null, IS_VPC, + null, LB_ID, PUBLIC_IP, PUBLIC_PORT, + PRIVATE_PORT, ALGORITHM, PROTOCOL); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertNull(command.getAccountId()); + Assert.assertNull(command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertNull(command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(LB_ID, command.getLbId()); + Assert.assertEquals(PUBLIC_IP, command.getPublicIp()); + Assert.assertEquals(PUBLIC_PORT, command.getPublicPort()); + Assert.assertEquals(PRIVATE_PORT, command.getPrivatePort()); + Assert.assertEquals(ALGORITHM, command.getAlgorithm()); + Assert.assertEquals(PROTOCOL, command.getProtocol()); + Assert.assertNull(command.getLbBackends()); + } + + @Test + public void testSetters() { + // Arrange + CreateOrUpdateNetrisLoadBalancerRuleCommand command = new CreateOrUpdateNetrisLoadBalancerRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, + null, LB_ID, PUBLIC_IP, PUBLIC_PORT, + PRIVATE_PORT, ALGORITHM, PROTOCOL); + + // Act + command.setCidrList(CIDR_LIST); + command.setRuleName(RULE_NAME); + + // Assert + Assert.assertEquals(CIDR_LIST, command.getCidrList()); + Assert.assertEquals(RULE_NAME, command.getRuleName()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + CreateOrUpdateNetrisLoadBalancerRuleCommand command = new CreateOrUpdateNetrisLoadBalancerRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, IS_VPC, + null, LB_ID, "", "", + "", "", ""); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals("", command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(LB_ID, command.getLbId()); + Assert.assertEquals("", command.getPublicIp()); + Assert.assertEquals("", command.getPublicPort()); + Assert.assertEquals("", command.getPrivatePort()); + Assert.assertEquals("", command.getAlgorithm()); + Assert.assertEquals("", command.getProtocol()); + Assert.assertNull(command.getLbBackends()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommandTest.java new file mode 100644 index 00000000000..ddc943810c4 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/CreateOrUpdateNetrisNatCommandTest.java @@ -0,0 +1,145 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class CreateOrUpdateNetrisNatCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String VPC_NAME = "test-vpc"; + private static final Long VPC_ID = 4L; + private static final String VNET_NAME = "test-vnet"; + private static final Long NETWORK_ID = 5L; + private static final boolean IS_VPC = true; + private static final String VPC_CIDR = "10.0.0.0/24"; + private static final String NAT_RULE_NAME = "test-nat-rule"; + private static final String NAT_IP = "10.0.0.1"; + private static final String NAT_RULE_TYPE = "DNAT"; + private static final String PROTOCOL = "TCP"; + private static final String SOURCE_ADDRESS = "192.168.1.0/24"; + private static final String SOURCE_PORT = "80"; + private static final String DESTINATION_ADDRESS = "10.0.0.10"; + private static final String DESTINATION_PORT = "8080"; + private static final String STATE = "enabled"; + private static final String VM_IP = "10.0.0.100"; + + @Test + public void testConstructorAndGetters() { + // Act + CreateOrUpdateNetrisNatCommand command = new CreateOrUpdateNetrisNatCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, VPC_NAME, VPC_ID, VNET_NAME, NETWORK_ID, IS_VPC, VPC_CIDR); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals(VPC_NAME, command.getVpcName()); + assertEquals(VPC_ID, command.getVpcId()); + assertEquals(VNET_NAME, command.getName()); + assertEquals(NETWORK_ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals(VPC_CIDR, command.getVpcCidr()); + assertNull(command.getNatRuleName()); + assertNull(command.getNatIp()); + assertNull(command.getNatRuleType()); + assertNull(command.getProtocol()); + assertNull(command.getSourceAddress()); + assertNull(command.getSourcePort()); + assertNull(command.getDestinationAddress()); + assertNull(command.getDestinationPort()); + assertNull(command.getState()); + assertNull(command.getVmIp()); + } + + @Test + public void testSettersAndGetters() { + // Arrange + CreateOrUpdateNetrisNatCommand command = new CreateOrUpdateNetrisNatCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, VPC_NAME, VPC_ID, VNET_NAME, NETWORK_ID, IS_VPC, VPC_CIDR); + + // Act + command.setNatRuleName(NAT_RULE_NAME); + command.setNatIp(NAT_IP); + command.setNatRuleType(NAT_RULE_TYPE); + command.setProtocol(PROTOCOL); + command.setSourceAddress(SOURCE_ADDRESS); + command.setSourcePort(SOURCE_PORT); + command.setDestinationAddress(DESTINATION_ADDRESS); + command.setDestinationPort(DESTINATION_PORT); + command.setState(STATE); + command.setVmIp(VM_IP); + command.setVpcName(VPC_NAME); + command.setVpcId(VPC_ID); + command.setVpcCidr(VPC_CIDR); + + // Assert + assertEquals(NAT_RULE_NAME, command.getNatRuleName()); + assertEquals(NAT_IP, command.getNatIp()); + assertEquals(NAT_RULE_TYPE, command.getNatRuleType()); + assertEquals(PROTOCOL, command.getProtocol()); + assertEquals(SOURCE_ADDRESS, command.getSourceAddress()); + assertEquals(SOURCE_PORT, command.getSourcePort()); + assertEquals(DESTINATION_ADDRESS, command.getDestinationAddress()); + assertEquals(DESTINATION_PORT, command.getDestinationPort()); + assertEquals(STATE, command.getState()); + assertEquals(VM_IP, command.getVmIp()); + assertEquals(VPC_NAME, command.getVpcName()); + assertEquals(VPC_ID, command.getVpcId()); + assertEquals(VPC_CIDR, command.getVpcCidr()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + CreateOrUpdateNetrisNatCommand command = new CreateOrUpdateNetrisNatCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", VPC_ID, "", NETWORK_ID, IS_VPC, ""); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals("", command.getVpcName()); + assertEquals(VPC_ID, command.getVpcId()); + assertEquals("", command.getName()); + assertEquals(NETWORK_ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals("", command.getVpcCidr()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + CreateOrUpdateNetrisNatCommand command = new CreateOrUpdateNetrisNatCommand( + ZONE_ID, null, null, VPC_NAME, null, VNET_NAME, null, IS_VPC, VPC_CIDR); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertNull(command.getAccountId()); + assertNull(command.getDomainId()); + assertEquals(VPC_NAME, command.getVpcName()); + assertNull(command.getVpcId()); + assertEquals(VNET_NAME, command.getName()); + assertNull(command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals(VPC_CIDR, command.getVpcCidr()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommandTest.java new file mode 100644 index 00000000000..6cc34efefb2 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisACLCommandTest.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import java.util.Arrays; +import java.util.List; + +public class DeleteNetrisACLCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-network"; + private static final Long ID = 4L; + private static final boolean IS_VPC = true; + private static final Long VPC_ID = 5L; + private static final String VPC_NAME = "test-vpc"; + private static final List ACL_RULE_NAMES = Arrays.asList("rule1", "rule2"); + + @Test + public void testConstructorAndGetters() { + // Act + DeleteNetrisACLCommand command = new DeleteNetrisACLCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, VPC_ID, VPC_NAME); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals(NAME, command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals(VPC_ID, command.getVpcId()); + assertEquals(VPC_NAME, command.getVpcName()); + assertNull(command.getAclRuleNames()); + } + + @Test + public void testSettersAndGetters() { + // Arrange + DeleteNetrisACLCommand command = new DeleteNetrisACLCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, VPC_ID, VPC_NAME); + + // Act + command.setAclRuleNames(ACL_RULE_NAMES); + + // Assert + assertEquals(ACL_RULE_NAMES, command.getAclRuleNames()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + DeleteNetrisACLCommand command = new DeleteNetrisACLCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, IS_VPC, VPC_ID, ""); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals("", command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals(VPC_ID, command.getVpcId()); + assertEquals("", command.getVpcName()); + assertNull(command.getAclRuleNames()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + DeleteNetrisACLCommand command = new DeleteNetrisACLCommand( + ZONE_ID, null, null, NAME, null, IS_VPC, null, VPC_NAME); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertNull(command.getAccountId()); + assertNull(command.getDomainId()); + assertEquals(NAME, command.getName()); + assertNull(command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getVpcId()); + assertEquals(VPC_NAME, command.getVpcName()); + assertNull(command.getAclRuleNames()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommandTest.java new file mode 100644 index 00000000000..b38d9674ec3 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisLoadBalancerRuleCommandTest.java @@ -0,0 +1,98 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Assert; +import org.junit.Test; + +public class DeleteNetrisLoadBalancerRuleCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-lb"; + private static final Long ID = 4L; + private static final boolean IS_VPC = true; + private static final Long LB_ID = 5L; + private static final String RULE_NAME = "test-rule"; + private static final String CIDR_LIST = "0.0.0.0/0"; + + @Test + public void testConstructorAndGetters() { + // Act + DeleteNetrisLoadBalancerRuleCommand command = new DeleteNetrisLoadBalancerRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, LB_ID); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(LB_ID, command.getLbId()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + DeleteNetrisLoadBalancerRuleCommand command = new DeleteNetrisLoadBalancerRuleCommand( + ZONE_ID, null, null, NAME, null, IS_VPC, LB_ID); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertNull(command.getAccountId()); + Assert.assertNull(command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertNull(command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(LB_ID, command.getLbId()); + } + + @Test + public void testSetters() { + // Arrange + DeleteNetrisLoadBalancerRuleCommand command = new DeleteNetrisLoadBalancerRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, LB_ID); + + // Act + command.setRuleName(RULE_NAME); + command.setCidrList(CIDR_LIST); + command.setLbId(LB_ID); + + // Assert + Assert.assertEquals(RULE_NAME, command.getRuleName()); + Assert.assertEquals(CIDR_LIST, command.getCidrList()); + Assert.assertEquals(LB_ID, command.getLbId()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + DeleteNetrisLoadBalancerRuleCommand command = new DeleteNetrisLoadBalancerRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, IS_VPC, LB_ID); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals("", command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(IS_VPC, command.isVpc()); + Assert.assertEquals(LB_ID, command.getLbId()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommandTest.java new file mode 100644 index 00000000000..eb02a5a53a7 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisNatRuleCommandTest.java @@ -0,0 +1,94 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Test; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertEquals; + +public class DeleteNetrisNatRuleCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String VNET_NAME = "test-vnet"; + private static final Long NETWORK_ID = 4L; + private static final String VPC_NAME = "test-vpc"; + private static final Long VPC_ID = 5L; + private static final boolean IS_VPC = true; + private static final String NAT_RULE_TYPE = "DNAT"; + private static final String NAT_RULE_NAME = "test-nat-rule"; + private static final String NAT_IP = "10.0.0.1"; + + @Test + public void testConstructorAndGetters() { + // Act + DeleteNetrisNatRuleCommand command = new DeleteNetrisNatRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, VPC_NAME, VPC_ID, VNET_NAME, NETWORK_ID, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals(VPC_NAME, command.getVpcName()); + assertEquals(VPC_ID, command.getVpcId()); + assertEquals(VNET_NAME, command.getName()); + assertEquals(NETWORK_ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getNatRuleType()); + assertNull(command.getNatRuleName()); + assertNull(command.getNatIp()); + } + + @Test + public void testSettersAndGetters() { + // Arrange + DeleteNetrisNatRuleCommand command = new DeleteNetrisNatRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, VPC_NAME, VPC_ID, VNET_NAME, NETWORK_ID, IS_VPC); + + // Act + command.setNatRuleType(NAT_RULE_TYPE); + command.setNatRuleName(NAT_RULE_NAME); + command.setNatIp(NAT_IP); + command.setVpcName(VPC_NAME); + command.setVpcId(VPC_ID); + + // Assert + assertEquals(NAT_RULE_TYPE, command.getNatRuleType()); + assertEquals(NAT_RULE_NAME, command.getNatRuleName()); + assertEquals(NAT_IP, command.getNatIp()); + assertEquals(VPC_NAME, command.getVpcName()); + assertEquals(VPC_ID, command.getVpcId()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + DeleteNetrisNatRuleCommand command = new DeleteNetrisNatRuleCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", VPC_ID, "", NETWORK_ID, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals("", command.getVpcName()); + assertEquals(VPC_ID, command.getVpcId()); + assertEquals("", command.getName()); + assertEquals(NETWORK_ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommandTest.java new file mode 100644 index 00000000000..8427e9f71ac --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVnetCommandTest.java @@ -0,0 +1,83 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Assert; +import org.junit.Test; + +public class DeleteNetrisVnetCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-vnet"; + private static final Long ID = 4L; + private static final String VPC_NAME = "test-vpc"; + private static final Long VPC_ID = 5L; + private static final String VNET_CIDR = "10.0.0.0/24"; + private static final boolean IS_VPC = true; + private static final String VNET_V6_CIDR = "2001:db8::/32"; + + @Test + public void testConstructorAndGetters() { + // Act + DeleteNetrisVnetCommand command = new DeleteNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, VPC_NAME, VPC_ID, VNET_CIDR, IS_VPC); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals(NAME, command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals(VPC_NAME, command.getVpcName()); + Assert.assertEquals(VPC_ID, command.getVpcId()); + Assert.assertEquals(VNET_CIDR, command.getVNetCidr()); + Assert.assertEquals(IS_VPC, command.isVpc()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + DeleteNetrisVnetCommand command = new DeleteNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, "", VPC_ID, VNET_CIDR, IS_VPC); + + // Assert + Assert.assertEquals(ZONE_ID, command.getZoneId()); + Assert.assertEquals(ACCOUNT_ID, command.getAccountId()); + Assert.assertEquals(DOMAIN_ID, command.getDomainId()); + Assert.assertEquals("", command.getName()); + Assert.assertEquals(ID, command.getId()); + Assert.assertEquals("", command.getVpcName()); + Assert.assertEquals(VPC_ID, command.getVpcId()); + Assert.assertEquals(VNET_CIDR, command.getVNetCidr()); + Assert.assertEquals(IS_VPC, command.isVpc()); + } + + @Test + public void testVnetV6CidrSetterAndGetter() { + // Arrange + DeleteNetrisVnetCommand command = new DeleteNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, VPC_NAME, VPC_ID, VNET_CIDR, IS_VPC); + + // Act + command.setvNetV6Cidr(VNET_V6_CIDR); + + // Assert + Assert.assertEquals(VNET_V6_CIDR, command.getvNetV6Cidr()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommandTest.java new file mode 100644 index 00000000000..40f9347e898 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/DeleteNetrisVpcCommandTest.java @@ -0,0 +1,64 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class DeleteNetrisVpcCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-vpc"; + private static final String CIDR = "10.0.0.0/24"; + private static final Long VPC_ID = 4L; + private static final boolean IS_VPC = true; + + @Test + public void testConstructorAndGetters() { + // Act + DeleteNetrisVpcCommand command = new DeleteNetrisVpcCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, CIDR, VPC_ID, IS_VPC); + + // Assert + assertEquals("Zone ID should match", ZONE_ID, command.getZoneId()); + assertEquals("Account ID should match", ACCOUNT_ID, command.getAccountId()); + assertEquals("Domain ID should match", DOMAIN_ID, command.getDomainId()); + assertEquals("Name should match", NAME, command.getName()); + assertEquals("CIDR should match", CIDR, command.getCidr()); + assertEquals("VPC ID should match", VPC_ID, command.getId()); + assertEquals("Is VPC flag should match", IS_VPC, command.isVpc()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + DeleteNetrisVpcCommand command = new DeleteNetrisVpcCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", CIDR, VPC_ID, IS_VPC); + + // Assert + assertEquals("Zone ID should match", ZONE_ID, command.getZoneId()); + assertEquals("Account ID should match", ACCOUNT_ID, command.getAccountId()); + assertEquals("Domain ID should match", DOMAIN_ID, command.getDomainId()); + assertEquals("Name should be empty", "", command.getName()); + assertEquals("CIDR should match", CIDR, command.getCidr()); + assertEquals("VPC ID should match", VPC_ID, command.getId()); + assertEquals("Is VPC flag should match", IS_VPC, command.isVpc()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommandTest.java new file mode 100644 index 00000000000..0713fad6c8b --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/ReleaseNatIpCommandTest.java @@ -0,0 +1,80 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class ReleaseNatIpCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-network"; + private static final Long ID = 4L; + private static final boolean IS_VPC = true; + private static final String NAT_IP = "10.0.0.1"; + + @Test + public void testConstructorAndGetters() { + // Act + ReleaseNatIpCommand command = new ReleaseNatIpCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC, NAT_IP); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals(NAME, command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals(NAT_IP, command.getNatIp()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + ReleaseNatIpCommand command = new ReleaseNatIpCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, IS_VPC, ""); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals("", command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals("", command.getNatIp()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + ReleaseNatIpCommand command = new ReleaseNatIpCommand( + ZONE_ID, null, null, NAME, null, IS_VPC, NAT_IP); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertNull(command.getAccountId()); + assertNull(command.getDomainId()); + assertEquals(NAME, command.getName()); + assertNull(command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertEquals(NAT_IP, command.getNatIp()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommandTest.java new file mode 100644 index 00000000000..93fd8105b7f --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/SetupNetrisPublicRangeCommandTest.java @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; + +public class SetupNetrisPublicRangeCommandTest { + + private static final Long ZONE_ID = 1L; + private static final String SUPER_CIDR = "10.0.0.0/16"; + private static final String EXACT_CIDR = "10.0.1.0/24"; + + @Test + public void testConstructorAndGetters() { + // Act + SetupNetrisPublicRangeCommand command = new SetupNetrisPublicRangeCommand( + ZONE_ID, SUPER_CIDR, EXACT_CIDR); + + // Assert + assertEquals(ZONE_ID.longValue(), command.getZoneId()); + assertEquals(SUPER_CIDR, command.getSuperCidr()); + assertEquals(EXACT_CIDR, command.getExactCidr()); + assertNull(command.getAccountId()); + assertNull(command.getDomainId()); + assertNull(command.getName()); + assertEquals(ZONE_ID, command.getId()); + assertFalse(command.isVpc()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + SetupNetrisPublicRangeCommand command = new SetupNetrisPublicRangeCommand( + ZONE_ID, "", ""); + + // Assert + assertEquals(ZONE_ID.longValue(), command.getZoneId()); + assertEquals("", command.getSuperCidr()); + assertEquals("", command.getExactCidr()); + assertNull(command.getAccountId()); + assertNull(command.getDomainId()); + assertNull(command.getName()); + assertEquals(ZONE_ID, command.getId()); + assertFalse(command.isVpc()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommandTest.java new file mode 100644 index 00000000000..7015f663433 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVnetCommandTest.java @@ -0,0 +1,105 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class UpdateNetrisVnetCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-network"; + private static final Long ID = 4L; + private static final boolean IS_VPC = true; + private static final String PREV_NETWORK_NAME = "prev-network"; + private static final String VPC_NAME = "test-vpc"; + private static final Long VPC_ID = 5L; + + @Test + public void testConstructorAndGetters() { + // Act + UpdateNetrisVnetCommand command = new UpdateNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals(NAME, command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getPrevNetworkName()); + assertNull(command.getVpcName()); + assertNull(command.getVpcId()); + } + + @Test + public void testSettersAndGetters() { + // Arrange + UpdateNetrisVnetCommand command = new UpdateNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC); + + // Act + command.setPrevNetworkName(PREV_NETWORK_NAME); + command.setVpcName(VPC_NAME); + command.setVpcId(VPC_ID); + + // Assert + assertEquals(PREV_NETWORK_NAME, command.getPrevNetworkName()); + assertEquals(VPC_NAME, command.getVpcName()); + assertEquals(VPC_ID, command.getVpcId()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + UpdateNetrisVnetCommand command = new UpdateNetrisVnetCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals("", command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getPrevNetworkName()); + assertNull(command.getVpcName()); + assertNull(command.getVpcId()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + UpdateNetrisVnetCommand command = new UpdateNetrisVnetCommand( + ZONE_ID, null, null, NAME, null, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertNull(command.getAccountId()); + assertNull(command.getDomainId()); + assertEquals(NAME, command.getName()); + assertNull(command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getPrevNetworkName()); + assertNull(command.getVpcName()); + assertNull(command.getVpcId()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommandTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommandTest.java new file mode 100644 index 00000000000..47bea8560f1 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/agent/api/UpdateNetrisVpcCommandTest.java @@ -0,0 +1,93 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.agent.api; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class UpdateNetrisVpcCommandTest { + + private static final long ZONE_ID = 1L; + private static final Long ACCOUNT_ID = 2L; + private static final Long DOMAIN_ID = 3L; + private static final String NAME = "test-vpc"; + private static final Long ID = 4L; + private static final boolean IS_VPC = true; + private static final String PREVIOUS_VPC_NAME = "previous-vpc"; + + @Test + public void testConstructorAndGetters() { + // Act + UpdateNetrisVpcCommand command = new UpdateNetrisVpcCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals(NAME, command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getPreviousVpcName()); + } + + @Test + public void testSettersAndGetters() { + // Arrange + UpdateNetrisVpcCommand command = new UpdateNetrisVpcCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, NAME, ID, IS_VPC); + + // Act + command.setPreviousVpcName(PREVIOUS_VPC_NAME); + + // Assert + assertEquals(PREVIOUS_VPC_NAME, command.getPreviousVpcName()); + } + + @Test + public void testConstructorWithEmptyStrings() { + // Act + UpdateNetrisVpcCommand command = new UpdateNetrisVpcCommand( + ZONE_ID, ACCOUNT_ID, DOMAIN_ID, "", ID, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertEquals(ACCOUNT_ID, command.getAccountId()); + assertEquals(DOMAIN_ID, command.getDomainId()); + assertEquals("", command.getName()); + assertEquals(ID, command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getPreviousVpcName()); + } + + @Test + public void testConstructorWithNullValues() { + // Act + UpdateNetrisVpcCommand command = new UpdateNetrisVpcCommand( + ZONE_ID, null, null, NAME, null, IS_VPC); + + // Assert + assertEquals(ZONE_ID, command.getZoneId()); + assertNull(command.getAccountId()); + assertNull(command.getDomainId()); + assertEquals(NAME, command.getName()); + assertNull(command.getId()); + assertEquals(IS_VPC, command.isVpc()); + assertNull(command.getPreviousVpcName()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/AddNetrisProviderCmdTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/AddNetrisProviderCmdTest.java new file mode 100644 index 00000000000..d27164a60f7 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/AddNetrisProviderCmdTest.java @@ -0,0 +1,122 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.network.netris.NetrisProvider; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.NetrisProviderResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.service.NetrisProviderService; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.Field; + +public class AddNetrisProviderCmdTest { + + @Mock + private NetrisProviderService netrisProviderService; + + @Mock + private CallContext callContext; + + @Mock + Object _responseObject; + + private MockedStatic callContextMockedStatic; + + @InjectMocks + private AddNetrisProviderCmd cmd; + + private AutoCloseable closeable; + + private static final long ZONE_ID = 1L; + private static final String NAME = "test-provider"; + private static final String URL = "http://domain.provider.dev"; + private static final String USERNAME = "test-user"; + private static final String PASSWORD = "test-password"; + private static final String SITE_NAME = "test-site"; + private static final String TENANT_NAME = "test-tenant"; + private static final String NETRIS_TAG = "test-tag"; + + @Before + public void setup() throws Exception { + closeable = MockitoAnnotations.openMocks(this); + callContextMockedStatic = Mockito.mockStatic(CallContext.class); + callContextMockedStatic.when(CallContext::current).thenReturn(callContext); + + // Set private fields using reflection + setPrivateField("zoneId", ZONE_ID); + setPrivateField("name", NAME); + setPrivateField("url", URL); + setPrivateField("username", USERNAME); + setPrivateField("password", PASSWORD); + setPrivateField("siteName", SITE_NAME); + setPrivateField("tenantName", TENANT_NAME); + setPrivateField("netrisTag", NETRIS_TAG); + } + + private void setPrivateField(String fieldName, Object value) throws Exception { + Field field = AddNetrisProviderCmd.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(cmd, value); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + callContextMockedStatic.close(); + } + + @Test + public void testExecuteSuccess() throws ConcurrentOperationException { + NetrisProvider provider = Mockito.mock(NetrisProvider.class); + NetrisProviderResponse response = Mockito.mock(NetrisProviderResponse.class); + Mockito.when(netrisProviderService.addProvider(cmd)).thenReturn(provider); + Mockito.when(netrisProviderService.createNetrisProviderResponse(provider)).thenReturn(response); + cmd.execute(); + Mockito.verify(netrisProviderService).addProvider(cmd); + Mockito.verify(netrisProviderService).createNetrisProviderResponse(provider); + Mockito.verify(response).setResponseName(cmd.getCommandName()); + Assert.assertEquals(response, cmd.getResponseObject()); + } + + @Test(expected = ServerApiException.class) + public void testExecuteFailure() throws ConcurrentOperationException { + NetrisProvider provider = Mockito.mock(NetrisProvider.class); + Mockito.when(netrisProviderService.addProvider(cmd)).thenReturn(provider); + Mockito.when(netrisProviderService.createNetrisProviderResponse(provider)).thenReturn(null); + cmd.execute(); + } + + @Test + public void testGetEntityOwnerId() { + long expectedAccountId = 123L; + Mockito.when(callContext.getCallingAccount()).thenReturn(Mockito.mock(com.cloud.user.Account.class)); + Mockito.when(callContext.getCallingAccount().getId()).thenReturn(expectedAccountId); + long actualAccountId = cmd.getEntityOwnerId(); + Assert.assertEquals(expectedAccountId, actualAccountId); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmdTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmdTest.java new file mode 100644 index 00000000000..527fecfad48 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmdTest.java @@ -0,0 +1,101 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.service.NetrisProviderService; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.lang.reflect.Field; + +public class DeleteNetrisProviderCmdTest { + + @Mock + private NetrisProviderService netrisProviderService; + + @InjectMocks + private DeleteNetrisProviderCmd cmd; + + private AutoCloseable closeable; + + private static final long PROVIDER_ID = 1L; + + @Before + public void setup() throws Exception { + closeable = MockitoAnnotations.openMocks(this); + setPrivateField("id", PROVIDER_ID); + } + + private void setPrivateField(String fieldName, Object value) throws Exception { + Field field = DeleteNetrisProviderCmd.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(cmd, value); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + } + + @Test + public void testExecuteSuccess() throws ConcurrentOperationException { + Mockito.when(netrisProviderService.deleteNetrisProvider(PROVIDER_ID)).thenReturn(true); + cmd.execute(); + Mockito.verify(netrisProviderService).deleteNetrisProvider(PROVIDER_ID); + Assert.assertTrue(cmd.getResponseObject() instanceof SuccessResponse); + SuccessResponse response = (SuccessResponse) cmd.getResponseObject(); + Assert.assertEquals(cmd.getCommandName(), response.getResponseName()); + } + + @Test(expected = ServerApiException.class) + public void testExecuteFailure() throws ConcurrentOperationException { + Mockito.when(netrisProviderService.deleteNetrisProvider(PROVIDER_ID)).thenReturn(false); + cmd.execute(); + } + + @Test(expected = ServerApiException.class) + public void testExecuteInvalidParameterException() throws ConcurrentOperationException { + String errorMessage = "Invalid provider ID"; + Mockito.when(netrisProviderService.deleteNetrisProvider(PROVIDER_ID)) + .thenThrow(new InvalidParameterValueException(errorMessage)); + cmd.execute(); + } + + @Test(expected = ServerApiException.class) + public void testExecuteCloudRuntimeException() throws ConcurrentOperationException { + String errorMessage = "Cloud runtime error"; + Mockito.when(netrisProviderService.deleteNetrisProvider(PROVIDER_ID)) + .thenThrow(new CloudRuntimeException(errorMessage)); + cmd.execute(); + } + + @Test + public void testGetEntityOwnerId() { + Assert.assertEquals(0L, cmd.getEntityOwnerId()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmdTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmdTest.java new file mode 100644 index 00000000000..c9d9a8a2d1b --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/api/command/ListNetrisProvidersCmdTest.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.NetrisProviderResponse; +import org.apache.cloudstack.service.NetrisProviderService; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.List; + +public class ListNetrisProvidersCmdTest { + + @Mock + private NetrisProviderService netrisProviderService; + + @InjectMocks + private ListNetrisProvidersCmd cmd; + + private AutoCloseable closeable; + + private static final long ZONE_ID = 1L; + + @Before + public void setup() throws Exception { + closeable = MockitoAnnotations.openMocks(this); + setPrivateField("zoneId", ZONE_ID); + } + + private void setPrivateField(String fieldName, Object value) throws Exception { + java.lang.reflect.Field field = ListNetrisProvidersCmd.class.getDeclaredField(fieldName); + field.setAccessible(true); + field.set(cmd, value); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + } + + @Test + public void testExecuteSuccess() throws ConcurrentOperationException { + // Setup + NetrisProviderResponse providerResponse = Mockito.mock(NetrisProviderResponse.class); + List providerList = Arrays.asList(providerResponse); + Mockito.when(netrisProviderService.listNetrisProviders(ZONE_ID)).thenReturn(providerList); + + // Execute + cmd.execute(); + + // Verify + Mockito.verify(netrisProviderService).listNetrisProviders(ZONE_ID); + Assert.assertTrue(cmd.getResponseObject() instanceof ListResponse); + ListResponse response = (ListResponse) cmd.getResponseObject(); + Assert.assertEquals(cmd.getCommandName(), response.getResponseName()); + } + + @Test + public void testExecuteWithoutZoneId() throws ConcurrentOperationException, Exception { + // Setup + setPrivateField("zoneId", null); + NetrisProviderResponse providerResponse = Mockito.mock(NetrisProviderResponse.class); + List providerList = Arrays.asList(providerResponse); + Mockito.when(netrisProviderService.listNetrisProviders(null)).thenReturn(providerList); + + // Execute + cmd.execute(); + + // Verify + Mockito.verify(netrisProviderService).listNetrisProviders(null); + Assert.assertTrue(cmd.getResponseObject() instanceof ListResponse); + ListResponse response = (ListResponse) cmd.getResponseObject(); + Assert.assertEquals(cmd.getCommandName(), response.getResponseName()); + } + + @Test + public void testGetEntityOwnerId() { + Assert.assertEquals(0L, cmd.getEntityOwnerId()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java new file mode 100644 index 00000000000..44bd9824b2d --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java @@ -0,0 +1,109 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.resource; + +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisNatCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.service.NetrisServiceImpl; +import org.junit.Assert; +import org.junit.Test; + +public class NetrisResourceObjectUtilsTest { + + private static final long zoneId = 1; + private static final long accountId = 2; + private static final long domainId = 2; + + private static final long vpcId = 8; + private static final String vpcName = "testVpc"; + private static final String vpcCidr = "10.10.0.0/16"; + + @Test + public void testCreateVpcName() { + CreateNetrisVpcCommand cmd = new CreateNetrisVpcCommand(zoneId, accountId, domainId, vpcName, vpcCidr, vpcId, true); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC); + String expectedNetrisVpcName = String.format("D%s-A%s-Z%s-V%s-%s", domainId, accountId, zoneId, vpcId, vpcName); + Assert.assertEquals(expectedNetrisVpcName, netrisVpcName); + } + + @Test + public void testCreateVpcNameWithSuffix() { + CreateNetrisVpcCommand cmd = new CreateNetrisVpcCommand(zoneId, accountId, domainId, vpcName, vpcCidr, vpcId, true); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, String.valueOf(vpcId)); + String expectedNetrisVpcName = String.format("D%s-A%s-Z%s-V%s", domainId, accountId, zoneId, vpcId); + Assert.assertEquals(expectedNetrisVpcName, netrisVpcName); + } + + @Test + public void testCreateVpcIpamAllocationName() { + CreateNetrisVpcCommand cmd = new CreateNetrisVpcCommand(zoneId, accountId, domainId, vpcName, vpcCidr, vpcId, true); + String ipamAllocationName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_ALLOCATION, vpcCidr); + String expectedNetrisVpcName = String.format("D%s-A%s-Z%s-V%s-%s", domainId, accountId, zoneId, vpcId, vpcCidr); + Assert.assertEquals(expectedNetrisVpcName, ipamAllocationName); + } + + @Test + public void testDeleteVpcName() { + DeleteNetrisVpcCommand cmd = new DeleteNetrisVpcCommand(zoneId, accountId, domainId, vpcName, vpcCidr, vpcId, true); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC); + String expectedNetrisVpcName = String.format("D%s-A%s-Z%s-V%s-%s", domainId, accountId, zoneId, vpcId, vpcName); + Assert.assertEquals(expectedNetrisVpcName, netrisVpcName); + } + + @Test + public void testSuffixesForDNAT() { + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, vpcName, null, true, vpcCidr); + cmd.setNatRuleType("DNAT"); + long ruleId = 23L; + String ruleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.DNAT, + String.valueOf(vpcId), String.format("R%s", ruleId)); + String expectedNetrisRuleName = String.format("D%s-A%s-Z%s-V%s-DNAT-R%s", domainId, accountId, zoneId, vpcId, ruleId); + Assert.assertEquals(expectedNetrisRuleName, ruleName); + } + + @Test + public void testSubnetName() { + String vNetName = ""; + Long vpcTierNetworkId = 240L; + String vpcTierNetworkCidr = "10.10.30.0/24"; + String vpcTierNetworkGateway = "10.10.30.1"; + CreateNetrisVnetCommand cmd = new CreateNetrisVnetCommand(zoneId, accountId, domainId, vpcName, vpcId, vNetName, vpcTierNetworkId, vpcTierNetworkCidr, vpcTierNetworkGateway, true); + String subnetName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.IPAM_SUBNET, String.valueOf(vpcId), vpcTierNetworkCidr); + String expectedName = String.format("D%s-A%s-Z%s-V%s-%s", domainId, accountId, zoneId, vpcId, vpcTierNetworkCidr); + Assert.assertEquals(expectedName, subnetName); + } + + @Test + public void testSourceNatName() { + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, null, null, true, vpcCidr); + String snatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.SNAT, String.valueOf(vpcId)); + String expectedName = String.format("D%s-A%s-Z%s-V%s-SNAT", domainId, accountId, zoneId, vpcId); + Assert.assertEquals(expectedName, snatRuleName); + } + + @Test + public void testStaticNatName() { + long vmId = 1234L; + CreateOrUpdateNetrisNatCommand cmd = new CreateOrUpdateNetrisNatCommand(zoneId, accountId, domainId, vpcName, vpcId, null, null, true, vpcCidr); + String[] suffixes = NetrisServiceImpl.getStaticNatResourceSuffixes(vpcId, null, true, vmId); + String staticNatRuleName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.STATICNAT, suffixes); + String expectedName = String.format("D%s-A%s-Z%s-V%s-VM%s-STATICNAT", domainId, accountId, zoneId, vpcId, vmId); + Assert.assertEquals(expectedName, staticNatRuleName); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceTest.java new file mode 100644 index 00000000000..1f09045d00e --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceTest.java @@ -0,0 +1,141 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.resource; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; +import org.apache.cloudstack.agent.api.AddOrUpdateNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisACLCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.CreateOrUpdateNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisACLCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisLoadBalancerRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisNatRuleCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisStaticRouteCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVnetCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.ReleaseNatIpCommand; +import org.apache.cloudstack.agent.api.SetupNetrisPublicRangeCommand; +import org.apache.cloudstack.service.NetrisApiClient; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.Arrays; +import java.util.List; + +public class NetrisResourceTest { + + @Mock + private NetrisApiClient netrisApiClient; + + @Spy + @InjectMocks + private NetrisResource netrisResource = new NetrisResource(); + + private AutoCloseable closeable; + + @Mock + private CreateNetrisVpcCommand createNetrisVpcCommand; + @Mock + private CreateNetrisVnetCommand createNetrisVnetCommand; + @Mock + private DeleteNetrisVnetCommand deleteNetrisVnetCommand; + @Mock + private DeleteNetrisVpcCommand deleteNetrisVpcCommand; + @Mock + private SetupNetrisPublicRangeCommand setupNetrisPublicRangeCommand; + @Mock + private DeleteNetrisNatRuleCommand deleteNetrisNatRuleCommand; + @Mock + private CreateOrUpdateNetrisACLCommand createNetrisACLCommand; + @Mock + private DeleteNetrisACLCommand deleteNetrisACLCommand; + @Mock + private AddOrUpdateNetrisStaticRouteCommand addOrUpdateNetrisStaticRouteCommand; + @Mock + private DeleteNetrisStaticRouteCommand deleteNetrisStaticRouteCommand; + @Mock + private ReleaseNatIpCommand releaseNatIpCommand; + @Mock + private CreateOrUpdateNetrisLoadBalancerRuleCommand createOrUpdateNetrisLoadBalancerRuleCommand; + @Mock + private DeleteNetrisLoadBalancerRuleCommand deleteNetrisLoadBalancerRuleCommand; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + } + + @Test + public void testExecuteRequest() { + List commands = Arrays.asList(createNetrisVpcCommand, createNetrisVnetCommand, deleteNetrisVnetCommand, + deleteNetrisVpcCommand, setupNetrisPublicRangeCommand, deleteNetrisNatRuleCommand, createNetrisACLCommand, + deleteNetrisACLCommand, addOrUpdateNetrisStaticRouteCommand, deleteNetrisStaticRouteCommand, + releaseNatIpCommand, createOrUpdateNetrisLoadBalancerRuleCommand, deleteNetrisLoadBalancerRuleCommand); + + for (boolean res : new boolean[]{true, false}) { + setMocksToValue(res); + for (Command command : commands) { + Answer answer = netrisResource.executeRequest(command); + Assert.assertEquals(res, answer.getResult()); + } + } + + Mockito.verify(netrisApiClient, Mockito.times(2)).createVpc(createNetrisVpcCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).createVnet(createNetrisVnetCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).deleteVnet(deleteNetrisVnetCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).deleteVpc(deleteNetrisVpcCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).setupZoneLevelPublicRange(setupNetrisPublicRangeCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).deleteNatRule(deleteNetrisNatRuleCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).addOrUpdateAclRule(Mockito.eq(createNetrisACLCommand), Mockito.anyBoolean()); + Mockito.verify(netrisApiClient, Mockito.times(2)).deleteAclRule(Mockito.eq(deleteNetrisACLCommand), Mockito.anyBoolean()); + Mockito.verify(netrisApiClient, Mockito.times(2)).addOrUpdateStaticRoute(addOrUpdateNetrisStaticRouteCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).deleteStaticRoute(deleteNetrisStaticRouteCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).releaseNatIp(releaseNatIpCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).createOrUpdateLbRule(createOrUpdateNetrisLoadBalancerRuleCommand); + Mockito.verify(netrisApiClient, Mockito.times(2)).deleteLbRule(deleteNetrisLoadBalancerRuleCommand); + } + + private void setMocksToValue(boolean value) { + Mockito.when(netrisApiClient.createVpc(createNetrisVpcCommand)).thenReturn(value); + Mockito.when(netrisApiClient.createVnet(createNetrisVnetCommand)).thenReturn(value); + Mockito.when(netrisApiClient.deleteVnet(deleteNetrisVnetCommand)).thenReturn(value); + Mockito.when(netrisApiClient.deleteVpc(deleteNetrisVpcCommand)).thenReturn(value); + Mockito.when(netrisApiClient.setupZoneLevelPublicRange(setupNetrisPublicRangeCommand)).thenReturn(value); + Mockito.when(netrisApiClient.deleteNatRule(deleteNetrisNatRuleCommand)).thenReturn(value); + Mockito.when(netrisApiClient.addOrUpdateAclRule(Mockito.eq(createNetrisACLCommand), Mockito.anyBoolean())).thenReturn(value); + Mockito.when(netrisApiClient.deleteAclRule(Mockito.eq(deleteNetrisACLCommand), Mockito.anyBoolean())).thenReturn(value); + Mockito.when(netrisApiClient.addOrUpdateStaticRoute(addOrUpdateNetrisStaticRouteCommand)).thenReturn(value); + Mockito.when(netrisApiClient.deleteStaticRoute(deleteNetrisStaticRouteCommand)).thenReturn(value); + Mockito.when(netrisApiClient.releaseNatIp(releaseNatIpCommand)).thenReturn(value); + Mockito.when(netrisApiClient.createOrUpdateLbRule(createOrUpdateNetrisLoadBalancerRuleCommand)).thenReturn(value); + Mockito.when(netrisApiClient.deleteLbRule(deleteNetrisLoadBalancerRuleCommand)).thenReturn(value); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisApiClientImplTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisApiClientImplTest.java new file mode 100644 index 00000000000..6ae440afbff --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisApiClientImplTest.java @@ -0,0 +1,103 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import io.netris.ApiClient; +import io.netris.ApiResponse; +import io.netris.api.v1.AuthenticationApi; +import io.netris.api.v1.SitesApi; +import io.netris.api.v1.TenantsApi; +import io.netris.model.GetSiteBody; +import io.netris.model.SitesResponseOK; +import io.netris.model.response.AuthResponse; +import io.netris.model.response.TenantResponse; +import io.netris.model.response.TenantsResponse; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.MockedConstruction; +import org.mockito.Mockito; +import org.mockito.Spy; + +import java.math.BigDecimal; +import java.util.List; + +public class NetrisApiClientImplTest { + + private static final String endpointUrl = "https://my-netris-controller.localdomain"; + private static final String username = "user"; + private static final String password = "password"; + private static final String siteName = "Datacenter-1"; + private static final String adminTenantName = "Admin"; + private static final int siteId = 1; + private static final int adminTenantId = 1; + + private MockedConstruction apiClientMockedConstruction; + + @Spy + @InjectMocks + private NetrisApiClientImpl client; + + @Before + public void setUp() { + GetSiteBody site = Mockito.mock(GetSiteBody.class); + SitesApi sitesApiMock = Mockito.mock(SitesApi.class); + Mockito.when(site.getName()).thenReturn(siteName); + Mockito.when(site.getId()).thenReturn(siteId); + TenantsApi tenantsApi = Mockito.mock(TenantsApi.class); + TenantResponse tenant = Mockito.mock(TenantResponse.class); + Mockito.when(tenant.getName()).thenReturn(adminTenantName); + Mockito.when(tenant.getId()).thenReturn(new BigDecimal(adminTenantId)); + + apiClientMockedConstruction = Mockito.mockConstruction(ApiClient.class, (mock, context) -> { + SitesResponseOK sitesResponse = Mockito.mock(SitesResponseOK.class); + Mockito.when(sitesResponse.getData()).thenReturn(List.of(site)); + Mockito.when(sitesApiMock.apiSitesGet()).thenReturn(sitesResponse); + Mockito.when(mock.getApiStubForMethod(SitesApi.class)).thenReturn(sitesApiMock); + Mockito.when(mock.getApiStubForMethod(TenantsApi.class)).thenReturn(tenantsApi); + ApiResponse tenantsResponse = Mockito.mock(ApiResponse.class); + Mockito.when(tenantsApi.apiTenantsGet()).thenReturn(tenantsResponse); + TenantsResponse tenantsResponseData = Mockito.mock(TenantsResponse.class); + Mockito.when(tenantsResponseData.getData()).thenReturn(List.of(tenant)); + Mockito.when(tenantsResponse.getData()).thenReturn(tenantsResponseData); + AuthenticationApi authenticationApi = Mockito.mock(AuthenticationApi.class); + Mockito.when(mock.getApiStubForMethod(AuthenticationApi.class)).thenReturn(authenticationApi); + ApiResponse authResponseApiResponse = Mockito.mock(ApiResponse.class); + Mockito.when(authenticationApi.apiAuthGet()).thenReturn(authResponseApiResponse); + Mockito.when(authResponseApiResponse.getStatusCode()).thenReturn(200); + }); + client = new NetrisApiClientImpl(endpointUrl, username, password, siteName, adminTenantName); + } + + @After + public void tearDown() { + apiClientMockedConstruction.close(); + } + + @Test + public void testConstructor() { + Assert.assertEquals(siteId, client.siteId); + Assert.assertEquals(adminTenantId, client.tenantId); + } + + @Test + public void testNetrisAuthStatus() { + Assert.assertTrue(client.isSessionAlive()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisElementTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisElementTest.java new file mode 100644 index 00000000000..a2622549deb --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisElementTest.java @@ -0,0 +1,141 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.as.AutoScaleCounter; +import com.cloud.network.as.Counter; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; +import com.cloud.vm.ReservationContext; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +public class NetrisElementTest { + + @Spy + @InjectMocks + private NetrisElement netrisElement = new NetrisElement();; + + @Mock + private NetrisService netrisService; + @Mock + private AccountManager accountManager; + @Mock + private NetworkDao networkDao; + @Mock + private DataCenterDao dataCenterDao; + @Mock + private DomainDao domainDao; + @Mock + private VpcDao vpcDao; + + private AutoCloseable closeable; + + private static long accountId = 2L; + private static long zoneId = 1L; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + } + + @Test + public void testAutoscalingCounterList() { + List counters = NetrisElement.getNetrisAutoScaleCounters(); + Assert.assertEquals(2, counters.size()); + Set counterNamesSet = counters.stream().map(AutoScaleCounter::getName).collect(Collectors.toSet()); + Set expected = Set.of(Counter.Source.CPU.name(), Counter.Source.MEMORY.name()); + Assert.assertEquals(expected, counterNamesSet); + } + + @Test + public void testInitCapabilities() { + Map> capabilities = NetrisElement.initCapabilities(); + Assert.assertTrue(capabilities.containsKey(Network.Service.Dns)); + Assert.assertTrue(capabilities.containsKey(Network.Service.Dhcp)); + Assert.assertTrue(capabilities.containsKey(Network.Service.SourceNat)); + Assert.assertTrue(capabilities.containsKey(Network.Service.StaticNat)); + Assert.assertTrue(capabilities.containsKey(Network.Service.Lb)); + Assert.assertTrue(capabilities.containsKey(Network.Service.PortForwarding)); + Assert.assertTrue(capabilities.containsKey(Network.Service.NetworkACL)); + } + + @Test + public void testDeleteNetwork() throws ResourceUnavailableException { + long networkId = 210L; + long domainId = 2L; + long vpcId = 8L; + String vpcName = "testVpc"; + String networkName = "testVpcTier"; + String networkCidr = "10.10.30.0/24"; + VpcVO vpc = Mockito.mock(VpcVO.class); + Mockito.when(vpc.getName()).thenReturn(vpcName); + Network network = Mockito.mock(Network.class); + Mockito.when(network.getAccountId()).thenReturn(accountId); + Mockito.when(network.getId()).thenReturn(networkId); + Mockito.when(network.getDataCenterId()).thenReturn(zoneId); + Mockito.when(network.getName()).thenReturn(networkName); + Mockito.when(network.getCidr()).thenReturn(networkCidr); + Mockito.when(network.getVpcId()).thenReturn(vpcId); + Account account = Mockito.mock(Account.class); + Mockito.when(account.getId()).thenReturn(accountId); + Mockito.when(account.getDomainId()).thenReturn(domainId); + NetworkVO networkVO = Mockito.mock(NetworkVO.class); + Mockito.when(networkVO.getName()).thenReturn(networkName); + DataCenterVO dataCenterVO = Mockito.mock(DataCenterVO.class); + Mockito.when(dataCenterVO.getId()).thenReturn(zoneId); + DomainVO domain = Mockito.mock(DomainVO.class); + Mockito.when(domain.getId()).thenReturn(domainId); + Mockito.when(accountManager.getAccount(accountId)).thenReturn(account); + Mockito.when(networkDao.findById(networkId)).thenReturn(networkVO); + Mockito.when(dataCenterDao.findById(zoneId)).thenReturn(dataCenterVO); + Mockito.when(domainDao.findById(domainId)).thenReturn(domain); + Mockito.when(vpcDao.findById(vpcId)).thenReturn(vpc); + ReservationContext context = Mockito.mock(ReservationContext.class); + netrisElement.destroy(network, context); + Mockito.verify(netrisService).deleteVnetResource(zoneId, accountId, domainId, vpcName, vpcId, + networkName, networkId, networkCidr); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisGuestNetworkGuruTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisGuestNetworkGuruTest.java new file mode 100644 index 00000000000..ad8d46c0dd8 --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisGuestNetworkGuruTest.java @@ -0,0 +1,230 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.event.ActionEventUtils; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.dao.NetworkDetailsDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.offerings.dao.NetworkOfferingDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.AccountVO; +import com.cloud.user.dao.AccountDao; +import com.cloud.vm.ReservationContext; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.Arrays; +import java.util.List; + +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; + +public class NetrisGuestNetworkGuruTest { + + @Mock + private NetworkOfferingServiceMapDao networkOfferingServiceMapDao; + @Mock + private PhysicalNetworkDao physicalNetworkDao; + @Mock + private DataCenterDao dataCenterDao; + @Mock + private NetworkModel networkModel; + @Mock + private AccountDao accountDao; + @Mock + private DomainDao domainDao; + @Mock + private NetworkOfferingDao networkOfferingDao; + @Mock + private VpcDao vpcDao; + @Mock + private NetrisService netrisService; + @Mock + private NetworkDetailsDao networkDetailsDao; + + @Spy + @InjectMocks + private NetrisGuestNetworkGuru guru = new NetrisGuestNetworkGuru(); + + @Mock + private NetworkOfferingVO networkOffering; + @Mock + private PhysicalNetworkVO physicalNetwork; + @Mock + private DeploymentPlan plan; + @Mock + private NetworkVO network; + @Mock + private AccountVO account; + @Mock + private DomainVO domain; + @Mock + private DataCenterVO zone; + @Mock + private VpcVO vpc; + + private AutoCloseable closeable; + private MockedStatic actionEventUtilsMocked; + + private static final long networkOfferingId = 10L; + private static final long physicalNetworkId = 2L; + private static final long zoneId = 1L; + private static final long accountId = 2L; + private static final long domainId = 7L; + private static final long vpcId = 12L; + private static final long networkId = 210L; + private static final String networkName = "test-network"; + private static final String vpcName = "test-vpc"; + private static final String networkCidr = "172.20.10.0/24"; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + Mockito.when(networkOffering.getId()).thenReturn(networkOfferingId); + Mockito.when(networkOffering.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + Mockito.when(networkOffering.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.NATTED); + Mockito.when(networkOffering.isRedundantRouter()).thenReturn(false); + Mockito.when(networkOfferingDao.findById(networkOfferingId)).thenReturn(networkOffering); + Mockito.when(physicalNetwork.getIsolationMethods()).thenReturn(List.of("netris")); + Mockito.when(physicalNetworkDao.findById(physicalNetworkId)).thenReturn(physicalNetwork); + Mockito.when(networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.Netris)).thenReturn(true); + Mockito.when(plan.getPhysicalNetworkId()).thenReturn(physicalNetworkId); + Mockito.when(plan.getDataCenterId()).thenReturn(zoneId); + Mockito.when(dataCenterDao.findById(zoneId)).thenReturn(zone); + Mockito.when(zone.getNetworkType()).thenReturn(DataCenter.NetworkType.Advanced); + Mockito.when(zone.getGuestNetworkCidr()).thenReturn("172.20.0.0/16"); + Mockito.when(zone.getId()).thenReturn(zoneId); + List offeringServices = Arrays.asList(Network.Service.Dns, Network.Service.Dhcp, + Network.Service.SourceNat, Network.Service.StaticNat, Network.Service.PortForwarding, + Network.Service.NetworkACL, Network.Service.Vpn); + Mockito.when(networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(offeringServices); + Mockito.when(accountDao.findById(accountId)).thenReturn(account); + Mockito.when(account.getDomainId()).thenReturn(domainId); + Mockito.when(account.getId()).thenReturn(accountId); + Mockito.when(domain.getId()).thenReturn(domainId); + Mockito.when(domainDao.findById(domainId)).thenReturn(domain); + Mockito.when(network.getAccountId()).thenReturn(accountId); + Mockito.when(network.getNetworkOfferingId()).thenReturn(networkOfferingId); + Mockito.when(network.getVpcId()).thenReturn(vpcId); + Mockito.when(network.getName()).thenReturn(networkName); + Mockito.when(network.getId()).thenReturn(networkId); + Mockito.when(network.getCidr()).thenReturn(networkCidr); + Mockito.when(network.getGateway()).thenReturn("172.20.10.1"); + Mockito.when(network.getDataCenterId()).thenReturn(zoneId); + Mockito.when(network.getPhysicalNetworkId()).thenReturn(physicalNetworkId); + Mockito.when(network.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + Mockito.when(network.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Netris); + Mockito.when(vpcDao.findById(vpcId)).thenReturn(vpc); + Mockito.when(vpc.getName()).thenReturn(vpcName); + Mockito.when(vpc.getId()).thenReturn(vpcId); + actionEventUtilsMocked = Mockito.mockStatic(ActionEventUtils.class); + Mockito.when(ActionEventUtils.onCompletedActionEvent(anyLong(), anyLong(), anyString(), anyString(), anyString(), anyLong(), anyString(), anyLong())).thenReturn(1L); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + actionEventUtilsMocked.close(); + } + + @Test + public void testCanHandleNetrisOfferingNatted() { + Assert.assertTrue(guru.canHandle(networkOffering, DataCenter.NetworkType.Advanced, physicalNetwork)); + } + + @Test + public void testCanHandleNetrisOfferingRouted() { + Mockito.when(networkOffering.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED); + Assert.assertTrue(guru.canHandle(networkOffering, DataCenter.NetworkType.Advanced, physicalNetwork)); + } + + @Test + public void testCannotHandleBasicNetwork() { + Assert.assertFalse(guru.canHandle(networkOffering, DataCenter.NetworkType.Basic, physicalNetwork)); + } + + @Test + public void testCannotHandleVlanIsolation() { + Mockito.when(physicalNetwork.getIsolationMethods()).thenReturn(List.of("vlan")); + Assert.assertFalse(guru.canHandle(networkOffering, DataCenter.NetworkType.Advanced, physicalNetwork)); + } + + @Test + public void testCannotHandleDifferentOfferingProvider() { + Mockito.when(networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingId, Network.Provider.Netris)).thenReturn(false); + Assert.assertFalse(guru.canHandle(networkOffering, DataCenter.NetworkType.Advanced, physicalNetwork)); + } + + @Test + public void testDesignNetrisNetwork() { + Network designedNetwork = guru.design(networkOffering, plan, network, networkName, 1L, account); + Assert.assertEquals(Networks.BroadcastDomainType.Netris, designedNetwork.getBroadcastDomainType()); + Assert.assertEquals(Network.State.Allocated, designedNetwork.getState()); + Assert.assertEquals(Networks.TrafficType.Guest, designedNetwork.getTrafficType()); + } + + @Test + public void testCreateNetrisVnetVpcNetworkRoutedMode() { + Mockito.when(networkOffering.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.ROUTED); + Mockito.when(netrisService.createVnetResource(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), + Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), + Mockito.anyBoolean())).thenReturn(true); + guru.createNetrisVnet(network, zone); + Mockito.verify(netrisService).createVnetResource(zoneId, accountId, domainId, vpcName, vpcId, + networkName, networkId, networkCidr, true); + } + + @Test + public void testImplementNetrisVpcNetwork() throws InsufficientVirtualNetworkCapacityException { + DeployDestination destination = Mockito.mock(DeployDestination.class); + ReservationContext context = Mockito.mock(ReservationContext.class); + String vnet = "1234"; + Mockito.when(dataCenterDao.allocateVnet(Mockito.eq(zoneId), Mockito.eq(physicalNetworkId), + Mockito.eq(accountId), Mockito.nullable(String.class), Mockito.anyBoolean())).thenReturn(vnet); + actionEventUtilsMocked.when(() -> ActionEventUtils.onCompletedActionEvent(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong())).thenReturn(1L); + Mockito.when(networkDetailsDao.findDetail(Mockito.anyLong(), Mockito.anyString())).thenReturn(null); + Network implemented = guru.implement(network, networkOffering, destination, context); + Assert.assertEquals(String.format("netris://%s", vnet), implemented.getBroadcastUri().toString()); + Assert.assertEquals(Network.State.Implemented, implemented.getState()); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisProviderServiceImplTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisProviderServiceImplTest.java new file mode 100644 index 00000000000..66684e0c54d --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisProviderServiceImplTest.java @@ -0,0 +1,220 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.host.dao.HostDetailsDao; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.dao.NetrisProviderDao; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.network.netris.NetrisService; +import com.cloud.resource.ResourceManager; +import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.response.NetrisProviderResponse; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.Arrays; +import java.util.List; + +public class NetrisProviderServiceImplTest { + + @Mock + private DataCenterDao dataCenterDao; + @Mock + private ResourceManager resourceManager; + @Mock + private NetrisProviderDao netrisProviderDao; + @Mock + private HostDetailsDao hostDetailsDao; + @Mock + private PhysicalNetworkDao physicalNetworkDao; + @Mock + private NetworkDao networkDao; + @Mock + private NetrisService netrisService; + + @InjectMocks + private NetrisProviderServiceImpl netrisProviderService; + + private AutoCloseable closeable; + private MockedStatic transactionMockedStatic; + + private static final long ZONE_ID = 1L; + private static final String NAME = "test-provider"; + private static final String HOSTNAME = "test-host"; + private static final String PORT = "8080"; + private static final String USERNAME = "test-user"; + private static final String PASSWORD = "test-password"; + private static final String SITE_NAME = "test-site"; + private static final String TENANT_NAME = "test-tenant"; + private static final String NETRIS_TAG = "test-tag"; + private static final long HOST_ID = 2L; + private static final long PROVIDER_ID = 3L; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + transactionMockedStatic = Mockito.mockStatic(Transaction.class); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + transactionMockedStatic.close(); + } + + @Test + public void testListNetrisProvidersWithZoneId() { + // Setup + NetrisProviderVO providerVO = Mockito.mock(NetrisProviderVO.class); + Mockito.when(netrisProviderDao.findByZoneId(ZONE_ID)).thenReturn(providerVO); + Mockito.when(providerVO.getZoneId()).thenReturn(ZONE_ID); + + DataCenterVO zone = Mockito.mock(DataCenterVO.class); + Mockito.when(dataCenterDao.findById(ZONE_ID)).thenReturn(zone); + Mockito.when(zone.getName()).thenReturn("test-zone"); + + // Execute + List result = netrisProviderService.listNetrisProviders(ZONE_ID); + + // Verify + Assert.assertEquals(1, result.size()); + Assert.assertTrue(result.get(0) instanceof NetrisProviderResponse); + } + + @Test + public void testListNetrisProvidersWithoutZoneId() { + // Setup + NetrisProviderVO providerVO = Mockito.mock(NetrisProviderVO.class); + Mockito.when(netrisProviderDao.listAll()).thenReturn(Arrays.asList(providerVO)); + + DataCenterVO zone = Mockito.mock(DataCenterVO.class); + Mockito.when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone); + Mockito.when(zone.getName()).thenReturn("test-zone"); + + // Execute + List result = netrisProviderService.listNetrisProviders(null); + + // Verify + Assert.assertEquals(1, result.size()); + Assert.assertTrue(result.get(0) instanceof NetrisProviderResponse); + } + + @Test + public void testDeleteNetrisProviderSuccess() { + // Setup + NetrisProviderVO providerVO = Mockito.mock(NetrisProviderVO.class); + Mockito.when(providerVO.getZoneId()).thenReturn(ZONE_ID); + Mockito.when(netrisProviderDao.findById(PROVIDER_ID)).thenReturn(providerVO); + + PhysicalNetworkVO physicalNetwork = Mockito.mock(PhysicalNetworkVO.class); + Mockito.when(physicalNetworkDao.listByZone(ZONE_ID)).thenReturn(Arrays.asList(physicalNetwork)); + + NetworkVO network = Mockito.mock(NetworkVO.class); + Mockito.when(networkDao.listByPhysicalNetwork(Mockito.anyLong())).thenReturn(Arrays.asList(network)); + Mockito.when(network.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Netris); + Mockito.when(network.getState()).thenReturn(Network.State.Shutdown); + + // Execute + boolean result = netrisProviderService.deleteNetrisProvider(PROVIDER_ID); + + // Verify + Assert.assertTrue(result); + Mockito.verify(netrisProviderDao).remove(PROVIDER_ID); + } + + @Test(expected = InvalidParameterValueException.class) + public void testDeleteNetrisProviderNotFound() { + // Setup + Mockito.when(netrisProviderDao.findById(PROVIDER_ID)).thenReturn(null); + + // Execute + netrisProviderService.deleteNetrisProvider(PROVIDER_ID); + } + + @Test(expected = CloudRuntimeException.class) + public void testDeleteNetrisProviderWithActiveNetworks() { + // Setup + NetrisProviderVO providerVO = Mockito.mock(NetrisProviderVO.class); + Mockito.when(providerVO.getZoneId()).thenReturn(ZONE_ID); + Mockito.when(netrisProviderDao.findById(PROVIDER_ID)).thenReturn(providerVO); + + PhysicalNetworkVO physicalNetwork = Mockito.mock(PhysicalNetworkVO.class); + Mockito.when(physicalNetworkDao.listByZone(ZONE_ID)).thenReturn(Arrays.asList(physicalNetwork)); + + NetworkVO network = Mockito.mock(NetworkVO.class); + Mockito.when(networkDao.listByPhysicalNetwork(Mockito.anyLong())).thenReturn(Arrays.asList(network)); + Mockito.when(network.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Netris); + Mockito.when(network.getState()).thenReturn(Network.State.Implemented); + + // Execute + netrisProviderService.deleteNetrisProvider(PROVIDER_ID); + } + + @Test + public void testCreateNetrisProviderResponse() { + // Setup + NetrisProviderVO provider = Mockito.mock(NetrisProviderVO.class); + Mockito.when(provider.getZoneId()).thenReturn(ZONE_ID); + Mockito.when(provider.getName()).thenReturn(NAME); + Mockito.when(provider.getSiteName()).thenReturn(SITE_NAME); + Mockito.when(provider.getTenantName()).thenReturn(TENANT_NAME); + Mockito.when(provider.getNetrisTag()).thenReturn(NETRIS_TAG); + + DataCenterVO zone = Mockito.mock(DataCenterVO.class); + Mockito.when(dataCenterDao.findById(ZONE_ID)).thenReturn(zone); + Mockito.when(zone.getName()).thenReturn("test-zone"); + + // Execute + NetrisProviderResponse response = netrisProviderService.createNetrisProviderResponse(provider); + + // Verify + Assert.assertNotNull(response); + Assert.assertEquals(NAME, response.getName()); + Assert.assertEquals(SITE_NAME, response.getSiteName()); + Assert.assertEquals(TENANT_NAME, response.getTenantName()); + Assert.assertEquals(NETRIS_TAG, response.getNetrisTag()); + } + + @Test(expected = CloudRuntimeException.class) + public void testCreateNetrisProviderResponseZoneNotFound() { + // Setup + NetrisProviderVO provider = Mockito.mock(NetrisProviderVO.class); + Mockito.when(provider.getZoneId()).thenReturn(ZONE_ID); + Mockito.when(dataCenterDao.findById(ZONE_ID)).thenReturn(null); + + // Execute + netrisProviderService.createNetrisProviderResponse(provider); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisPublicNetworkGuruTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisPublicNetworkGuruTest.java new file mode 100644 index 00000000000..531e343f6aa --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisPublicNetworkGuruTest.java @@ -0,0 +1,225 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.dc.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.Networks; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.vpc.VpcOfferingVO; +import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; +import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.NetworkOfferingVO; +import com.cloud.user.AccountVO; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; +import com.cloud.vm.NicProfile; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.api.ApiConstants; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.Arrays; + +public class NetrisPublicNetworkGuruTest { + + @Mock + private NetworkModel networkModel; + @Mock + private IPAddressDao ipAddressDao; + @Mock + private VpcDao vpcDao; + @Mock + private VlanDetailsDao vlanDetailsDao; + @Mock + private VpcOfferingDao vpcOfferingDao; + @Mock + private VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Mock + private NetrisService netrisService; + @Spy + @InjectMocks + private NetrisPublicNetworkGuru guru = new NetrisPublicNetworkGuru(); + + @Mock + private NetworkOfferingVO networkOffering; + @Mock + private DeploymentPlan deploymentPlan; + @Mock + private NetworkVO network; + @Mock + private AccountVO account; + @Mock + private NicProfile nicProfile; + @Mock + private VirtualMachineProfile virtualMachineProfile; + @Mock + private IPAddressVO ipAddressVpcVR; + @Mock + private IPAddressVO ipAddressVpcSourceNat; + @Mock + private VpcVO vpc; + + private AutoCloseable closeable; + + private static final long networkOfferingId = 10L; + private static final long physicalNetworkId = 2L; + private static final long zoneId = 1L; + private static final long vpcId = 12L; + private static final String vrNicIp = "10.10.10.10"; + private static final String vpcSourceNatIp = "10.10.20.20"; + + @Before + public void setup() { + closeable = MockitoAnnotations.openMocks(this); + Mockito.when(networkOffering.getId()).thenReturn(networkOfferingId); + Mockito.when(networkOffering.getTrafficType()).thenReturn(Networks.TrafficType.Public); + Mockito.when(networkOffering.isSystemOnly()).thenReturn(true); + Mockito.when(networkModel.isProviderForNetworkOffering(Network.Provider.Netris, networkOfferingId)).thenReturn(true); + Mockito.when(network.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Netris); + Mockito.when(deploymentPlan.getDataCenterId()).thenReturn(zoneId); + Mockito.when(deploymentPlan.getPhysicalNetworkId()).thenReturn(physicalNetworkId); + Mockito.when(networkOffering.isRedundantRouter()).thenReturn(false); + Mockito.when(nicProfile.getIPv4Address()).thenReturn(vrNicIp); + Mockito.when(ipAddressDao.findByIp(vrNicIp)).thenReturn(ipAddressVpcVR); + Mockito.when(ipAddressVpcVR.getVpcId()).thenReturn(vpcId); + Mockito.when(vpcDao.findById(vpcId)).thenReturn(vpc); + Mockito.when(vpc.getId()).thenReturn(vpcId); + Mockito.when(ipAddressDao.listByAssociatedVpc(vpcId, true)) + .thenReturn(Arrays.asList(ipAddressVpcVR, ipAddressVpcSourceNat)); + Ip ipMock = Mockito.mock(Ip.class); + Mockito.when(ipMock.addr()).thenReturn(vrNicIp); + Mockito.when(ipAddressVpcVR.getAddress()).thenReturn(ipMock); + Ip ipVrMock = Mockito.mock(Ip.class); + Mockito.when(ipVrMock.addr()).thenReturn(vpcSourceNatIp); + Mockito.when(ipAddressVpcSourceNat.getAddress()).thenReturn(ipVrMock); + Mockito.when(ipAddressVpcSourceNat.isSourceNat()).thenReturn(true); + Mockito.when(ipAddressVpcSourceNat.isForSystemVms()).thenReturn(false); + Mockito.when(ipAddressVpcSourceNat.getVlanId()).thenReturn(4L); + VlanDetailsVO vlanDetailsVO = Mockito.mock(VlanDetailsVO.class); + Mockito.when(vlanDetailsVO.getValue()).thenReturn("true"); + Mockito.when(vlanDetailsDao.findDetail(4L, ApiConstants.NETRIS_DETAIL_KEY)).thenReturn(vlanDetailsVO); + } + + @After + public void tearDown() throws Exception { + closeable.close(); + } + + @Test + public void testCanHandleNetrisPublic() { + Assert.assertTrue(guru.canHandle(networkOffering)); + } + + @Test + public void testCannotHandleNonNetrisPublic() { + Mockito.when(networkModel.isProviderForNetworkOffering(Network.Provider.Netris, networkOfferingId)).thenReturn(false); + Assert.assertFalse(guru.canHandle(networkOffering)); + } + + @Test + public void testCannotHandleNonPublicTraffic() { + Mockito.when(networkOffering.getTrafficType()).thenReturn(Networks.TrafficType.Guest); + Assert.assertFalse(guru.canHandle(networkOffering)); + } + + @Test + public void testDesignNetrisNetwork() { + String name = "test-network"; + long vpcId = 10L; + Network design = guru.design(networkOffering, deploymentPlan, network, name, vpcId, account); + Assert.assertEquals(Network.State.Setup, design.getState()); + Assert.assertEquals(Networks.BroadcastDomainType.Netris, design.getBroadcastDomainType()); + } + + @Test(expected = CloudRuntimeException.class) + public void testAllocateNetrisNetworkMissingIpAddress() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + Mockito.when(ipAddressDao.findByIp(vrNicIp)).thenReturn(null); + guru.allocate(network, nicProfile, virtualMachineProfile); + } + + @Test(expected = CloudRuntimeException.class) + public void testAllocateNetrisNetworkMissingVpc() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + Mockito.when(vpcDao.findById(vpcId)).thenReturn(null); + guru.allocate(network, nicProfile, virtualMachineProfile); + } + + @Test(expected = CloudRuntimeException.class) + public void testAllocateNetrisNetworkSourceNatIps() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + Mockito.when(vpcDao.findById(vpcId)).thenReturn(null); + guru.allocate(network, nicProfile, virtualMachineProfile); + } + + @Test(expected = CloudRuntimeException.class) + public void testAllocateNetrisNetworkMissingIps() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + Mockito.when(ipAddressDao.listByAssociatedVpc(vpcId, true)).thenReturn(null); + guru.allocate(network, nicProfile, virtualMachineProfile); + } + + @Test + public void testAllocateNetrisNetwork() throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + long vpcOfferingId = 20L; + long accountId = 2L; + long domainId = 8L; + long networkId = 210L; + String vpcName = "test-vpc"; + String vpcCidr = "172.20.10.1/28"; + String networkName = "vpc-tier"; + Mockito.when(vpc.getAccountId()).thenReturn(accountId); + Mockito.when(vpc.getZoneId()).thenReturn(zoneId); + Mockito.when(vpc.getDomainId()).thenReturn(domainId); + Mockito.when(vpc.getVpcOfferingId()).thenReturn(vpcOfferingId); + Mockito.when(vpc.getName()).thenReturn(vpcName); + Mockito.when(vpc.getCidr()).thenReturn(vpcCidr); + Mockito.when(network.getName()).thenReturn(networkName); + Mockito.when(network.getId()).thenReturn(networkId); + VpcOfferingVO vpcOffering = Mockito.mock(VpcOfferingVO.class); + Mockito.when(vpcOfferingDao.findById(vpcOfferingId)).thenReturn(vpcOffering); + Mockito.when(vpcOffering.getNetworkMode()).thenReturn(NetworkOffering.NetworkMode.NATTED); + Mockito.when(vpcOfferingServiceMapDao.areServicesSupportedByVpcOffering( + vpcOfferingId, new Network.Service[]{Network.Service.SourceNat})).thenReturn(true); + Mockito.when(netrisService.createVpcResource(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), + Mockito.anyLong(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyString(), + Mockito.anyBoolean())).thenReturn(true); + Mockito.when(netrisService.createSnatRule(Mockito.anyLong(), Mockito.anyLong(), Mockito.anyLong(), + Mockito.anyString(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyLong(), + Mockito.anyBoolean(), Mockito.anyString(), Mockito.anyString())).thenReturn(true); + guru.allocate(network, nicProfile, virtualMachineProfile); + Mockito.verify(netrisService).createVpcResource(zoneId, accountId, domainId, vpcId, vpcName, true, + vpcCidr, true); + Mockito.verify(netrisService).createSnatRule(zoneId, accountId, domainId, vpcName, vpcId, networkName, + networkId, true, vpcCidr, vpcSourceNatIp); + } +} diff --git a/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisServiceImplTest.java b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisServiceImplTest.java new file mode 100644 index 00000000000..807324f404a --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/service/NetrisServiceImplTest.java @@ -0,0 +1,33 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import org.junit.Assert; +import org.junit.Test; + +public class NetrisServiceImplTest { + + private NetrisServiceImpl service = new NetrisServiceImpl(); + + @Test + public void testCalculateSubnetCidrFromIpRange() { + String ipRange = "100.99.18.140-100.99.18.159"; + String expectedCidr = "100.99.18.128/27"; + String cidr = service.calculateSubnetCidrFromIpRange(ipRange); + Assert.assertEquals(expectedCidr, cidr); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/DeleteNsxControllerCmd.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/DeleteNsxControllerCmd.java index 5a3e5586400..f7bf0a11bda 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/DeleteNsxControllerCmd.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/DeleteNsxControllerCmd.java @@ -41,7 +41,8 @@ public class DeleteNsxControllerCmd extends BaseCmd { @Inject protected NsxProviderService nsxProviderService; -///////////////////////////////////////////////////// + + ///////////////////////////////////////////////////// //////////////// API parameters ///////////////////// ///////////////////////////////////////////////////// diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java index c11141db9d4..9c85c49adde 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxNetworkRule.java @@ -16,7 +16,7 @@ // under the License. package org.apache.cloudstack.resource; -import com.cloud.network.Network; +import com.cloud.network.SDNProviderNetworkRule; import java.util.List; @@ -26,140 +26,16 @@ public class NsxNetworkRule { ALLOW, DROP } - private long domainId; - private long accountId; - private long zoneId; - private Long networkResourceId; - private String networkResourceName; - private boolean isVpcResource; - private long vmId; - private long ruleId; - private String publicIp; - private String vmIp; - private String publicPort; - private String privatePort; - private String protocol; - private String algorithm; + private SDNProviderNetworkRule baseRule; private List memberList; private NsxRuleAction aclAction; - private List sourceCidrList; - private List destinationCidrList; - private Integer icmpCode; - private Integer icmpType; - private String trafficType; - private Network.Service service; - - public long getDomainId() { - return domainId; + public SDNProviderNetworkRule getBaseRule() { + return baseRule; } - public void setDomainId(long domainId) { - this.domainId = domainId; - } - - public long getAccountId() { - return accountId; - } - - public void setAccountId(long accountId) { - this.accountId = accountId; - } - - public long getZoneId() { - return zoneId; - } - - public void setZoneId(long zoneId) { - this.zoneId = zoneId; - } - - public Long getNetworkResourceId() { - return networkResourceId; - } - - public void setNetworkResourceId(Long networkResourceId) { - this.networkResourceId = networkResourceId; - } - - public String getNetworkResourceName() { - return networkResourceName; - } - - public void setNetworkResourceName(String networkResourceName) { - this.networkResourceName = networkResourceName; - } - - public boolean isVpcResource() { - return isVpcResource; - } - - public void setVpcResource(boolean vpcResource) { - isVpcResource = vpcResource; - } - - public long getVmId() { - return vmId; - } - - public void setVmId(long vmId) { - this.vmId = vmId; - } - - public long getRuleId() { - return ruleId; - } - - public void setRuleId(long ruleId) { - this.ruleId = ruleId; - } - - public String getPublicIp() { - return publicIp; - } - - public void setPublicIp(String publicIp) { - this.publicIp = publicIp; - } - - public String getVmIp() { - return vmIp; - } - - public void setVmIp(String vmIp) { - this.vmIp = vmIp; - } - - public String getPublicPort() { - return publicPort; - } - - public void setPublicPort(String publicPort) { - this.publicPort = publicPort; - } - - public String getPrivatePort() { - return privatePort; - } - - public void setPrivatePort(String privatePort) { - this.privatePort = privatePort; - } - - public String getProtocol() { - return protocol; - } - - public void setProtocol(String protocol) { - this.protocol = protocol; - } - - public void setAlgorithm(String algorithm) { - this.algorithm = algorithm; - } - - public String getAlgorithm() { - return algorithm; + public void setBaseRule(SDNProviderNetworkRule baseRule) { + this.baseRule = baseRule; } public List getMemberList() { @@ -177,221 +53,4 @@ public class NsxNetworkRule { public void setAclAction(NsxRuleAction aclAction) { this.aclAction = aclAction; } - - public Network.Service getService() { - return service; - } - - public void setService(Network.Service service) { - this.service = service; - } - - public Integer getIcmpCode() { - return icmpCode; - } - - public void setIcmpCode(Integer icmpCode) { - this.icmpCode = icmpCode; - } - - public Integer getIcmpType() { - return icmpType; - } - - public void setIcmpType(Integer icmpType) { - this.icmpType = icmpType; - } - - public List getSourceCidrList() { - return sourceCidrList; - } - - public void setSourceCidrList(List sourceCidrList) { - this.sourceCidrList = sourceCidrList; - } - - public List getDestinationCidrList() { - return destinationCidrList; - } - - public void setDestinationCidrList(List destinationCidrList) { - this.destinationCidrList = destinationCidrList; - } - - public String getTrafficType() { - return trafficType; - } - - public void setTrafficType(String trafficType) { - this.trafficType = trafficType; - } - - public static final class Builder { - private long domainId; - private long accountId; - private long zoneId; - private Long networkResourceId; - private String networkResourceName; - private boolean isVpcResource; - private long vmId; - - private long ruleId; - private String publicIp; - private String vmIp; - private String publicPort; - private String privatePort; - private String protocol; - private String algorithm; - private List memberList; - private NsxRuleAction aclAction; - private List sourceCidrList; - private List destinationidrList; - private String trafficType; - private Integer icmpType; - private Integer icmpCode; - private Network.Service service; - - public Builder() { - // Default constructor - } - - public Builder setDomainId(long domainId) { - this.domainId = domainId; - return this; - } - - public Builder setAccountId(long accountId) { - this.accountId = accountId; - return this; - } - - public Builder setZoneId(long zoneId) { - this.zoneId = zoneId; - return this; - } - - public Builder setNetworkResourceId(Long networkResourceId) { - this.networkResourceId = networkResourceId; - return this; - } - - public Builder setNetworkResourceName(String networkResourceName) { - this.networkResourceName = networkResourceName; - return this; - } - - public Builder setVpcResource(boolean isVpcResource) { - this.isVpcResource = isVpcResource; - return this; - } - - - public Builder setVmId(long vmId) { - this.vmId = vmId; - return this; - } - - public Builder setRuleId(long ruleId) { - this.ruleId = ruleId; - return this; - } - - public Builder setPublicIp(String publicIp) { - this.publicIp = publicIp; - return this; - } - - public Builder setVmIp(String vmIp) { - this.vmIp = vmIp; - return this; - } - - public Builder setPublicPort(String publicPort) { - this.publicPort = publicPort; - return this; - } - - public Builder setPrivatePort(String privatePort) { - this.privatePort = privatePort; - return this; - } - - public Builder setProtocol(String protocol) { - this.protocol = protocol; - return this; - } - - public Builder setAlgorithm(String algorithm) { - this.algorithm = algorithm; - return this; - } - - public Builder setMemberList(List memberList) { - this.memberList = memberList; - return this; - } - - - public Builder setAclAction(NsxRuleAction aclAction) { - this.aclAction = aclAction; - return this; - } - - public Builder setTrafficType(String trafficType) { - this.trafficType = trafficType; - return this; - } - - public Builder setIcmpType(Integer icmpType) { - this.icmpType = icmpType; - return this; - } - - public Builder setIcmpCode(Integer icmpCode) { - this.icmpCode = icmpCode; - return this; - } - - public Builder setSourceCidrList(List sourceCidrList) { - this.sourceCidrList = sourceCidrList; - return this; - } - - public Builder setDestinationCidrList(List destinationCidrList) { - this.destinationidrList = destinationCidrList; - return this; - } - - public Builder setService(Network.Service service) { - this.service = service; - return this; - } - - public NsxNetworkRule build() { - NsxNetworkRule rule = new NsxNetworkRule(); - rule.setDomainId(this.domainId); - rule.setAccountId(this.accountId); - rule.setZoneId(this.zoneId); - rule.setNetworkResourceId(this.networkResourceId); - rule.setNetworkResourceName(this.networkResourceName); - rule.setVpcResource(this.isVpcResource); - rule.setVmId(this.vmId); - rule.setVmIp(this.vmIp); - rule.setPublicIp(this.publicIp); - rule.setPublicPort(this.publicPort); - rule.setPrivatePort(this.privatePort); - rule.setProtocol(this.protocol); - rule.setRuleId(this.ruleId); - rule.setAlgorithm(this.algorithm); - rule.setMemberList(this.memberList); - rule.setAclAction(this.aclAction); - rule.setIcmpType(this.icmpType); - rule.setIcmpCode(this.icmpCode); - rule.setSourceCidrList(this.sourceCidrList); - rule.setDestinationCidrList(this.destinationidrList); - rule.setTrafficType(this.trafficType); - rule.setService(service); - return rule; - } - } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java index b7631f78143..7ad27c4a635 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApiClient.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.service; import com.cloud.network.Network; +import com.cloud.network.SDNProviderNetworkRule; import com.cloud.network.nsx.NsxService; import com.cloud.utils.exception.CloudRuntimeException; import com.vmware.nsx.cluster.Status; @@ -1024,7 +1025,8 @@ public class NsxApiClient { } public void deleteDistributedFirewallRules(String segmentName, List nsxRules) { - for(NsxNetworkRule rule : nsxRules) { + for(NsxNetworkRule nsxRule : nsxRules) { + SDNProviderNetworkRule rule = nsxRule.getBaseRule(); String ruleId = NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(segmentName, rule.getRuleId()); String svcName = getServiceName(ruleId, rule.getPrivatePort(), rule.getProtocol(), rule.getIcmpType(), rule.getIcmpCode()); // delete rules @@ -1042,10 +1044,11 @@ public class NsxApiClient { if (Objects.isNull(groupPath)) { throw new CloudRuntimeException(String.format("Failed to find group for segment %s", segmentName)); } - for (NsxNetworkRule rule : nsxRules) { + for (NsxNetworkRule nsxRule : nsxRules) { + SDNProviderNetworkRule rule = nsxRule.getBaseRule(); String ruleId = NsxControllerUtils.getNsxDistributedFirewallPolicyRuleId(segmentName, rule.getRuleId()); Rule ruleToAdd = new Rule.Builder() - .setAction(rule.getAclAction().toString()) + .setAction(nsxRule.getAclAction().toString()) .setId(ruleId) .setDisplayName(ruleId) .setResourceType("SecurityPolicy") @@ -1059,7 +1062,7 @@ public class NsxApiClient { return rules; } - private List getServicesListForDistributedFirewallRule(NsxNetworkRule rule, String segmentName) { + private List getServicesListForDistributedFirewallRule(SDNProviderNetworkRule rule, String segmentName) { List services = List.of("ANY"); if (!rule.getProtocol().equalsIgnoreCase("all")) { String ruleName = String.format("%s-R%s", segmentName, rule.getRuleId()); @@ -1070,7 +1073,7 @@ public class NsxApiClient { return services; } - protected List getGroupsForTraffic(NsxNetworkRule rule, + protected List getGroupsForTraffic(SDNProviderNetworkRule rule, String segmentName, boolean source) { List segmentGroup = List.of(String.format("%s/%s", GROUPS_PATH_PREFIX, segmentName)); List sourceCidrList = rule.getSourceCidrList(); diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java index 85d203f4125..0486de96dd1 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java @@ -45,6 +45,7 @@ import com.cloud.network.NetworkModel; import com.cloud.network.Networks; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.PublicIpAddress; +import com.cloud.network.SDNProviderNetworkRule; import com.cloud.network.VirtualRouterProvider; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; @@ -110,7 +111,7 @@ import org.apache.cloudstack.api.command.admin.internallb.ListInternalLoadBalanc import org.apache.cloudstack.network.element.InternalLoadBalancerElementService; import org.apache.cloudstack.resource.NsxLoadBalancerMember; import org.apache.cloudstack.resource.NsxNetworkRule; -import org.apache.cloudstack.resource.NsxOpObject; +import com.cloud.network.SDNProviderOpObject; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.cloudstack.resourcedetail.FirewallRuleDetailVO; @@ -554,12 +555,12 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns if (vm == null && rule.getState() != FirewallRule.State.Revoke) { continue; } - NsxOpObject nsxObject = getNsxOpObject(network); - String publicPort = getPublicPortRange(rule); + SDNProviderOpObject nsxObject = getNsxOpObject(network); + String publicPort = PortForwardingServiceProvider.getPublicPortRange(rule); - String privatePort = getPrivatePFPortRange(rule); + String privatePort = PortForwardingServiceProvider.getPrivatePFPortRange(rule); - NsxNetworkRule networkRule = new NsxNetworkRule.Builder() + SDNProviderNetworkRule networkRule = new SDNProviderNetworkRule.Builder() .setDomainId(nsxObject.getDomainId()) .setAccountId(nsxObject.getAccountId()) .setZoneId(nsxObject.getZoneId()) @@ -574,12 +575,16 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns .setRuleId(rule.getId()) .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)) .build(); + + NsxNetworkRule nsxNetworkRule = new NsxNetworkRule(); + nsxNetworkRule.setBaseRule(networkRule); + FirewallRuleDetailVO ruleDetail = firewallRuleDetailsDao.findDetail(rule.getId(), ApiConstants.FOR_NSX); if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(rule.getState())) { if ((ruleDetail == null && FirewallRule.State.Add == rule.getState()) || (ruleDetail != null && !ruleDetail.getValue().equalsIgnoreCase("true"))) { logger.debug("Creating port forwarding rule on NSX for VM {} to ports {} - {}", vm, rule.getDestinationPortStart(), rule.getDestinationPortEnd()); - NsxAnswer answer = nsxService.createPortForwardRule(networkRule); + NsxAnswer answer = nsxService.createPortForwardRule(nsxNetworkRule); boolean pfRuleResult = answer.getResult(); if (pfRuleResult && !answer.isObjectExistent()) { logger.debug("Port forwarding rule {} created on NSX, adding detail on firewall rules details", rule); @@ -596,7 +601,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns } } else if (rule.getState() == FirewallRule.State.Revoke) { if (ruleDetail == null || (ruleDetail != null && ruleDetail.getValue().equalsIgnoreCase("true"))) { - boolean pfRuleResult = nsxService.deletePortForwardRule(networkRule); + boolean pfRuleResult = nsxService.deletePortForwardRule(nsxNetworkRule); if (pfRuleResult && ruleDetail != null) { logger.debug("Updating firewall rule detail {} () for rule {}, set to false", ruleDetail.getId(), ruleDetail.getName(), rule); ruleDetail.setValue("false"); @@ -635,30 +640,6 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns return new Pair<>(vpc, network); } - private static String getPublicPortRange(PortForwardingRule rule) { - return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? - String.valueOf(rule.getSourcePortStart()) : - String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); - } - - private static String getPrivatePFPortRange(PortForwardingRule rule) { - return rule.getDestinationPortStart() == rule.getDestinationPortEnd() ? - String.valueOf(rule.getDestinationPortStart()) : - String.valueOf(rule.getDestinationPortStart()).concat("-").concat(String.valueOf(rule.getDestinationPortEnd())); - } - - private static String getPrivatePortRange(FirewallRule rule) { - return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? - String.valueOf(rule.getSourcePortStart()) : - String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); - } - - private static String getPrivatePortRangeForACLRule(NetworkACLItem rule) { - return Objects.equals(rule.getSourcePortStart(), rule.getSourcePortEnd()) ? - String.valueOf(rule.getSourcePortStart()) : - String.valueOf(rule.getSourcePortStart()).concat("-").concat(String.valueOf(rule.getSourcePortEnd())); - } - private long getResourceId(String resource, VpcVO vpc, NetworkVO network) { switch (resource) { case "domain": @@ -672,7 +653,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns } } - private NsxOpObject getNsxOpObject(Network network) { + private SDNProviderOpObject getNsxOpObject(Network network) { Pair vpcOrNetwork = getVpcOrNetwork(network.getVpcId(), network.getId()); VpcVO vpc = vpcOrNetwork.first(); NetworkVO networkVO = vpcOrNetwork.second(); @@ -680,7 +661,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns long accountId = getResourceId("account", vpc, networkVO); long zoneId = getResourceId("zone", vpc, networkVO); - return new NsxOpObject.Builder() + return new SDNProviderOpObject.Builder() .vpcVO(vpc) .networkVO(networkVO) .domainId(domainId) @@ -695,25 +676,27 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns for (LoadBalancingRule loadBalancingRule : rules) { IPAddressVO publicIp = ipAddressDao.findByIpAndDcId(network.getDataCenterId(), loadBalancingRule.getSourceIp().addr()); - NsxOpObject nsxObject = getNsxOpObject(network); + SDNProviderOpObject nsxObject = getNsxOpObject(network); List lbMembers = getLoadBalancerMembers(loadBalancingRule); - NsxNetworkRule networkRule = new NsxNetworkRule.Builder() - .setDomainId(nsxObject.getDomainId()) - .setAccountId(nsxObject.getAccountId()) - .setZoneId(nsxObject.getZoneId()) - .setNetworkResourceId(nsxObject.getNetworkResourceId()) - .setNetworkResourceName(nsxObject.getNetworkResourceName()) - .setVpcResource(nsxObject.isVpcResource()) - .setMemberList(lbMembers) - .setPublicIp(LoadBalancerContainer.Scheme.Public == loadBalancingRule.getScheme() ? + SDNProviderNetworkRule baseNetRule = new SDNProviderNetworkRule.Builder() + .setDomainId(nsxObject.getDomainId()) + .setAccountId(nsxObject.getAccountId()) + .setZoneId(nsxObject.getZoneId()) + .setNetworkResourceId(nsxObject.getNetworkResourceId()) + .setNetworkResourceName(nsxObject.getNetworkResourceName()) + .setVpcResource(nsxObject.isVpcResource()) + .setPublicIp(LoadBalancerContainer.Scheme.Public == loadBalancingRule.getScheme() ? publicIp.getAddress().addr() : loadBalancingRule.getSourceIp().addr()) - .setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart())) - .setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart())) - .setRuleId(loadBalancingRule.getId()) - .setProtocol(loadBalancingRule.getLbProtocol().toUpperCase(Locale.ROOT)) - .setAlgorithm(loadBalancingRule.getAlgorithm()) + .setPublicPort(String.valueOf(loadBalancingRule.getSourcePortStart())) + .setPrivatePort(String.valueOf(loadBalancingRule.getDefaultPortStart())) + .setRuleId(loadBalancingRule.getId()) + .setProtocol(loadBalancingRule.getLbProtocol().toUpperCase(Locale.ROOT)) + .setAlgorithm(loadBalancingRule.getAlgorithm()) .build(); + NsxNetworkRule networkRule = new NsxNetworkRule(); + networkRule.setBaseRule(baseNetRule); + networkRule.setMemberList(lbMembers); if (Arrays.asList(FirewallRule.State.Add, FirewallRule.State.Active).contains(loadBalancingRule.getState())) { result &= nsxService.createLbRule(networkRule); } else if (loadBalancingRule.getState() == FirewallRule.State.Revoke) { @@ -758,7 +741,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns List nsxDelNetworkRules = new ArrayList<>(); boolean success = true; for (NetworkACLItem rule : rules) { - String privatePort = getPrivatePortRangeForACLRule(rule); + String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule); NsxNetworkRule networkRule = getNsxNetworkRuleForAcl(rule, privatePort); if (Arrays.asList(NetworkACLItem.State.Active, NetworkACLItem.State.Add).contains(rule.getState())) { success = success && nsxService.addFirewallRules(network, List.of(networkRule)); @@ -780,7 +763,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns public boolean reorderAclRules(Vpc vpc, List networks, List networkACLItems) { List aclRulesList = new ArrayList<>(); for (NetworkACLItem rule : networkACLItems) { - String privatePort = getPrivatePortRangeForACLRule(rule); + String privatePort = PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule); aclRulesList.add(getNsxNetworkRuleForAcl(rule, privatePort)); } for (Network network: networks) { @@ -796,18 +779,20 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns } private NsxNetworkRule getNsxNetworkRuleForAcl(NetworkACLItem rule, String privatePort) { - return new NsxNetworkRule.Builder() - .setRuleId(rule.getId()) - .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) - .setAclAction(transformActionValue(rule.getAction())) - .setTrafficType(rule.getTrafficType().toString()) - .setProtocol(rule.getProtocol().toUpperCase()) - .setPublicPort(String.valueOf(rule.getSourcePortStart())) - .setPrivatePort(privatePort) - .setIcmpCode(rule.getIcmpCode()) - .setIcmpType(rule.getIcmpType()) - .setService(Network.Service.NetworkACL) - .build(); + NsxNetworkRule nsxNetworkRule = new NsxNetworkRule(); + SDNProviderNetworkRule networkRule = new SDNProviderNetworkRule.Builder() + .setRuleId(rule.getId()) + .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) + .setTrafficType(rule.getTrafficType().toString()) + .setProtocol(rule.getProtocol().toUpperCase()) + .setPublicPort(String.valueOf(rule.getSourcePortStart())) + .setPrivatePort(privatePort) + .setIcmpCode(rule.getIcmpCode()) + .setIcmpType(rule.getIcmpType()) + .setService(Network.Service.NetworkACL).build(); + nsxNetworkRule.setBaseRule(networkRule); + nsxNetworkRule.setAclAction(transformActionValue(rule.getAction())); + return nsxNetworkRule; } @Override public boolean applyFWRules(Network network, List rules) throws ResourceUnavailableException { @@ -818,20 +803,21 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, Dns List nsxAddNetworkRules = new ArrayList<>(); List nsxDelNetworkRules = new ArrayList<>(); for (FirewallRule rule : rules) { - NsxNetworkRule networkRule = new NsxNetworkRule.Builder() - .setRuleId(rule.getId()) - .setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW) - .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? - transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) - .setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList()) ? - transformCidrListValues(rule.getDestinationCidrList()) : List.of("ANY")) - .setIcmpCode(rule.getIcmpCode()) - .setIcmpType(rule.getIcmpType()) - .setPrivatePort(getPrivatePortRange(rule)) - .setTrafficType(rule.getTrafficType().toString()) - .setService(Network.Service.Firewall) - .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)) - .build(); + NsxNetworkRule networkRule = new NsxNetworkRule(); + SDNProviderNetworkRule baseNetRule = new SDNProviderNetworkRule.Builder() + .setRuleId(rule.getId()) + .setSourceCidrList(Objects.nonNull(rule.getSourceCidrList()) ? + transformCidrListValues(rule.getSourceCidrList()) : List.of("ANY")) + .setDestinationCidrList(Objects.nonNull(rule.getDestinationCidrList()) ? + transformCidrListValues(rule.getDestinationCidrList()) : List.of("ANY")) + .setIcmpCode(rule.getIcmpCode()) + .setIcmpType(rule.getIcmpType()) + .setPrivatePort(PortForwardingServiceProvider.getPrivatePortRange(rule)) + .setTrafficType(rule.getTrafficType().toString()) + .setService(Network.Service.Firewall) + .setProtocol(rule.getProtocol().toUpperCase(Locale.ROOT)).build(); + networkRule.setBaseRule(baseNetRule); + networkRule.setAclAction(NsxNetworkRule.NsxRuleAction.ALLOW); if (rule.getState() == FirewallRule.State.Add) { nsxAddNetworkRules.add(networkRule); } else if (rule.getState() == FirewallRule.State.Revoke) { diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java index 0ab622c1808..0f7865d7d73 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java @@ -23,7 +23,6 @@ import com.cloud.dc.DataCenter; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.domain.DomainVO; -import com.cloud.domain.dao.DomainDao; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.exception.InvalidParameterValueException; @@ -40,9 +39,7 @@ import com.cloud.network.guru.GuestNetworkGuru; import com.cloud.network.vpc.VpcVO; import com.cloud.offering.NetworkOffering; import com.cloud.offerings.NetworkOfferingVO; -import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.Account; -import com.cloud.user.dao.AccountDao; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; @@ -67,15 +64,9 @@ import java.util.Objects; public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigrationResponder { protected Logger logger = LogManager.getLogger(getClass()); - @Inject - NetworkOfferingServiceMapDao networkOfferingServiceMapDao; @Inject NsxControllerUtils nsxControllerUtils; @Inject - AccountDao accountDao; - @Inject - DomainDao domainDao; - @Inject NetworkModel networkModel; public NsxGuestNetworkGuru() { diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java index c7931b46c82..9c631ac9a6d 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxPublicNetworkGuru.java @@ -17,7 +17,6 @@ package org.apache.cloudstack.service; import com.cloud.dc.VlanDetailsVO; -import com.cloud.dc.dao.VlanDetailsDao; import com.cloud.deploy.DeploymentPlan; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; @@ -31,11 +30,7 @@ import com.cloud.network.guru.PublicNetworkGuru; import com.cloud.network.vpc.VpcOffering; import com.cloud.network.vpc.VpcOfferingVO; import com.cloud.network.vpc.VpcVO; -import com.cloud.network.vpc.dao.VpcDao; -import com.cloud.network.vpc.dao.VpcOfferingDao; -import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.offering.NetworkOffering; -import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.user.Account; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.NicProfile; @@ -55,20 +50,10 @@ import java.util.stream.Collectors; public class NsxPublicNetworkGuru extends PublicNetworkGuru { - @Inject - private VlanDetailsDao vlanDetailsDao; - @Inject - private VpcDao vpcDao; - @Inject - private VpcOfferingServiceMapDao vpcOfferingServiceMapDao; @Inject private NsxControllerUtils nsxControllerUtils; @Inject private NsxService nsxService; - @Inject - private VpcOfferingDao vpcOfferingDao; - @Inject - private NetworkOfferingDao offeringDao; protected Logger logger = LogManager.getLogger(getClass()); @@ -78,7 +63,8 @@ public class NsxPublicNetworkGuru extends PublicNetworkGuru { @Override protected boolean canHandle(NetworkOffering offering) { - return isMyTrafficType(offering.getTrafficType()) && offering.isSystemOnly() && offering.isForNsx(); + boolean isForNsx = networkModel.isProviderForNetworkOffering(Network.Provider.Nsx, offering.getId()); + return isMyTrafficType(offering.getTrafficType()) && offering.isSystemOnly() && isForNsx; } @Override diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java index 64a2514fc51..427ad4cbfed 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java @@ -18,6 +18,7 @@ package org.apache.cloudstack.service; import com.cloud.network.IpAddress; import com.cloud.network.Network; +import com.cloud.network.SDNProviderNetworkRule; import com.cloud.network.nsx.NsxService; import com.cloud.network.dao.NetworkVO; import com.cloud.network.vpc.Vpc; @@ -138,7 +139,8 @@ public class NsxServiceImpl implements NsxService, Configurable { return result.getResult(); } - public NsxAnswer createPortForwardRule(NsxNetworkRule netRule) { + public NsxAnswer createPortForwardRule(NsxNetworkRule nsxNetRule) { + SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule(); // TODO: if port doesn't exist in default list of services, create a service entry CreateNsxPortForwardRuleCommand createPortForwardCmd = new CreateNsxPortForwardRuleCommand(netRule.getDomainId(), netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), @@ -147,7 +149,8 @@ public class NsxServiceImpl implements NsxService, Configurable { return nsxControllerUtils.sendNsxCommand(createPortForwardCmd, netRule.getZoneId()); } - public boolean deletePortForwardRule(NsxNetworkRule netRule) { + public boolean deletePortForwardRule(NsxNetworkRule nsxNetRule) { + SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule(); DeleteNsxNatRuleCommand deleteCmd = new DeleteNsxNatRuleCommand(netRule.getDomainId(), netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getVmId(), netRule.getRuleId(), netRule.getPrivatePort(), netRule.getProtocol()); @@ -156,20 +159,22 @@ public class NsxServiceImpl implements NsxService, Configurable { return result.getResult(); } - public boolean createLbRule(NsxNetworkRule netRule) { + public boolean createLbRule(NsxNetworkRule nsxNetRule) { + SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule(); CreateNsxLoadBalancerRuleCommand command = new CreateNsxLoadBalancerRuleCommand(netRule.getDomainId(), netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), - netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getMemberList(), netRule.getRuleId(), + netRule.getNetworkResourceName(), netRule.isVpcResource(), nsxNetRule.getMemberList(), netRule.getRuleId(), netRule.getPublicPort(), netRule.getPrivatePort(), netRule.getAlgorithm(), netRule.getProtocol()); command.setPublicIp(netRule.getPublicIp()); NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId()); return result.getResult(); } - public boolean deleteLbRule(NsxNetworkRule netRule) { + public boolean deleteLbRule(NsxNetworkRule nsxNetRule) { + SDNProviderNetworkRule netRule = nsxNetRule.getBaseRule(); DeleteNsxLoadBalancerRuleCommand command = new DeleteNsxLoadBalancerRuleCommand(netRule.getDomainId(), netRule.getAccountId(), netRule.getZoneId(), netRule.getNetworkResourceId(), - netRule.getNetworkResourceName(), netRule.isVpcResource(), netRule.getMemberList(), netRule.getRuleId(), + netRule.getNetworkResourceName(), netRule.isVpcResource(), nsxNetRule.getMemberList(), netRule.getRuleId(), netRule.getVmId()); NsxAnswer result = nsxControllerUtils.sendNsxCommand(command, netRule.getZoneId()); return result.getResult(); diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java index fbcca86a28b..f9ee8daea4b 100644 --- a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxApiClientTest.java @@ -17,6 +17,7 @@ package org.apache.cloudstack.service; import com.cloud.network.Network; +import com.cloud.network.SDNProviderNetworkRule; import com.vmware.nsx.cluster.Status; import com.vmware.nsx.model.ClusterStatus; import com.vmware.nsx.model.ControllerClusterStatus; @@ -24,7 +25,6 @@ import com.vmware.nsx_policy.infra.domains.Groups; import com.vmware.nsx_policy.model.Group; import com.vmware.nsx_policy.model.PathExpression; import com.vmware.vapi.bindings.Service; -import org.apache.cloudstack.resource.NsxNetworkRule; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -73,7 +73,7 @@ public class NsxApiClientTest { @Test public void testGetGroupsForTrafficIngress() { - NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class); + SDNProviderNetworkRule rule = Mockito.mock(SDNProviderNetworkRule.class); Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY")); Mockito.when(rule.getTrafficType()).thenReturn("Ingress"); Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL); @@ -86,7 +86,7 @@ public class NsxApiClientTest { @Test public void testGetGroupsForTrafficEgress() { - NsxNetworkRule rule = Mockito.mock(NsxNetworkRule.class); + SDNProviderNetworkRule rule = Mockito.mock(SDNProviderNetworkRule.class); Mockito.when(rule.getSourceCidrList()).thenReturn(List.of("ANY")); Mockito.when(rule.getTrafficType()).thenReturn("Egress"); Mockito.when(rule.getService()).thenReturn(Network.Service.NetworkACL); diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java index 7c44a7324fb..a807155a2dc 100644 --- a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxElementTest.java @@ -36,6 +36,7 @@ import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.element.PortForwardingServiceProvider; import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.rules.FirewallRule; import com.cloud.network.rules.FirewallRuleVO; @@ -72,7 +73,6 @@ import org.mockito.junit.MockitoJUnitRunner; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.List; import static org.junit.Assert.assertTrue; @@ -307,84 +307,60 @@ public class NsxElementTest { assertNotNull(vpcNetworkPair.second()); } - private Method getPublicPortRangeMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPublicPortRange", PortForwardingRule.class); - method.setAccessible(true); - return method; - } - - private Method getPrivatePFPortRangeMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPrivatePFPortRange", PortForwardingRule.class); - method.setAccessible(true); - return method; - } - - private Method getPrivatePortRangeMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPrivatePortRange", FirewallRule.class); - method.setAccessible(true); - return method; - } - - private Method getPrivatePortRangeForACLRuleMethod() throws NoSuchMethodException { - Method method = NsxElement.class.getDeclaredMethod("getPrivatePortRangeForACLRule", NetworkACLItem.class); - method.setAccessible(true); - return method; - } - @Test public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, 5L, 2L, 15L); - assertEquals("80-90", getPublicPortRangeMethod().invoke(null, rule)); + assertEquals("80-90", PortForwardingServiceProvider.getPublicPortRange(rule)); } @Test public void testGetPublicPortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L, 5L, 2L, 15L); - assertEquals("80", getPublicPortRangeMethod().invoke(null, rule)); + assertEquals("80", PortForwardingServiceProvider.getPublicPortRange(rule)); } @Test public void testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 90, new Ip("172.30.10.11"), 8080, 8090, "tcp", 12L, 5L, 2L, 15L); - assertEquals("8080-8090", getPrivatePFPortRangeMethod().invoke(null, rule)); + assertEquals("8080-8090", PortForwardingServiceProvider.getPrivatePFPortRange(rule)); } @Test public void testGetPrivatePFPortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { PortForwardingRule rule = new PortForwardingRuleVO("1", 11L, 80, 80, new Ip("172.30.10.11"), 8080, 8080, "tcp", 12L, 5L, 2L, 15L); - assertEquals("8080", getPrivatePFPortRangeMethod().invoke(null, rule)); + assertEquals("8080", PortForwardingServiceProvider.getPrivatePFPortRange(rule)); } @Test public void testGetPrivatePortRangeWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 80, "tcp", 23L, 5L, 2L, FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); - assertEquals("80", getPrivatePortRangeMethod().invoke(null, rule)); + assertEquals("80", PortForwardingServiceProvider.getPrivatePortRange(rule)); } @Test public void testGetPrivatePortRangeWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { FirewallRuleVO rule = new FirewallRuleVO("1", 11L, 80, 90, "tcp", 23L, 5L, 2L, FirewallRule.Purpose.Firewall, List.of("172.30.10.0/24"), null, null, null, null, FirewallRule.TrafficType.Egress, FirewallRule.FirewallRuleType.User); - assertEquals("80-90", getPrivatePortRangeMethod().invoke(null, rule)); + assertEquals("80-90", PortForwardingServiceProvider.getPrivatePortRange(rule)); } @Test public void testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreSame() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { NetworkACLItem rule = new NetworkACLItemVO(80, 80, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, 2, null); - assertEquals("80", getPrivatePortRangeForACLRuleMethod().invoke(null, rule)); + assertEquals("80", PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule)); } @Test public void testGetPrivatePortRangeForACLWhenStartAndEndPortNumbersAreDifferent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { NetworkACLItem rule = new NetworkACLItemVO(80, 90, "udp", 10L, List.of("172.30.10.0/24"), null, null, NetworkACLItem.TrafficType.Ingress, NetworkACLItem.Action.Allow, 2, null); - assertEquals("80-90", getPrivatePortRangeForACLRuleMethod().invoke(null, rule)); + assertEquals("80-90", PortForwardingServiceProvider.getPrivatePortRangeForACLRule(rule)); } @Test diff --git a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxPublicNetworkGuruTest.java b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxPublicNetworkGuruTest.java index 1abef392345..ae3f3f3ecd5 100644 --- a/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxPublicNetworkGuruTest.java +++ b/plugins/network-elements/nsx/src/test/java/org/apache/cloudstack/service/NsxPublicNetworkGuruTest.java @@ -22,10 +22,10 @@ import com.cloud.deploy.DeploymentPlan; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.network.Network; +import com.cloud.network.NetworkModel; import com.cloud.network.Networks; import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; -import com.cloud.network.guru.PublicNetworkGuru; import com.cloud.network.vpc.VpcOfferingVO; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.VpcDao; @@ -56,6 +56,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.times; @@ -80,23 +81,26 @@ public class NsxPublicNetworkGuruTest { VpcOfferingDao vpcOfferingDao; @Mock NsxControllerUtils nsxControllerUtils; + @Mock + NetworkModel networkModel; @Before public void setup() { guru = new NsxPublicNetworkGuru(); - ReflectionTestUtils.setField((PublicNetworkGuru) guru, "_ipAddressDao", ipAddressDao); + ReflectionTestUtils.setField(guru, "_ipAddressDao", ipAddressDao); ReflectionTestUtils.setField(guru, "vpcDao", vpcDao); ReflectionTestUtils.setField(guru, "vlanDetailsDao", vlanDetailsDao); ReflectionTestUtils.setField(guru, "vpcOfferingServiceMapDao", vpcOfferingServiceMapDao); ReflectionTestUtils.setField(guru, "nsxService", nsxService); ReflectionTestUtils.setField(guru, "vpcOfferingDao", vpcOfferingDao); ReflectionTestUtils.setField(guru, "nsxControllerUtils", nsxControllerUtils); + ReflectionTestUtils.setField(guru, "networkModel", networkModel); offering = Mockito.mock(NetworkOffering.class); when(offering.getTrafficType()).thenReturn(Networks.TrafficType.Public); - when(offering.isForNsx()).thenReturn(true); when(offering.isSystemOnly()).thenReturn(true); + when(networkModel.isProviderForNetworkOffering(eq(Network.Provider.Nsx), anyLong())).thenReturn(true); } @Test diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmd.java index d4ee924858e..efb564e35bc 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmd.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ConfigTungstenFabricServiceCmd.java @@ -165,7 +165,6 @@ public class ConfigTungstenFabricServiceCmd extends BaseCmd { "Default offering for Tungsten-Fabric Network", Networks.TrafficType.Guest, false, false, null, null, true, NetworkOffering.Availability.Optional, null, Network.GuestType.Isolated, false, false, false, false, true, false); - networkOfferingVO.setForTungsten(true); networkOfferingVO.setState(NetworkOffering.State.Enabled); networkOfferingDao.persist(networkOfferingVO); diff --git a/plugins/pom.xml b/plugins/pom.xml index 3b84ba072a4..0471e5a3228 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -232,6 +232,7 @@ hypervisors/vmware network-elements/cisco-vnmc network-elements/nsx + network-elements/netris network-elements/juniper-contrail network-elements/tungsten diff --git a/pom.xml b/pom.xml index 663e2cdf0fa..06e9969a160 100644 --- a/pom.xml +++ b/pom.xml @@ -140,7 +140,7 @@ 3.0.2 1.42.3 2.4.17 - 1.7.2 + 2.10.1 31.1-jre 4.5.14 4.4.16 diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 15d8c7309d4..a8c0991b7dc 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -39,6 +39,18 @@ import java.util.stream.Collectors; import javax.inject.Inject; +import com.cloud.bgp.ASNumber; +import com.cloud.bgp.ASNumberRange; +import com.cloud.configuration.ConfigurationService; +import com.cloud.dc.ASNumberRangeVO; +import com.cloud.dc.ASNumberVO; +import com.cloud.dc.VlanDetailsVO; +import com.cloud.dc.dao.ASNumberDao; +import com.cloud.dc.dao.ASNumberRangeDao; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.network.vpc.VpcGateway; +import com.cloud.storage.BucketVO; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.affinity.AffinityGroup; @@ -264,8 +276,6 @@ import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.api.query.vo.VolumeJoinVO; import com.cloud.api.query.vo.VpcOfferingJoinVO; import com.cloud.api.response.ApiResponseSerializer; -import com.cloud.bgp.ASNumber; -import com.cloud.bgp.ASNumberRange; import com.cloud.capacity.Capacity; import com.cloud.capacity.CapacityVO; import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity; @@ -274,8 +284,6 @@ import com.cloud.configuration.Resource.ResourceOwnerType; import com.cloud.configuration.Resource.ResourceType; import com.cloud.configuration.ResourceCount; import com.cloud.configuration.ResourceLimit; -import com.cloud.dc.ASNumberRangeVO; -import com.cloud.dc.ASNumberVO; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; @@ -286,11 +294,7 @@ import com.cloud.dc.Pod; import com.cloud.dc.StorageNetworkIpRange; import com.cloud.dc.Vlan; import com.cloud.dc.Vlan.VlanType; -import com.cloud.dc.VlanDetailsVO; import com.cloud.dc.VlanVO; -import com.cloud.dc.dao.ASNumberDao; -import com.cloud.dc.dao.ASNumberRangeDao; -import com.cloud.dc.dao.VlanDetailsDao; import com.cloud.domain.Domain; import com.cloud.domain.DomainVO; import com.cloud.event.Event; @@ -300,7 +304,6 @@ import com.cloud.gpu.GPU; import com.cloud.host.ControlState; import com.cloud.host.Host; import com.cloud.host.HostVO; -import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.HypervisorCapabilities; import com.cloud.network.GuestVlan; import com.cloud.network.GuestVlanRange; @@ -385,7 +388,6 @@ import com.cloud.server.ResourceIconManager; import com.cloud.server.ResourceTag; import com.cloud.server.ResourceTag.ResourceObjectType; import com.cloud.service.ServiceOfferingVO; -import com.cloud.storage.BucketVO; import com.cloud.storage.DataStoreRole; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.GuestOS; @@ -1004,8 +1006,7 @@ public class ApiResponseHelper implements ResponseGenerator { } } vlanResponse.setForSystemVms(isForSystemVms(vlan.getId())); - VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(vlan.getId(), ApiConstants.NSX_DETAIL_KEY); - vlanResponse.setForNsx(Objects.nonNull(vlanDetail) && vlanDetail.getValue().equals("true")); + vlanResponse.setProvider(getProviderFromVlanDetailKey(vlan)); vlanResponse.setObjectName("vlan"); return vlanResponse; } catch (InstantiationException | IllegalAccessException e) { @@ -1013,6 +1014,15 @@ public class ApiResponseHelper implements ResponseGenerator { } } + private String getProviderFromVlanDetailKey(Vlan vlan) { + for (Map.Entry entry : ConfigurationService.ProviderDetailKeyMap.entrySet()) { + VlanDetailsVO vlanDetail = vlanDetailsDao.findDetail(vlan.getId(), entry.getValue()); + if (Objects.nonNull(vlanDetail) && "true".equals(vlanDetail.getValue())) { + return entry.getKey(); + } + } + return null; + } /** * Return true if vlan IP range is dedicated for system vms (SSVM and CPVM), false if not * @param vlanId vlan id @@ -1034,6 +1044,9 @@ public class ApiResponseHelper implements ResponseGenerator { addSystemVmInfoToIpResponse(nic, response); } } + if (ipAddress.isForRouter()) { + response.setVirtualMachineType(Type.DomainRouter.toString()); + } if (ipAddress.getAssociatedWithVmId() != null) { addUserVmDetailsInIpResponse(response, ipAddress); } @@ -1060,12 +1073,25 @@ public class ApiResponseHelper implements ResponseGenerator { } private void addUserVmDetailsInIpResponse(IPAddressResponse response, IpAddress ipAddress) { - UserVm userVm = ApiDBUtils.findUserVmById(ipAddress.getAssociatedWithVmId()); - if (userVm != null) { - response.setVirtualMachineId(userVm.getUuid()); - response.setVirtualMachineName(userVm.getHostName()); - response.setVirtualMachineType(userVm.getType().toString()); - response.setVirtualMachineDisplayName(ObjectUtils.firstNonNull(userVm.getDisplayName(), userVm.getHostName())); + VirtualMachine vm = ApiDBUtils.findVMInstanceById(ipAddress.getAssociatedWithVmId()); + if (vm == null) { + return; + } + if (vm.getType().equals(Type.User)) { + UserVm userVm = ApiDBUtils.findUserVmById(ipAddress.getAssociatedWithVmId()); + if (userVm != null) { + response.setVirtualMachineId(userVm.getUuid()); + response.setVirtualMachineName(userVm.getHostName()); + response.setVirtualMachineType(userVm.getType().toString()); + response.setVirtualMachineDisplayName(ObjectUtils.firstNonNull(userVm.getDisplayName(), userVm.getHostName())); + } + } else if (vm.getType().equals(Type.DomainRouter)) { + final boolean isAdmin = Account.Type.ADMIN.equals(CallContext.current().getCallingAccount().getType()); + if (isAdmin) { + response.setVirtualMachineId(vm.getUuid()); + response.setVirtualMachineName(vm.getHostName()); + } + response.setVirtualMachineType(vm.getType().toString()); } } @@ -1166,6 +1192,9 @@ public class ApiResponseHelper implements ResponseGenerator { ipResponse.setPortable(ipAddr.isPortable()); ipResponse.setForSystemVms(ipAddr.isForSystemVms()); + if (Objects.nonNull(getProviderFromVlanDetailKey(vlan))) { + ipResponse.setForProvider(true); + } //set tag information List tags = ApiDBUtils.listByResourceTypeAndId(ResourceObjectType.PublicIpAddress, ipAddr.getId()); @@ -1229,6 +1258,13 @@ public class ApiResponseHelper implements ResponseGenerator { ipResponse.setVirtualMachineDisplayName(vm.getHostName()); } } + } else if (nic.getVmType() == Type.DomainRouter) { + VirtualMachine vm = ApiDBUtils.findVMInstanceById(nic.getInstanceId()); + if (vm != null) { + ipResponse.setVirtualMachineId(vm.getUuid()); + ipResponse.setVirtualMachineName(vm.getHostName()); + ipResponse.setVirtualMachineType(vm.getType().toString()); + } } else if (nic.getVmType().isUsedBySystem()) { ipResponse.setIsSystem(true); addSystemVmInfoToIpResponse(nic, ipResponse); @@ -2446,8 +2482,8 @@ public class ApiResponseHelper implements ResponseGenerator { serviceResponses.add(svcRsp); } response.setForVpc(_configMgr.isOfferingForVpc(offering)); - response.setForTungsten(offering.isForTungsten()); - response.setForNsx(offering.isForNsx()); + response.setForTungsten(_ntwkModel.isProviderForNetworkOffering(Provider.Tungsten, offering.getId())); + response.setForNsx(_ntwkModel.isProviderForNetworkOffering(Provider.Nsx, offering.getId())); if (offering.getNetworkMode() != null) { response.setNetworkMode(offering.getNetworkMode().name()); } @@ -3177,12 +3213,6 @@ public class ApiResponseHelper implements ResponseGenerator { List serviceProviders = ApiDBUtils.getProvidersForService(service); List serviceProvidersResponses = new ArrayList(); for (Network.Provider serviceProvider : serviceProviders) { - // return only Virtual Router/JuniperSRX/CiscoVnmc as a provider for the firewall - if (service == Service.Firewall - && !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.CiscoVnmc || serviceProvider == Provider.PaloAlto || serviceProvider == Provider.BigSwitchBcf || serviceProvider == Provider.Tungsten)) { - continue; - } - ProviderResponse serviceProviderResponse = createServiceProviderResponse(serviceProvider); serviceProvidersResponses.add(serviceProviderResponse); } @@ -3793,6 +3823,16 @@ public class ApiResponseHelper implements ResponseGenerator { response.setVpcId(vpc.getUuid()); } } + if (result.getVpcGatewayId() != null) { + VpcGateway vpcGateway = _entityMgr.findById(VpcGateway.class, result.getVpcGatewayId()); + if (vpcGateway != null) { + response.setVpcGatewayId(vpcGateway.getUuid()); + response.setVpcGatewayIp(vpcGateway.getIp4Address()); + } + } + if (result.getNextHop() != null) { + response.setNextHop(result.getNextHop()); + } response.setCidr(result.getCidr()); StaticRoute.State state = result.getState(); diff --git a/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java index b311beeb0cc..a3177594e7f 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DataCenterJoinDaoImpl.java @@ -25,7 +25,10 @@ import javax.inject.Inject; import com.cloud.cpu.CPU; import com.cloud.dc.ASNumberRangeVO; import com.cloud.dc.dao.ASNumberRangeDao; +import com.cloud.network.Network; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NetrisProviderVO; import com.cloud.network.element.NsxProviderVO; import org.apache.cloudstack.annotation.AnnotationService; import org.apache.cloudstack.annotation.dao.AnnotationDao; @@ -63,6 +66,8 @@ public class DataCenterJoinDaoImpl extends GenericDaoBase clusterArchs = ApiDBUtils.listZoneClustersArchs(dataCenter.getId()); zoneResponse.setMultiArch(CollectionUtils.isNotEmpty(clusterArchs) && clusterArchs.size() > 1); @@ -165,6 +167,19 @@ public class DataCenterJoinDaoImpl extends GenericDaoBase sc = dofIdSearch.create(); diff --git a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java index afa5c206f0f..7ea4b7d5834 100644 --- a/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/VpcOfferingJoinDaoImpl.java @@ -19,6 +19,8 @@ package com.cloud.api.query.dao; import java.util.List; +import com.cloud.network.Network; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import org.apache.cloudstack.api.response.VpcOfferingResponse; import org.apache.commons.lang3.StringUtils; @@ -29,8 +31,13 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.net.NetUtils; +import javax.inject.Inject; + public class VpcOfferingJoinDaoImpl extends GenericDaoBase implements VpcOfferingJoinDao { + @Inject + private VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + private SearchBuilder sofIdSearch; protected VpcOfferingJoinDaoImpl() { @@ -76,7 +83,7 @@ public class VpcOfferingJoinDaoImpl extends GenericDaoBase netrisServiceProvider; + @Inject VMLeaseManager vmLeaseManager; // FIXME - why don't we have interface for DataCenterLinkLocalIpAddressDao? @@ -2807,10 +2814,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final boolean success = _zoneDao.remove(zoneId); if (success) { - NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); - if (Objects.nonNull(nsxProvider)) { - nsxProviderDao.remove(nsxProvider.getId()); - } + deleteExternalProviderIfAny(zoneId); // delete template refs for this zone templateZoneDao.deleteByZoneId(zoneId); @@ -2836,6 +2840,17 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati }); } + private void deleteExternalProviderIfAny(Long zoneId) { + NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + if (Objects.nonNull(nsxProvider)) { + nsxProviderDao.remove(nsxProvider.getId()); + } + NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(zoneId); + if (Objects.nonNull(netrisProvider)) { + netrisProviderDao.remove(netrisProvider.getId()); + } + } + @Override @DB @ActionEvent(eventType = EventTypes.EVENT_ZONE_EDIT, eventDescription = "editing zone", async = false) @@ -4790,6 +4805,19 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); } + // If external provider is provided, verify zone has that provider enabled and the controller added + Provider provider = cmd.getProvider(); + NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(zoneId); + if (Objects.nonNull(provider) && ObjectUtils.anyNotNull(nsxProvider, netrisProvider)) { + boolean unsupported = + (Provider.Nsx == provider && nsxProvider == null) || + (Provider.Netris == provider && netrisProvider == null); + if (unsupported) { + throw new InvalidParameterValueException(String.format("Cannot add public IP range as the zone does not support provider: %s", provider.getName())); + } + } + // verify that physical network exists PhysicalNetworkVO pNtwk = null; if (physicalNetworkId != null) { @@ -4919,7 +4947,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } return commitVlan(zoneId, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, forVirtualNetwork, forSystemVms, networkId, physicalNetworkId, startIPv6, endIPv6, ip6Gateway, - ip6Cidr, domain, vlanOwner, network, sameSubnet, cmd.isForNsx()); + ip6Cidr, domain, vlanOwner, network, sameSubnet, cmd.getProvider()); } private Network getNetwork(Long networkId) { @@ -4950,7 +4978,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal, final String vlanId, final Boolean forVirtualNetwork, final Boolean forSystemVms, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6, - final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair> sameSubnet, boolean forNsx) { + final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair> sameSubnet, Provider provider) { final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan"); commitVlanLock.lock(5); logger.debug("Acquiring lock for committing vlan"); @@ -4978,13 +5006,19 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati newVlanNetmask = sameSubnet.second().second(); } final Vlan vlan = createVlanAndPublicIpRange(zoneId, networkId, physicalNetworkId, forVirtualNetwork, forSystemVms, podId, startIP, endIP, newVlanGateway, newVlanNetmask, vlanId, - false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr, forNsx); + false, domain, vlanOwner, startIPv6, endIPv6, ip6Gateway, ip6Cidr, provider); // create an entry in the nic_secondary table. This will be the new // gateway that will be configured on the corresponding routervm. return vlan; } }); + if (provider == Provider.Netris && netrisProviderDao.findByZoneId(zoneId) != null) { + if (Objects.nonNull(netrisServiceProvider) && Objects.nonNull(netrisServiceProvider.get())) { + NetrisService netrisService = netrisServiceProvider.get(); + netrisService.createIPAMAllocationsForZoneLevelPublicRanges(zoneId); + } + } messageBus.publish(_name, MESSAGE_CREATE_VLAN_IP_RANGE_EVENT, PublishScope.LOCAL, vlan); return vlan; @@ -5105,7 +5139,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati @Override @DB public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final boolean forVirtualNetwork, final boolean forSystemVms, final Long podId, final String startIP, final String endIP, - final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr, boolean forNsx) { + final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr, Provider provider) { final Network network = _networkModel.getNetwork(networkId); boolean ipv4 = false, ipv6 = false; @@ -5155,6 +5189,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // 1) if vlan is specified for the guest network range, it should be the // same as network's vlan // 2) if vlan is missing, default it to the guest network's vlan + boolean forExternalProvider = ConfigurationService.IsIpRangeForProvider(provider); if (network.getTrafficType() == TrafficType.Guest) { boolean connectivityWithoutVlan = isConnectivityWithoutVlan(network); String networkVlanId = getNetworkVlanId(network, connectivityWithoutVlan); @@ -5167,11 +5202,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else { vlanId = networkVlanId; } - } else if (network.getTrafficType() == TrafficType.Public && vlanId == null && !forNsx) { + } else if (network.getTrafficType() == TrafficType.Public && vlanId == null && !forExternalProvider) { throw new InvalidParameterValueException("Unable to determine vlan id or untagged vlan for public network"); } - if (vlanId == null && !forNsx) { + if (vlanId == null && !forExternalProvider) { vlanId = Vlan.UNTAGGED; } @@ -5268,7 +5303,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (isSharedNetworkWithoutSpecifyVlan) { bypassVlanOverlapCheck = true; } - if (!bypassVlanOverlapCheck && !forNsx && !_zoneDao.findVnet(zoneId, physicalNetworkId, BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId))).isEmpty()) { + if (!bypassVlanOverlapCheck && !forExternalProvider && !_zoneDao.findVnet(zoneId, physicalNetworkId, BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId))).isEmpty()) { throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); } @@ -5284,7 +5319,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // Everything was fine, so persist the VLAN final VlanVO vlan = commitVlanAndIpRange(zoneId, networkId, physicalNetworkId, podId, startIP, endIP, vlanGateway, vlanNetmask, vlanId, domain, vlanOwner, vlanIp6Gateway, vlanIp6Cidr, - ipv4, zone, vlanType, ipv6Range, ipRange, forSystemVms, forNsx); + ipv4, zone, vlanType, ipv6Range, ipRange, forSystemVms, provider); return vlan; } @@ -5385,14 +5420,16 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati private VlanVO commitVlanAndIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final Long podId, final String startIP, final String endIP, final String vlanGateway, final String vlanNetmask, final String vlanId, final Domain domain, final Account vlanOwner, final String vlanIp6Gateway, final String vlanIp6Cidr, - final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms, final boolean forNsx) { + final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms, final Provider provider) { return Transaction.execute(new TransactionCallback<>() { @Override public VlanVO doInTransaction(final TransactionStatus status) { VlanVO vlan = new VlanVO(vlanType, vlanId, vlanGateway, vlanNetmask, zone.getId(), ipRange, networkId, physicalNetworkId, vlanIp6Gateway, vlanIp6Cidr, ipv6Range); logger.debug("Saving vlan range " + vlan); vlan = _vlanDao.persist(vlan); - vlanDetailsDao.addDetail(vlan.getId(), ApiConstants.NSX_DETAIL_KEY, String.valueOf(forNsx), true); + if (Objects.nonNull(provider)) { + addProviderVlanDetailKey(vlan, provider); + } // IPv6 use a used ip map, is different from ipv4, no need to save // public ip range @@ -5433,6 +5470,15 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } + private void addProviderVlanDetailKey(Vlan vlan, Provider provider) { + vlanDetailsDao.addDetail(vlan.getId(), getProviderDetailKey(provider.getName()), + String.valueOf(ConfigurationService.IsIpRangeForProvider(provider)), true); + } + + private String getProviderDetailKey(String providerName) { + return ConfigurationService.ProviderDetailKeyMap.get(providerName); + } + @Override public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException,ResourceAllocationException { @@ -6378,7 +6424,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Map detailsStr = cmd.getDetails(); final Boolean egressDefaultPolicy = cmd.getEgressDefaultPolicy(); Boolean forVpc = cmd.getForVpc(); - Boolean forNsx = cmd.isForNsx(); + boolean forNsx = cmd.isForNsx(); + boolean forNetris = cmd.isForNetris(); Boolean forTungsten = cmd.getForTungsten(); String networkModeStr = cmd.getNetworkMode(); boolean nsxSupportInternalLbSvc = cmd.getNsxSupportsInternalLbService(); @@ -6417,8 +6464,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - if (Boolean.TRUE.equals(forNsx) && Boolean.TRUE.equals(forTungsten)) { - throw new InvalidParameterValueException("Network Offering cannot be for both Tungsten-Fabric and NSX"); + if ((Boolean.TRUE.equals(forTungsten) ? 1 : 0) + (forNetris ? 1 : 0) + (forNsx ? 1 : 0) > 1) { + throw new InvalidParameterValueException("Network Offering cannot be for multiple providers - Tungsten-Fabric, NSX and Netris"); } NetworkOffering.NetworkMode networkMode = null; @@ -6631,7 +6678,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // offering final Map sourceNatServiceCapabilityMap = cmd.getServiceCapabilities(Service.SourceNat); if (!serviceProviderMap.containsKey(Service.SourceNat) && sourceNatServiceCapabilityMap != null && !sourceNatServiceCapabilityMap.isEmpty()) { - throw new InvalidParameterValueException("Capabilities for source NAT service can be specifed only when source NAT service is enabled for network offering."); + throw new InvalidParameterValueException("Capabilities for source NAT service can be specified only when source NAT service is enabled for network offering."); } validateSourceNatServiceCapablities(sourceNatServiceCapabilityMap); @@ -6639,7 +6686,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati // offering final Map staticNatServiceCapabilityMap = cmd.getServiceCapabilities(Service.StaticNat); if (!serviceProviderMap.containsKey(Service.StaticNat) && sourceNatServiceCapabilityMap != null && !staticNatServiceCapabilityMap.isEmpty()) { - throw new InvalidParameterValueException("Capabilities for static NAT service can be specifed only when static NAT service is enabled for network offering."); + throw new InvalidParameterValueException("Capabilities for static NAT service can be specified only when static NAT service is enabled for network offering."); } validateStaticNatServiceCapablities(staticNatServiceCapabilityMap); @@ -6700,7 +6747,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } final NetworkOfferingVO offering = createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, forNsx, networkMode, domainIds, zoneIds, enable, internetProtocol, routingMode, specifyAsNumber); + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, forNsx, forNetris, networkMode, domainIds, zoneIds, enable, internetProtocol, routingMode, specifyAsNumber); if (Boolean.TRUE.equals(forNsx) && nsxSupportInternalLbSvc) { offering.setInternalLb(true); offering.setPublicLb(false); @@ -6867,7 +6914,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati final Long serviceOfferingId, final boolean conserveMode, final Map> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent, final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc, - Boolean forTungsten, boolean forNsx, NetworkOffering.NetworkMode networkMode, final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol, + Boolean forTungsten, boolean forNsx, boolean forNetris, NetworkOffering.NetworkMode networkMode, final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol, final NetworkOffering.RoutingMode routingMode, final boolean specifyAsNumber) { String servicePackageUuid; @@ -6962,6 +7009,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } else { serviceProviderMap.put(Service.Gateway, Sets.newHashSet(Provider.VirtualRouter)); } + } else { + Set providers = serviceProviderMap.get(Service.NetworkACL); + serviceProviderMap.put(Service.Gateway, Sets.newHashSet(providers.iterator().next())); } } } @@ -7094,9 +7144,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (serviceOfferingId != null) { offeringFinal.setServiceOfferingId(serviceOfferingId); } - - offeringFinal.setForTungsten(Objects.requireNonNullElse(forTungsten, false)); - offeringFinal.setForNsx(Objects.requireNonNullElse(forNsx, false)); offeringFinal.setNetworkMode(networkMode); if (enableOffering) { @@ -7167,7 +7214,7 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati logger.trace("Added service for the network offering: " + offService + " with provider " + provider.getName()); } - if (vpcOff && !forNsx) { + if (vpcOff && !forNsx && !forNetris) { final List supportedSvcs = new ArrayList<>(); supportedSvcs.addAll(serviceProviderMap.keySet()); _vpcMgr.validateNtwkOffForVpc(offering, supportedSvcs); diff --git a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java index feb7e66159d..68b057fef13 100644 --- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -2044,7 +2044,7 @@ StateListener, Configurable { } public static String logDeploymentWithoutException(VirtualMachine vm, DeploymentPlan plan, ExcludeList avoids, DeploymentPlanner planner) { - return LogUtils.logGsonWithoutException("Trying to deploy VM [%s] and details: Plan [%s]; avoid list [%s] and planner: [%s].", vm, plan, avoids, planner); + return LogUtils.logGsonWithoutException("Trying to deploy VM [%s] and details: Plan [%s]; avoid list [%s] and planner: [%s].", vm, plan, avoids, planner != null ? planner.getName() : null); } @Override public ConfigKey[] getConfigKeys() { diff --git a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java index ca47393f434..b99a2f553c4 100644 --- a/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java +++ b/server/src/main/java/com/cloud/network/IpAddressManagerImpl.java @@ -33,8 +33,20 @@ import java.util.stream.Collectors; import javax.inject.Inject; +import com.cloud.dc.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.network.dao.NetrisProviderDao; +import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PublicIpQuarantineDao; +import com.cloud.network.dao.RemoteAccessVpnDao; +import com.cloud.network.dao.Site2SiteVpnGatewayDao; +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.network.element.NsxProviderVO; import com.cloud.network.vo.PublicIpQuarantineVO; +import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcOffering; +import com.cloud.network.vpc.VpcOfferingServiceMapVO; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.resourcelimit.CheckedReservation; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -189,6 +201,7 @@ import com.cloud.vm.dao.NicIpAliasDao; import com.cloud.vm.dao.NicSecondaryIpDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; +import org.apache.commons.lang3.ObjectUtils; public class IpAddressManagerImpl extends ManagerBase implements IpAddressManager, Configurable { @@ -266,6 +279,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage @Inject NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; @Inject + VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Inject PhysicalNetworkDao _physicalNetworkDao; @Inject PhysicalNetworkServiceProviderDao _pNSPDao; @@ -313,9 +328,19 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage private AnnotationDao annotationDao; @Inject MessageBus messageBus; + @Inject + NsxProviderDao nsxProviderDao; + @Inject + NetrisProviderDao netrisProviderDao; + @Inject + VlanDetailsDao vlanDetailsDao; @Inject PublicIpQuarantineDao publicIpQuarantineDao; + @Inject + RemoteAccessVpnDao remoteAccessVpnDao; + @Inject + Site2SiteVpnGatewayDao site2SiteVpnGatewayDao; SearchBuilder AssignIpAddressSearch; SearchBuilder AssignIpAddressFromPodVlanSearch; @@ -733,6 +758,21 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage throw new CloudRuntimeException("Unable to acquire lock on public IP."); } + if (ipToBeDisassociated.isForRouter()) { + if (remoteAccessVpnDao.findByPublicIpAddress(ipToBeDisassociated.getId()) != null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Can't release IP address as the IP address is used by a Remote Access VPN"); + ex.addProxyObject(ipToBeDisassociated.getUuid(), "ipId"); + throw ex; + + } + if (site2SiteVpnGatewayDao.findByPublicIpAddress(ipToBeDisassociated.getId()) != null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Can't release IP address as the IP address is used by a VPC gateway"); + ex.addProxyObject(ipToBeDisassociated.getUuid(), "ipId"); + throw ex; + + } + } + PublicIpQuarantine publicIpQuarantine = null; // Cleanup all ip address resources - PF/LB/Static nat rules if (!cleanupIpResources(ipAddress, userId, caller)) { @@ -774,6 +814,28 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage } else if (publicIpQuarantine != null) { removePublicIpAddressFromQuarantine(publicIpQuarantine.getId(), "Public IP address removed from quarantine as there was an error while disassociating it."); } + Network network = _networksDao.findById(ipToBeDisassociated.getAssociatedWithNetworkId()); + Vpc vpc = _vpcDao.findById(ip.getVpcId()); + if (ObjectUtils.allNull(network, vpc)) { + return success; + } + List providers; + if (Objects.nonNull(network)) { + NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); + providers = _ntwkOfferingSrvcDao.listProvidersForServiceForNetworkOffering(offering.getId(), Service.NetworkACL); + } else { + VpcOffering offering = vpcOfferingDao.findById(vpc.getVpcOfferingId()); + List servicesMap = vpcOfferingServiceMapDao.listProvidersForServiceForVpcOffering(offering.getId(), Service.NetworkACL); + providers = servicesMap.stream().map(VpcOfferingServiceMapVO::getProvider).collect(Collectors.toList()); + } + + if (!providers.isEmpty()) { + String provider = providers.get(0); + NetworkElement element = _networkModel.getElementImplementingProvider(provider); + if (element != null) { + element.releaseIp(ipToBeDisassociated); + } + } } finally { _ipAddressDao.releaseFromLockTable(addrId); } @@ -1315,6 +1377,30 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage } } + /** + * When the zone is linked to external provider NSX or Netris: check if the IP to be associated is from the suitable pool + * Otherwise, no checks are performed + */ + private void checkPublicIpOnExternalProviderZone(DataCenter zone, String ip) { + long zoneId = zone.getId(); + NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(zoneId); + NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + if (ObjectUtils.allNull(netrisProvider, nsxProvider)) { + return; + } + IPAddressVO ipAddress = _ipAddressDao.findByIpAndDcId(zoneId, ip); + if (ipAddress != null) { + String detailKey = nsxProvider != null ? ApiConstants.NSX_DETAIL_KEY : ApiConstants.NETRIS_DETAIL_KEY; + VlanDetailsVO vlanDetailVO = vlanDetailsDao.findDetail(ipAddress.getVlanId(), detailKey); + if (vlanDetailVO == null || vlanDetailVO.getValue().equalsIgnoreCase("false")) { + String msg = String.format("Cannot acquire IP %s on the zone %s as the IP is not from the reserved pool " + + "for the external provider", ip, zone.getName()); + logger.error(msg); + throw new CloudRuntimeException(msg); + } + } + } + @DB @Override public IpAddress allocateIp(final Account ipOwner, final boolean isSystem, Account caller, User callerUser, final DataCenter zone, final Boolean displayIp, final String ipaddress) @@ -1323,6 +1409,8 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage final VlanType vlanType = VlanType.VirtualNetwork; final boolean assign = false; + checkPublicIpOnExternalProviderZone(zone, ipaddress); + if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getId())) { // zone is of type DataCenter. See DataCenterVO.java. PermissionDeniedException ex = new PermissionDeniedException(generateErrorMessageForOperationOnDisabledZone("allocate IP addresses", zone)); diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index 6cc18aaef54..5a7df7df32d 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -207,7 +207,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi DomainManager _domainMgr; @Inject - NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; + protected NetworkOfferingServiceMapDao _ntwkOfferingSrvcDao; @Inject PhysicalNetworkDao _physicalNetworkDao; @Inject @@ -494,7 +494,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi @Override public Map> getProviderToIpList(Network network, Map> ipToServices) { NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId()); - if (!offering.isConserveMode() && !offering.isForNsx()) { + boolean isForNsx = isProviderForNetworkOffering(Provider.Nsx, offering.getId()); + if (!offering.isConserveMode() && !isForNsx) { for (PublicIpAddress ip : ipToServices.keySet()) { Set services = new HashSet(); services.addAll(ipToServices.get(ip)); @@ -1631,7 +1632,8 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi if (!canIpUsedForService(publicIp, service, networkId)) { return false; } - if (!offering.isConserveMode() && !offering.isForNsx()) { + boolean isForNsx = isProviderForNetworkOffering(Provider.Nsx, offering.getId()); + if (!offering.isConserveMode() && !isForNsx) { return canIpUsedForNonConserveService(publicIp, service); } return true; @@ -2310,6 +2312,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi } if (capabilities != null && implementedProvider != null) { for (Service service : capabilities.keySet()) { + logger.info("Add provider {} and service {}", implementedProvider.getName(), service.getName()); if (s_serviceToImplementedProvidersMap.containsKey(service)) { List providers = s_serviceToImplementedProvidersMap.get(service); providers.add(implementedProvider); diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index bd3a3975eac..f593212a13a 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -32,6 +32,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -40,6 +41,7 @@ import java.util.UUID; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.utils.component.AdapterBase; import com.cloud.dc.dao.ASNumberDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.acl.SecurityChecker.AccessType; @@ -1832,10 +1834,6 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.hideIpAddressUsage, String.valueOf(hideIpAddressUsage), false)); } - if (ip6GatewayCidr != null) { - ipv6Service.assignIpv6SubnetToNetwork(ip6Cidr, network.getId()); - } - // assign to network if (NetworkOffering.NetworkMode.ROUTED.equals(ntwkOff.getNetworkMode())) { routedIpv4Manager.assignIpv4SubnetToNetwork(network); @@ -2333,9 +2331,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C } if (createVlan && network != null) { + Provider networkProvider = getNetworkOfferingProvider(ntwkOff); // Create vlan ip range _configMgr.createVlanAndPublicIpRange(pNtwk.getDataCenterId(), network.getId(), physicalNetworkId, false, false, null, startIP, endIP, gateway, netmask, vlanId, - bypassVlanOverlapCheck, null, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr, ntwkOff.isForNsx()); + bypassVlanOverlapCheck, null, null, startIPv6, endIPv6, ip6Gateway, ip6Cidr, networkProvider); } if (associatedNetwork != null) { _networkDetailsDao.persist(new NetworkDetailVO(network.getId(), Network.AssociatedNetworkId, String.valueOf(associatedNetwork.getId()), true)); @@ -2361,6 +2360,15 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C } } + private Provider getNetworkOfferingProvider(NetworkOffering networkOffering) { + if (_networkModel.isProviderForNetworkOffering(Provider.Nsx, networkOffering.getId())) { + return Provider.Nsx; + } else if (_networkModel.isProviderForNetworkOffering(Provider.Netris, networkOffering.getId())) { + return Provider.Netris; + } + return null; + } + @Override public Pair, Integer> searchForNetworks(ListNetworksCmd cmd) { Long id = cmd.getId(); @@ -3114,7 +3122,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C // verify input parameters final NetworkVO network = getNetworkVO(networkId, "Specified network id doesn't exist in the system"); - + String prevNetworkName = network.getName(); //perform below validation if the network is vpc network if (network.getVpcId() != null && networkOfferingId != null) { Vpc vpc = _entityMgr.findById(Vpc.class, network.getVpcId()); @@ -3597,9 +3605,17 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C } Network updatedNetwork = getNetwork(network.getId()); UsageEventUtils.publishNetworkUpdate(updatedNetwork); + updateProviderNetwork(updatedNetwork, prevNetworkName); return updatedNetwork; } + private void updateProviderNetwork(Network network, String prevNetworkName) { + final NetworkGuru guru = AdapterBase.getAdapterByName(_networkGurus, network.getGuruName()); + if (Objects.nonNull(guru) && !guru.update(network, prevNetworkName)) { + logger.error("Failed to update name of network on provider"); + } + } + protected Pair validateMtuOnUpdate(NetworkVO network, Long zoneId, Integer publicMtu, Integer privateMtu) { if (!AllowUsersToSpecifyVRMtu.valueIn(zoneId)) { return new Pair<>(null, null); @@ -4269,6 +4285,13 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C logger.warn("Failed to add NSX provider to physical network due to:", ex.getMessage()); } + // Add Netris provider + try { + addNetrisProviderToPhysicalNetwork(pNetwork.getId()); + } catch (Exception ex) { + logger.warn("Failed to add Netris provider to physical network due to:", ex.getMessage()); + } + CallContext.current().putContextParameter(PhysicalNetwork.class, pNetwork.getUuid()); return pNetwork; @@ -4465,7 +4488,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C if (network.getIsolationMethods().contains("GRE")) { minVnet = MIN_GRE_KEY; maxVnet = MAX_GRE_KEY; - } else if (network.getIsolationMethods().contains("VXLAN")) { + } else if (network.getIsolationMethods().contains("VXLAN") || network.getIsolationMethods().contains("Netris")) { minVnet = MIN_VXLAN_VNI; maxVnet = MAX_VXLAN_VNI; // fail if zone already contains VNI, need to be unique per zone. @@ -5097,11 +5120,14 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C // validate Services boolean addGatewayService = false; + boolean isRoutedMode = enabledServices.stream().noneMatch(svc -> svc.equalsIgnoreCase(Service.SourceNat.getName())); for (String serviceName : enabledServices) { Network.Service service = Network.Service.getService(serviceName); if (service == null || service == Service.Gateway) { throw new InvalidParameterValueException("Invalid Network Service specified=" + serviceName); - } else if (service == Service.SourceNat) { + } else if (service == Service.SourceNat || + (isRoutedMode && Arrays.asList(Provider.Nsx.getName().toLowerCase(Locale.ROOT), + Provider.Netris.getName().toLowerCase(Locale.ROOT)).contains(providerName.toLowerCase(Locale.ROOT)))) { addGatewayService = true; } @@ -5678,6 +5704,22 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C return null; } + private PhysicalNetworkServiceProvider addNetrisProviderToPhysicalNetwork(long physicalNetworkId) { + PhysicalNetworkVO pvo = _physicalNetworkDao.findById(physicalNetworkId); + DataCenterVO dvo = _dcDao.findById(pvo.getDataCenterId()); + if (dvo.getNetworkType() == NetworkType.Advanced) { + + Provider provider = Network.Provider.getProvider(Provider.Netris.getName()); + if (provider == null) { + return null; + } + + addProviderToPhysicalNetwork(physicalNetworkId, Provider.Netris.getName(), null, null); + enableProvider(Provider.Netris.getName()); + } + return null; + } + protected boolean isNetworkSystem(Network network) { NetworkOffering no = _networkOfferingDao.findByIdIncludingRemoved(network.getNetworkOfferingId()); if (no.isSystemOnly()) { diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java b/server/src/main/java/com/cloud/network/SDNProviderOpObject.java similarity index 94% rename from plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java rename to server/src/main/java/com/cloud/network/SDNProviderOpObject.java index bb411249b88..902e47545e9 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxOpObject.java +++ b/server/src/main/java/com/cloud/network/SDNProviderOpObject.java @@ -14,14 +14,14 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -package org.apache.cloudstack.resource; +package com.cloud.network; import com.cloud.network.dao.NetworkVO; import com.cloud.network.vpc.VpcVO; import java.util.Objects; -public class NsxOpObject { +public class SDNProviderOpObject { VpcVO vpcVO; NetworkVO networkVO; long accountId; @@ -116,8 +116,8 @@ public class NsxOpObject { return this; } - public NsxOpObject build() { - NsxOpObject object = new NsxOpObject(); + public SDNProviderOpObject build() { + SDNProviderOpObject object = new SDNProviderOpObject(); object.setVpcVO(this.vpcVO); object.setNetworkVO(this.networkVO); object.setDomainId(this.domainId); diff --git a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java index 9d001080400..8884a5edb1f 100644 --- a/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java +++ b/server/src/main/java/com/cloud/network/as/AutoScaleManagerImpl.java @@ -2250,8 +2250,9 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage Network.Provider provider = getLoadBalancerServiceProvider(asGroup.getLoadBalancerId()); if (Network.Provider.Netscaler.equals(provider)) { checkNetScalerAsGroup(asGroup); - } else if (Network.Provider.VirtualRouter.equals(provider) || Network.Provider.VPCVirtualRouter.equals(provider)) { - checkVirtualRouterAsGroup(asGroup); + } else if (Network.Provider.VirtualRouter.equals(provider) || Network.Provider.VPCVirtualRouter.equals(provider) || + Network.Provider.Netris.equals(provider)) { + checkAutoscalingGroup(asGroup); } } } @@ -2631,7 +2632,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage countersNumberMap.put(key, countersNumberMap.get(key) + 1); } - protected void monitorVirtualRouterAsGroup(AutoScaleVmGroupVO asGroup) { + protected void monitorAutoscalingGroup(AutoScaleVmGroupVO asGroup) { if (!checkAsGroupMaxAndMinMembers(asGroup)) { return; } @@ -2661,7 +2662,7 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage } } - protected void checkVirtualRouterAsGroup(AutoScaleVmGroupVO asGroup) { + protected void checkAutoscalingGroup(AutoScaleVmGroupVO asGroup) { AutoScaleVmGroupTO groupTO = lbRulesMgr.toAutoScaleVmGroupTO(asGroup); Map countersMap = new HashMap<>(); @@ -3011,8 +3012,9 @@ public class AutoScaleManagerImpl extends ManagerBase implements AutoScaleManage Network.Provider provider = getLoadBalancerServiceProvider(asGroup.getLoadBalancerId()); if (Network.Provider.Netscaler.equals(provider)) { logger.debug("Skipping the monitoring on AutoScale VmGroup with Netscaler provider: " + asGroup); - } else if (Network.Provider.VirtualRouter.equals(provider) || Network.Provider.VPCVirtualRouter.equals(provider)) { - monitorVirtualRouterAsGroup(asGroup); + } else if (Network.Provider.VirtualRouter.equals(provider) || Network.Provider.VPCVirtualRouter.equals(provider) || + Network.Provider.Netris.equals(provider)) { + monitorAutoscalingGroup(asGroup); } } } catch (final Exception e) { diff --git a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java index 263ff523ab6..430d4757944 100644 --- a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java @@ -947,7 +947,6 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ return true; } - @Override public boolean configDhcpSupportForSubnet(final Network network, final NicProfile nic, final VirtualMachineProfile vm, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { diff --git a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java index 954c70f610e..3b4af537feb 100644 --- a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -269,8 +269,9 @@ public class ExternalGuestNetworkGuru extends GuestNetworkGuru { profile.setIPv4Netmask(null); } - if (config.getVpcId() == null && vm.getType() == VirtualMachine.Type.DomainRouter) { - boolean isPublicNetwork = _networkModel.isProviderSupportServiceInNetwork(config.getId(), Service.SourceNat, Provider.VirtualRouter); + if (vm.getType() == VirtualMachine.Type.DomainRouter) { + boolean isPublicNetwork = _networkModel.isProviderSupportServiceInNetwork(config.getId(), Service.SourceNat, Provider.VirtualRouter) + || _networkModel.isProviderSupportServiceInNetwork(config.getId(), Service.SourceNat, Provider.VPCVirtualRouter); if (!isPublicNetwork) { Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(config, null); if (placeholderNic == null) { diff --git a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java index 2f668b59d62..7e09501a15e 100644 --- a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java @@ -17,11 +17,15 @@ package com.cloud.network.guru; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Random; import javax.inject.Inject; +import com.cloud.domain.dao.DomainDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; +import com.cloud.user.dao.AccountDao; import org.apache.cloudstack.api.ApiCommandResourceType; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -124,6 +128,12 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur @Inject DomainRouterDao domainRouterDao; @Inject + public NetworkOfferingServiceMapDao networkOfferingServiceMapDao; + @Inject + public AccountDao accountDao; + @Inject + public DomainDao domainDao; + @Inject RoutedIpv4Manager routedIpv4Manager; Random _rand = new Random(System.currentTimeMillis()); @@ -519,12 +529,16 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur return; // Nothing to do here if the uri is null already } - if ((profile.getBroadcastDomainType() == BroadcastDomainType.Vlan || profile.getBroadcastDomainType() == BroadcastDomainType.Vxlan) && !offering.isSpecifyVlan()) { + if ((profile.getBroadcastDomainType() == BroadcastDomainType.Vlan || profile.getBroadcastDomainType() == BroadcastDomainType.Vxlan || profile.getBroadcastDomainType() == BroadcastDomainType.Netris) && !offering.isSpecifyVlan()) { logger.debug("Releasing vnet for the network: {}", profile); _dcDao.releaseVnet(BroadcastDomainType.getValue(profile.getBroadcastUri()), profile.getDataCenterId(), profile.getPhysicalNetworkId(), profile.getAccountId(), profile.getReservationId()); - ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(), profile.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_ZONE_VLAN_RELEASE, - String.format("Released Zone Vnet: %s for Network: %s", BroadcastDomainType.getValue(profile.getBroadcastUri()), profile), + String eventType = EventTypes.EVENT_ZONE_VLAN_RELEASE; + if (Arrays.asList(BroadcastDomainType.Vxlan, BroadcastDomainType.Netris).contains(profile.getBroadcastDomainType())) { + eventType = EventTypes.EVENT_ZONE_VXLAN_RELEASE; + } + ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(), profile.getAccountId(), EventVO.LEVEL_INFO, eventType, + "Released Zone Vnet: " + BroadcastDomainType.getValue(profile.getBroadcastUri()) + " for Network: " + profile.getId(), profile.getDataCenterId(), ApiCommandResourceType.Zone.toString(), 0); } diff --git a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java index f5434388f40..bac397f2809 100644 --- a/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/PublicNetworkGuru.java @@ -18,6 +18,10 @@ package com.cloud.network.guru; import javax.inject.Inject; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; import com.cloud.dc.DataCenter; @@ -74,7 +78,15 @@ public class PublicNetworkGuru extends AdapterBase implements NetworkGuru { @Inject Ipv6Service ipv6Service; @Inject - NetworkModel networkModel; + protected NetworkModel networkModel; + @Inject + protected VpcDao vpcDao; + @Inject + protected VlanDetailsDao vlanDetailsDao; + @Inject + protected VpcOfferingDao vpcOfferingDao; + @Inject + protected VpcOfferingServiceMapDao vpcOfferingServiceMapDao; private static final TrafficType[] TrafficTypes = {TrafficType.Public}; diff --git a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index 015cbe49049..ee4fe62aef9 100644 --- a/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import javax.inject.Inject; @@ -1007,6 +1008,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements return false; } if (provider.get(0) == Provider.Netscaler || provider.get(0) == Provider.F5BigIp || + provider.get(0) == Provider.Netris || provider.get(0) == Provider.VirtualRouter || provider.get(0) == Provider.VPCVirtualRouter) { return true; } @@ -2245,6 +2247,7 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements lb.setLbProtocol(lbProtocol); } + validateInputsForExternalNetworkProvider(lb, algorithm, lbProtocol); // Validate rule in LB provider LoadBalancingRule rule = getLoadBalancerRuleToApply(lb); if (!validateLbRule(rule)) { @@ -2294,6 +2297,18 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements return lb; } + private void validateInputsForExternalNetworkProvider(LoadBalancerVO lb, String algorithm, String protocol) { + Network network = _networkDao.findById(lb.getNetworkId()); + if (_networkOfferingServiceDao.canProviderSupportServiceInNetworkOffering(network.getNetworkOfferingId(), Service.Lb, Provider.Netris)) { + if (Objects.nonNull(algorithm)) { + throw new InvalidParameterValueException(String.format("Algorithm: %s specified for Netris Provider is not supported.", algorithm)); + } + if (Objects.nonNull(protocol) && "tcp-proxy".equalsIgnoreCase(protocol)) { + throw new InvalidParameterValueException("TCP Proxy protocol is not supported for Netris Provider."); + } + } + } + @Override public Pair, List> listLoadBalancerInstances(ListLoadBalancerRuleInstancesCmd cmd) throws PermissionDeniedException { Account caller = CallContext.current().getCallingAccount(); diff --git a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 5a53c1016cf..10da04d04ca 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -869,7 +869,11 @@ public class CommandSetupHelper { String vlanTag = ipAddr.getVlanTag(); String key = null; if (Objects.isNull(vlanTag)) { - key = "nsx-" + ipAddr.getAddress().addr(); + if (Hypervisor.HypervisorType.VMware == router.getHypervisorType()) { + key = "nsx-" + ipAddr.getAddress().addr(); + } else if (Hypervisor.HypervisorType.KVM == router.getHypervisorType()) { + key = "netris-" + ipAddr.getAddress().addr(); + } } else { key = BroadcastDomainType.getValue(BroadcastDomainType.fromString(ipAddr.getVlanTag())); } @@ -1218,7 +1222,10 @@ public class CommandSetupHelper { final SetupGuestNetworkCommand setupCmd = new SetupGuestNetworkCommand(dhcpRange, networkDomain, router.getIsRedundantRouter(), defaultDns1, defaultDns2, add, _itMgr.toNicTO(nicProfile, router.getHypervisorType())); - setupCmd.setVrGuestGateway(networkOfferingVO.isForNsx()); + boolean isVrGuestGateway = _networkModel.isAnyServiceSupportedInNetwork(network.getId(), Provider.VPCVirtualRouter, Service.SourceNat, Service.Gateway); + setupCmd.setVrGuestGateway(isVrGuestGateway); + setupCmd.setNetworkId(network.getId()); + NicVO publicNic = _nicDao.findDefaultNicForVM(router.getId()); if (publicNic != null) { updateSetupGuestNetworkCommandIpv6(setupCmd, network, publicNic, defaultIp6Dns1, defaultIp6Dns2); diff --git a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java index ee2081adc73..b844d2b8958 100644 --- a/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java @@ -28,6 +28,9 @@ import java.util.Map; import javax.annotation.PostConstruct; import javax.inject.Inject; +import com.cloud.network.vpc.VpcManager; +import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.utils.validation.ChecksumUtil; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -84,7 +87,6 @@ import com.cloud.network.lb.LoadBalancingRule; import com.cloud.network.router.VirtualRouter.RedundantState; import com.cloud.network.router.VirtualRouter.Role; import com.cloud.network.rules.LbStickinessMethod; -import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpn.Site2SiteVpnManager; import com.cloud.offering.NetworkOffering; import com.cloud.resource.ResourceManager; @@ -103,7 +105,6 @@ import com.cloud.user.dao.UserDao; import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; -import com.cloud.utils.validation.ChecksumUtil; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; @@ -176,6 +177,8 @@ public class NetworkHelperImpl implements NetworkHelper { CapacityManager capacityMgr; @Inject VpcDao vpcDao; + @Inject + VpcManager vpcManager; protected final Map> hypervisorsMap = new HashMap<>(); @@ -275,6 +278,10 @@ public class NetworkHelperImpl implements NetworkHelper { _itMgr.expunge(router.getUuid()); _routerHealthCheckResultDao.expungeHealthChecks(router.getId()); _routerDao.remove(router.getId()); + + if (router.getVpcId() != null) { + vpcManager.reconfigStaticNatForVpcVr(router.getVpcId()); + } return router; } @@ -808,7 +815,8 @@ public class NetworkHelperImpl implements NetworkHelper { logger.debug("Adding nic for Virtual Router in Guest network " + guestNetwork); String defaultNetworkStartIp = null, defaultNetworkStartIpv6 = null; final Nic placeholder = _networkModel.getPlaceholderNicForRouter(guestNetwork, routerDeploymentDefinition.getPodId()); - if (!routerDeploymentDefinition.isPublicNetwork()) { + if (!routerDeploymentDefinition.isPublicNetwork() + || !_networkModel.isAnyServiceSupportedInNetwork(guestNetwork.getId(), Network.Provider.VPCVirtualRouter, Network.Service.SourceNat, Network.Service.Gateway)) { if (guestNetwork.getCidr() != null) { if (placeholder != null && placeholder.getIPv4Address() != null) { logger.debug("Requesting ipv4 address " + placeholder.getIPv4Address() + " stored in placeholder nic for the network " diff --git a/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java b/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java index 399019db3e2..649689d8d77 100644 --- a/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java +++ b/server/src/main/java/com/cloud/network/router/NicProfileHelperImpl.java @@ -120,7 +120,9 @@ public class NicProfileHelperImpl implements NicProfileHelper { public NicProfile createGuestNicProfileForVpcRouter(final RouterDeploymentDefinition vpcRouterDeploymentDefinition, final Network guestNetwork) { final NicProfile guestNic = new NicProfile(); - if (BroadcastDomainType.NSX == guestNetwork.getBroadcastDomainType()) { + if (BroadcastDomainType.NSX == guestNetwork.getBroadcastDomainType() || + BroadcastDomainType.Netris == guestNetwork.getBroadcastDomainType() || + !_vpcMgr.isSrcNatIpRequiredForVpcVr(vpcRouterDeploymentDefinition.getVpc().getVpcOfferingId())) { NicVO vrNic = _nicDao.findByNetworkIdAndTypeIncludingRemoved(guestNetwork.getId(), VirtualMachine.Type.DomainRouter); if (vrNic != null) { guestNic.setIPv4Address(vrNic.getIPv4Address()); diff --git a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java index fa3c3abc681..8e486127364 100644 --- a/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java +++ b/server/src/main/java/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java @@ -203,6 +203,7 @@ import com.cloud.network.rules.StaticNatImpl; import com.cloud.network.rules.StaticNatRule; import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcService; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.network.vpn.Site2SiteVpnManager; @@ -335,6 +336,7 @@ Configurable, StateListener it = profile.getNics().iterator(); while (it.hasNext()) { final NicProfile nic = it.next(); if (nic.getTrafficType() == TrafficType.Public || nic.getTrafficType() == TrafficType.Guest) { // save dns information - if (nic.getTrafficType() == TrafficType.Public) { + if (nic.getTrafficType() == TrafficType.Public || !isDnsConfigured) { defaultDns1 = nic.getIPv4Dns1(); defaultDns2 = nic.getIPv4Dns2(); defaultIp6Dns1 = nic.getIPv6Dns1(); defaultIp6Dns2 = nic.getIPv6Dns2(); + isDnsConfigured = true; } logger.debug("Removing nic " + nic + " of type " + nic.getTrafficType() + " from the nics passed on vm start. " + "The nic will be plugged later"); it.remove(); @@ -532,17 +533,8 @@ public class VpcVirtualNetworkApplianceManagerImpl extends VirtualNetworkApplian } // 4) RE-APPLY ALL STATIC ROUTE RULES - final List routes = _staticRouteDao.listByVpcId(domainRouterVO.getVpcId()); - final List staticRouteProfiles = new ArrayList(routes.size()); - final Map gatewayMap = new HashMap(); - for (final StaticRoute route : routes) { - VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId()); - if (gateway == null) { - gateway = _entityMgr.findById(VpcGateway.class, route.getVpcGatewayId()); - gatewayMap.put(gateway.getId(), gateway); - } - staticRouteProfiles.add(new StaticRouteProfile(route, gateway)); - } + final List routes = _vpcMgr.getVpcStaticRoutes(domainRouterVO.getVpcId()); + final List staticRouteProfiles = _vpcMgr.getVpcStaticRoutes(routes); logger.debug("Found " + staticRouteProfiles.size() + " static routes to apply as a part of vpc route " + domainRouterVO + " start"); if (!staticRouteProfiles.isEmpty()) { diff --git a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java index bfcaca72b31..db79cad9d65 100644 --- a/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/main/java/com/cloud/network/rules/RulesManagerImpl.java @@ -59,6 +59,8 @@ import com.cloud.network.dao.IPAddressDao; import com.cloud.network.dao.IPAddressVO; import com.cloud.network.dao.LoadBalancerVMMapDao; import com.cloud.network.dao.LoadBalancerVMMapVO; +import com.cloud.network.dao.RemoteAccessVpnDao; +import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.rules.FirewallRule.FirewallRuleType; import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRule.State; @@ -155,6 +157,10 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules VpcService _vpcSvc; @Inject VMTemplateDao _templateDao; + @Inject + RemoteAccessVpnDao remoteAccessVpnDao; + @Inject + Site2SiteVpnGatewayDao site2SiteVpnGatewayDao; protected void checkIpAndUserVm(IpAddress ipAddress, UserVm userVm, Account caller, Boolean ignoreVmState) { if (ipAddress == null || ipAddress.getAllocatedTime() == null || ipAddress.getAllocatedToAccountId() == null) { @@ -1270,6 +1276,25 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules throw ex; } + if (ipAddress.isForRouter()) { + if (remoteAccessVpnDao.findByPublicIpAddress(ipAddress.getId()) != null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Can't disable static nat as the IP address is used by a Remote Access VPN"); + ex.addProxyObject(ipAddress.getUuid(), "ipId"); + throw ex; + + } + if (site2SiteVpnGatewayDao.findByPublicIpAddress(ipAddress.getId()) != null) { + InvalidParameterValueException ex = new InvalidParameterValueException("Can't disable static nat as the IP address is used by a VPC gateway"); + ex.addProxyObject(ipAddress.getUuid(), "ipId"); + throw ex; + + } + if (disableStaticNat(ipId, caller, ctx.getCallingUserId(), false)) { + return true; + } + return false; + } + Long vmId = ipAddress.getAssociatedWithVmId(); if (vmId == null) { InvalidParameterValueException ex = new InvalidParameterValueException("Specified IP address id is not associated with any vm Id"); @@ -1302,7 +1327,7 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules IPAddressVO ipAddress = _ipAddressDao.findById(ipId); checkIpAndUserVm(ipAddress, null, caller, false); - long networkId = ipAddress.getAssociatedWithNetworkId(); + Long networkId = ipAddress.getAssociatedWithNetworkId(); if (!ipAddress.isOneToOneNat()) { InvalidParameterValueException ex = new InvalidParameterValueException("One to one nat is not enabled for the specified ip id"); @@ -1337,11 +1362,14 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules ipAddress.setAssociatedWithVmId(null); ipAddress.setRuleState(null); ipAddress.setVmIp(null); + ipAddress.setForRouter(false); if (isIpSystem && !releaseIpIfElastic) { ipAddress.setSystem(false); } _ipAddressDao.update(ipAddress.getId(), ipAddress); - _vpcMgr.unassignIPFromVpcNetwork(ipAddress.getId(), networkId); + if (networkId != null) { + _vpcMgr.unassignIPFromVpcNetwork(ipAddress.getId(), networkId); + } if (isIpSystem && releaseIpIfElastic && !_ipAddrMgr.handleSystemIpRelease(ipAddress)) { logger.warn("Failed to release system ip address " + ipAddress); @@ -1379,7 +1407,8 @@ public class RulesManagerImpl extends ManagerBase implements RulesManager, Rules return new StaticNatRuleImpl(ruleVO, dstIp); } - protected boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) { + @Override + public boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) { IpAddress sourceIp = _ipAddressDao.findById(sourceIpId); List staticNats = createStaticNatForIp(sourceIp, caller, forRevoke); diff --git a/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java index 5335b24e897..5dac69d96da 100644 --- a/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLManagerImpl.java @@ -369,15 +369,16 @@ public class NetworkACLManagerImpl extends ManagerBase implements NetworkACLMana } @Override - public boolean reorderAclRules(VpcVO vpc, List networks, List networkACLItems) { - List nsxElements = new ArrayList<>(); - nsxElements.add((NetworkACLServiceProvider) _ntwkModel.getElementImplementingProvider(Network.Provider.Nsx.getName())); + public boolean reorderAclRules(VpcVO vpc, List networks, + List networkACLItems, Network.Provider networkProvider) { + List providers = new ArrayList<>(); + providers.add((NetworkACLServiceProvider) _ntwkModel.getElementImplementingProvider(networkProvider.getName())); try { - for (final NetworkACLServiceProvider provider : nsxElements) { + for (final NetworkACLServiceProvider provider : providers) { return provider.reorderAclRules(vpc, networks, networkACLItems); } } catch (final Exception ex) { - logger.debug("Failed to reorder ACLs on NSX due to: " + ex.getLocalizedMessage()); + logger.debug(String.format("Failed to reorder ACLs on %s due to: %s", networkProvider.getName(), ex.getLocalizedMessage())); } return false; } diff --git a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java index 0791ca7ecd3..2a9bc27f302 100644 --- a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java @@ -28,7 +28,9 @@ import javax.inject.Inject; import com.cloud.dc.DataCenter; import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NetrisProviderVO; import com.cloud.network.element.NsxProviderVO; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ServerApiException; @@ -41,6 +43,7 @@ import org.apache.cloudstack.api.command.user.network.UpdateNetworkACLListCmd; import org.apache.cloudstack.context.CallContext; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; @@ -104,6 +107,8 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ private VpcService _vpcSvc; @Inject private NsxProviderDao nsxProviderDao; + @Inject + private NetrisProviderDao netrisProviderDao; private String supportedProtocolsForAclRules = "tcp,udp,icmp,all"; @@ -1031,10 +1036,12 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ } final DataCenter dc = _entityMgr.findById(DataCenter.class, vpc.getZoneId()); final NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dc.getId()); + final NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(dc.getId()); List networks = _networkDao.listByAclId(lockedAcl.getId()); - if (Objects.nonNull(nsxProvider) && !networks.isEmpty()) { + if (ObjectUtils.anyNotNull(nsxProvider, netrisProvider) && !networks.isEmpty()) { allAclRules = getAllAclRulesSortedByNumber(lockedAcl.getId()); - _networkAclMgr.reorderAclRules(vpc, networks, allAclRules); + Network.Provider networkProvider = nsxProvider != null ? Network.Provider.Nsx : Network.Provider.Netris; + _networkAclMgr.reorderAclRules(vpc, networks, allAclRules, networkProvider); } return networkACLItem; } finally { diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 7a2e789996f..e63394ee445 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -48,8 +48,22 @@ import com.cloud.bgp.BGPService; import com.cloud.dc.ASNumberVO; import com.cloud.dc.dao.ASNumberDao; import com.cloud.dc.Vlan; +import com.cloud.network.RemoteAccessVpn; +import com.cloud.network.Site2SiteVpnConnection; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.dao.RemoteAccessVpnDao; +import com.cloud.network.dao.RemoteAccessVpnVO; +import com.cloud.network.dao.Site2SiteCustomerGatewayDao; +import com.cloud.network.dao.Site2SiteCustomerGatewayVO; +import com.cloud.network.dao.Site2SiteVpnConnectionDao; +import com.cloud.network.dao.Site2SiteVpnConnectionVO; +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.network.element.NetworkACLServiceProvider; import com.cloud.network.element.NsxProviderVO; +import com.cloud.network.rules.RulesManager; +import com.cloud.network.vpn.RemoteAccessVpnService; +import com.cloud.vm.dao.VMInstanceDao; import com.google.common.collect.Sets; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.alert.AlertService; @@ -292,13 +306,29 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Inject private NsxProviderDao nsxProviderDao; @Inject + private NetrisProviderDao netrisProviderDao; + @Inject RoutedIpv4Manager routedIpv4Manager; + @Inject + DomainRouterDao domainRouterDao; + @Inject + RulesManager rulesManager; + @Inject + VMInstanceDao vmInstanceDao; + @Inject + RemoteAccessVpnDao remoteAccessVpnDao; + @Inject + RemoteAccessVpnService remoteAccessVpnMgr; + @Inject + Site2SiteVpnConnectionDao site2SiteVpnConnectionDao; + @Inject + Site2SiteCustomerGatewayDao site2SiteCustomerGatewayDao; private final ScheduledExecutorService _executor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("VpcChecker")); private List vpcElements = null; private final List nonSupportedServices = Arrays.asList(Service.SecurityGroup, Service.Firewall); private final List supportedProviders = Arrays.asList(Provider.VPCVirtualRouter, Provider.NiciraNvp, Provider.InternalLbVm, Provider.Netscaler, - Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.BigSwitchBcf, Provider.ConfigDrive, Provider.Nsx); + Provider.JuniperContrailVpcRouter, Provider.Ovs, Provider.BigSwitchBcf, Provider.ConfigDrive, Provider.Nsx, Provider.Netris); int _cleanupInterval; int _maxNetworks; @@ -354,7 +384,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap, true, State.Enabled, null, false, - false, false, false, null, null, false); + false, false, null, null, false); } // configure default vpc offering with Netscaler as LB Provider @@ -374,7 +404,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName, - svcProviderMap, false, State.Enabled, null, false, false, false, false, null, null, false); + svcProviderMap, false, State.Enabled, null, false, false, false, null, null, false); } @@ -395,7 +425,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } createVpcOffering(VpcOffering.redundantVPCOfferingName, VpcOffering.redundantVPCOfferingName, svcProviderMap, true, State.Enabled, - null, false, false, true, false, null, null, false); + null, false, false, true, null, null, false); } // configure default vpc offering with NSX as network service provider in NAT mode @@ -412,7 +442,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, svcProviderMap, false, - State.Enabled, null, false, false, false, true, NetworkOffering.NetworkMode.NATTED, null, false); + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false); } @@ -430,7 +460,43 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, svcProviderMap, false, - State.Enabled, null, false, false, false, true, NetworkOffering.NetworkMode.ROUTED, null, false); + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false); + + } + + // configure default vpc offering with Netris as network service provider in Route mode + if (_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME) == null) { + logger.debug(String.format("Creating default VPC offering for Netris network service provider %s in Routed mode", VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME)); + final Map> svcProviderMap = new HashMap<>(); + final Set defaultProviders = Set.of(Provider.Netris); + for (final Service svc : getSupportedServices()) { + if (List.of(Service.UserData, Service.Dhcp, Service.Dns).contains(svc)) { + final Set userDataProvider = Set.of(Provider.VPCVirtualRouter); + svcProviderMap.put(svc, userDataProvider); + } else if (List.of(Service.SourceNat, Service.NetworkACL).contains(svc)){ + svcProviderMap.put(svc, defaultProviders); + } + } + createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME, svcProviderMap, false, + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false); + + } + + // configure default vpc offering with Netris as network service provider in NAT mode + if (_vpcOffDao.findByUniqueName(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME) == null) { + logger.debug(String.format("Creating default VPC offering for Netris network service provider %s in NAT mode", VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME)); + final Map> svcProviderMap = new HashMap<>(); + final Set defaultProviders = Set.of(Provider.Netris); + for (final Service svc : getSupportedServices()) { + if (List.of(Service.UserData, Service.Dhcp, Service.Dns, Service.Vpn).contains(svc)) { + final Set userDataProvider = Set.of(Provider.VPCVirtualRouter); + svcProviderMap.put(svc, userDataProvider); + } else { + svcProviderMap.put(svc, defaultProviders); + } + } + createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, svcProviderMap, false, + State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false); } } @@ -490,7 +556,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final Long serviceOfferingId = cmd.getServiceOfferingId(); final List domainIds = cmd.getDomainIds(); final List zoneIds = cmd.getZoneIds(); - final Boolean forNsx = cmd.isForNsx(); + final String provider = cmd.getProvider(); + final Boolean forNsx = Objects.nonNull(provider) && provider.equalsIgnoreCase("NSX"); final String networkModeStr = cmd.getNetworkMode(); final boolean enable = cmd.getEnable(); @@ -552,7 +619,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } return createVpcOffering(vpcOfferingName, displayText, supportedServices, - serviceProviderList, serviceCapabilityList, internetProtocol, serviceOfferingId, forNsx, networkMode, + serviceProviderList, serviceCapabilityList, internetProtocol, serviceOfferingId, provider, networkMode, domainIds, zoneIds, (enable ? State.Enabled : State.Disabled), routingMode, specifyAsNumber); } @@ -560,7 +627,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @ActionEvent(eventType = EventTypes.EVENT_VPC_OFFERING_CREATE, eventDescription = "creating vpc offering", create = true) public VpcOffering createVpcOffering(final String name, final String displayText, final List supportedServices, final Map> serviceProviders, final Map serviceCapabilityList, final NetUtils.InternetProtocol internetProtocol, final Long serviceOfferingId, - final Boolean forNsx, final NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, State state, + final String externalProvider, final NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, State state, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber) { if (!Ipv6Service.Ipv6OfferingCreationEnabled.value() && !(internetProtocol == null || NetUtils.InternetProtocol.IPv4.equals(internetProtocol))) { @@ -644,7 +711,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis Service redundantRouterService = Service.SourceNat; if (CollectionUtils.isNotEmpty(sourceNatServiceProviders)) { svcProviderMap.put(Service.Gateway, sourceNatServiceProviders); - } else if (NetworkOffering.NetworkMode.ROUTED.equals(networkMode)) { + } else if (NetworkOffering.NetworkMode.ROUTED.equals(networkMode) && org.apache.commons.lang3.StringUtils.isBlank(externalProvider)) { + // For Routed mode, add the Gateway service except for external providers such as NSX, Netris to not override the svcProviderMap mapping svcProviderMap.put(Service.Gateway, Sets.newHashSet(Provider.VPCVirtualRouter)); redundantRouterService = Service.Gateway; } @@ -655,7 +723,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final boolean offersRegionLevelVPC = isVpcOfferingForRegionLevelVpc(serviceCapabilityList); final boolean redundantRouter = isVpcOfferingRedundantRouter(serviceCapabilityList, redundantRouterService); final VpcOfferingVO offering = createVpcOffering(name, displayText, svcProviderMap, false, state, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC, - redundantRouter, forNsx, networkMode, routingMode, specifyAsNumber); + redundantRouter, networkMode, routingMode, specifyAsNumber); if (offering != null) { List detailsVO = new ArrayList<>(); @@ -681,9 +749,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } @DB - protected VpcOfferingVO createVpcOffering(final String name, final String displayText, final Map> svcProviderMap, + protected VpcOfferingVO createVpcOffering(final String name, final String displayText, final Map> svcProviderMap, final boolean isDefault, final State state, final Long serviceOfferingId, final boolean supportsDistributedRouter, final boolean offersRegionLevelVPC, - final boolean redundantRouter, Boolean forNsx, NetworkOffering.NetworkMode networkMode, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber) { + final boolean redundantRouter, NetworkOffering.NetworkMode networkMode, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber) { return Transaction.execute(new TransactionCallback() { @Override @@ -694,7 +762,6 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (state != null) { offering.setState(state); } - offering.setForNsx(forNsx); offering.setNetworkMode(networkMode); offering.setSpecifyAsNumber(specifyAsNumber); if (Objects.nonNull(routingMode)) { @@ -1309,11 +1376,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu(), cmd.getCidrSize(), cmd.getAsNumber(), bgpPeerIds, cmd.getUseVrIpResolver()); String sourceNatIP = cmd.getSourceNatIP(); - boolean forNsx = isVpcForNsx(vpc); + boolean forNsx = isVpcForProvider(Provider.Nsx, vpc); + boolean forNetris = isVpcForProvider(Provider.Netris, vpc); try { - if (sourceNatIP != null || forNsx) { - if (forNsx) { - logger.info("Provided source NAT IP will be ignored in an NSX-enabled zone"); + if (sourceNatIP != null || forNsx || forNetris) { + if (forNsx || forNetris) { + logger.info("Provided source NAT IP will be ignored in an NSX-enabled or Netris-enabled zone"); sourceNatIP = null; } logger.info(String.format("Trying to allocate the specified IP [%s] as the source NAT of VPC [%s].", sourceNatIP, vpc)); @@ -1342,15 +1410,11 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis return NetworkOffering.RoutingMode.Dynamic == vpcOffering.getRoutingMode(); } - private boolean isVpcForNsx(Vpc vpc) { + private boolean isVpcForProvider(Provider provider, Vpc vpc) { if (vpc == null) { return false; } - VpcOfferingServiceMapVO mapVO = _vpcOffSvcMapDao.findByServiceProviderAndOfferingId(Service.SourceNat.getName(), Provider.Nsx.getName(), vpc.getVpcOfferingId()); - if (mapVO != null) { - logger.debug(String.format("The VPC %s is NSX-based and supports the %s service", vpc.getName(), Service.SourceNat.getName())); - } - return mapVO != null; + return _vpcOffSvcMapDao.isProviderForVpcOffering(provider, vpc.getVpcOfferingId()); } private void allocateSourceNatIp(Vpc vpc, String sourceNatIP) { @@ -1358,9 +1422,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis DataCenter zone = _dcDao.findById(vpc.getZoneId()); // reserve this ip and then try { - if (isVpcForNsx(vpc) && org.apache.commons.lang3.StringUtils.isBlank(sourceNatIP)) { + if (isVpcForProvider(Provider.Nsx, vpc) && org.apache.commons.lang3.StringUtils.isBlank(sourceNatIP)) { logger.debug(String.format("Reserving a source NAT IP for NSX VPC %s", vpc.getName())); - sourceNatIP = reserveSourceNatIpForNsxVpc(account, zone); + sourceNatIP = reserveSourceNatIpForProviderVpc(account, zone, Provider.Nsx); + } else if (isVpcForProvider(Provider.Netris, vpc) && org.apache.commons.lang3.StringUtils.isBlank(sourceNatIP)) { + logger.debug(String.format("Reserving a source NAT IP for Netris VPC %s", vpc.getName())); + sourceNatIP = reserveSourceNatIpForProviderVpc(account, zone, Provider.Netris); } IpAddress ip = _ipAddrMgr.allocateIp(account, false, CallContext.current().getCallingAccount(), CallContext.current().getCallingUser(), zone, null, sourceNatIP); this.associateIPToVpc(ip.getId(), vpc.getId()); @@ -1369,8 +1436,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } - private String reserveSourceNatIpForNsxVpc(Account account, DataCenter zone) throws ResourceAllocationException { - IpAddress ipAddress = _ntwkSvc.reserveIpAddressWithVlanDetail(account, zone, true, ApiConstants.NSX_DETAIL_KEY); + private String reserveSourceNatIpForProviderVpc(Account account, DataCenter zone, Provider provider) throws ResourceAllocationException { + String detailKey = provider == Provider.Nsx ? ApiConstants.NSX_DETAIL_KEY : ApiConstants.NETRIS_DETAIL_KEY; + IpAddress ipAddress = _ntwkSvc.reserveIpAddressWithVlanDetail(account, zone, true, detailKey); return ipAddress.getAddress().addr(); } @@ -1534,6 +1602,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis _accountMgr.checkAccess(caller, null, false, vpcToUpdate); final VpcVO vpc = vpcDao.createForUpdate(vpcId); + String previousVpcName = vpcToUpdate.getName(); if (vpcName != null) { vpc.setName(vpcName); @@ -1569,10 +1638,20 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } else { if (logger.isDebugEnabled()) { logger.debug("no restart needed."); + if (isVpcForProvider(Provider.Netris, vpcToUpdate)) { + final String aclProvider = _vpcSrvcDao.getProviderForServiceInVpc(vpc.getId(), Service.NetworkACL); + for (final VpcProvider provider : getVpcElements()) { + if ((provider instanceof NetworkACLServiceProvider && provider.getName().equalsIgnoreCase(aclProvider))) { + vpcToUpdate.setName(vpcName); + provider.updateVpc(vpcToUpdate, previousVpcName); + break; + } + } + } } } return vpcDao.findById(vpcId); - } else if (isVpcForNsx(vpcToUpdate)) { + } else if (isVpcForProvider(Provider.Nsx, vpcToUpdate)) { if (logger.isDebugEnabled()) { logger.debug("no restart needed."); } @@ -1591,14 +1670,15 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (! userIps.isEmpty()) { try { _ipAddrMgr.updateSourceNatIpAddress(requestedIp, userIps); - if (isVpcForNsx(vpc)) { - VpcProvider nsxElement = (VpcProvider) _ntwkModel.getElementImplementingProvider(Provider.Nsx.getName()); - if (nsxElement == null) { - return true; + if (isVpcForProvider(Provider.Nsx, vpc) || isVpcForProvider(Provider.Netris, vpc)) { + boolean isForNsx = _vpcOffSvcMapDao.isProviderForVpcOffering(Provider.Nsx, vpc.getVpcOfferingId()); + String providerName = isForNsx ? Provider.Nsx.getName() : Provider.Netris.getName(); + VpcProvider providerElement = (VpcProvider) _ntwkModel.getElementImplementingProvider(providerName); + if (Objects.nonNull(providerElement)) { + providerElement.updateVpcSourceNatIp(vpc, requestedIp); + return false; } - nsxElement.updateVpcSourceNatIp(vpc, requestedIp); - // The NSX source NAT IP change does not require to update the VPC VR - return false; + return true; } } catch (Exception e) { // pokemon exception from transaction String msg = String.format("Update of source NAT ip to %s for network \"%s\"/%s failed due to %s", @@ -2054,7 +2134,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // 5) When aclId is provided, verify that ACLProvider is supported by // network offering - if (aclId != null && !_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.NetworkACL) && !guestNtwkOff.isForNsx()) { + boolean isForNsx = _ntwkModel.isProviderForNetworkOffering(Provider.Nsx, guestNtwkOff.getId()); + if (aclId != null && !_ntwkModel.areServicesSupportedByNetworkOffering(guestNtwkOff.getId(), Service.NetworkACL) && !isForNsx) { throw new InvalidParameterValueException("Cannot apply NetworkACL. Network Offering does not support NetworkACL service"); } @@ -2072,7 +2153,9 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // 2) Only Isolated networks with Source nat service enabled can be // added to vpc - if (!guestNtwkOff.isForNsx() + boolean isForNsx = _ntwkModel.isProviderForNetworkOffering(Provider.Nsx, guestNtwkOff.getId()); + boolean isForNNetris = _ntwkModel.isProviderForNetworkOffering(Provider.Netris, guestNtwkOff.getId()); + if (!isForNsx && !isForNNetris && !(guestNtwkOff.getGuestType() == GuestType.Isolated && (supportedSvcs.contains(Service.SourceNat) || supportedSvcs.contains(Service.Gateway)))) { throw new InvalidParameterValueException("Only network offerings of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() @@ -2200,6 +2283,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis logger.debug("Cleaning up existed site to site VPN gateways"); _s2sVpnMgr.cleanupVpnGatewayByVpc(vpc.getId()); + List vpns = remoteAccessVpnDao.listByVpcId(vpc.getId()); + for (RemoteAccessVpnVO vpn : vpns) { + logger.debug("Disabling remote access VPN on {}", vpn.getServerAddressId()); + remoteAccessVpnMgr.destroyRemoteAccessVpnForIp(vpn.getServerAddressId(), caller, true); + } + // 2) release all ip addresses final List ipsToRelease = _ipAddressDao.listByAssociatedVpc(vpc.getId(), null); logger.debug("Releasing ips for vpc {} as a part of vpc cleanup", vpc); @@ -2334,6 +2423,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis restartRequired = true; return false; } + reconfigStaticNatForVpcVr(vpcId); return true; } @@ -2840,28 +2930,38 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override public boolean applyStaticRoutesForVpc(final long vpcId) throws ResourceUnavailableException { final Account caller = CallContext.current().getCallingAccount(); - final List routes = _staticRouteDao.listByVpcId(vpcId); + final List routes = getVpcStaticRoutes(vpcId); return applyStaticRoutes(routes, caller, true); } - protected boolean applyStaticRoutes(final List routes, final Account caller, final boolean updateRoutesInDB) throws ResourceUnavailableException { - final boolean success = true; - final List staticRouteProfiles = new ArrayList(routes.size()); - final Map gatewayMap = new HashMap(); - for (final StaticRoute route : routes) { - VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId()); - if (gateway == null) { - gateway = _vpcGatewayDao.findById(route.getVpcGatewayId()); - gatewayMap.put(gateway.getId(), gateway); + @Override + public boolean applyStaticRouteForVpcVpnIfNeeded(final Long vpcId, boolean updateAllVpn) throws ResourceUnavailableException { + if (isProviderSupportServiceInVpc(vpcId, Service.Vpn, Network.Provider.VPCVirtualRouter)) { + boolean isVpcVRSourceNat = isProviderSupportServiceInVpc(vpcId, Service.SourceNat, Network.Provider.VPCVirtualRouter); + if (isVpcVRSourceNat) { + logger.debug("Skipping static route configuration as VPC VR is Source NAT"); + return true; } - staticRouteProfiles.add(new StaticRouteProfile(route, gateway)); + logger.debug("Configuring static route for VPC VR of VPC " + vpcId); + final Account caller = CallContext.current().getCallingAccount(); + final List routes = getVpcStaticRoutes(vpcId, updateAllVpn); + return applyStaticRoutes(routes, caller, false); } + return true; + } + + protected boolean applyStaticRoutes(final List routes, final Account caller, final boolean updateRoutesInDB) throws ResourceUnavailableException { + final boolean success = true; + final List staticRouteProfiles = getVpcStaticRoutes(routes); if (!applyStaticRoutes(staticRouteProfiles)) { logger.warn("Routes are not completely applied"); return false; } else { if (updateRoutesInDB) { - for (final StaticRoute route : routes) { + for (final StaticRouteVO route : routes) { + if (route.isForVpn()) { + continue; + } if (route.getState() == StaticRoute.State.Revoke) { _staticRouteDao.remove(route.getId()); logger.debug("Removed route " + route + " from the DB"); @@ -2924,7 +3024,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @DB protected boolean revokeStaticRoutesForVpc(final Vpc vpc, final Account caller) throws ResourceUnavailableException { // get all static routes for the vpc - final List routes = _staticRouteDao.listByVpcId(vpc.getId()); + final List routes = getVpcStaticRoutes(vpc.getId()); logger.debug("Found {} to revoke for the vpc {}", routes.size(), vpc); if (!routes.isEmpty()) { // mark all of them as revoke @@ -2945,23 +3045,46 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Override @DB @ActionEvent(eventType = EventTypes.EVENT_STATIC_ROUTE_CREATE, eventDescription = "creating static route", create = true) - public StaticRoute createStaticRoute(final long gatewayId, final String cidr) throws NetworkRuleConflictException { + public StaticRoute createStaticRoute(final Long gatewayId, Long vpcId, final String nextHop, final String cidr) throws NetworkRuleConflictException { final Account caller = CallContext.current().getCallingAccount(); // parameters validation - final VpcGateway gateway = _vpcGatewayDao.findById(gatewayId); - if (gateway == null) { - throw new InvalidParameterValueException("Invalid gateway id is given"); + if (gatewayId == null && nextHop == null) { + throw new InvalidParameterValueException("one of gatewayId and nextHop must be specified"); } - if (gateway.getState() != VpcGateway.State.Ready) { - throw new InvalidParameterValueException("Gateway is not in the " + VpcGateway.State.Ready + " state: " + gateway.getState()); + if (gatewayId != null && nextHop != null) { + throw new InvalidParameterValueException("Only one of gatewayId and nextHop can be specified"); } - final Vpc vpc = getActiveVpc(gateway.getVpcId()); + if (gatewayId != null) { + final VpcGateway gateway = _vpcGatewayDao.findById(gatewayId); + if (gateway == null) { + throw new InvalidParameterValueException("Invalid gateway id is given"); + } + + if (gateway.getState() != VpcGateway.State.Ready) { + throw new InvalidParameterValueException("Gateway is not in the " + VpcGateway.State.Ready + " state: " + gateway.getState()); + } + + if (vpcId != null) { + if (!vpcId.equals(gateway.getVpcId())) { + throw new InvalidParameterValueException("Invalid gateway id is given"); + } + } else { + vpcId = gateway.getVpcId(); + } + } else if (nextHop != null) { + if (vpcId == null) { + throw new InvalidParameterValueException("vpcId must be specified"); + } + } + + final Vpc vpc = getActiveVpc(vpcId); if (vpc == null) { throw new InvalidParameterValueException("Can't add static route to VPC that is being deleted"); } + _accountMgr.checkAccess(caller, null, false, vpc); if (!NetUtils.isValidIp4Cidr(cidr)) { @@ -2984,10 +3107,15 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis throw new InvalidParameterValueException("The static gateway cidr overlaps with one of the denied routes of the zone the VPC belongs to"); } + // 4) validate next hop + if (nextHop != null && !isNextHopValid(nextHop, vpc)) { + throw new InvalidParameterValueException(String.format("Next hop %s is invalid. It must be within VPC CIDR or on the same public or private network", nextHop)); + } + return Transaction.execute(new TransactionCallbackWithException() { @Override public StaticRouteVO doInTransaction(final TransactionStatus status) throws NetworkRuleConflictException { - StaticRouteVO newRoute = new StaticRouteVO(gateway.getId(), cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId()); + StaticRouteVO newRoute = new StaticRouteVO(gatewayId, cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), nextHop); logger.debug("Adding static route " + newRoute); newRoute = _staticRouteDao.persist(newRoute); @@ -3003,6 +3131,44 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis }); } + private boolean isNextHopValid(String nextHop, Vpc vpc) { + // Scenario 1: VM as next hop + if (NetUtils.isIpWithInCidrRange(nextHop, vpc.getCidr())) { + logger.debug("The next Hop {} is valid as it is within the VPC cidr {}", nextHop, vpc.getCidr()); + return true; + } + // Scenario 2: Another public IP as next hop + List ips = _ipAddressDao.listByAssociatedVpc(vpc.getId(), null); + List vlanIds = new ArrayList<>(); + for (IPAddressVO ip : ips) { + if (vlanIds.contains(ip.getVlanId())) { + continue; + } + VlanVO vlan = _vlanDao.findById(ip.getVlanId()); + if (vlan != null) { + String vlanCidr = NetUtils.getCidrFromGatewayAndNetmask(vlan.getVlanGateway(), vlan.getVlanNetmask()); + if (NetUtils.isIpWithInCidrRange(nextHop, vlanCidr)) { + logger.debug("The next Hop {} is valid as it is on the same network as Public IP address {} ", nextHop, ip.getAddress()); + return true; + } + } + vlanIds.add(ip.getVlanId()); + } + + // Scenario 3: An IP on private gateway as next hop + List vpcGateways = _vpcGatewayDao.listByVpcId(vpc.getId()); + for (VpcGatewayVO vpcGateway : vpcGateways) { + String vpcGatewayCidr = NetUtils.getCidrFromGatewayAndNetmask(vpcGateway.getGateway(), vpcGateway.getNetmask()); + if (NetUtils.isIpWithInCidrRange(nextHop, vpcGatewayCidr)) { + logger.debug("The next Hop {} is valid as it is on the same network as private gateway {} ", nextHop, vpcGateway.getIp4Address()); + return true; + } + } + + logger.debug("The next Hop {} is invalid", nextHop); + return false; + } + protected boolean isCidrDenylisted(final String cidr, final long zoneId) { final String routesStr = NetworkOrchestrationService.DeniedRoutes.valueIn(zoneId); if (routesStr != null && !routesStr.isEmpty()) { @@ -3208,7 +3374,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis logger.debug(String.format("Associating IP [%s] to VPC [%s]", ipToAssoc, vpc)); - final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(vpc.getAccountId(), vpcId, false) == null; + final boolean isSourceNatFinal = isSrcNatIpRequired(vpc.getVpcOfferingId()) && getExistingSourceNatInVpc(vpc.getAccountId(), vpcId, false, false) == null; try { IPAddressVO updatedIpAddress = Transaction.execute((TransactionCallbackWithException) status -> { final IPAddressVO ip = _ipAddressDao.findById(ipId); @@ -3311,7 +3477,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis return guestNetwork; } - protected IPAddressVO getExistingSourceNatInVpc(final long ownerId, final long vpcId, final boolean forNsx) { + protected IPAddressVO getExistingSourceNatInVpc(final long ownerId, final long vpcId, final boolean forNsx, final boolean forNetris) { final List addrs = listPublicIpsAssignedToVpc(ownerId, true, vpcId); @@ -3322,7 +3488,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis // Account already has ip addresses for (final IPAddressVO addr : addrs) { if (addr.isSourceNat()) { - if (!forNsx) { + if (!forNsx && !forNetris) { sourceNatIp = addr; } else { if (addr.isForSystemVms()) { @@ -3359,16 +3525,21 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final long dcId = vpc.getZoneId(); NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(dcId); boolean forNsx = nsxProvider != null; + NetrisProviderVO netrisProvider = netrisProviderDao.findByZoneId(dcId); + boolean forNetris = netrisProvider != null; - final IPAddressVO sourceNatIp = getExistingSourceNatInVpc(owner.getId(), vpc.getId(), forNsx); + final IPAddressVO sourceNatIp = getExistingSourceNatInVpc(owner.getId(), vpc.getId(), forNsx, forNetris); PublicIp ipToReturn = null; if (sourceNatIp != null) { ipToReturn = PublicIp.createFromAddrAndVlan(sourceNatIp, _vlanDao.findById(sourceNatIp.getVlanId())); } else { - if (forNsx) { - ipToReturn = _ipAddrMgr.assignPublicIpAddress(dcId, podId, owner, Vlan.VlanType.VirtualNetwork, null, null, false, true); + if (forNsx || forNetris) { + // Assign VR (helper VM) public NIC IP address from the separate provider Public IP range/pool + // NSX: VR uses Public IP from the system VM range + // Netris: VR uses Public IP from the non system VM range + ipToReturn = _ipAddrMgr.assignPublicIpAddress(dcId, podId, owner, Vlan.VlanType.VirtualNetwork, null, null, false, forNsx); } else { ipToReturn = _ipAddrMgr.assignDedicateIpAddress(owner, null, vpc.getId(), dcId, true); } @@ -3411,11 +3582,23 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis final Map> vpcOffSvcProvidersMap = getVpcOffSvcProvidersMap(vpcOfferingId); return (Objects.nonNull(vpcOffSvcProvidersMap.get(Network.Service.SourceNat)) && (vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter) - || vpcOffSvcProvidersMap.get(Service.SourceNat).contains(Provider.Nsx))) + || vpcOffSvcProvidersMap.get(Service.SourceNat).contains(Provider.Nsx) + || vpcOffSvcProvidersMap.get(Service.SourceNat).contains(Provider.Netris))) || (Objects.nonNull(vpcOffSvcProvidersMap.get(Network.Service.Gateway)) - && vpcOffSvcProvidersMap.get(Service.Gateway).contains(Network.Provider.VPCVirtualRouter)); + && (vpcOffSvcProvidersMap.get(Service.Gateway).contains(Network.Provider.VPCVirtualRouter) + || vpcOffSvcProvidersMap.get(Service.Gateway).contains(Provider.Nsx) + || vpcOffSvcProvidersMap.get(Service.Gateway).contains(Network.Provider.Netris))); } + @Override + public boolean isSrcNatIpRequiredForVpcVr(long vpcOfferingId) { + final Map> vpcOffSvcProvidersMap = getVpcOffSvcProvidersMap(vpcOfferingId); + return (Objects.nonNull(vpcOffSvcProvidersMap.get(Network.Service.SourceNat)) + && vpcOffSvcProvidersMap.get(Network.Service.SourceNat).contains(Network.Provider.VPCVirtualRouter)) + || (Objects.nonNull(vpcOffSvcProvidersMap.get(Network.Service.Gateway)) + && vpcOffSvcProvidersMap.get(Service.Gateway).contains(Network.Provider.VPCVirtualRouter)); + } + /** * rollingRestartVpc performs restart of routers of a VPC by first * deploying a new VR and then destroying old VRs in rolling fashion. For @@ -3505,4 +3688,244 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis protected boolean isDefaultAcl(long aclId) { return aclId == NetworkACL.DEFAULT_ALLOW || aclId == NetworkACL.DEFAULT_DENY; } + + @Override + public List getVpcStaticRoutes(final List routes) { + final List staticRouteProfiles = new ArrayList<>(routes.size()); + final Map gatewayMap = new HashMap(); + for (final StaticRoute route : routes) { + if (route.getVpcGatewayId() != null) { + VpcGateway gateway = gatewayMap.get(route.getVpcGatewayId()); + if (gateway == null) { + gateway = _entityMgr.findById(VpcGateway.class, route.getVpcGatewayId()); + gatewayMap.put(gateway.getId(), gateway); + } + staticRouteProfiles.add(new StaticRouteProfile(route, gateway)); + } else { + staticRouteProfiles.add(new StaticRouteProfile(route)); + } + } + return staticRouteProfiles; + } + + @Override + public List getVpcStaticRoutes(Long vpcId) { + return getVpcStaticRoutes(vpcId, false); + } + + public List getVpcStaticRoutes(Long vpcId, boolean updateAllVpn) { + final List routes = _staticRouteDao.listByVpcId(vpcId); + + if (isProviderSupportServiceInVpc(vpcId, Service.Vpn, Network.Provider.VPCVirtualRouter) + && !isProviderSupportServiceInVpc(vpcId, Service.SourceNat, Network.Provider.VPCVirtualRouter)) { + + Vpc vpc = vpcDao.findById(vpcId); + IPAddressVO ipAddressForVpcVR = getIpAddressForVpcVr(vpc, null, false); + String nextHop = getFirstGuestIpAddressForVpcVr(vpc.getId()); + + if (ipAddressForVpcVR != null && (updateAllVpn || nextHop != null)) { + // Add Static Routes for Remote Access VPN + List staticRoutesForRemoteAccessVpn = new ArrayList<>(); + RemoteAccessVpnVO remoteAccessVpn = remoteAccessVpnDao.findByPublicIpAddress(ipAddressForVpcVR.getId()); + if (remoteAccessVpn != null) { + String ipRange = remoteAccessVpn.getIpRange(); + String startIp = ipRange.split("-")[0]; + String endIp = ipRange.split("-")[1]; + int cidrSize = NetUtils.getBigCidrSizeOfIpRange(NetUtils.ip2Long(startIp), NetUtils.ip2Long(endIp)); + String cidr = NetUtils.transformCidr(startIp + "/" + cidrSize); + if (nextHop == null || RemoteAccessVpn.State.Removed.equals(remoteAccessVpn.getState())) { + StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), null, + StaticRoute.State.Revoke, true); + staticRoutesForRemoteAccessVpn.add(newRoute); + } else { + StaticRoute.State state = updateAllVpn ? StaticRoute.State.Update : StaticRoute.State.Add; + StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), nextHop, + state, true); + staticRoutesForRemoteAccessVpn.add(newRoute); + } + } + logger.debug("Adding {} static routes for Remote Access VPN", staticRoutesForRemoteAccessVpn.size()); + routes.addAll(staticRoutesForRemoteAccessVpn); + + // Add Static Routes for Site-to-Site VPN connections + List staticRoutesForSite2SiteVpn = new ArrayList<>(); + List vpnConnections = site2SiteVpnConnectionDao.listByVpcId(vpcId); + for (Site2SiteVpnConnectionVO vpnConnection : vpnConnections) { + Site2SiteCustomerGatewayVO customerGateway = site2SiteCustomerGatewayDao.findById(vpnConnection.getCustomerGatewayId()); + if (nextHop == null || Site2SiteVpnConnection.State.Removed.equals(vpnConnection.getState())) { + for (String cidr: customerGateway.getGuestCidrList().split(",")) { + StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), null, + StaticRoute.State.Revoke, true); + staticRoutesForSite2SiteVpn.add(newRoute); + } + } else { + StaticRoute.State state = updateAllVpn ? StaticRoute.State.Update : StaticRoute.State.Add; + for (String cidr : customerGateway.getGuestCidrList().split(",")) { + StaticRouteVO newRoute = new StaticRouteVO(cidr, vpc.getId(), vpc.getAccountId(), vpc.getDomainId(), nextHop, + state, true); + staticRoutesForSite2SiteVpn.add(newRoute); + } + } + } + logger.debug("Adding {} static routes for {} Site-to-Site VPN connections", + staticRoutesForSite2SiteVpn.size(), vpnConnections.size()); + routes.addAll(staticRoutesForSite2SiteVpn); + } + } + + logger.debug("Found {} static routes for VPC {}", routes.size(), vpcId); + return routes; + } + + @Override + public boolean isProviderSupportServiceInVpc(long vpcId, Service service, Provider provider) { + return _vpcSrvcDao.canProviderSupportServiceInVpc(vpcId, service, provider); + } + + @Override + public IPAddressVO getIpAddressForVpcVr(Vpc vpc, IPAddressVO ipAddress, boolean allocateIpIfNeeded) { + // Validate if the IP address is associated to a VPC VR + final List ips = _ipAddressDao.listByAssociatedVpc(vpc.getId(), null); + IPAddressVO ipAddressForVR = ips.stream().filter(ip -> ip.isForRouter()).findFirst().orElse(null); + if (ipAddressForVR != null) { + if (ipAddress != null && ipAddressForVR.getId() != ipAddress.getId()) { + throw new InvalidParameterValueException(String.format("Cannot assign Public IP %s to VPC VR as %s has been associated to the VPC VR.", + ipAddress.getAddress().addr(), ipAddressForVR.getAddress().addr())); + } + return ipAddressForVR; + } else if (ipAddress != null) { + if (ipAddress.isSourceNat()) { + throw new InvalidParameterValueException("Vpn service can not be configured on the Source NAT IP of VPC id=" + ipAddress.getVpcId()); + } + return ipAddress; + } + + if (allocateIpIfNeeded) { + Account account = _accountMgr.getAccount(vpc.getAccountId()); + DataCenter zone = _dcDao.findById(vpc.getZoneId()); + try { + IpAddress ip = _ipAddrMgr.allocateIp(account, false, CallContext.current().getCallingAccount(), + CallContext.current().getCallingUser(), zone, null, null); + this.associateIPToVpc(ip.getId(), vpc.getId()); + return _ipAddressDao.findById(ip.getId()); + } catch (InsufficientAddressCapacityException | ResourceAllocationException | + ResourceUnavailableException ex) { + throw new InvalidParameterValueException("Cannot assign Public IP to VPC VR: " + ex.getMessage()); + } + } else { + return null; + } + } + + /* This method configures the Static Nat for VPC VR if it is used for VPN but not Source NAT. + * (1) Update forRouter to true and one-to-one to true + * (2) Get current network and router ID/IP + * (3) Get new network and router ID/IP + * (4) If network or IP is changed (in case VPC tier is removed or shutdown), disable/apply Static NAT with new VM ID and VM IP + * (5) otherwise, If VPC VR ID does not exist or is changed, update the VM ID. + * (6) otherwise, do nothing + * + * This is used in the following processes + * (1) create remote access VPN + * (2) create S2S VPN + * (3) destroy Router + * (4) restart Vpc with cleanup + * (5) add VPC tier + * (6) delete VPC tier + * (7) remove VPC + */ + + @Override + public boolean configStaticNatForVpcVr(Vpc vpc, IPAddressVO ipAddress) { + logger.debug("Configuring static nat for VPC VR of VPC " + vpc.getId()); + // (1) Update forRouter to true and one-to-one to true + if (!ipAddress.isForRouter()) { + ipAddress.setForRouter(true); + ipAddress.setOneToOneNat(true); + _ipAddressDao.update(ipAddress.getId(), ipAddress); + } + + // (2) Get current network and router ID/IP + Long currentNetworkId = ipAddress.getAssociatedWithNetworkId(); + Long currentRouterId = ipAddress.getAssociatedWithVmId(); + String currentRouterIp = ipAddress.getVmIp(); + + // (3) Get new network and router ID/IP + Long newNetworkId = null; + Long newRouterId = null; + String newRouterIp = null; + List networks = _ntwkDao.listByVpc(vpc.getId()); + for (NetworkVO network : networks) { + NicVO newNic = nicDao.findNonPlaceHolderByNetworkIdAndType(network.getId(), VirtualMachine.Type.DomainRouter); + if (newNic != null) { + logger.debug("Got VPC VR NIC for network {}: {}", network.getId(), newNic); + newNetworkId = network.getId(); + newRouterId = newNic.getInstanceId(); + newRouterIp = newNic.getIPv4Address(); + break; + } + } + + // Do nothing if the current and new network and router are Null + if (ObjectUtils.allNull(currentNetworkId, currentRouterId, newNetworkId, newRouterId)) { + logger.debug("The current and new network and router are Null, do nothing"); + return true; + } + + if (currentNetworkId == null || !currentNetworkId.equals(newNetworkId)) { + // (4) If network or IP is changed (in case VPC tier is removed or shutdown), disable/apply Static NAT with new VM ID and VM IP + if (currentNetworkId != null) { + // Disable Static NAT for current VPC VR + logger.debug("Disabling static nat for VPC VR (network: {}, router: {})", currentNetworkId, currentRouterId); + CallContext ctx = CallContext.current(); + if (!rulesManager.applyStaticNatForIp(ipAddress.getId(), false, ctx.getCallingAccount(),true)) { + throw new CloudRuntimeException("Failed to disable static nat for VPC VR"); + } + ipAddress.setAssociatedWithNetworkId(null); + ipAddress.setAssociatedWithVmId(null); + ipAddress.setVmIp(null); + _ipAddressDao.update(ipAddress.getId(), ipAddress); + } + if (newNetworkId != null) { + // Enable static nat for the new VPC VR + logger.debug("Enabling static nat for VPC VR (network: {}, router: {})", newNetworkId, newRouterId); + ipAddress.setAssociatedWithNetworkId(newNetworkId); + ipAddress.setAssociatedWithVmId(newRouterId); + ipAddress.setVmIp(newRouterIp); + _ipAddressDao.update(ipAddress.getId(), ipAddress); + CallContext ctx = CallContext.current(); + if (!rulesManager.applyStaticNatForIp(ipAddress.getId(), false, ctx.getCallingAccount(),false)) { + throw new CloudRuntimeException("Failed to enable static nat for VPC VR"); + } + } + } else if (currentRouterId == null || !currentRouterId.equals(newRouterId)) { + // (5) otherwise, If VPC VR ID does not exist or is changed, update the VM ID. + ipAddress.setAssociatedWithVmId(newRouterId); + ipAddress.setVmIp(newRouterIp); + _ipAddressDao.update(ipAddress.getId(), ipAddress); + } + return true; + } + + @Override + public void reconfigStaticNatForVpcVr(Long vpcId) { + Vpc vpc = vpcDao.findById(vpcId); + IPAddressVO ipAddressForVpcVR = getIpAddressForVpcVr(vpc, null, false); + if (ipAddressForVpcVR != null && !configStaticNatForVpcVr(vpc, ipAddressForVpcVR)) { + throw new CloudRuntimeException("Failed to reconfig static nat for VPC VR as part of the process"); + } + } + + private String getFirstGuestIpAddressForVpcVr(Long vpcId) { + String nextHop = null; + List networks = _ntwkDao.listByVpc(vpcId); + for (NetworkVO network : networks) { + NicVO nic = nicDao.findNonPlaceHolderByNetworkIdAndType(network.getId(), VirtualMachine.Type.DomainRouter); + if (nic != null) { + nextHop = nic.getIPv4Address(); + break; + } + } + return nextHop; + } } diff --git a/server/src/main/java/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java b/server/src/main/java/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java index 29c0106dc18..24c2f2221d9 100644 --- a/server/src/main/java/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpn/RemoteAccessVpnManagerImpl.java @@ -67,6 +67,7 @@ import com.cloud.network.rules.FirewallRule.Purpose; import com.cloud.network.rules.FirewallRuleVO; import com.cloud.network.rules.RulesManager; import com.cloud.network.vpc.Vpc; +import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.dao.VpcDao; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.server.ConfigurationServer; @@ -124,6 +125,9 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc UsageEventDao _usageEventDao; @Inject ConfigurationDao _configDao; + @Inject + VpcManager vpcManager; + List _vpnServiceProviders; @Inject @@ -181,7 +185,11 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc Long networkId = ipAddress.getAssociatedWithNetworkId(); if (networkId != null) { - _networkMgr.checkIpForService(ipAddress, Service.Vpn, null); + if (ipAddress.isForRouter()) { + logger.debug("The IP address is reserved for Domain Router, skipping the check now"); + } else { + _networkMgr.checkIpForService(ipAddress, Service.Vpn, null); + } } final Long vpcId = ipAddress.getVpcId(); @@ -218,6 +226,7 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc Pair cidr = null; if (networkId != null) { + Network network = _networkMgr.getNetwork(networkId); long ipAddressOwner = ipAddr.getAccountId(); vpnVO = _remoteAccessVpnDao.findByAccountAndNetwork(ipAddressOwner, networkId); if (vpnVO != null) { @@ -225,16 +234,17 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc return vpnVO; } - throw new InvalidParameterValueException(String.format("A remote access VPN already exists for the account [%s].", ipAddressOwner)); + throw new InvalidParameterValueException(String.format("A remote access VPN already exists for the network %s.", network)); } - Network network = _networkMgr.getNetwork(networkId); if (!_networkMgr.areServicesSupportedInNetwork(network.getId(), Service.Vpn)) { throw new InvalidParameterValueException("Vpn service is not supported in network id=" + ipAddr.getAssociatedWithNetworkId()); } cidr = NetUtils.getCidr(network.getCidr()); + validateIpAddressForVpnServiceOnNetwork(network, ipAddress); } else { Vpc vpc = _vpcDao.findById(vpcId); cidr = NetUtils.getCidr(vpc.getCidr()); + validateIpAddressForVpnServiceOnVpc(vpc, ipAddress); } String[] guestIpRange = NetUtils.getIpRangeFromCidr(cidr.first(), cidr.second()); @@ -257,13 +267,59 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc if (forDisplay != null) { remoteAccessVpnVO.setDisplay(forDisplay); } - return _remoteAccessVpnDao.persist(remoteAccessVpnVO); + remoteAccessVpnVO = _remoteAccessVpnDao.persist(remoteAccessVpnVO); + if (vpcId != null) { + try { + vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpcId, false); + } catch (ResourceUnavailableException | CloudRuntimeException e) { + logger.error("Unable to apply static routes for vpc " + vpcId + " due to " + e.getMessage()); + } + } + return remoteAccessVpnVO; }); } finally { _ipAddressDao.releaseFromLockTable(publicIpId); } } + private void validateIpAddressForVpnServiceOnNetwork(Network network, IPAddressVO ipAddress) { + Long networkId = network.getId(); + if (_networkMgr.isProviderSupportServiceInNetwork(networkId, Service.Vpn, Network.Provider.VirtualRouter)) { + // if VR is the VPN provider, + // (1) if VR is Source NAT, the IP address must be used as Source NAT + // (2) if VR is not Source NAT, the IP address must not be used as Source NAT + boolean isVRSourceNat = _networkMgr.isProviderSupportServiceInNetwork(networkId, Service.SourceNat, Network.Provider.VirtualRouter); + if (isVRSourceNat && !ipAddress.isSourceNat()) { + throw new InvalidParameterValueException("Vpn service can only be configured on the Source NAT IP of network id=" + ipAddress.getAssociatedWithNetworkId()); + } + if (!isVRSourceNat && ipAddress.isSourceNat()) { + throw new InvalidParameterValueException("Vpn service can not be configured on the Source NAT IP of network id=" + ipAddress.getAssociatedWithNetworkId()); + } + if (!isVRSourceNat) { + throw new InvalidParameterValueException("Currently it is not supported to create Vpn service on a non-Source NAT IP of network id=" + ipAddress.getAssociatedWithNetworkId()); + } + } + } + + private void validateIpAddressForVpnServiceOnVpc(Vpc vpc, IPAddressVO ipAddress) { + Long vpcId = vpc.getId(); + if (vpcManager.isProviderSupportServiceInVpc(vpcId, Service.Vpn, Network.Provider.VPCVirtualRouter)) { + // if VPC VR is the VPN provider, + // (1) if VPC VR is Source NAT, the IP address must be used as Source NAT + // (2) if VPC VR is not Source NAT, the IP address must not be used as Source NAT + boolean isVpcVRSourceNat = vpcManager.isProviderSupportServiceInVpc(vpcId, Service.SourceNat, Network.Provider.VPCVirtualRouter); + if (isVpcVRSourceNat && !ipAddress.isSourceNat()) { + throw new InvalidParameterValueException("Vpn service can only be configured on the Source NAT IP of VPC id=" + ipAddress.getVpcId()); + } + if (!isVpcVRSourceNat) { + IPAddressVO ipAddressForVpcVR = vpcManager.getIpAddressForVpcVr(vpc, ipAddress, true); + if (!vpcManager.configStaticNatForVpcVr(vpc, ipAddressForVpcVR)) { + throw new CloudRuntimeException("Failed to enable static nat for VPC VR as part of remote access vpn creation"); + } + } + } + } + private void validateRemoteAccessVpnConfiguration() throws ConfigurationException { String ipRange = RemoteAccessVpnClientIpRange.value(); if (ipRange == null) { @@ -364,6 +420,14 @@ public class RemoteAccessVpnManagerImpl extends ManagerBase implements RemoteAcc Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { + if (vpn.getVpcId() != null) { + try { + vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpn.getVpcId(), false); + } catch (ResourceUnavailableException | CloudRuntimeException e) { + logger.error("Unable to apply static routes for vpc " + vpn.getVpcId() + " due to " + e.getMessage()); + } + } + _remoteAccessVpnDao.remove(vpn.getId()); List vpnUsers = _vpnUsersDao.listByAccount(vpn.getAccountId()); diff --git a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java index 8be97644bf5..ad1d1f02682 100644 --- a/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpn/Site2SiteVpnManagerImpl.java @@ -48,6 +48,8 @@ import com.cloud.event.EventTypes; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.IpAddressManager; +import com.cloud.network.Network; import com.cloud.network.Site2SiteCustomerGateway; import com.cloud.network.Site2SiteVpnConnection; import com.cloud.network.Site2SiteVpnConnection.State; @@ -61,9 +63,12 @@ import com.cloud.network.dao.Site2SiteVpnConnectionVO; import com.cloud.network.dao.Site2SiteVpnGatewayDao; import com.cloud.network.dao.Site2SiteVpnGatewayVO; import com.cloud.network.element.Site2SiteVpnServiceProvider; +import com.cloud.network.vpc.Vpc; import com.cloud.network.vpc.VpcManager; import com.cloud.network.vpc.VpcVO; +import com.cloud.network.vpc.VpcOfferingServiceMapVO; import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; import com.cloud.projects.Project.ListProjectResourcesCriteria; import com.cloud.user.Account; import com.cloud.user.AccountManager; @@ -80,6 +85,7 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.NetUtils; import com.cloud.vm.DomainRouterVO; +import com.cloud.vm.dao.DomainRouterDao; @Component public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpnManager { @@ -100,11 +106,17 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn @Inject ConfigurationDao _configDao; @Inject - VpcManager _vpcMgr; - @Inject AccountManager _accountMgr; @Inject private AnnotationDao annotationDao; + @Inject + VpcOfferingServiceMapDao vpcOfferingServiceMapDao; + @Inject + private DomainRouterDao domainRouterDao; + @Inject + private IpAddressManager ipAddressManager; + @Inject + private VpcManager vpcManager; int _connLimit; int _subnetsLimit; @@ -136,13 +148,10 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn if (gws != null) { throw new InvalidParameterValueException(String.format("The VPN gateway of VPC %s already existed!", vpc)); } - //Use source NAT ip for VPC - List ips = _ipAddressDao.listByAssociatedVpc(vpcId, true); - if (ips.size() != 1) { - throw new CloudRuntimeException(String.format("Cannot found source nat ip of vpc %s", vpc)); - } - Site2SiteVpnGatewayVO gw = new Site2SiteVpnGatewayVO(owner.getAccountId(), owner.getDomainId(), ips.get(0).getId(), vpcId); + IPAddressVO requestedIp = _ipAddressDao.findById(cmd.getIpAddressId()); + IPAddressVO ipAddress = getIpAddressIdForVpn(vpcId, vpc.getVpcOfferingId(), requestedIp); + Site2SiteVpnGatewayVO gw = new Site2SiteVpnGatewayVO(owner.getAccountId(), owner.getDomainId(), ipAddress.getId(), vpcId); if (cmd.getDisplay() != null) { gw.setDisplay(cmd.getDisplay()); @@ -152,6 +161,32 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn return gw; } + private IPAddressVO getIpAddressIdForVpn(Long vpcId, Long vpcOferingId, IPAddressVO requestedIp) { + VpcOfferingServiceMapVO mapForSourceNat = vpcOfferingServiceMapDao.findByServiceProviderAndOfferingId(Network.Service.SourceNat.getName(), Network.Provider.VPCVirtualRouter.getName(), vpcOferingId); + VpcOfferingServiceMapVO mapForVpn = vpcOfferingServiceMapDao.findByServiceProviderAndOfferingId(Network.Service.Vpn.getName(), Network.Provider.VPCVirtualRouter.getName(), vpcOferingId); + if (mapForSourceNat == null && mapForVpn != null) { + // Use Static NAT IP of VPC VR + logger.debug(String.format("The VPC VR provides %s Service, however it does not provide %s service, trying to configure using IP of VPC VR", Network.Service.Vpn.getName(), Network.Service.SourceNat.getName())); + + Vpc vpc = _vpcDao.findById(vpcId); + IPAddressVO ipAddressForVpcVR = vpcManager.getIpAddressForVpcVr(vpc, requestedIp, true); + if (!vpcManager.configStaticNatForVpcVr(vpc, ipAddressForVpcVR)) { + throw new CloudRuntimeException("Failed to enable static nat for VPC VR as part of vpn gateway"); + } + return ipAddressForVpcVR; + } else { + //Use source NAT ip for VPC + List ips = _ipAddressDao.listByAssociatedVpc(vpcId, true); + if (ips.size() != 1) { + throw new CloudRuntimeException("Cannot found source nat ip of vpc " + vpcId); + } + if (requestedIp != null && requestedIp.getId() != ips.get(0).getId()) { + throw new CloudRuntimeException(String.format("Cannot use requested IP %s as it is not the Source NAT IP", requestedIp.getAddress().addr())); + } + return ips.get(0); + } + } + protected void checkCustomerGatewayCidrList(String guestCidrList) { String[] cidrList = guestCidrList.split(","); if (cidrList.length > _subnetsLimit) { @@ -190,6 +225,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn if (!NetUtils.isValidCidrList(peerCidrList)) { throw new InvalidParameterValueException("The customer gateway peer cidr list " + peerCidrList + " contains an invalid cidr!"); } + peerCidrList = NetUtils.getCleanIp4CidrList(peerCidrList); String ipsecPsk = cmd.getIpsecPsk(); String ikePolicy = cmd.getIkePolicy(); String espPolicy = cmd.getEspPolicy(); @@ -272,7 +308,8 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn String[] cidrList = customerGateway.getGuestCidrList().split(","); // Remote sub nets cannot overlap VPC's sub net - String vpcCidr = _vpcDao.findById(vpnGateway.getVpcId()).getCidr(); + Vpc vpc = _vpcDao.findById(vpnGateway.getVpcId()); + String vpcCidr = vpc.getCidr(); for (String cidr : cidrList) { if (NetUtils.isNetworksOverlap(vpcCidr, cidr)) { throw new InvalidParameterValueException(String.format("The subnets of customer gateway %s subnet %s is overlapped with VPC cidr %s!", customerGateway, cidr, vpcCidr)); @@ -307,6 +344,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn } _vpnConnectionDao.persist(conn); + return conn; } @@ -364,6 +402,13 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn conn.setState(State.Pending); _vpnConnectionDao.persist(conn); + final Site2SiteVpnGateway vpnGateway = _vpnGatewayDao.findById(conn.getVpnGatewayId()); + try { + vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpnGateway.getVpcId(), false); + } catch (ResourceUnavailableException | CloudRuntimeException e) { + logger.error("Unable to apply static routes for vpc " + vpnGateway.getVpcId() + "as part of start of VPN connection, due to " + e.getMessage()); + } + boolean result = true; for (Site2SiteVpnServiceProvider element : _s2sProviders) { result = result & element.startSite2SiteVpn(conn); @@ -466,6 +511,7 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn if (!NetUtils.isValidCidrList(guestCidrList)) { throw new InvalidParameterValueException("The customer gateway peer cidr list " + guestCidrList + " contains an invalid cidr!"); } + guestCidrList = NetUtils.getCleanIp4CidrList(guestCidrList); String ipsecPsk = cmd.getIpsecPsk(); String ikePolicy = cmd.getIkePolicy(); String espPolicy = cmd.getEspPolicy(); @@ -582,7 +628,19 @@ public class Site2SiteVpnManagerImpl extends ManagerBase implements Site2SiteVpn if (conn.getState() != State.Pending) { stopVpnConnection(id); } + + conn.setState(State.Removed); + _vpnConnectionDao.update(id, conn); + + final Site2SiteVpnGateway vpnGateway = _vpnGatewayDao.findById(conn.getVpnGatewayId()); + try { + vpcManager.applyStaticRouteForVpcVpnIfNeeded(vpnGateway.getVpcId(), false); + } catch (ResourceUnavailableException | CloudRuntimeException e) { + logger.error("Unable to apply static routes for vpc " + vpnGateway.getVpcId() + "as part of deletion of VPN connection, due to " + e.getMessage()); + } + _vpnConnectionDao.remove(id); + return true; } diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java index 0c836d7347d..fce848aa30d 100644 --- a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java @@ -1055,8 +1055,6 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio NetworkOfferingVO defaultTungstenSharedSGNetworkOffering = new NetworkOfferingVO(NetworkOffering.DEFAULT_TUNGSTEN_SHARED_NETWORK_OFFERING_WITH_SGSERVICE, "Offering for Tungsten Shared Security group enabled networks", TrafficType.Guest, false, true, null, null, true, Availability.Optional, null, Network.GuestType.Shared, true, true, false, false, false, false); - - defaultTungstenSharedSGNetworkOffering.setForTungsten(true); defaultTungstenSharedSGNetworkOffering.setState(NetworkOffering.State.Enabled); defaultTungstenSharedSGNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultTungstenSharedSGNetworkOffering); @@ -1200,66 +1198,77 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio _networkOfferingDao.persistDefaultL2NetworkOfferings(); // Offering #9 - network offering for NSX provider - NATTED mode - createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING, "Offering for NSX enabled networks - NAT mode", - NetworkOffering.NetworkMode.NATTED, false, true); + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING, "Offering for NSX enabled networks - NAT mode", + NetworkOffering.NetworkMode.NATTED, false, true, false, Provider.Nsx); // Offering #10 - network offering for NSX provider - ROUTED mode - createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_ROUTED_NSX_OFFERING, "Offering for NSX enabled networks - ROUTED mode", - NetworkOffering.NetworkMode.ROUTED, false, true); + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_ROUTED_NSX_OFFERING, "Offering for NSX enabled networks - ROUTED mode", + NetworkOffering.NetworkMode.ROUTED, false, true, false, Provider.Nsx); // Offering #11 - network offering for NSX provider for VPCs - NATTED mode - createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC, "Offering for NSX enabled networks on VPCs - NAT mode", - NetworkOffering.NetworkMode.NATTED, true, true); + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC, "Offering for NSX enabled networks on VPCs - NAT mode", + NetworkOffering.NetworkMode.NATTED, true, true, false, Provider.Nsx); // Offering #12 - network offering for NSX provider for VPCs - ROUTED mode - createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC, "Offering for NSX enabled networks on VPCs - ROUTED mode", - NetworkOffering.NetworkMode.ROUTED, true, true); + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC, "Offering for NSX enabled networks on VPCs - ROUTED mode", + NetworkOffering.NetworkMode.ROUTED, true, true, false, Provider.Nsx); // Offering #13 - network offering for NSX provider for VPCs with Internal LB - NATTED mode - createAndPersistDefaultNsxOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB, "Offering for NSX enabled networks on VPCs with internal LB - NAT mode", - NetworkOffering.NetworkMode.NATTED, true, false); + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB, "Offering for NSX enabled networks on VPCs with internal LB - NAT mode", + NetworkOffering.NetworkMode.NATTED, true, false, false, Provider.Nsx); + + // Offering #14 - network offering for Netris provider for VPCs - ROUTED mode + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_ROUTED_NETRIS_OFFERING_FOR_VPC, "Offering for Netris enabled networks on VPCs - ROUTED mode", + NetworkOffering.NetworkMode.ROUTED, true, true, false, Provider.Netris); + + // Offering #15 - network offering for Netris provider for VPCs - NATTED mode + createAndPersistDefaultProviderOffering(NetworkOffering.DEFAULT_NAT_NETRIS_OFFERING_FOR_VPC, "Offering for Netris enabled networks on VPCs - NAT mode", + NetworkOffering.NetworkMode.NATTED, true, true, true, Provider.Netris); } }); } - private void createAndPersistDefaultNsxOffering(String name, String displayText, NetworkOffering.NetworkMode networkMode, - boolean forVpc, boolean publicLB) { - NetworkOfferingVO defaultNatNSXNetworkOffering = + private void createAndPersistDefaultProviderOffering(String name, String displayText, NetworkOffering.NetworkMode networkMode, + boolean forVpc, boolean publicLB, boolean supportVmAutoscaling, Provider provider) { + NetworkOfferingVO providerNetworkOffering = new NetworkOfferingVO(name, displayText, TrafficType.Guest, false, false, null, null, true, Availability.Optional, null, GuestType.Isolated, false, false, false, false, false, forVpc); - defaultNatNSXNetworkOffering.setPublicLb(publicLB); - defaultNatNSXNetworkOffering.setInternalLb(!publicLB); - defaultNatNSXNetworkOffering.setForNsx(true); - defaultNatNSXNetworkOffering.setNetworkMode(networkMode); - defaultNatNSXNetworkOffering.setState(NetworkOffering.State.Enabled); - defaultNatNSXNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNatNSXNetworkOffering); + providerNetworkOffering.setPublicLb(publicLB); + providerNetworkOffering.setInternalLb(!publicLB); + providerNetworkOffering.setNetworkMode(networkMode); + providerNetworkOffering.setState(NetworkOffering.State.Enabled); + providerNetworkOffering.setSupportsVmAutoScaling(supportVmAutoscaling); + providerNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(providerNetworkOffering); - Map serviceProviderMap = getServicesAndProvidersForNSXNetwork(networkMode, forVpc, publicLB); + Map serviceProviderMap = getServicesAndProvidersForProviderNetwork(networkMode, forVpc, provider); for (Map.Entry service : serviceProviderMap.entrySet()) { NetworkOfferingServiceMapVO offService = - new NetworkOfferingServiceMapVO(defaultNatNSXNetworkOffering.getId(), service.getKey(), service.getValue()); + new NetworkOfferingServiceMapVO(providerNetworkOffering.getId(), service.getKey(), service.getValue()); _ntwkOfferingServiceMapDao.persist(offService); logger.trace("Added service for the network offering: " + offService); } } - private Map getServicesAndProvidersForNSXNetwork(NetworkOffering.NetworkMode networkMode, boolean forVpc, boolean publicLB) { + private Map getServicesAndProvidersForProviderNetwork(NetworkOffering.NetworkMode networkMode, boolean forVpc, Provider provider) { final Map serviceProviderMap = new HashMap<>(); Provider routerProvider = forVpc ? Provider.VPCVirtualRouter : Provider.VirtualRouter; serviceProviderMap.put(Service.Dhcp, routerProvider); serviceProviderMap.put(Service.Dns, routerProvider); serviceProviderMap.put(Service.UserData, routerProvider); if (forVpc) { - serviceProviderMap.put(Service.NetworkACL, Provider.Nsx); + serviceProviderMap.put(Service.NetworkACL, provider); } else { - serviceProviderMap.put(Service.Firewall, Provider.Nsx); + serviceProviderMap.put(Service.Firewall, provider); } if (networkMode == NetworkOffering.NetworkMode.NATTED) { - serviceProviderMap.put(Service.SourceNat, Provider.Nsx); - serviceProviderMap.put(Service.StaticNat, Provider.Nsx); - serviceProviderMap.put(Service.PortForwarding, Provider.Nsx); - serviceProviderMap.put(Service.Lb, Provider.Nsx); + serviceProviderMap.put(Service.SourceNat, provider); + serviceProviderMap.put(Service.StaticNat, provider); + serviceProviderMap.put(Service.PortForwarding, provider); + serviceProviderMap.put(Service.Lb, provider); + if (provider == Provider.Netris) { + serviceProviderMap.put(Service.Vpn, routerProvider); + } } return serviceProviderMap; } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index ea6c595ae13..650028e1247 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -44,6 +44,13 @@ import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.cpu.CPU; +import com.cloud.dc.VlanDetailsVO; +import com.cloud.dc.dao.VlanDetailsDao; +import com.cloud.network.dao.NetrisProviderDao; +import com.cloud.network.dao.NsxProviderDao; + +import com.cloud.utils.security.CertificateHelper; import com.cloud.api.query.dao.ManagementServerJoinDao; import com.cloud.api.query.vo.ManagementServerJoinVO; import org.apache.cloudstack.acl.ControlledEntity; @@ -693,7 +700,6 @@ import com.cloud.configuration.Config; import com.cloud.configuration.ConfigurationManagerImpl; import com.cloud.consoleproxy.ConsoleProxyManagementState; import com.cloud.consoleproxy.ConsoleProxyManager; -import com.cloud.cpu.CPU; import com.cloud.dc.AccountVlanMapVO; import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenterVO; @@ -840,7 +846,6 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.fsm.StateMachine2; import com.cloud.utils.net.MacAddress; import com.cloud.utils.net.NetUtils; -import com.cloud.utils.security.CertificateHelper; import com.cloud.utils.ssh.SSHKeysHelper; import com.cloud.vm.ConsoleProxyVO; import com.cloud.vm.DiskProfile; @@ -904,6 +909,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject private VlanDao _vlanDao; @Inject + private VlanDetailsDao vlanDetailsDao; + @Inject private AccountVlanMapDao _accountVlanMapDao; @Inject private PodVlanMapDao _podVlanMapDao; @@ -946,7 +953,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject private StoragePoolJoinDao _poolJoinDao; @Inject - private NetworkDao networkDao; + protected NetworkDao networkDao; @Inject private StorageManager _storageMgr; @Inject @@ -1016,7 +1023,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject private NetworkModel _networkMgr; @Inject - private VpcDao _vpcDao; + protected VpcDao _vpcDao; @Inject private DomainVlanMapDao _domainVlanMapDao; @Inject @@ -1048,6 +1055,10 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe protected AffinityGroupVMMapDao _affinityGroupVMMapDao; @Inject ResourceLimitService resourceLimitService; + @Inject + NsxProviderDao nsxProviderDao; + @Inject + NetrisProviderDao netrisProviderDao; private LockControllerListener _lockControllerListener; private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker")); @@ -2632,6 +2643,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe final String address = cmd.getIpAddress(); final Boolean forLoadBalancing = cmd.isForLoadBalancing(); final Map tags = cmd.getTags(); + boolean forProvider = cmd.isForProvider(); sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ); sb.and("address", sb.entity().getAddress(), SearchCriteria.Op.EQ); @@ -2677,13 +2689,21 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe if (isAllocated != null && isAllocated) { sb.and("allocated", sb.entity().getAllocatedTime(), SearchCriteria.Op.NNULL); } + + if (forProvider) { + SearchBuilder vlanDetailsSearch = vlanDetailsDao.createSearchBuilder(); + vlanDetailsSearch.and("name", vlanDetailsSearch.entity().getName(), SearchCriteria.Op.IN); + vlanDetailsSearch.and("value", vlanDetailsSearch.entity().getValue(), SearchCriteria.Op.EQ); + sb.join("vlanDetailSearch", vlanDetailsSearch, sb.entity().getVlanId(), vlanDetailsSearch.entity().getResourceId(), JoinType.LEFT); + } } protected void setParameters(SearchCriteria sc, final ListPublicIpAddressesCmd cmd, VlanType vlanType, Boolean isAllocated) { final Object keyword = cmd.getKeyword(); final Long physicalNetworkId = cmd.getPhysicalNetworkId(); final Long sourceNetworkId = cmd.getNetworkId(); - final Long zone = cmd.getZoneId(); + final Long vpcId = cmd.getVpcId(); + Long zone = cmd.getZoneId(); final String address = cmd.getIpAddress(); final Long vlan = cmd.getVlanId(); final Long ipId = cmd.getId(); @@ -2692,6 +2712,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe final Boolean forDisplay = cmd.getDisplay(); final String state = cmd.getState(); final Boolean forSystemVms = cmd.getForSystemVMs(); + final boolean forProvider = cmd.isForProvider(); final Map tags = cmd.getTags(); sc.setJoinParameters("vlanSearch", "vlanType", vlanType); @@ -2757,6 +2778,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } else { sc.setParameters(FOR_SYSTEMVMS, forSystemVms); } + + if (forProvider) { + sc.setJoinParameters("vlanDetailSearch", "name", ApiConstants.NETRIS_DETAIL_KEY, ApiConstants.NSX_DETAIL_KEY); + sc.setJoinParameters("vlanDetailSearch", "value", "true"); + } } @Override diff --git a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java index debe9eee6da..4187586736d 100644 --- a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java +++ b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinition.java @@ -23,15 +23,18 @@ import java.util.Objects; import com.cloud.dc.DataCenter; import com.cloud.dc.Vlan; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NetworkDetailVO; import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.element.NetrisProviderVO; import com.cloud.network.element.NsxProviderVO; import com.cloud.network.router.VirtualRouter; import com.cloud.storage.DiskOfferingVO; import com.cloud.storage.dao.DiskOfferingDao; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.commons.lang3.ObjectUtils; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; @@ -94,6 +97,7 @@ public class RouterDeploymentDefinition { protected NetworkDao networkDao; protected DomainRouterDao routerDao; protected NsxProviderDao nsxProviderDao; + protected NetrisProviderDao netrisProviderDao; protected PhysicalNetworkServiceProviderDao physicalProviderDao; protected PhysicalNetworkDao pNtwkDao; protected NetworkModel networkModel; @@ -397,10 +401,11 @@ public class RouterDeploymentDefinition { if (Objects.nonNull(zone)) { zoneId = zone.getId(); } - NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + + boolean isExternalProvider = isExternalProviderPresent(zoneId); if (isPublicNetwork) { - if (Objects.isNull(nsxProvider)) { + if (!isExternalProvider) { sourceNatIp = ipAddrMgr.assignSourceNatIpAddressToGuestNetwork(owner, guestNetwork); } else { sourceNatIp = ipAddrMgr.assignPublicIpAddress(zoneId, getPodId(), owner, Vlan.VlanType.VirtualNetwork, null, null, false, true); @@ -408,6 +413,16 @@ public class RouterDeploymentDefinition { } } + protected boolean isExternalProviderPresent(Long zoneId) { + NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + NetrisProviderVO netrisProviderVO = netrisProviderDao.findByZoneId(zoneId); + + if (ObjectUtils.anyNotNull(nsxProvider, netrisProviderVO)) { + return true; + } + return false; + } + protected void findDefaultServiceOfferingId() { ServiceOfferingVO serviceOffering = serviceOfferingDao.findDefaultSystemOffering(ServiceOffering.routerDefaultOffUniqueName, ConfigurationManagerImpl.SystemVMUseLocalStorage.valueIn(dest.getDataCenter().getId())); serviceOfferingId = serviceOffering.getId(); diff --git a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java index 227ae8d641e..de95956a406 100644 --- a/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java +++ b/server/src/main/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionBuilder.java @@ -22,6 +22,7 @@ import java.util.Map; import javax.inject.Inject; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NetworkDetailsDao; import com.cloud.network.dao.NsxProviderDao; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -66,6 +67,8 @@ public class RouterDeploymentDefinitionBuilder { @Inject private NsxProviderDao nsxProviderDao; @Inject + private NetrisProviderDao netrisProviderDao; + @Inject private PhysicalNetworkServiceProviderDao physicalProviderDao; @Inject private NetworkModel networkModel; @@ -129,6 +132,7 @@ public class RouterDeploymentDefinitionBuilder { routerDeploymentDefinition.networkDao = networkDao; routerDeploymentDefinition.routerDao = routerDao; routerDeploymentDefinition.nsxProviderDao = nsxProviderDao; + routerDeploymentDefinition.netrisProviderDao = netrisProviderDao; routerDeploymentDefinition.physicalProviderDao = physicalProviderDao; routerDeploymentDefinition.networkModel = networkModel; routerDeploymentDefinition.vrProviderDao = vrProviderDao; diff --git a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java index b9ff50f369d..063565ebf46 100644 --- a/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java +++ b/server/src/main/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinition.java @@ -23,7 +23,6 @@ import java.util.Objects; import com.cloud.dc.DataCenter; import com.cloud.network.dao.IPAddressVO; -import com.cloud.network.element.NsxProviderVO; import com.cloud.dc.dao.VlanDao; import com.cloud.deploy.DataCenterDeployment; @@ -125,10 +124,11 @@ public class VpcRouterDeploymentDefinition extends RouterDeploymentDefinition { if (Objects.nonNull(zone)) { zoneId = zone.getId(); } - NsxProviderVO nsxProvider = nsxProviderDao.findByZoneId(zoneId); + + boolean isExternalProvider = isExternalProviderPresent(zoneId); if (isPublicNetwork) { - if (Objects.isNull(nsxProvider)) { + if (!isExternalProvider) { sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc, null); } else { sourceNatIp = vpcMgr.assignSourceNatIpAddressToVpc(owner, vpc, getPodId()); diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java index e83363877aa..2bddabce719 100644 --- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java +++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java @@ -34,6 +34,7 @@ import com.cloud.network.NetworkModel; import com.cloud.network.NetworkService; import com.cloud.network.Networks; import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.element.NsxProviderVO; @@ -135,6 +136,8 @@ public class ConfigurationManagerImplTest { @Mock NsxProviderDao nsxProviderDao; @Mock + NetrisProviderDao netrisProviderDao; + @Mock DataCenterDao zoneDao; @Mock HostDao hostDao; @@ -418,6 +421,7 @@ public class ConfigurationManagerImplTest { DataCenterVO dataCenterVO = Mockito.mock(DataCenterVO.class); when(nsxProviderDao.findByZoneId(anyLong())).thenReturn(nsxProviderVO); + when(netrisProviderDao.findByZoneId(anyLong())).thenReturn(null); when(zoneDao.findById(anyLong())).thenReturn(dataCenterVO); lenient().when(hostDao.findByDataCenterId(anyLong())).thenReturn(Collections.emptyList()); when(podDao.listByDataCenterId(anyLong())).thenReturn(Collections.emptyList()); diff --git a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java index 889031f2b50..70bbe2d1b80 100644 --- a/server/src/test/java/com/cloud/network/NetworkModelImplTest.java +++ b/server/src/test/java/com/cloud/network/NetworkModelImplTest.java @@ -30,6 +30,7 @@ import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.network.vpc.VpcVO; import com.cloud.network.vpc.dao.VpcDao; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.utils.Pair; import com.cloud.utils.net.Ip; import org.junit.Assert; @@ -44,6 +45,7 @@ import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.test.util.ReflectionTestUtils; +import javax.inject.Inject; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -60,6 +62,8 @@ public class NetworkModelImplTest { @Mock private VpcDao vpcDao; + @Inject + private NetworkOfferingServiceMapDao networkOfferingServiceMapDao; @InjectMocks private NetworkModelImpl networkModel = new NetworkModelImpl(); @@ -70,8 +74,10 @@ public class NetworkModelImplTest { public void setUp() { networkOfferingDao = Mockito.mock(NetworkOfferingDao.class); networkServiceMapDao = Mockito.mock(NetworkServiceMapDao.class); + networkOfferingServiceMapDao = Mockito.mock(NetworkOfferingServiceMapDao.class); networkModel._networkOfferingDao = networkOfferingDao; networkModel._ntwkSrvcDao = networkServiceMapDao; + networkModel._ntwkOfferingSrvcDao = networkOfferingServiceMapDao; } private void prepareMocks(boolean isIp6, Network network, DataCenter zone, VpcVO vpc, @@ -216,7 +222,6 @@ public class NetworkModelImplTest { PublicIpAddress publicIpAddress2 = new PublicIp(ipAddressVO2, vlanVO, 0x0ac00000L); NetworkOfferingVO networkOfferingVO = new NetworkOfferingVO(); networkOfferingVO.setForVpc(true); - networkOfferingVO.setForNsx(false); Network network = new NetworkVO(); List networkServiceMapVOs = new ArrayList<>(); networkServiceMapVOs.add(new NetworkServiceMapVO(15L, Network.Service.Firewall, Network.Provider.VPCVirtualRouter)); @@ -229,6 +234,7 @@ public class NetworkModelImplTest { Map> ipToServices = new HashMap<>(); ipToServices.put(publicIpAddress1, services1); ipToServices.put(publicIpAddress2, services2); + Mockito.when(networkOfferingServiceMapDao.isProviderForNetworkOffering(networkOfferingVO.getId(), Network.Provider.Nsx)).thenReturn(false); Map> result = networkModel.getProviderToIpList(network, ipToServices); Assert.assertNotNull(result); } diff --git a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java index 6b169a89267..510cd7ac1a6 100644 --- a/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java +++ b/server/src/test/java/com/cloud/network/as/AutoScaleManagerImplTest.java @@ -1577,11 +1577,11 @@ public class AutoScaleManagerImplTest { when(asVmGroupMock.getState()).thenReturn(AutoScaleVmGroup.State.ENABLED); when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId); Mockito.doReturn(Network.Provider.VirtualRouter).when(autoScaleManagerImplSpy).getLoadBalancerServiceProvider(loadBalancerId); - Mockito.doNothing().when(autoScaleManagerImplSpy).checkVirtualRouterAsGroup(asVmGroupMock); + Mockito.doNothing().when(autoScaleManagerImplSpy).checkAutoscalingGroup(asVmGroupMock); autoScaleManagerImplSpy.checkAutoScaleVmGroup(asVmGroupMock); - Mockito.verify(autoScaleManagerImplSpy).checkVirtualRouterAsGroup(asVmGroupMock); + Mockito.verify(autoScaleManagerImplSpy).checkAutoscalingGroup(asVmGroupMock); Mockito.verify(autoScaleManagerImplSpy, never()).checkNetScalerAsGroup(asVmGroupMock); } @@ -1590,11 +1590,11 @@ public class AutoScaleManagerImplTest { when(asVmGroupMock.getState()).thenReturn(AutoScaleVmGroup.State.ENABLED); when(asVmGroupMock.getLoadBalancerId()).thenReturn(loadBalancerId); Mockito.doReturn(Network.Provider.VPCVirtualRouter).when(autoScaleManagerImplSpy).getLoadBalancerServiceProvider(loadBalancerId); - Mockito.doNothing().when(autoScaleManagerImplSpy).checkVirtualRouterAsGroup(asVmGroupMock); + Mockito.doNothing().when(autoScaleManagerImplSpy).checkAutoscalingGroup(asVmGroupMock); autoScaleManagerImplSpy.checkAutoScaleVmGroup(asVmGroupMock); - Mockito.verify(autoScaleManagerImplSpy).checkVirtualRouterAsGroup(asVmGroupMock); + Mockito.verify(autoScaleManagerImplSpy).checkAutoscalingGroup(asVmGroupMock); Mockito.verify(autoScaleManagerImplSpy, never()).checkNetScalerAsGroup(asVmGroupMock); } @@ -1607,7 +1607,7 @@ public class AutoScaleManagerImplTest { autoScaleManagerImplSpy.checkAutoScaleVmGroup(asVmGroupMock); - Mockito.verify(autoScaleManagerImplSpy, never()).checkVirtualRouterAsGroup(asVmGroupMock); + Mockito.verify(autoScaleManagerImplSpy, never()).checkAutoscalingGroup(asVmGroupMock); Mockito.verify(autoScaleManagerImplSpy).checkNetScalerAsGroup(asVmGroupMock); } @@ -1989,7 +1989,7 @@ public class AutoScaleManagerImplTest { Mockito.doNothing().when(autoScaleManagerImplSpy).doScaleUp(vmGroupId, 1); Mockito.doNothing().when(autoScaleManagerImplSpy).cleanupAsVmGroupStatistics(groupTO); - autoScaleManagerImplSpy.checkVirtualRouterAsGroup(asVmGroupMock); + autoScaleManagerImplSpy.checkAutoscalingGroup(asVmGroupMock); Mockito.verify(autoScaleManagerImplSpy).doScaleUp(vmGroupId, 1); } @@ -2005,7 +2005,7 @@ public class AutoScaleManagerImplTest { Mockito.doNothing().when(autoScaleManagerImplSpy).doScaleDown(vmGroupId); Mockito.doNothing().when(autoScaleManagerImplSpy).cleanupAsVmGroupStatistics(groupTO); - autoScaleManagerImplSpy.checkVirtualRouterAsGroup(asVmGroupMock); + autoScaleManagerImplSpy.checkAutoscalingGroup(asVmGroupMock); Mockito.verify(autoScaleManagerImplSpy).doScaleDown(vmGroupId); } @@ -2225,7 +2225,7 @@ public class AutoScaleManagerImplTest { Mockito.doNothing().when(autoScaleManagerImplSpy).getVmStatsFromHosts(groupTO); Mockito.doNothing().when(autoScaleManagerImplSpy).getNetworkStatsFromVirtualRouter(groupTO); - autoScaleManagerImplSpy.monitorVirtualRouterAsGroup(asVmGroupMock); + autoScaleManagerImplSpy.monitorAutoscalingGroup(asVmGroupMock); Mockito.verify(autoScaleManagerImplSpy).getVmStatsFromHosts(groupTO); Mockito.verify(autoScaleManagerImplSpy).getNetworkStatsFromVirtualRouter(groupTO); diff --git a/server/src/test/java/com/cloud/network/lb/UpdateLoadBalancerTest.java b/server/src/test/java/com/cloud/network/lb/UpdateLoadBalancerTest.java index c3e8923b943..729d2ea8ff5 100644 --- a/server/src/test/java/com/cloud/network/lb/UpdateLoadBalancerTest.java +++ b/server/src/test/java/com/cloud/network/lb/UpdateLoadBalancerTest.java @@ -33,6 +33,7 @@ import com.cloud.network.dao.LoadBalancerVO; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.element.LoadBalancingServiceProvider; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.Account; import com.cloud.user.AccountVO; import com.cloud.user.MockAccountManagerImpl; @@ -52,6 +53,7 @@ import java.util.UUID; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -63,6 +65,7 @@ public class UpdateLoadBalancerTest { private LoadBalancerDao lbDao = Mockito.mock(LoadBalancerDao.class); private NetworkDao netDao = Mockito.mock(NetworkDao.class); private NetworkModel netModel = Mockito.mock(NetworkModel.class); + private NetworkOfferingServiceMapDao ntwkOffServiceMapDao = Mockito.mock(NetworkOfferingServiceMapDao.class); private LoadBalancingServiceProvider lbServiceProvider= Mockito.mock(LoadBalancingServiceProvider.class); private static long domainId = 5L; @@ -73,6 +76,7 @@ public class UpdateLoadBalancerTest { _lbMgr._accountMgr = new MockAccountManagerImpl(); _lbMgr._autoScaleVmGroupDao = Mockito.mock(AutoScaleVmGroupDao.class); _lbMgr._networkDao = netDao; + _lbMgr._networkOfferingServiceDao = ntwkOffServiceMapDao; _lbMgr._networkModel = netModel; _lbMgr._lb2healthcheckDao = Mockito.mock(LBHealthCheckPolicyDao.class); _lbMgr._lb2stickinesspoliciesDao = Mockito.mock(LBStickinessPolicyDao.class); @@ -99,7 +103,8 @@ public class UpdateLoadBalancerTest { when(netDao.findById(anyLong())).thenReturn(Mockito.mock(NetworkVO.class)); when(lbServiceProvider.validateLBRule(any(Network.class), any(LoadBalancingRule.class))).thenReturn(true); when(lbDao.update(isNull(), eq(lb))).thenReturn(true); - + when(netDao.findById(nullable(Long.class))).thenReturn(Mockito.mock(NetworkVO.class)); + when(ntwkOffServiceMapDao.canProviderSupportServiceInNetworkOffering(nullable(Long.class), any(Network.Service.class), any(Network.Provider.class))).thenReturn(false); _lbMgr.updateLoadBalancerRule(updateLbRuleCmd); InOrder inOrder = Mockito.inOrder(lbServiceProvider, lbDao); diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index cdd902bcebd..2982c19ccdd 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -548,7 +548,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, - Boolean forTungsten, boolean forNsx, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol, + Boolean forTungsten, boolean forNsx, boolean forNetris, NetworkOffering.NetworkMode networkMode, List domainIds, List zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber) { // TODO Auto-generated method stub return null; @@ -559,7 +559,7 @@ public class MockConfigurationManagerImpl extends ManagerBase implements Configu */ @Override public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, - String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6, boolean forNsx) + String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6, Provider provider) throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { // TODO Auto-generated method stub return null; diff --git a/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java b/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java index 6579a892ec6..bcc45ed911f 100644 --- a/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java +++ b/server/src/test/java/com/cloud/vpc/NetworkACLServiceTest.java @@ -17,6 +17,7 @@ package com.cloud.vpc; import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.NetworkModel; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NetworkDao; import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.vpc.NetworkACLItemDao; @@ -81,6 +82,8 @@ public class NetworkACLServiceTest extends TestCase { private EntityManager _entityMgr; @Inject private NsxProviderDao nsxProviderDao; + @Inject + private NetrisProviderDao netrisProviderDao; private NetworkACLVO acl; private NetworkACLItemVO aclItem; @@ -190,6 +193,9 @@ public class NetworkACLServiceTest extends TestCase { @Bean public NsxProviderDao nsxProviderDao() { return Mockito.mock(NsxProviderDao.class); } + @Bean + public NetrisProviderDao netrisProviderDao() { return Mockito.mock(NetrisProviderDao.class); } + public static class Library implements TypeFilter { @Override public boolean match(MetadataReader mdr, MetadataReaderFactory arg1) throws IOException { diff --git a/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java b/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java index 5685c504ab2..27aba5c013c 100644 --- a/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java +++ b/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.vpc.dao; +import com.cloud.network.Network; import com.cloud.network.Network.Service; import com.cloud.network.vpc.VpcOfferingServiceMapVO; import com.cloud.network.vpc.dao.VpcOfferingServiceMapDao; @@ -62,6 +63,16 @@ public class MockVpcOfferingServiceMapDaoImpl extends GenericDaoBase listProvidersForServiceForVpcOffering(long vpcOfferingId, Service service) { + return List.of(); + } + @Override public VpcOfferingServiceMapVO persist(VpcOfferingServiceMapVO vo) { return vo; diff --git a/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java b/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java index 0b4c48e99b4..3dec0fc2b66 100644 --- a/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java +++ b/server/src/test/java/org/apache/cloudstack/network/router/deployment/RouterDeploymentDefinitionTest.java @@ -30,6 +30,7 @@ import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; import com.cloud.network.VirtualRouterProvider.Type; import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PhysicalNetworkDao; @@ -79,6 +80,8 @@ public class RouterDeploymentDefinitionTest extends RouterDeploymentDefinitionTe PhysicalNetworkDao physicalNetworkDao; @Mock protected NsxProviderDao nsxProviderDao; + @Mock + protected NetrisProviderDao netrisProviderDao; protected RouterDeploymentDefinition deployment; diff --git a/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java b/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java index d3ab6d8904b..e7f75f5dbbb 100644 --- a/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java +++ b/server/src/test/java/org/apache/cloudstack/network/router/deployment/VpcRouterDeploymentDefinitionTest.java @@ -24,6 +24,7 @@ import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.StorageUnavailableException; import com.cloud.network.addr.PublicIp; +import com.cloud.network.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; import com.cloud.network.dao.PhysicalNetworkDao; import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; @@ -65,6 +66,8 @@ public class VpcRouterDeploymentDefinitionTest extends RouterDeploymentDefinitio @Mock protected NsxProviderDao nsxProviderDao; @Mock + protected NetrisProviderDao netrisProviderDao; + @Mock protected PhysicalNetworkDao mockPhNwDao; protected PhysicalNetworkServiceProviderDao mockPhProviderDao; diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index 2a1a0237009..eab5d3eeffd 100644 --- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -131,7 +131,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null, null, false); + null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } @@ -139,7 +139,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithNoVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, true, false, null, false, null, true, false, false, false, null, null,null, false, null, null, false); + false, null, false, null, true, false, null, false, null, true, false, false, false, false,null, null,null, false, null, null, false); assertNotNull("Shared network offering with specifyVlan=false was created", off); } @@ -147,7 +147,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null, null, false); + null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -156,7 +156,7 @@ public class CreateNetworkOfferingTest extends TestCase { public void createSharedNtwkOffWithoutSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, false, false, null, false, null, true, false, false, false, null,null, null, false, null, null, false); + false, null, false, null, false, false, null, false, null, true, false, false, false,false, null,null, null, false, null, null, false); assertNull("Shared network offering with specifyIpRanges=false was created", off); } @@ -169,7 +169,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, null, null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, false,null, null, null, false, null, null, false); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -182,7 +182,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, null,null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -195,7 +195,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } @@ -206,7 +206,7 @@ public class CreateNetworkOfferingTest extends TestCase { Set vrProvider = new HashSet(); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, null,null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false, false, false,null,null, null, false, null, null, false); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } @@ -224,7 +224,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.Lb, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc provider ", off); } @@ -244,7 +244,7 @@ public class CreateNetworkOfferingTest extends TestCase { serviceProviderMap.put(Network.Service.Lb, lbProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, null, null, null, false, null, null, false); + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false, false, false,null, null, null, false, null, null, false); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); } diff --git a/server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java b/server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java new file mode 100644 index 00000000000..9f590dc1807 --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/service/NetrisServiceMockTest.java @@ -0,0 +1,134 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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 org.apache.cloudstack.service; + +import com.cloud.network.IpAddress; +import com.cloud.network.Network; +import com.cloud.network.SDNProviderNetworkRule; +import com.cloud.network.netris.NetrisNetworkRule; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.vpc.StaticRoute; +import com.cloud.network.vpc.Vpc; + +import java.util.List; + +public class NetrisServiceMockTest implements NetrisService { + @Override + public boolean createIPAMAllocationsForZoneLevelPublicRanges(long zoneId) { + return true; + } + + @Override + public boolean createVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, boolean sourceNatEnabled, String cidr, boolean isVpcNetwork) { + return true; + } + + @Override + public boolean updateVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, String previousVpcName) { + return true; + } + + @Override + public boolean deleteVpcResource(long zoneId, long accountId, long domainId, Vpc vpc) { + return true; + } + + @Override + public boolean createVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr, Boolean globalRouting) { + return true; + } + + @Override + public boolean updateVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String prevNetworkName) { + return true; + } + + @Override + public boolean deleteVnetResource(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr) { + return true; + } + + @Override + public boolean createSnatRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, long networkId, boolean isForVpc, String vpcCidr, String sourceNatIp) { + return true; + } + + @Override + public boolean createPortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule) { + return true; + } + + @Override + public boolean deletePortForwardingRule(long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, boolean isForVpc, String vpcCidr, SDNProviderNetworkRule networkRule) { + return true; + } + + @Override + public boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address) { + return true; + } + + @Override + public boolean createStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String vpcCidr, String staticNatIp, String vmIp, long vmId) { + return true; + } + + @Override + public boolean deleteStaticNatRule(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String staticNatIp, long vmId) { + return true; + } + + @Override + public List listStaticRoutes(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId) { + return List.of(); + } + + @Override + public boolean addFirewallRules(Network network, List firewallRules) { + return true; + } + + @Override + public boolean deleteFirewallRules(Network network, List firewallRules) { + return true; + } + + @Override + public boolean addOrUpdateStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId, boolean updateRoute) { + return true; + } + + @Override + public boolean deleteStaticRoute(long zoneId, long accountId, long domainId, String networkResourceName, Long networkResourceId, boolean isForVpc, String prefix, String nextHop, Long routeId) { + return true; + } + + @Override + public boolean releaseNatIp(long zoneId, String publicIp) { + return true; + } + + @Override + public boolean createOrUpdateLbRule(NetrisNetworkRule rule) { + return true; + } + + @Override + public boolean deleteLbRule(NetrisNetworkRule rule) { + return true; + } +} diff --git a/server/src/test/resources/createNetworkOffering.xml b/server/src/test/resources/createNetworkOffering.xml index 5a0a51516af..81359cdc72f 100644 --- a/server/src/test/resources/createNetworkOffering.xml +++ b/server/src/test/resources/createNetworkOffering.xml @@ -74,6 +74,8 @@ + + diff --git a/systemvm/debian/opt/cloud/bin/configure.py b/systemvm/debian/opt/cloud/bin/configure.py index 908f798a665..c3c91d90c5a 100755 --- a/systemvm/debian/opt/cloud/bin/configure.py +++ b/systemvm/debian/opt/cloud/bin/configure.py @@ -1024,13 +1024,19 @@ class CsSite2SiteVpn(CsDataBag): local_ip = self.dbag[vpn]['local_public_ip'] dev = CsHelper.get_device(local_ip) + if not self.config.has_public_network(): + interface = self.config.address().get_guest_if_by_network_id() + if interface: + dev = interface.get_device() + local_ip = interface.get_ip() + if dev == "": logging.error("Request for ipsec to %s not possible because ip is not configured", local_ip) continue CsHelper.start_if_stopped("ipsec") - self.configure_iptables(dev, self.dbag[vpn]) - self.configure_ipsec(self.dbag[vpn]) + self.configure_iptables(dev, local_ip, self.dbag[vpn]) + self.configure_ipsec(local_ip, self.dbag[vpn]) # Delete vpns that are no longer in the configuration for ip in self.confips: @@ -1046,10 +1052,10 @@ class CsSite2SiteVpn(CsDataBag): os.remove(vpnsecretsfile) CsHelper.execute("ipsec reload") - def configure_iptables(self, dev, obj): - self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])]) - self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 4500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])]) - self.fw.append(["", "front", "-A INPUT -i %s -p esp -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], obj['local_public_ip'])]) + def configure_iptables(self, dev, local_ip, obj): + self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], local_ip)]) + self.fw.append(["", "front", "-A INPUT -i %s -p udp -m udp --dport 4500 -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], local_ip)]) + self.fw.append(["", "front", "-A INPUT -i %s -p esp -s %s -d %s -j ACCEPT" % (dev, obj['peer_gateway_ip'], local_ip)]) self.fw.append(["nat", "front", "-A POSTROUTING -t nat -o %s -m mark --mark 0x525 -j ACCEPT" % dev]) for net in obj['peer_guest_cidr_list'].lstrip().rstrip().split(','): self.fw.append(["mangle", "front", @@ -1061,7 +1067,7 @@ class CsSite2SiteVpn(CsDataBag): self.fw.append(["mangle", "", "-A INPUT -s %s -d %s -j MARK --set-xmark 0x524/0xffffffff" % (net, obj['local_guest_cidr'])]) - def configure_ipsec(self, obj): + def configure_ipsec(self, local_ip, obj): leftpeer = obj['local_public_ip'] rightpeer = obj['peer_gateway_ip'] peerlist = obj['peer_guest_cidr_list'].replace(' ', '') @@ -1083,7 +1089,8 @@ class CsSite2SiteVpn(CsDataBag): file.repopulate() # This avoids issues when switching off split_connections or removing subnets with split_connections == true file.add("#conn for vpn-%s" % rightpeer, 0) file.search("conn ", "conn vpn-%s" % rightpeer) - file.addeq(" left=%s" % leftpeer) + file.addeq(" left=%s" % local_ip) + file.addeq(" leftid=%s" % leftpeer) file.addeq(" leftsubnet=%s" % obj['local_guest_cidr']) file.addeq(" right=%s" % rightpeer) file.addeq(" rightsubnet=%s" % peerlist) @@ -1224,9 +1231,16 @@ class CsRemoteAccessVpn(CsDataBag): logging.debug("Enabling remote access vpn on " + public_ip) CsHelper.start_if_stopped("ipsec") - self.configure_l2tpIpsec(public_ip, self.dbag[public_ip]) + logging.debug("Remote accessvpn data bag %s", self.dbag) - self.remoteaccessvpn_iptables(public_ip, self.dbag[public_ip]) + if not self.config.has_public_network(): + interface = self.config.address().get_guest_if_by_network_id() + if interface: + self.configure_l2tpIpsec(interface.get_ip(), self.dbag[public_ip]) + self.remoteaccessvpn_iptables(interface.get_device(), interface.get_ip(), self.dbag[public_ip]) + else: + self.configure_l2tpIpsec(public_ip, self.dbag[public_ip]) + self.remoteaccessvpn_iptables(self.dbag[public_ip]['public_interface'], public_ip, self.dbag[public_ip]) CsHelper.execute("ipsec update") CsHelper.execute("systemctl start xl2tpd") @@ -1251,6 +1265,7 @@ class CsRemoteAccessVpn(CsDataBag): # Left l2tpfile = CsFile(l2tpconffile) l2tpfile.addeq(" left=%s" % left) + l2tpfile.addeq(" leftid=%s" % obj['vpn_server_ip']) l2tpfile.commit() secret = CsFile(vpnsecretfilte) @@ -1267,8 +1282,7 @@ class CsRemoteAccessVpn(CsDataBag): xl2tpoptions.search("ms-dns ", "ms-dns %s" % localip) xl2tpoptions.commit() - def remoteaccessvpn_iptables(self, publicip, obj): - publicdev = obj['public_interface'] + def remoteaccessvpn_iptables(self, publicdev, publicip, obj): localcidr = obj['local_cidr'] local_ip = obj['local_ip'] diff --git a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py index 1c4695df806..3b4ad3d7472 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsAddress.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsAddress.py @@ -45,6 +45,19 @@ class CsAddress(CsDataBag): interfaces.append(CsInterface(ip, self.config)) return interfaces + def get_guest_if_by_network_id(self): + guest_interface = None + lowest_network_id = 1000 + for interface in self.get_interfaces(): + if interface.is_guest() and interface.is_added(): + if not self.config.is_vpc(): + return interface + network_id = self.config.guestnetwork().get_network_id(interface.get_device()) + if network_id and network_id < lowest_network_id: + lowest_network_id = network_id + guest_interface = interface + return guest_interface + def get_guest_if(self): """ Return CsInterface object for the lowest in use guest interface @@ -262,12 +275,15 @@ class CsDevice: self.fw = config.get_fw() self.cl = config.cmdline() - def configure_rp(self): + def configure_rp(self, enable=True): """ Configure Reverse Path Filtering """ filename = "/proc/sys/net/ipv4/conf/%s/rp_filter" % self.dev - CsHelper.updatefile(filename, "1\n", "w") + if enable: + CsHelper.updatefile(filename, "1\n", "w") + else: + CsHelper.updatefile(filename, "0\n", "w") def buildlist(self): """ @@ -344,7 +360,7 @@ class CsIP: interfaces = [CsInterface(address, self.config)] CsHelper.reconfigure_interfaces(self.cl, interfaces) - if self.get_type() in ['public'] and not self.config.is_routed(): + if self.get_type() in ['public'] and not self.config.is_routed() and self.config.has_public_network(): self.set_mark() if 'gateway' in self.address: @@ -361,7 +377,13 @@ class CsIP: # The code looks redundant here, but we actually have to cater for routers and # VPC routers in a different manner. Please do not remove this block otherwise # The VPC default route will be broken. - if self.get_type() in ["public"] and address["device"] == CsHelper.PUBLIC_INTERFACES[self.cl.get_type()]: + if not self.config.has_public_network(): + interface = self.config.address().get_guest_if_by_network_id() + if interface: + gateway = interface.get_gateway() + route.add_or_change_defaultroute(gateway) + CsDevice(self.dev, self.config).configure_rp(False) + elif self.get_type() in ["public"] and address["device"] == CsHelper.PUBLIC_INTERFACES[self.cl.get_type()]: gateway = str(address["gateway"]) route.add_defaultroute(gateway) else: @@ -427,7 +449,7 @@ class CsIP: self.fw.append(["filter", "", "-P FORWARD DROP"]) def fw_router(self): - if self.config.is_vpc() or self.config.is_routed(): + if self.config.is_vpc() or self.config.is_routed() or self.config.is_dhcp(): return self.fw.append(["mangle", "front", "-A PREROUTING " + @@ -524,20 +546,24 @@ class CsIP: self.fw.append(["mangle", "front", "-A PREROUTING " + " -i %s -m state --state RELATED,ESTABLISHED " % self.dev + "-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"]) - guestNetworkCidr = self.address['network'] - self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" % - (guestNetworkCidr, self.dev, self.dev)]) - self.fw.append( - ["filter", "front", "-A ACL_INBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev]) - self.fw.append( - ["filter", "front", "-A ACL_INBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev]) - self.fw.append( - ["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev]) - self.fw.append( - ["mangle", "front", "-A ACL_OUTBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev]) - self.fw.append( - ["mangle", "front", "-A ACL_OUTBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev]) + guestNetworkCidr = self.address['network'] + if self.config.has_public_network(): + self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" % + (guestNetworkCidr, self.dev, self.dev)]) + self.fw.append( + ["filter", "front", "-A ACL_INBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev]) + self.fw.append( + ["filter", "front", "-A ACL_INBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev]) + self.fw.append( + ["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev]) + self.fw.append( + ["mangle", "front", "-A ACL_OUTBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev]) + self.fw.append( + ["mangle", "front", "-A ACL_OUTBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev]) + else: + self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACCEPT" % (guestNetworkCidr, self.dev)]) + self.fw.append( ["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev]) self.fw.append( @@ -552,9 +578,11 @@ class CsIP: ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 443 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)]) self.fw.append( ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 8080 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)]) - self.fw.append(["mangle", "", - "-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" % - (self.dev, guestNetworkCidr, self.address['gateway'], self.dev)]) + + if self.config.has_public_network(): + self.fw.append(["mangle", "", + "-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" % + (self.dev, guestNetworkCidr, self.address['gateway'], self.dev)]) if self.is_private_gateway(): self.fw.append(["filter", "front", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" % @@ -706,6 +734,47 @@ class CsIP: self.nft_ipv4_acl.append({'type': "", 'chain': 'FORWARD', 'rule': "iifname %s oifname %s ct state related,established counter accept" % (self.dev, self.dev)}) + def fw_dhcpserver(self): + if not self.config.is_dhcp(): + return + + self.fw.append(["mangle", "front", + "-A POSTROUTING " + + "-p udp -m udp --dport 68 -j CHECKSUM --checksum-fill"]) + + self.fw.append(["filter", "", "-A INPUT -d 224.0.0.18/32 -j ACCEPT"]) + self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"]) + self.fw.append(["filter", "", "-A INPUT -i %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % + self.dev]) + self.fw.append(["filter", "", "-A INPUT -p icmp -j ACCEPT"]) + self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"]) + + if self.config.is_vpc(): + self.fw.append( + ["filter", "", "-A INPUT -i eth0 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"]) + else: + self.fw.append( + ["filter", "", "-A INPUT -i eth1 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"]) + + if self.get_type() in ["guest"]: + guestNetworkCidr = self.address['network'] + self.fw.append( + ["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev]) + self.fw.append( + ["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)]) + self.fw.append( + ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)]) + self.fw.append( + ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 80 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)]) + self.fw.append( + ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 443 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)]) + self.fw.append( + ["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 8080 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)]) + self.fw.append( + ["filter", "", "-A FORWARD -i %s -o %s -m state --state RELATED,ESTABLISHED -j ACCEPT" % (self.dev, self.dev)]) + self.fw.append( + ["filter", "", "-A FORWARD -i %s -o %s -m state --state NEW -j ACCEPT" % (self.dev, self.dev)]) + def post_config_change(self, method): route = CsRoute() @@ -755,6 +824,7 @@ class CsIP: self.fw_vpcrouter() self.fw_router_routing() self.fw_vpcrouter_routing() + self.fw_dhcpserver() cmdline = self.config.cmdline() diff --git a/systemvm/debian/opt/cloud/bin/cs/CsConfig.py b/systemvm/debian/opt/cloud/bin/cs/CsConfig.py index e6e738b042a..549b08f75fc 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsConfig.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsConfig.py @@ -152,3 +152,6 @@ class CsConfig(object): return 'mangle' else: return "" + + def has_public_network(self): + return self.cmdline().idata().get('has_public_network', 'true') == 'true' diff --git a/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py b/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py index 4c6b61240b8..fdffb4dd288 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsDatabag.py @@ -262,3 +262,10 @@ class CsGuestNetwork(CsDataBag): if ip6gateway: return ip6gateway return False + + def get_network_id(self, devname): + nw = self.get_dev_data(devname) + networkidkey = "network_id" + if networkidkey not in nw: + return False + return nw[networkidkey] diff --git a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py index 1b34ee7e68d..e74e801f59d 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsDhcp.py @@ -146,9 +146,9 @@ class CsDhcp(CsDataBag): listen_address.append(gateway) listen_address.append(ip) # Add localized "data-server" records in /etc/hosts for VPC routers - if (self.config.is_vpc() or self.config.is_router()) and ('is_vr_guest_gateway' not in gn.data or (not gn.data['is_vr_guest_gateway'])): + if (self.config.is_vpc() and gn.is_vr_guest_gateway()) or self.config.is_router(): self.add_host(gateway, "%s data-server" % CsHelper.get_hostname()) - elif self.config.is_dhcp() or (self.config.is_vpc() or self.config.is_router() and gn.data['is_vr_guest_gateway']) : + elif self.config.is_dhcp() or (self.config.is_vpc() and not gn.is_vr_guest_gateway()): self.add_host(ip, "%s data-server" % CsHelper.get_hostname()) idx += 1 diff --git a/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py b/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py index 65200fb8796..a6667c852fd 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsGuestNetwork.py @@ -34,6 +34,9 @@ class CsGuestNetwork: def is_guestnetwork(self): return self.guest + def is_vr_guest_gateway(self): + return self.guest and ('is_vr_guest_gateway' not in self.data or self.data['is_vr_guest_gateway']) + def get_dns(self): if not self.guest: return self.config.get_dns() @@ -42,8 +45,11 @@ class CsGuestNetwork: return [self.data['router_guest_ip']] dns = [] - if 'router_guest_gateway' in self.data and not self.config.use_extdns() and ('is_vr_guest_gateway' not in self.data or not self.data['is_vr_guest_gateway']): - dns.append(self.data['router_guest_gateway']) + if not self.config.use_extdns(): + if 'router_guest_gateway' in self.data and self.is_vr_guest_gateway(): + dns.append(self.data['router_guest_gateway']) + elif 'router_guest_ip' in self.data and not self.is_vr_guest_gateway(): + dns.append(self.data['router_guest_ip']) if 'dns' in self.data: dns.extend(self.data['dns'].split(',')) diff --git a/systemvm/debian/opt/cloud/bin/cs/CsRoute.py b/systemvm/debian/opt/cloud/bin/cs/CsRoute.py index 796ef505722..b0c8bf44ea5 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsRoute.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsRoute.py @@ -85,6 +85,9 @@ class CsRoute: if not found and method == "add": logging.info("Add " + cmd) cmd = "ip route add " + cmd + elif not found and method == "change": + logging.info("Change " + cmd) + cmd = "ip route change " + cmd elif found and method == "delete": logging.info("Delete " + cmd) cmd = "ip route delete " + cmd @@ -122,6 +125,24 @@ class CsRoute: logging.warn("No default route found!") return False + def add_or_change_defaultroute(self, gateway): + """ Add a default route if not found, or change the default route if found + :param str gateway + :return: bool + """ + if not gateway: + raise Exception("Gateway cannot be None.") + + cmd = "default via " + gateway + if self.defaultroute_exists(): + logging.info("Changing default route") + self.set_route(cmd, method="change") + return True + else: + logging.info("Adding default route") + self.set_route(cmd) + return True + def findRule(self, rule): for i in CsHelper.execute("ip rule show"): if rule in i.strip(): diff --git a/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py index 9e918f94a42..6f1ec62cd08 100755 --- a/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py +++ b/systemvm/debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py @@ -58,6 +58,8 @@ class CsVpcGuestNetwork(CsDataBag): self.enable_ipv6(entry['device']) cidr_size = entry['router_guest_ip6_cidr'].split("/")[-1] full_addr = entry['router_guest_ip6_gateway'] + "/" + cidr_size + if entry['router_guest_ip6'] != entry['router_guest_ip6_gateway']: + full_addr = entry['router_guest_ip6'] + "/" + cidr_size if not CsHelper.execute("ip -6 addr show dev %s | grep -w %s" % (entry['device'], full_addr)): CsHelper.execute("ip -6 addr add %s dev %s" % (full_addr, entry['device'])) if 'router_ip6' in list(entry.keys()) and entry['router_ip6']: @@ -74,6 +76,8 @@ class CsVpcGuestNetwork(CsDataBag): if 'router_guest_ip6' in list(entry.keys()) and entry['router_guest_ip6']: cidr_size = entry['router_guest_ip6_cidr'].split("/")[-1] full_addr = entry['router_guest_ip6_gateway'] + "/" + cidr_size + if entry['router_guest_ip6'] != entry['router_guest_ip6_gateway']: + full_addr = entry['router_guest_ip6'] + "/" + cidr_size CsHelper.execute("ip -6 addr del %s dev %s" % (full_addr, entry['device'])) if 'router_ip6' in list(entry.keys()) and entry['router_ip6']: full_public_addr = entry['router_ip6'] + "/" + cidr_size @@ -103,11 +107,12 @@ class CsVpcGuestNetwork(CsDataBag): self.conf.append(" AdvSendAdvert on;") self.conf.append(" MinRtrAdvInterval 5;") self.conf.append(" MaxRtrAdvInterval 15;") - self.conf.append(" prefix %s" % full_addr) - self.conf.append(" {") - self.conf.append(" AdvOnLink on;") - self.conf.append(" AdvAutonomous on;") - self.conf.append(" };") + if entry['router_guest_ip6'] == entry['router_guest_ip6_gateway']: + self.conf.append(" prefix %s" % full_addr) + self.conf.append(" {") + self.conf.append(" AdvOnLink on;") + self.conf.append(" AdvAutonomous on;") + self.conf.append(" };") if 'dns6' in list(entry.keys()) and entry['dns6']: for dns in entry['dns6'].split(","): self.conf.append(" RDNSS %s" % dns) diff --git a/systemvm/debian/opt/cloud/bin/passwd_server_ip.py b/systemvm/debian/opt/cloud/bin/passwd_server_ip.py index 8051951a18f..bf1eab2db02 100755 --- a/systemvm/debian/opt/cloud/bin/passwd_server_ip.py +++ b/systemvm/debian/opt/cloud/bin/passwd_server_ip.py @@ -28,6 +28,7 @@ import binascii import cgi import os +import socketserver import sys import syslog import threading @@ -97,9 +98,17 @@ def removePassword(ip): del passMap[ip] -class ThreadedHTTPServer(ThreadingMixIn, HTTPServer): - pass +class CloudStackPasswordServer(socketserver.TCPServer): + allow_reuse_address = 1 + def server_bind(self): + """Override server_bind to store the server name.""" + socketserver.TCPServer.server_bind(self) + host, port = self.server_address[:2] + self.server_name = host + self.server_port = port +class ThreadedHTTPServer(ThreadingMixIn, CloudStackPasswordServer): + pass class PasswordRequestHandler(BaseHTTPRequestHandler): server_version = 'CloudStack Password Server' diff --git a/test/integration/component/test_project_usage.py b/test/integration/component/test_project_usage.py index ea7f740be85..bfb0f0b6d08 100644 --- a/test/integration/component/test_project_usage.py +++ b/test/integration/component/test_project_usage.py @@ -1707,17 +1707,10 @@ class TestVpnUsage(cloudstackTestCase): listall=True ) if isinstance(networks, list): - network = networks[0] + cls.network = networks[0] else: raise Exception("List networks call failed") - cls.public_ip = PublicIPAddress.create( - cls.api_client, - zoneid=cls.zone.zoneid, - services=cls.services["server"], - networkid=network.id, - projectid=cls.project.id - ) cls._cleanup = [ cls.project, cls.service_offering, @@ -1760,12 +1753,20 @@ class TestVpnUsage(cloudstackTestCase): # this account in cloud.usage_event table # 4. Delete this account. - self.debug("Created VPN with public IP: %s" % - self.public_ip.ipaddress.id) - #Assign VPN to Public IP + # Listing source NAT IP of newly added network + ipAddresses = PublicIPAddress.list( + self.apiclient, + associatednetworkid=self.network.id, + projectid=self.project.id, + issourcenat=True) + + sourceNatIP = ipAddresses[0] + self.debug("Created VPN with source NAT IP: %s" % + sourceNatIP.id) + #Assign VPN to source NAT IP vpn = Vpn.create( self.apiclient, - self.public_ip.ipaddress.id, + sourceNatIP.id, projectid=self.project.id ) diff --git a/test/integration/component/test_vpn_users.py b/test/integration/component/test_vpn_users.py index 980e21bba27..ee7a0ea3ee0 100644 --- a/test/integration/component/test_vpn_users.py +++ b/test/integration/component/test_vpn_users.py @@ -165,18 +165,18 @@ class TestVPNUsers(cloudstackTestCase): def create_VPN(self, public_ip): """Creates VPN for the network""" - self.debug("Creating VPN with public IP: %s" % public_ip.ipaddress.id) + self.debug("Creating VPN with public IP: %s" % public_ip.id) try: # Assign VPN to Public IP vpn = Vpn.create(self.apiclient, - self.public_ip.ipaddress.id, + public_ip.id, account=self.account.name, domainid=self.account.domainid) self.cleanup.append(vpn) self.debug("Verifying the remote VPN access") vpns = Vpn.list(self.apiclient, - publicipid=public_ip.ipaddress.id, + publicipid=public_ip.id, listall=True) self.assertEqual( isinstance(vpns, list), @@ -244,7 +244,23 @@ class TestVPNUsers(cloudstackTestCase): self.debug("Enabling the VPN access for IP: %s" % self.public_ip.ipaddress) - self.create_VPN(self.public_ip) + network_id = self.virtual_machine.nic[0].networkid + src_nat_list = PublicIPAddress.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + listall=True, + issourcenat=True, + associatednetworkid=network_id + ) + self.assertEqual( + validateList(src_nat_list)[0], + PASS, + "Failed to list source nat ip address" + ) + ip = src_nat_list[0] + + self.create_VPN(ip) self.debug("Creating %s VPN users" % limit) for x in range(limit): self.create_VPN_Users() @@ -296,9 +312,24 @@ class TestVPNUsers(cloudstackTestCase): # 3. add a port forward rule for UDP port 1701. Should result in error # saying that VPN is enabled over port 1701 + network_id = self.virtual_machine.nic[0].networkid + src_nat_list = PublicIPAddress.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + listall=True, + issourcenat=True, + associatednetworkid=network_id + ) + self.assertEqual( + validateList(src_nat_list)[0], + PASS, + "Failed to list source nat ip address" + ) + ip = src_nat_list[0] self.debug("Enabling the VPN connection for IP: %s" % - self.public_ip.ipaddress) - self.create_VPN(self.public_ip) + ip.address) + self.create_VPN(ip) self.debug("Creating a port forwarding rule on port 1701") # Create NAT rule @@ -307,7 +338,7 @@ class TestVPNUsers(cloudstackTestCase): self.apiclient, self.virtual_machine, self.services["natrule"], - self.public_ip.ipaddress.id) + ip.id) self.debug("Create NAT rule failed! Test successful!") return @@ -322,9 +353,25 @@ class TestVPNUsers(cloudstackTestCase): # 3. We should be able to successfully establish a VPN connection using # the newly added user credential. + network_id = self.virtual_machine.nic[0].networkid + src_nat_list = PublicIPAddress.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + listall=True, + issourcenat=True, + associatednetworkid=network_id + ) + self.assertEqual( + validateList(src_nat_list)[0], + PASS, + "Failed to list source nat ip address" + ) + ip = src_nat_list[0] + self.debug("Enabling the VPN connection for IP: %s" % - self.public_ip.ipaddress) - self.create_VPN(self.public_ip) + ip.address) + self.create_VPN(ip) try: self.debug("Adding new VPN user to account: %s" % @@ -349,9 +396,24 @@ class TestVPNUsers(cloudstackTestCase): # 2. Add a VPN user say "abc" that already an added user to the VPN. # 3. Adding this VPN user should fail. + network_id = self.virtual_machine.nic[0].networkid + src_nat_list = PublicIPAddress.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + listall=True, + issourcenat=True, + associatednetworkid=network_id + ) + self.assertEqual( + validateList(src_nat_list)[0], + PASS, + "Failed to list source nat ip address" + ) + ip = src_nat_list[0] self.debug("Enabling the VPN connection for IP: %s" % - self.public_ip.ipaddress) - self.create_VPN(self.public_ip) + ip.address) + self.create_VPN(ip) self.debug("Adding new VPN user to account: %s" % self.account.name) @@ -379,9 +441,24 @@ class TestVPNUsers(cloudstackTestCase): # 2. We should be able to use this newly created user credential to # establish VPN connection that will give access all VMs of this user + network_id = self.virtual_machine.nic[0].networkid + src_nat_list = PublicIPAddress.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + listall=True, + issourcenat=True, + associatednetworkid=network_id + ) + self.assertEqual( + validateList(src_nat_list)[0], + PASS, + "Failed to list source nat ip address" + ) + ip = src_nat_list[0] self.debug("Enabling VPN connection to account: %s" % self.account.name) - self.create_VPN(self.public_ip) + self.create_VPN(ip) self.debug("Creating VPN user for the account: %s" % self.account.name) self.create_VPN_Users() @@ -422,9 +499,24 @@ class TestVPNUsers(cloudstackTestCase): # 2. We should be able to use this newly created user credential to # establish VPN connection that will give access all VMs of this user + network_id = self.virtual_machine.nic[0].networkid + src_nat_list = PublicIPAddress.list( + self.apiclient, + account=self.account.name, + domainid=self.account.domainid, + listall=True, + issourcenat=True, + associatednetworkid=network_id + ) + self.assertEqual( + validateList(src_nat_list)[0], + PASS, + "Failed to list source nat ip address" + ) + ip = src_nat_list[0] self.debug("Enabling VPN connection to account: %s" % self.account.name) - self.create_VPN(self.public_ip) + self.create_VPN(ip) self.debug("Creating VPN user for the account: %s" % self.account.name) self.create_VPN_Users() diff --git a/test/integration/smoke/test_usage.py b/test/integration/smoke/test_usage.py index 1a6ff37cedb..a65e4917a46 100644 --- a/test/integration/smoke/test_usage.py +++ b/test/integration/smoke/test_usage.py @@ -1732,6 +1732,14 @@ class TestVpnUsage(cloudstackTestCase): domainid=cls.virtual_machine.domainid, services=cls.services["server"] ) + src_nat_list = PublicIPAddress.list( + cls.api_client, + accountid=cls.virtual_machine.account, + zoneid=cls.virtual_machine.zoneid, + domainid=cls.virtual_machine.domainid, + issourcenat=True + ) + cls.public_ip = src_nat_list[0] return @classmethod @@ -1770,11 +1778,11 @@ class TestVpnUsage(cloudstackTestCase): # 4. Delete this account. self.debug("Created VPN with public IP: %s" % - self.public_ip.ipaddress.id) + self.public_ip.ipaddress) # Assign VPN to Public IP vpn = Vpn.create( self.apiclient, - self.public_ip.ipaddress.id, + self.public_ip.id, account=self.account.name, domainid=self.account.domainid ) diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 8d507670ba8..0db89372581 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -98,6 +98,7 @@ known_categories = { 'listNsxControllers': 'NSX', 'addNsxController': 'NSX', 'deleteNsxController': 'NSX', + 'NetrisProvider': 'Netris', 'Vpn': 'VPN', 'Limit': 'Resource Limit', 'Netscaler': 'Netscaler', diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 93485043010..e26cd4d494e 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1546,6 +1546,16 @@ "label.native": "Native", "label.ncc": "NCC", "label.netmask": "Netmask", +"label.netris": "Netris", +"label.netristag": "Netris tag", +"label.netris.provider": "Netris Provider", +"label.netris.provider.name": "Netris provider name", +"label.netris.provider.username": "Netris provider username", +"label.netris.provider.password": "Netris provider password", +"label.netris.provider.site": "Netris provider Site name", +"label.netris.provider.tenant.name": "Netris provider Admin Tenant name", +"label.netris.provider.tag": "Netris Tag", +"label.netris.provider.url": "Netris provider URL", "label.netscaler": "NetScaler", "label.netscaler.mpx": "NetScaler MPX LoadBalancer", "label.netscaler.sdx": "NetScaler SDX LoadBalancer", @@ -1599,6 +1609,7 @@ "label.newinstance": "New Instance", "label.newname": "New name", "label.next": "Next", +"label.nexthop": "Next hop", "label.nfs": "NFS", "label.nfsmountopts": "NFS mount options", "label.nfsserver": "NFS server", @@ -1841,6 +1852,7 @@ "label.public.ips": "Public IP addresses", "label.public.lb": "Public LB", "label.public.traffic": "Public traffic", +"label.public.traffic.netris": "Netris Public IP Pool", "label.public.traffic.nsx": "NSX Public traffic", "label.publicinterface": "Public interface", "label.publicip": "IP address", @@ -2160,8 +2172,9 @@ "label.shutdown": "Shutdown", "label.shutdown.provider": "Shutdown provider", "label.simplified.chinese.keyboard": "Simplified Chinese keyboard", +"label.site": "Netris Site", "label.site.to.site.vpn": "Site-to-site VPN", -"label.site.to.site.vpn.connections": "Site-to-site VPN Connections", +"label.site.to.site.vpn.connections": "VPN Connections", "label.size": "Size", "label.sizegb": "Size", "label.smb.domain": "SMB domain", @@ -2324,6 +2337,7 @@ "label.systemvm": "System VM", "label.systemvmtype": "System VM type", "label.tag": "Tag", +"label.tag.netris": "netris", "label.tag.nsx": "nsx", "label.tag.key": "Tag key", "label.tag.systemvm": "systemvm", @@ -2355,6 +2369,7 @@ "label.templatesubject": "Subject", "label.templatetype": "Template type", "label.templateversion": "Template version", +"label.tenantname": "Netris Tenant", "label.term.type": "Term type", "label.test": "Test", "label.test.webhook.delivery": "Test Webhook Delivery", @@ -2635,6 +2650,7 @@ "label.volumetype": "Volume Type", "label.vpc": "VPC", "label.vpcs": "VPCs", +"label.vpc.gateway.ip": "VPC Gateway IP", "label.vpc.id": "VPC ID", "label.vpc.offerings": "VPC offerings", "label.vpc.virtual.router": "VPC virtual router", @@ -2859,6 +2875,7 @@ "message.remove.ip.v6.firewall.rule.failed": "Failed to remove IPv6 firewall rule", "message.remove.ip.v6.firewall.rule.processing": "Removing IPv6 firewall rule...", "message.remove.ip.v6.firewall.rule.success": "Removed IPv6 firewall rule", +"message.add.netris.controller": "Add Netris Provider", "message.add.nsx.controller": "Add NSX Provider", "message.add.network": "Add a new network for zone: ", "message.add.network.acl.failed": "Adding network ACL list failed.", @@ -2949,6 +2966,7 @@ "message.configuring.guest.traffic": "Configuring guest traffic", "message.configuring.physical.networks": "Configuring physical Networks", "message.configuring.public.traffic": "Configuring public traffic", +"message.configuring.netris.public.traffic": "Configuring Netris public traffic", "message.configuring.storage.access.failed": "Configuring storage access failed", "message.configuring.nsx.public.traffic": "Configuring NSX public traffic", "message.configuring.storage.traffic": "Configuring storage traffic", @@ -3079,6 +3097,7 @@ "message.delete.vpn.connection": "Please confirm that you want to delete VPN connection.", "message.delete.vpn.customer.gateway": "Please confirm that you want to delete this VPN customer gateway.", "message.delete.vpn.gateway": "Please confirm that you want to delete this VPN Gateway.", +"message.delete.vpn.gateway.failed": "Failed to delete VPN Gateway.", "message.delete.webhook": "Please confirm that you want to delete this Webhook.", "message.delete.webhook.delivery": "Please confirm that you want to delete this Webhook delivery.", "message.deleting.firewall.policy": "Deleting Firewall Policy", @@ -3144,7 +3163,7 @@ "message.enable.vpn": "Please confirm that you want remote access VPN enabled for this IP address.", "message.enable.vpn.failed": "Failed to enable VPN.", "message.enable.vpn.processing": "Enabling VPN...", -"message.enabled.vpn": "Your remote access VPN is currently enabled and can be accessed via the IP.", +"message.enabled.vpn": "Your remote access VPN is currently enabled and can be accessed via the IP", "message.enabled.vpn.ip.sec": "Your IPSec pre-shared key is", "message.enabling.security.group.provider": "Enabling security group provider", "message.enter.valid.nic.ip": "Please enter a valid IP address for NIC", @@ -3325,6 +3344,7 @@ "message.import.volume": "Please specify the domain, account or project name.
If not set, the volume will be imported for the caller.", "message.info.cloudian.console": "Cloudian Management Console should open in another window.", "message.installwizard.cloudstack.helptext.website": " * Project website:\t ", +"message.infra.setup.netris.description": "This zone must contain a Netris provider because the isolation method is Netris", "message.infra.setup.nsx.description": "This zone must contain an NSX provider because the isolation method is NSX", "message.infra.setup.tungsten.description": "This zone must contain a Tungsten-Fabric provider because the isolation method is TF", "message.installwizard.cloudstack.helptext.document": " * Documentation:\t ", @@ -3342,6 +3362,13 @@ "message.installwizard.tooltip.configureguesttraffic.guestgateway": "The gateway that the guests should use.", "message.installwizard.tooltip.configureguesttraffic.guestnetmask": "The netmask in use on the subnet that the guests should use.", "message.installwizard.tooltip.configureguesttraffic.gueststartip": "The range of IP addresses that will be available for allocation to guests in this zone. If one NIC is used, these IPs should be in the same CIDR as the pod CIDR.", +"message.installwizard.tooltip.netris.provider.name": "Netris Provider name is required", +"message.installwizard.tooltip.netris.provider.url": "Netris Provider URL not provided", +"message.installwizard.tooltip.netris.provider.username": "Netris Provider username not provided", +"message.installwizard.tooltip.netris.provider.password": "Netris Provider password not provided", +"message.installwizard.tooltip.netris.provider.site": "Netris Provider Site name not provided", +"message.installwizard.tooltip.netris.provider.tag": "Netris Tag to be assigned to vNets", +"message.installwizard.tooltip.netris.provider.tenant.name": "Netris Provider Admin Tenant name not provided", "message.installwizard.tooltip.nsx.provider.hostname": "NSX Provider hostname / IP address not provided", "message.installwizard.tooltip.nsx.provider.username": "NSX Provider username not provided", "message.installwizard.tooltip.nsx.provider.password": "NSX Provider password not provided", @@ -3644,6 +3671,7 @@ "message.success.delete.tungsten.router.table": "Successfully removed Router Table", "message.success.delete.tungsten.tag": "Successfully removed Tag", "message.success.delete.vm": "Successfully deleted Instance", +"message.success.delete.vpn.gateway": "Successfully deleted VPN gateway", "message.success.disable.saml.auth": "Successfully disabled SAML authorization", "message.success.disable.vpn": "Successfully disabled VPN", "message.success.edit.acl": "Successfully edited ACL rule", diff --git a/ui/src/components/CheckBoxSelectPair.vue b/ui/src/components/CheckBoxSelectPair.vue index 4fba1da2556..480e515be29 100644 --- a/ui/src/components/CheckBoxSelectPair.vue +++ b/ui/src/components/CheckBoxSelectPair.vue @@ -21,7 +21,7 @@ {{ checkBoxLabel }} @@ -32,7 +32,7 @@ :label="selectLabel"> {{ $t('label.vmname') }}
- {{ resource.vmname || resource.vm || resource.virtualmachinename || resource.virtualmachineid }} + {{ resource.vmname || resource.vm || resource.virtualmachinename || resource.virtualmachineid }}
diff --git a/ui/src/config/section/infra/phynetworks.js b/ui/src/config/section/infra/phynetworks.js index 578a12516fa..977fc984d2c 100644 --- a/ui/src/config/section/infra/phynetworks.js +++ b/ui/src/config/section/infra/phynetworks.js @@ -57,7 +57,7 @@ export default { args: ['name', 'zoneid', 'isolationmethods', 'vlan', 'tags', 'networkspeed', 'broadcastdomainrange'], mapping: { isolationmethods: { - options: ['VLAN', 'VXLAN', 'GRE', 'STT', 'BCF_SEGMENT', 'SSP', 'ODL', 'L3VPN', 'VCS'] + options: ['VLAN', 'VXLAN', 'GRE', 'STT', 'BCF_SEGMENT', 'SSP', 'ODL', 'L3VPN', 'VCS', 'NSX', 'NETRIS'] } } }, diff --git a/ui/src/config/section/network.js b/ui/src/config/section/network.js index 4e58c7a4cd8..42af53274f7 100644 --- a/ui/src/config/section/network.js +++ b/ui/src/config/section/network.js @@ -800,7 +800,7 @@ export default { }, { name: 'vpn', component: shallowRef(defineAsyncComponent(() => import('@/views/network/VpnDetails.vue'))), - show: (record) => { return record.issourcenat } + show: (record) => { return record.issourcenat || record.virtualmachinetype === 'DomainRouter' || !record.hasrules } }, { name: 'events', @@ -1021,7 +1021,6 @@ export default { title: 'label.site.to.site.vpn.connections', docHelp: 'adminguide/networking_and_traffic.html#setting-up-a-site-to-site-vpn-connection', icon: 'sync-outlined', - hidden: true, permission: ['listVpnConnections'], columns: ['publicip', 'state', 'gateway', 'ipsecpsk', 'ikepolicy', 'esppolicy'], details: ['publicip', 'gateway', 'passive', 'cidrlist', 'ipsecpsk', 'ikepolicy', 'esppolicy', 'ikelifetime', 'ikeversion', 'esplifetime', 'dpd', 'splitconnections', 'forceencap', 'created'], diff --git a/ui/src/views/AutogenView.vue b/ui/src/views/AutogenView.vue index 3199b0cdeeb..ab086cf189f 100644 --- a/ui/src/views/AutogenView.vue +++ b/ui/src/views/AutogenView.vue @@ -1950,7 +1950,6 @@ export default { this.rules[field.name].push(rule) break case (this.currentAction.mapping && field.name in this.currentAction.mapping && 'options' in this.currentAction.mapping[field.name]): - console.log('op: ' + field) rule.required = field.required rule.message = this.$t('message.error.select') this.rules[field.name].push(rule) @@ -1961,20 +1960,17 @@ export default { this.rules[field.name].push(rule) break case (field.type === 'uuid'): - console.log('uuid: ' + field) rule.required = field.required rule.message = this.$t('message.error.select') this.rules[field.name].push(rule) break case (field.type === 'list'): - console.log('list: ' + field) rule.type = 'array' rule.required = field.required rule.message = this.$t('message.error.select') this.rules[field.name].push(rule) break case (field.type === 'long'): - console.log(field) rule.type = 'number' rule.required = field.required rule.message = this.$t('message.validate.number') diff --git a/ui/src/views/infra/network/IpRangesTabPublic.vue b/ui/src/views/infra/network/IpRangesTabPublic.vue index e1137bd0419..61f15ddedc3 100644 --- a/ui/src/views/infra/network/IpRangesTabPublic.vue +++ b/ui/src/views/infra/network/IpRangesTabPublic.vue @@ -230,6 +230,16 @@ + + + + + {{ $t('label.nsx') }} + {{ $t('label.netris') }} + +
@@ -244,6 +254,16 @@ + + + + + {{ $t('label.nsx') }} + {{ $t('label.netris') }} + +
@@ -633,6 +653,7 @@ export default { params.podid = values.podid params.networkid = this.network.id } + params.provider = values.provider postAPI('createVlanIpRange', params).then(() => { this.$notification.success({ message: this.$t('message.success.add.iprange') diff --git a/ui/src/views/infra/network/ServiceProvidersTab.vue b/ui/src/views/infra/network/ServiceProvidersTab.vue index 06031b52278..b17b173f962 100644 --- a/ui/src/views/infra/network/ServiceProvidersTab.vue +++ b/ui/src/views/infra/network/ServiceProvidersTab.vue @@ -1128,6 +1128,50 @@ export default { columns: ['name', 'hostname', 'port', 'tier0gateway', 'edgecluster', 'transportzone'] } ] + }, + { + title: 'Netris', + details: ['name', 'state', 'id', 'physicalnetworkid', 'servicelist'], + actions: [ + { + api: 'updateNetworkServiceProvider', + icon: 'stop-outlined', + listView: true, + label: 'label.disable.provider', + confirm: 'message.confirm.disable.provider', + show: (record) => { return (record && record.id && record.state === 'Enabled') }, + mapping: { + state: { + value: (record) => { return 'Disabled' } + } + } + }, + { + api: 'updateNetworkServiceProvider', + icon: 'play-circle-outlined', + listView: true, + label: 'label.enable.provider', + confirm: 'message.confirm.enable.provider', + show: (record) => { return (record && record.id && record.state === 'Disabled') }, + mapping: { + state: { + value: (record) => { return 'Enabled' } + } + } + } + ], + lists: [ + { + title: 'label.netris.provider', + api: 'listNetrisProviders', + mapping: { + zoneid: { + value: (record) => { return record.zoneid } + } + }, + columns: ['name', 'hostname', 'port', 'site', 'tenantname', 'netristag'] + } + ] } ] } @@ -1168,7 +1212,6 @@ export default { this.fetchLoading = true getAPI('listNetworkServiceProviders', { physicalnetworkid: this.resource.id, name: name }).then(json => { const sps = json.listnetworkserviceprovidersresponse.networkserviceprovider || [] - console.log(sps) if (sps.length > 0) { for (const sp of sps) { this.nsps[sp.name] = sp diff --git a/ui/src/views/infra/network/TrafficTypesTab.vue b/ui/src/views/infra/network/TrafficTypesTab.vue index af5f931fc3e..c65f8ec2aec 100644 --- a/ui/src/views/infra/network/TrafficTypesTab.vue +++ b/ui/src/views/infra/network/TrafficTypesTab.vue @@ -21,7 +21,7 @@ -