diff --git a/api/src/main/java/com/cloud/configuration/ConfigurationService.java b/api/src/main/java/com/cloud/configuration/ConfigurationService.java index 97d4b42974b..5a4dcb3f569 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; @@ -372,4 +376,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/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/netris/NetrisProvider.java b/api/src/main/java/com/cloud/network/netris/NetrisProvider.java index b7892484bb9..82dc5a271a7 100644 --- a/api/src/main/java/com/cloud/network/netris/NetrisProvider.java +++ b/api/src/main/java/com/cloud/network/netris/NetrisProvider.java @@ -25,4 +25,6 @@ public interface NetrisProvider extends InternalIdentity, Identity { String getHostname(); String getPort(); String getUsername(); + String getSiteName(); + String getTenantName(); } 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..e11fb640632 --- /dev/null +++ b/api/src/main/java/com/cloud/network/netris/NetrisService.java @@ -0,0 +1,25 @@ +// 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.vpc.Vpc; + +public interface NetrisService { + boolean createVpcResource(long zoneId, long accountId, long domainId, Long vpcId, String vpcName, boolean sourceNatEnabled, String cidr, boolean isVpcNetwork); + boolean deleteVpcResource(long zoneId, long accountId, long domainId, Vpc vpc); + boolean createVnetResource(Long zoneId, long accountId, long domainId, String vpcName, Long vpcId, String networkName, Long networkId, String cidr); +} 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 1358b13a4fe..77d52991130 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcOffering.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcOffering.java @@ -57,8 +57,6 @@ public interface VpcOffering extends InternalIdentity, Identity { */ boolean isDefault(); - boolean isForNsx(); - NetworkOffering.NetworkMode getNetworkMode(); /** diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index e70e8949ad7..4df01bd8986 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -103,10 +103,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 bb16b0ff90d..b0d01e89c7d 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -325,6 +325,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"; @@ -448,6 +450,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"; @@ -490,6 +493,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"; @@ -1143,6 +1147,7 @@ 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 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/vlan/CreateVlanIpRangeCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vlan/CreateVlanIpRangeCmd.java index c0ba99a8233..87a4bd07a68 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.20.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/response/AsyncJobResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/AsyncJobResponse.java index 3eeaaef2afa..e1db5aa6824 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; @@ -119,11 +115,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/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index a80317c83cd..e7ad244e1da 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 @@ -208,14 +208,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; @@ -612,14 +604,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/SystemVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java index 31a8b731491..c98235b2347 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..2ee748f0c59 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 whether IP range is dedicated to NSX resources or not", since = "4.20.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 143dfad0eaf..475c8b9eef2 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.20") @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.20.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; @@ -368,6 +373,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 d89dbbbbe9d..dd9432b82da 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -1097,6 +1097,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/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/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 01fd54430d6..330fada48c3 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 @@ -227,7 +227,7 @@ public interface ConfigurationManager { 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/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 dfa4d480b94..1d6a9ee6946 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,7 @@ 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.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.annotation.AnnotationService; @@ -355,6 +356,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra @Inject private NsxProviderDao nsxProviderDao; @Inject + private NetrisProviderDao netrisProviderDao; + @Inject private ASNumberDao asNumberDao; @Inject private BGPService bgpService; @@ -1082,10 +1085,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 nsxGuru = AdapterBase.getAdapterByName(networkGurus, guruName); + nsxGuru.allocate(network, profile, vm); } if (isDefaultNic != null) { @@ -1148,7 +1155,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; } @@ -1158,7 +1165,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; } @@ -1168,14 +1177,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) { 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..5eba3f60cbf --- /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().getHostname(), + 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/element/NetrisProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/NetrisProviderVO.java index 3a759bceb11..2df1faae077 100644 --- a/engine/schema/src/main/java/com/cloud/network/element/NetrisProviderVO.java +++ b/engine/schema/src/main/java/com/cloud/network/element/NetrisProviderVO.java @@ -24,6 +24,7 @@ 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 @@ -59,6 +60,18 @@ public class NetrisProviderVO implements NetrisProvider { @Column(name = "password") private String password; + @Column(name = "site_name") + private String siteName; + + @Column(name = "tenant_name") + private String tenantName; + + @Column(name = "created") + private Date created; + + @Column(name = "removed") + private Date removed; + public NetrisProviderVO() { this.uuid = UUID.randomUUID().toString(); } @@ -141,4 +154,112 @@ public class NetrisProviderVO implements NetrisProvider { 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 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 hostname; + private String port; + private String username; + private String password; + private String siteName; + private String tenantName; + + 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 setHostname(String hostname) { + this.hostname = hostname; + return this; + } + + public Builder setPort(String port) { + this.port = port; + 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 NetrisProviderVO build() { + NetrisProviderVO provider = new NetrisProviderVO(); + provider.setZoneId(this.zoneId); + provider.setHostId(this.hostId); + provider.setUuid(UUID.randomUUID().toString()); + provider.setName(this.name); + provider.setHostname(this.hostname); + provider.setPort(this.port); + provider.setUsername(this.username); + provider.setPassword(this.password); + provider.setSiteName(this.siteName); + provider.setTenantName(this.tenantName); + provider.setCreated(new Date()); + return provider; + } + } } 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 41254ba4a8b..7945642c1d6 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 @@ -59,9 +59,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; @@ -158,14 +155,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..9519cd08a0b 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,6 @@ public interface VpcOfferingServiceMapDao extends GenericDao sc = AllFieldsSearch.create(); + sc.setParameters("vpcOffId", vpcOfferingId); + sc.setParameters("provider", provider.getName()); + return findOneBy(sc) != null; + } } 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 0bf110757d7..cf766551421 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java @@ -133,12 +133,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; @@ -199,24 +193,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/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 171685ce413..9a0bd416aca 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 @@ -137,6 +137,7 @@ + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41910to42000.sql b/engine/schema/src/main/resources/META-INF/db/schema-41910to42000.sql index 7a1a3678973..9873c355baa 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41910to42000.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41910to42000.sql @@ -437,9 +437,18 @@ CREATE TABLE `cloud`.`netris_providers` ( `port` varchar(255), `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, - `created` datetime NOT NULL COMMENT 'date created', - `removed` datetime COMMENT 'date removed if not null', + `site_name` varchar(255) NOT NULL, + `tenant_name` 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`; 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 b6abaabcd48..4fb12ce0388 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/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 71be8b1a475..b5afc13dadd 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 @@ -2008,7 +2008,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 6025a41d69c..b6cdbccf69c 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 @@ -712,7 +712,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/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/CreateNetrisVnetCommand.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.java new file mode 100644 index 00000000000..ed02a09b42c --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/CreateNetrisVnetCommand.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 CreateNetrisVnetCommand extends NetrisCommand { + private String vpcName; + private Long vpcId; + private String cidr; + private Integer vxlanId; + + public CreateNetrisVnetCommand(Long zoneId, Long accountId, Long domainId, String vpcName, Long vpcId, String vNetName, Long networkId, String cidr, boolean isVpc) { + super(zoneId, accountId, domainId, vNetName, networkId, isVpc); + this.vpcId = vpcId; + this.vpcName = vpcName; + this.cidr = cidr; + } + + + 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; + } +} 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/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/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..440892e6e87 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/agent/api/NetrisCommand.java @@ -0,0 +1,67 @@ +// 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 final 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 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/api/command/AddNetrisProviderCmd.java b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/AddNetrisProviderCmd.java index f7068793b80..d8e49e776ae 100644 --- 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 @@ -17,25 +17,103 @@ package org.apache.cloudstack.api.command; import com.cloud.exception.ConcurrentOperationException; -import com.cloud.exception.InsufficientCapacityException; -import com.cloud.exception.NetworkRuleConflictException; -import com.cloud.exception.ResourceAllocationException; -import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.netris.NetrisProvider; 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, since = "4.20") 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.HOST_NAME, type = CommandType.STRING, required = true, description = "Netris provider hostname / IP address") + private String hostname; + + @Parameter(name = ApiConstants.PORT, type = CommandType.STRING, description = "Netris provider port") + private String port; + + @Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, required = true, description = "Username to log 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 = "Password to login into Netris") + private String tenantName; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getZoneId() { + return zoneId; + } + + public String getName() { + return name; + } + + public String getHostname() { + return hostname; + } + + public String getPort() { + return port; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public String getSiteName() { + return siteName; + } + + public String getTenantName() { + return tenantName; + } @Override - public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { - + 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 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..27e29071c45 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/api/command/DeleteNetrisProviderCmd.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.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.exception.CloudRuntimeException; +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, since = "4.20.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..ed3d64e867a --- /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.20.0") +public class ListNetrisProvidersCmd extends BaseListCmd { + public static final String APINAME = "listNetrisProviders"; + + @Inject + NetrisProviderService netrisProviderService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + /// + @Parameter(name = ApiConstants.ZONE_ID, description = "Netris provider added to the specific 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 index be8b72261bb..0a6030659f0 100644 --- 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 @@ -29,6 +29,10 @@ public class NetrisProviderResponse extends BaseResponse { @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; @@ -45,9 +49,13 @@ public class NetrisProviderResponse extends BaseResponse { @Param(description = "Netris Provider port") private String port; - @SerializedName(ApiConstants.USERNAME) - @Param(description = "Netris Provider username") - private String username; + @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; public String getName() { return name; @@ -57,6 +65,14 @@ public class NetrisProviderResponse extends BaseResponse { this.name = name; } + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + public String getZoneId() { return zoneId; } @@ -89,11 +105,19 @@ public class NetrisProviderResponse extends BaseResponse { this.port = port; } - public String getUsername() { - return username; + public String getSiteName() { + return siteName; } - public void setUsername(String username) { - this.username = username; + public void setSiteName(String siteName) { + this.siteName = siteName; + } + + public String getTenantName() { + return tenantName; + } + + public void setTenantName(String tenantName) { + this.tenantName = tenantName; } } 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..ac3f06e34f5 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResource.java @@ -0,0 +1,244 @@ +// 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.resource.ServerResource; +import com.cloud.utils.exception.CloudRuntimeException; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.NetrisAnswer; +import org.apache.cloudstack.StartupNetrisCommand; +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.Map; + +public class NetrisResource implements ServerResource { + protected Logger logger = LogManager.getLogger(getClass()); + + private String name; + protected String hostname; + 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 DeleteNetrisVpcCommand) { + return executeRequest((DeleteNetrisVpcCommand) cmd); + } else if (cmd instanceof CreateNetrisVnetCommand) { + return executeRequest((CreateNetrisVnetCommand) 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 { + hostname = (String) params.get("hostname"); + if (hostname == null) { + throw new ConfigurationException("Missing Netris hostname 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(hostname, 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(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(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"); + } + + @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..8cfc5ea7918 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/resource/NetrisResourceObjectUtils.java @@ -0,0 +1,65 @@ +// 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; + +public class NetrisResourceObjectUtils { + + public enum NetrisObjectType { + VPC, IPAM_ALLOCATION, IPAM_SUBNET, VNET + } + + 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(); + + StringBuilder stringBuilder = new StringBuilder(); + 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: + case IPAM_SUBNET: + stringBuilder.append(String.format("%s%s", prefix, objectId)); + break; + case VNET: + 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 index 1085b780a18..f0317687b95 100644 --- 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 @@ -20,6 +20,9 @@ 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.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; import java.util.List; @@ -28,4 +31,20 @@ public interface NetrisApiClient { 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); + + /** + * 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); + + boolean createVnet(CreateNetrisVnetCommand 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 index e2e4c9a90f1..5acaafefe17 100644 --- 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 @@ -16,6 +16,7 @@ // under the License. package org.apache.cloudstack.service; +import com.cloud.utils.Pair; import com.cloud.utils.exception.CloudRuntimeException; import io.netris.ApiClient; import io.netris.ApiException; @@ -23,18 +24,46 @@ 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.api.v2.IpamApi; +import io.netris.api.v2.VNetApi; import io.netris.api.v2.VpcApi; +import io.netris.model.AllocationBody; +import io.netris.model.AllocationBodyVpc; import io.netris.model.GetSiteBody; +import io.netris.model.InlineResponse2004; +import io.netris.model.IpTreeAllocationTenant; +import io.netris.model.IpTreeSubnetSites; import io.netris.model.SitesResponseOK; +import io.netris.model.SubnetBody; +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.VnetResAddBody; import io.netris.model.response.AuthResponse; import io.netris.model.response.TenantResponse; import io.netris.model.response.TenantsResponse; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.resource.NetrisResourceObjectUtils; +import org.apache.commons.collections.CollectionUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.math.BigDecimal; +import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; public class NetrisApiClientImpl implements NetrisApiClient { @@ -42,17 +71,52 @@ public class NetrisApiClientImpl implements NetrisApiClient { private static ApiClient apiClient; - public NetrisApiClientImpl(String endpointBaseUrl, String username, String password) { + private final int siteId; + private final String siteName; + private 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); + logger.error(msg, e); throw new CloudRuntimeException(msg); } @@ -103,4 +167,264 @@ public class NetrisApiClientImpl implements NetrisApiClient { } 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 InlineResponse2004 createVpcAllocationInternal(VPCResponseObjectOK createdVpc, String cidr, int adminTenantId, + String adminTenantName, String netrisIpamAllocationName) { + logger.debug(String.format("Creating Netris VPC Allocation %s for VPC %s", cidr, createdVpc.getData().getName())); + try { + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + AllocationBody body = new AllocationBody(); + AllocationBodyVpc allocationBodyVpc = new AllocationBodyVpc(); + allocationBodyVpc.setId(createdVpc.getData().getId()); + allocationBodyVpc.setName(createdVpc.getData().getName()); + body.setVpc(allocationBodyVpc); + body.setName(netrisIpamAllocationName); + body.setPrefix(cidr); + IpTreeAllocationTenant allocationTenant = new IpTreeAllocationTenant(); + allocationTenant.setId(new BigDecimal(adminTenantId)); + allocationTenant.setName(adminTenantName); + body.setTenant(allocationTenant); + return ipamApi.apiV2IpamAllocationPost(body); + } catch (ApiException e) { + logAndThrowException(String.format("Error creating Netris Allocation %s for VPC %s", cidr, createdVpc.getData().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(); + InlineResponse2004 ipamResponse = createVpcAllocationInternal(createdVpc, vpcCidr, tenantId, tenantName, netrisIpamAllocationName); + if (ipamResponse == null || !ipamResponse.isIsSuccess()) { + String reason = ipamResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris Allocation {} for VPC {} creation failed: {}", vpcCidr, cmd.getName(), reason); + return false; + } + logger.debug(String.format("Successfully created VPC %s and its IPAM Allocation %s on Netris", cmd.getName(), vpcCidr)); + return true; + } + + private void deleteVpcIpamAllocationInternal(VPCListing vpcResource, String vpcCidr) { + logger.debug(String.format("Deleting Netris VPC IPAM Allocation %s for VPC %s", vpcCidr, vpcResource.getName())); + try { + VpcApi vpcApi = apiClient.getApiStubForMethod(VpcApi.class); + VPCResponseResourceOK vpcResourcesResponse = vpcApi.apiV2VpcVpcIdResourcesGet(vpcResource.getId()); + VPCResourceIpam vpcAllocationResource = getVpcAllocationResource(vpcResourcesResponse); + 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", vpcCidr, vpcResource.getName()), e); + } + } + + private VPCResourceIpam getVpcAllocationResource(VPCResponseResourceOK vpcResourcesResponse) { + VPCResource resource = vpcResourcesResponse.getData().get(0); + List vpcAllocations = resource.getAllocation(); + if (CollectionUtils.isNotEmpty(vpcAllocations)) { + if (vpcAllocations.size() > 1) { + logger.warn("Unexpected VPC allocations size {}, one expected", vpcAllocations.size()); + } + return vpcAllocations.get(0); + } + 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.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 vpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC); + VPCListing vpcResource = getVpcByNameAndTenant(vpcName); + if (vpcResource == null) { + logger.error(String.format("Could not find the Netris VPC resource with name %s and tenant ID %s", vpcName, tenantId)); + return false; + } + String vpcCidr = cmd.getCidr(); + deleteVpcIpamAllocationInternal(vpcResource, vpcCidr); + 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(); + boolean isVpc = cmd.isVpc(); + + String suffix = String.format("%s-%s", vpcId, vpcName); + String netrisVpcName = NetrisResourceObjectUtils.retrieveNetrisResourceObjectName(cmd, NetrisResourceObjectUtils.NetrisObjectType.VPC, suffix); + VPCListing associatedVpc = getVpcByNameAndTenant(netrisVpcName); + if (associatedVpc == null) { + logger.error(String.format("Failed to find Netris VPC with name: %s, to create the corresponding vNet for network %s", vpcName, 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, vnetCidr) ; + + InlineResponse2004 subnetResponse = createVpcSubnetInternal(associatedVpc, vNetName, vnetCidr, netrisSubnetName); + if (subnetResponse == null || !subnetResponse.isIsSuccess()) { + String reason = subnetResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris Subnet {} for VPC {} for network {} creation failed: {}", vnetCidr, vpcName, networkName, reason); + return false; + } + logger.debug("Successfully created VPC {} and its IPAM Subnet {} on Netris", vpcName, vnetCidr); + + VnetResAddBody vnetResponse = createVnetInternal(associatedVpc, netrisVnetName, vnetCidr); + if (vnetResponse == null || !vnetResponse.isIsSuccess()) { + String reason = vnetResponse == null ? "Empty response" : "Operation failed on Netris"; + logger.debug("The Netris vNet creation {} for VPC {} failed: {}", vNetName, vpcName, reason); + return false; + } + return true; + } + + private InlineResponse2004 createVpcSubnetInternal(VPCListing associatedVpc, String vNetName, String vNetCidr, String netrisSubnetName) { + logger.debug("Creating Netris VPC Subnet {} for VPC {} for vNet {}", vNetCidr, associatedVpc.getName(), vNetName); + try { + + SubnetBody subnetBody = new SubnetBody(); + subnetBody.setName(netrisSubnetName); + + AllocationBodyVpc vpcAllocationBody = new AllocationBodyVpc(); + vpcAllocationBody.setName(associatedVpc.getName()); + vpcAllocationBody.setId(associatedVpc.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(SubnetBody.PurposeEnum.COMMON); + subnetBody.setPrefix(vNetCidr); + IpamApi ipamApi = apiClient.getApiStubForMethod(IpamApi.class); + return ipamApi.apiV2IpamSubnetPost(subnetBody); + } catch (ApiException e) { + logAndThrowException(String.format("Error creating Netris Subnet %s for VPC %s", vNetCidr, associatedVpc.getName()), e); + return null; + } + } + + VnetResAddBody createVnetInternal(VPCListing associatedVpc, String netrisVnetName, String vNetCidr) { + logger.debug("Creating Netris VPC vNet {} for CIDR {}", netrisVnetName, vNetCidr); + try { + VnetAddBody vnetBody = new VnetAddBody(); + + vnetBody.setCustomAnycastMac(""); + + VnetAddBodyGateways gateways = new VnetAddBodyGateways(); + gateways.prefix(vNetCidr); + gateways.setDhcpEnabled(false); + VnetAddBodyDhcp dhcp = new VnetAddBodyDhcp(); + dhcp.setEnd(""); + dhcp.setStart(""); + dhcp.setOptionSet(new VnetAddBodyDhcpOptionSet()); + gateways.setDhcp(dhcp); + List gatewaysList = new ArrayList<>(); + gatewaysList.add(gateways); + vnetBody.setGateways(gatewaysList); + + vnetBody.setGuestTenants(new ArrayList<>()); + vnetBody.setL3vpn(false); + vnetBody.setName(netrisVnetName); + vnetBody.setNativeVlan(0); + 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); + + 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; + } + } } 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..f15090dc3f4 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisElement.java @@ -0,0 +1,350 @@ +// 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.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.deploy.DeployDestination; +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.element.DhcpServiceProvider; +import com.cloud.network.element.DnsServiceProvider; +import com.cloud.network.element.VirtualRouterElement; +import com.cloud.network.element.VpcProvider; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.rules.LoadBalancerContainer; +import com.cloud.network.vpc.NetworkACLItem; +import com.cloud.network.vpc.PrivateGateway; +import com.cloud.network.vpc.StaticRouteProfile; +import com.cloud.network.vpc.Vpc; +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.utils.component.AdapterBase; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.StartupNetrisCommand; +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.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Component +public class NetrisElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, ResourceStateAdapter, + Listener, VpcProvider { + + @Inject + NetworkModel networkModel; + @Inject + AgentManager agentManager; + @Inject + ResourceManager resourceManager; + @Inject + private NetrisService netrisService; + + protected Logger logger = LogManager.getLogger(getClass()); + + private final Map> capabilities = initCapabilities(); + + private 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())); + + 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.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 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 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 { + 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 { + return true; + } + + @Override + public boolean applyACLItemsToPrivateGw(PrivateGateway gateway, List rules) throws ResourceUnavailableException { + return true; + } + + @Override + public boolean updateVpcSourceNatIp(Vpc vpc, IpAddress address) { + return true; + } +} 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..95056c95460 --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisGuestNetworkGuru.java @@ -0,0 +1,270 @@ +// 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.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.Networks; +import com.cloud.network.PhysicalNetwork; +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 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; + + 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)); + } + 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 Network implement(Network network, NetworkOffering offering, DeployDestination dest, + ReservationContext context) { + 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()); + } + implemented.setBroadcastUri(Networks.BroadcastDomainType.Netris.toUri("netris")); + return implemented; + } + + @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 + } + + 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; + 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 a Tier 1 Gateway for the network %s before creating the NSX segment", networkVO.getName())); + long networkOfferingId = networkVO.getNetworkOfferingId(); + NetworkOfferingVO networkOfferingVO = networkOfferingDao.findById(networkOfferingId); + 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()); + 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 index a7c60859791..7d5f4146ab1 100644 --- 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 @@ -18,8 +18,15 @@ 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 index 5ebb0673a9c..ef4cd265d8c 100644 --- 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 @@ -16,17 +16,184 @@ // under the License. package org.apache.cloudstack.service; +import com.amazonaws.util.CollectionUtils; +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.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 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 { + + @Inject + DataCenterDao dataCenterDao; + @Inject + ResourceManager resourceManager; + @Inject + NetrisProviderDao netrisProviderDao; + @Inject + HostDetailsDao hostDetailsDao; + @Inject + PhysicalNetworkDao physicalNetworkDao; + @Inject + NetworkDao networkDao; + @Override public NetrisProvider addProvider(AddNetrisProviderCmd cmd) { - return null; + final Long zoneId = cmd.getZoneId(); + final String name = cmd.getName(); + final String hostname = cmd.getHostname(); + final String port = cmd.getPort(); + final String username = cmd.getUsername(); + final String password = cmd.getPassword(); + final String tenantName = cmd.getTenantName(); + final String siteName = cmd.getSiteName(); + + Map params = new HashMap<>(); + params.put("guid", UUID.randomUUID().toString()); + params.put("zoneId", zoneId.toString()); + params.put("name", name); + params.put("hostname", hostname); + params.put("port", port); + params.put("username", username); + params.put("password", password); + params.put("siteName", siteName); + params.put("tenantName", tenantName); + + Map hostdetails = new HashMap<>(params); + NetrisProvider netrisProvider; + + NetrisResource netrisResource = new NetrisResource(); + try { + netrisResource.configure(hostname, 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) + .setPort(port) + .setHostname(hostname) + .setUsername(username) + .setPassword(password) + .setSiteName(siteName) + .setTenantName(tenantName) + .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."); + } + } 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.isNullOrEmpty(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.getHostname()); + response.setPort(provider.getPort()); + response.setZoneId(zone.getUuid()); + response.setZoneName(zone.getName()); + response.setSiteName(provider.getSiteName()); + response.setTenantName(provider.getTenantName()); + 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 @@ -34,6 +201,8 @@ public class NetrisProviderServiceImpl implements NetrisProviderService { 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..11db60a5aca --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisPublicNetworkGuru.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.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; + } + } + } + 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..66d972b043e --- /dev/null +++ b/plugins/network-elements/netris/src/main/java/org/apache/cloudstack/service/NetrisServiceImpl.java @@ -0,0 +1,97 @@ +// 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.exception.InvalidParameterValueException; +import com.cloud.network.dao.NetrisProviderDao; +import com.cloud.network.element.NetrisProviderVO; +import com.cloud.network.netris.NetrisService; +import com.cloud.network.vpc.Vpc; +import org.apache.cloudstack.agent.api.CreateNetrisVnetCommand; +import org.apache.cloudstack.agent.api.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +import org.apache.cloudstack.agent.api.NetrisAnswer; +import org.apache.cloudstack.agent.api.NetrisCommand; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import javax.inject.Inject; +import java.util.Objects; + +public class NetrisServiceImpl implements NetrisService, Configurable { + + protected Logger logger = LogManager.getLogger(getClass()); + + @Inject + private NetrisProviderDao netrisProviderDao; + @Inject + private AgentManager agentMgr; + + @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; + } + + @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 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) { + CreateNetrisVnetCommand cmd = new CreateNetrisVnetCommand(zoneId, accountId, domainId, vpcName, vpcId, networkName, networkId, cidr, !Objects.isNull(vpcId)); + NetrisAnswer answer = sendNetrisCommand(cmd, zoneId); + return answer.getResult(); + } +} 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/spring-netris-context.xml b/plugins/network-elements/netris/src/main/resources/META-INF/cloudstack/netris/spring-netris-context.xml index f0dfe703a2b..a0551b7804a 100644 --- 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 @@ -25,6 +25,17 @@ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> + + + + + + + + + + + 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..11b4af48fed --- /dev/null +++ b/plugins/network-elements/netris/src/test/java/org/apache/cloudstack/resource/NetrisResourceObjectUtilsTest.java @@ -0,0 +1,57 @@ +// 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.CreateNetrisVpcCommand; +import org.apache.cloudstack.agent.api.DeleteNetrisVpcCommand; +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 = 10; + 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 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); + } +} 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 index 760b25e53b7..d57fbae1c86 100644 --- 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 @@ -30,8 +30,10 @@ public class NetrisApiClientImplTest { private static final String endpointUrl = "https://shapeblue-ctl.netris.dev"; private static final String username = "netris"; private static final String password = "qHHa$CZ2oJv*@!7mwoSR"; + private static final String siteName = "Datacenter-1"; + private static final String adminTenantName = "Admin"; - private static final NetrisApiClientImpl client = new NetrisApiClientImpl(endpointUrl, username, password); + private static final NetrisApiClientImpl client = new NetrisApiClientImpl(endpointUrl, username, password, siteName, adminTenantName); @Test public void testNetrisAuthStatus() { 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/service/NsxGuestNetworkGuru.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxGuestNetworkGuru.java index 032967d4061..047ee5837ae 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 4df71056601..d7605a1a858 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/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 19bf0a33909..83e1a1d182c 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 69cd7930a69..c667cbd6dae 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -234,6 +234,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 29fc939f553..735d68c03ef 100644 --- a/pom.xml +++ b/pom.xml @@ -142,7 +142,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 810f0abd7e0..2f5c6d2832a 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -41,6 +41,7 @@ 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; @@ -997,8 +998,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) { @@ -1006,6 +1006,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 @@ -2414,8 +2423,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()); } 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 2b3be728bd3..079929d68ec 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; @@ -62,6 +65,8 @@ public class DataCenterJoinDaoImpl extends GenericDaoBase clusterArchs = ApiDBUtils.listZoneClustersArchs(dataCenter.getId()); zoneResponse.setMultiArch(CollectionUtils.isNotEmpty(clusterArchs) && clusterArchs.size() > 1); @@ -152,6 +154,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> 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"); @@ -4729,7 +4741,7 @@ 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; @@ -4856,7 +4868,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; @@ -4906,6 +4918,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) { String networkVlanId = null; boolean connectivityWithoutVlan = false; @@ -4938,11 +4951,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; } @@ -5039,7 +5052,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()); } @@ -5055,7 +5068,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; } @@ -5126,14 +5139,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 @@ -5174,6 +5189,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 { @@ -6829,9 +6853,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) { diff --git a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java index 19760e6d025..95006bd5388 100644 --- a/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java +++ b/server/src/main/java/com/cloud/deploy/DeploymentPlanningManagerImpl.java @@ -2046,7 +2046,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/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index 1276ec22067..b8533b472ec 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)); @@ -1623,7 +1624,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; diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java index 2ccd5fdd820..05be4ea6307 100644 --- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java @@ -2305,9 +2305,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)); @@ -2333,6 +2334,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(); @@ -4236,6 +4246,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; @@ -5646,6 +5663,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/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java index c46be9bf428..957c5b1287a 100644 --- a/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/GuestNetworkGuru.java @@ -22,6 +22,9 @@ 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; @@ -121,6 +124,12 @@ public abstract class GuestNetworkGuru extends AdapterBase implements NetworkGur Ipv6AddressManager ipv6AddressManager; @Inject DomainRouterDao domainRouterDao; + @Inject + public NetworkOfferingServiceMapDao networkOfferingServiceMapDao; + @Inject + public AccountDao accountDao; + @Inject + public DomainDao domainDao; Random _rand = new Random(System.currentTimeMillis()); 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/router/CommandSetupHelper.java b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java index 5c962a1cbff..83a3dbcfaa7 100644 --- a/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java +++ b/server/src/main/java/com/cloud/network/router/CommandSetupHelper.java @@ -866,7 +866,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())); } @@ -1215,7 +1219,8 @@ 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 isForNsx = _networkModel.isProviderForNetworkOffering(Provider.Nsx, networkOfferingVO.getId()); + setupCmd.setVrGuestGateway(isForNsx); 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/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index df4a2e76d52..de17c25a72d 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -48,7 +48,9 @@ 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.dao.NetrisProviderDao; import com.cloud.network.dao.NsxProviderDao; +import com.cloud.network.element.NetrisProviderVO; import com.cloud.network.element.NsxProviderVO; import com.cloud.resourcelimit.CheckedReservation; import com.google.common.collect.Sets; @@ -291,13 +293,15 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis @Inject private NsxProviderDao nsxProviderDao; @Inject + private NetrisProviderDao netrisProviderDao; + @Inject RoutedIpv4Manager routedIpv4Manager; 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; @@ -353,7 +357,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 @@ -373,7 +377,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); } @@ -394,7 +398,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 @@ -411,7 +415,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); } @@ -429,7 +433,7 @@ 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); } @@ -447,7 +451,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_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); } } @@ -660,7 +664,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<>(); @@ -686,9 +690,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 @@ -699,7 +703,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)) { @@ -1308,11 +1311,12 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu(), cmd.getCidrSize(), cmd.getAsNumber(), bgpPeerIds); 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)); @@ -1341,15 +1345,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) { @@ -1357,9 +1357,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().getCallingUserId(), zone, null, sourceNatIP); this.associateIPToVpc(ip.getId(), vpc.getId()); @@ -1368,8 +1371,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(); } @@ -1571,7 +1575,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis } } return vpcDao.findById(vpcId); - } else if (isVpcForNsx(vpcToUpdate)) { + } else if (isVpcForProvider(Provider.Nsx, vpcToUpdate)) { if (logger.isDebugEnabled()) { logger.debug("no restart needed."); } @@ -1590,7 +1594,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis if (! userIps.isEmpty()) { try { _ipAddrMgr.updateSourceNatIpAddress(requestedIp, userIps); - if (isVpcForNsx(vpc)) { + if (isVpcForProvider(Provider.Nsx, vpc) || isVpcForProvider(Provider.Netris, vpc)) { VpcProvider nsxElement = (VpcProvider) _ntwkModel.getElementImplementingProvider(Provider.Nsx.getName()); if (nsxElement == null) { return true; @@ -2053,7 +2057,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"); } @@ -2071,7 +2076,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() @@ -3196,7 +3203,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis logger.debug("Associating ip " + ipToAssoc + " to vpc " + 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 (CheckedReservation publicIpReservation = new CheckedReservation(owner, ResourceType.public_ip, 1l, reservationDao, _resourceLimitMgr)) { Transaction.execute(new TransactionCallbackNoReturn() { @Override @@ -3298,7 +3305,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); @@ -3309,7 +3316,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()) { @@ -3346,15 +3353,17 @@ 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) { + if (forNsx || forNetris) { ipToReturn = _ipAddrMgr.assignPublicIpAddress(dcId, podId, owner, Vlan.VlanType.VirtualNetwork, null, null, false, true); } else { ipToReturn = _ipAddrMgr.assignDedicateIpAddress(owner, null, vpc.getId(), dcId, true); @@ -3398,7 +3407,8 @@ 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)); } diff --git a/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java b/server/src/main/java/com/cloud/server/ConfigurationServerImpl.java index b4715974d2d..f21b84cdc02 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); @@ -1234,7 +1232,6 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio false, false, false, false, forVpc); defaultNatProviderNetworkOffering.setPublicLb(publicLB); defaultNatProviderNetworkOffering.setInternalLb(!publicLB); - defaultNatProviderNetworkOffering.setForNsx(Provider.Nsx.equals(provider)); defaultNatProviderNetworkOffering.setNetworkMode(networkMode); defaultNatProviderNetworkOffering.setState(NetworkOffering.State.Enabled); defaultNatProviderNetworkOffering = _networkOfferingDao.persistDefaultNetworkOffering(defaultNatProviderNetworkOffering); 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 817cfe07e58..016f52b8ade 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,14 +23,17 @@ 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.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; @@ -93,6 +96,7 @@ public class RouterDeploymentDefinition { protected NetworkDao networkDao; protected DomainRouterDao routerDao; protected NsxProviderDao nsxProviderDao; + protected NetrisProviderDao netrisProviderDao; protected PhysicalNetworkServiceProviderDao physicalProviderDao; protected NetworkModel networkModel; protected VirtualRouterProviderDao vrProviderDao; @@ -395,10 +399,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); @@ -406,6 +411,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 405575c65b1..5d5798f60e6 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; @@ -127,10 +126,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/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/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 8f05b716725..9b0822cf0b1 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -558,7 +558,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/dao/MockVpcOfferingServiceMapDaoImpl.java b/server/src/test/java/com/cloud/vpc/dao/MockVpcOfferingServiceMapDaoImpl.java index 5685c504ab2..3d45d8e839f 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,11 @@ public class MockVpcOfferingServiceMapDaoImpl extends GenericDaoBase + diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 49ce94e86fa..6894caf3702 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -98,6 +98,9 @@ known_categories = { 'listNsxControllers': 'NSX', 'addNsxController': 'NSX', 'deleteNsxController': 'NSX', + 'addNetrisProvider': 'Netris', + 'listNetrisProviders': 'Netris', + 'deleteNetrisProvider': 'Netris', 'Vpn': 'VPN', 'Limit': 'Resource Limit', 'Netscaler': 'Netscaler', diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 43e8407fe9c..9ac5d54f98e 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1491,6 +1491,8 @@ "label.netris.provider.port": "Netris provider port", "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.netscaler": "NetScaler", "label.netscaler.mpx": "NetScaler MPX LoadBalancer", "label.netscaler.sdx": "NetScaler SDX LoadBalancer", @@ -2077,6 +2079,7 @@ "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.size": "Size", @@ -2265,6 +2268,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", @@ -2745,6 +2749,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.", @@ -2832,6 +2837,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.nsx.public.traffic": "Configuring NSX public traffic", "message.configuring.storage.traffic": "Configuring storage traffic", "message.confirm.action.force.reconnect": "Please confirm that you want to force reconnect this host.", @@ -3221,6 +3227,8 @@ "message.installwizard.tooltip.netris.provider.hostname": "Netris Provider hostname / IP address 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.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", 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/views/infra/network/ServiceProvidersTab.vue b/ui/src/views/infra/network/ServiceProvidersTab.vue index 5eb8e3dbcce..16c965763c3 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'] + } + ] } ] } @@ -1168,7 +1212,6 @@ export default { this.fetchLoading = true api('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 41da48d993c..a4bc20e4dbe 100644 --- a/ui/src/views/infra/network/TrafficTypesTab.vue +++ b/ui/src/views/infra/network/TrafficTypesTab.vue @@ -21,7 +21,7 @@ traffic.type === 'public' || traffic.type === 'guest') > -1) { this.stepData.isNsxZone = true } - if (physicalNetwork.isolationMethod === 'NETRIS' && + if (physicalNetwork.isolationMethod.toLowerCase() === 'netris' && physicalNetwork.traffics.findIndex(traffic => traffic.type === 'public' || traffic.type === 'guest') > -1) { this.stepData.isNetrisZone = true } @@ -921,7 +920,7 @@ export default { let stopNow = false this.stepData.returnedPublicTraffic = this.stepData?.returnedPublicTraffic || [] let publicIpRanges = this.prefillContent['public-ipranges'] - publicIpRanges = publicIpRanges.filter(item => item.fornsx === (idx === 1)) + publicIpRanges = publicIpRanges.filter(item => (item.fornsx || item.fornetris) === (idx === 1)) for (let index = 0; index < publicIpRanges.length; index++) { const publicVlanIpRange = publicIpRanges[index] let isExisting = false @@ -944,16 +943,22 @@ export default { params.zoneId = this.stepData.zoneReturned.id if (publicVlanIpRange.vlan && publicVlanIpRange.vlan.length > 0) { params.vlan = publicVlanIpRange.vlan - } else if (publicVlanIpRange.fornsx) { // TODO: should this be the same for Netris? + } else if (publicVlanIpRange.fornsx || publicVlanIpRange.fornetris) { // TODO: should this be the same for Netris? params.vlan = null } else { params.vlan = 'untagged' } + let provider = null + if (publicVlanIpRange.fornsx) { + provider = 'Nsx' + } else if (publicVlanIpRange.fornetris) { + provider = 'Netris' + } params.gateway = publicVlanIpRange.gateway params.netmask = publicVlanIpRange.netmask params.startip = publicVlanIpRange.startIp params.endip = publicVlanIpRange.endIp - params.fornsx = publicVlanIpRange.fornsx + params.provider = provider params.forsystemvms = publicVlanIpRange.forsystemvms if (this.isBasicZone) { @@ -986,16 +991,20 @@ export default { if (stopNow) { return } - if (idx === 0) { - await this.stepConfigurePublicTraffic('message.configuring.nsx.public.traffic', 'nsxPublicTraffic', 1) + const isolationMethods = Object.values(this.stepData.physicalNetworkItem).map(network => network.isolationmethods.toLowerCase()) + if (isolationMethods.includes('nsx')) { + await this.stepConfigurePublicTraffic('message.configuring.nsx.public.traffic', 'nsxPublicTraffic', 1) + } else if (isolationMethods.includes('netris')) { + await this.stepConfigurePublicTraffic('message.configuring.netris.public.traffic', 'netrisPublicTraffic', 1) + } } else { if (this.stepData.isTungstenZone) { await this.stepCreateTungstenFabricPublicNetwork() } else if (this.stepData.isNsxZone) { await this.stepAddNsxController() } else if (this.stepData.isNetrisZone) { - await this.stepAddNetrisController() + await this.stepAddNetrisProvider() } else { await this.stepConfigureStorageTraffic() } @@ -1099,7 +1108,7 @@ export default { this.setStepStatus(STATUS_FAILED) } }, - async stepAddNetrisController () { + async stepAddNetrisProvider () { this.setStepStatus(STATUS_FINISH) this.currentStep++ this.addStep('message.add.netris.controller', 'netris') @@ -1111,14 +1120,16 @@ export default { if (!this.stepData.stepMove.includes('addNetrisProvider')) { const providerParams = {} providerParams.name = this.prefillContent?.netrisName || '' - providerParams.netrisproviderhostname = this.prefillContent?.netrisHostname || '' - providerParams.netrisproviderport = this.prefillContent?.netrisPort || '' + providerParams.hostname = this.prefillContent?.hostname || '' + providerParams.port = this.prefillContent?.netrisPort || '' providerParams.username = this.prefillContent?.username || '' providerParams.password = this.prefillContent?.password || '' providerParams.zoneid = this.stepData.zoneReturned.id + providerParams.sitename = this.prefillContent?.siteName || '' + providerParams.tenantname = this.prefillContent?.tenantName || '' await this.addNetrisProvider(providerParams) - this.stepData.stepMove.push('addNetrisController') + this.stepData.stepMove.push('addNetrisProvider') } this.stepData.stepMove.push('netris') await this.stepConfigureStorageTraffic() @@ -2285,7 +2296,7 @@ export default { }) }) }, - addNetrisPovider (args) { + addNetrisProvider (args) { return new Promise((resolve, reject) => { api('addNetrisProvider', {}, 'POST', args).then(json => { resolve() diff --git a/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue b/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue index 3bc84bab37f..863bb6a375c 100644 --- a/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue +++ b/ui/src/views/infra/zone/ZoneWizardNetworkSetupStep.vue @@ -129,7 +129,7 @@
{ @@ -635,7 +637,7 @@ export default { } } this.networkOfferings = filteredOfferings - if (this.isNsxEnabled) { + if (this.isNsxEnabled || ['netris', 'nsx'].includes(this.zoneExtNetProvider.toLowerCase())) { this.networkOfferings = this.networkOfferings.filter(offering => offering.networkmode === (this.isOfferingNatMode ? 'NATTED' : 'ROUTED')) } if (this.resource.asnumberid) { diff --git a/utils/src/test/java/com/cloud/utils/LogUtilsTest.java b/utils/src/test/java/com/cloud/utils/LogUtilsTest.java index 350c9e946cd..e369c0fcac6 100644 --- a/utils/src/test/java/com/cloud/utils/LogUtilsTest.java +++ b/utils/src/test/java/com/cloud/utils/LogUtilsTest.java @@ -24,7 +24,7 @@ public class LogUtilsTest { @Test public void logGsonWithoutExceptionTestLogCorrectlyPrimitives() { - String expected = "test primitives: int [1], double [1.11], float [1.2222], boolean [true], null [], char [\"c\"]."; + String expected = "test primitives: int [1], double [1.11], float [1.2222], boolean [true], null [null], char [\"c\"]."; String log = LogUtils.logGsonWithoutException("test primitives: int [%s], double [%s], float [%s], boolean [%s], null [%s], char [%s].", 1, 1.11d, 1.2222f, true, null, 'c'); assertEquals(expected, log);