add create/delete segment and UI integration

This commit is contained in:
Pearl Dsilva 2023-09-06 15:08:06 -04:00
parent 2cccd53944
commit 37d634406d
13 changed files with 422 additions and 24 deletions

View File

@ -430,6 +430,8 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
long getDataCenterId();
long getAccountId();
long getNetworkOfferingId();
@Override

View File

@ -369,6 +369,10 @@ public class NetworkVO implements Network {
return mode;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
@Override
public long getAccountId() {
return accountId;

View File

@ -0,0 +1,35 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.agent.api;
import com.cloud.network.dao.NetworkVO;
public class CreateNsxSegmentCommand extends CreateNsxTier1GatewayCommand {
private NetworkVO tierNetwork;
public CreateNsxSegmentCommand(String zoneName, Long zoneId, String accountName, Long accountId, String vpcName, NetworkVO tierNetwork) {
super(zoneName, zoneId, accountName, accountId, vpcName);
this.tierNetwork = tierNetwork;
}
public NetworkVO getTierNetwork() {
return tierNetwork;
}
public void setTierNetwork(NetworkVO tierNetwork) {
this.tierNetwork = tierNetwork;
}
}

View File

@ -0,0 +1,9 @@
package org.apache.cloudstack.agent.api;
import com.cloud.network.dao.NetworkVO;
public class DeleteNsxSegmentCommand extends CreateNsxSegmentCommand {
public DeleteNsxSegmentCommand(String accountName, NetworkVO network) {
super(null, network.getDataCenterId(), accountName, network.getAccountId(), null, network);
}
}

View File

@ -16,47 +16,60 @@
// under the License.
package org.apache.cloudstack.resource;
import static org.apache.cloudstack.utils.NsxApiClientUtils.PoolAllocation.ROUTING;
import static org.apache.cloudstack.utils.NsxApiClientUtils.HAMode.ACTIVE_STANDBY;
import static org.apache.cloudstack.utils.NsxApiClientUtils.createApiClient;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.Answer;
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.exception.InvalidParameterValueException;
import com.cloud.host.Host;
import com.cloud.resource.ServerResource;
import com.cloud.utils.exception.CloudRuntimeException;
import com.vmware.nsx.EdgeClusters;
import com.vmware.nsx.model.EdgeCluster;
import com.vmware.nsx_policy.infra.Segments;
import com.vmware.nsx_policy.infra.Tier1s;
import com.vmware.nsx_policy.infra.segments.ServiceSegments;
import com.vmware.nsx_policy.infra.tier_0s.LocaleServices;
import com.vmware.nsx_policy.model.ApiError;
import com.vmware.nsx_policy.model.ChildLocaleServices;
import com.vmware.nsx_policy.model.LocaleServicesListResult;
import com.vmware.nsx_policy.model.Segment;
import com.vmware.nsx_policy.model.SegmentSubnet;
import com.vmware.nsx_policy.model.ServiceSegmentListResult;
import com.vmware.nsx_policy.model.Tier1;
import com.vmware.vapi.bindings.Service;
import com.vmware.vapi.std.errors.Error;
import org.apache.cloudstack.NsxAnswer;
import org.apache.cloudstack.StartupNsxCommand;
import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand;
import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand;
import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand;
import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
import org.apache.cloudstack.service.NsxApi;
import org.apache.cloudstack.utils.NsxApiClientUtils;
import org.apache.log4j.Logger;
import javax.naming.ConfigurationException;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import static java.util.Objects.isNull;
import static org.apache.cloudstack.utils.NsxApiClientUtils.HAMode.ACTIVE_STANDBY;
import static org.apache.cloudstack.utils.NsxApiClientUtils.FailoverMode.PREEMPTIVE;
import static org.apache.cloudstack.utils.NsxApiClientUtils.PoolAllocation.ROUTING;
import static org.apache.cloudstack.utils.NsxApiClientUtils.createApiClient;
public class NsxResource implements ServerResource {
private static final Logger LOGGER = Logger.getLogger(NsxResource.class);
private static final String TIER_0_GATEWAY_PATH_PREFIX = "/infra/tier-0s/";
private static final String TIER_1_GATEWAY_PATH_PREFIX = "/infra/tier-1s/";
private static final String TIER_1_RESOURCE_TYPE = "Tier1";
// private static final String ROUTING = "ROUTING";
private static final String SEGMENT_RESOURCE_TYPE = "Segment";
private String name;
protected String hostname;
protected String username;
@ -98,7 +111,11 @@ public class NsxResource implements ServerResource {
return executeRequest((ReadyCommand) cmd);
} else if (cmd instanceof DeleteNsxTier1GatewayCommand) {
return executeRequest((DeleteNsxTier1GatewayCommand) cmd);
} else if (cmd instanceof CreateNsxTier1GatewayCommand) {
} else if (cmd instanceof DeleteNsxSegmentCommand) {
return executeRequest((DeleteNsxSegmentCommand) cmd);
} else if (cmd instanceof CreateNsxSegmentCommand) {
return executeRequest((CreateNsxSegmentCommand) cmd);
} else if (cmd instanceof CreateNsxTier1GatewayCommand) {
return executeRequest((CreateNsxTier1GatewayCommand) cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
@ -206,15 +223,13 @@ public class NsxResource implements ServerResource {
}
private Function<Class, Service> nsxService = svcClass -> { return nsxApi.getApiClient().createStub(svcClass); };
private Service getService(Class svcClass) {
return nsxApi.getApiClient().createStub(svcClass);
}
private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) {
String name = getTier1GatewayName(cmd);
Tier1 tier1 = getTier1Gateway(name);
if (tier1 != null) {
throw new InvalidParameterValueException(String.format("VPC network with name %s exists in NSX zone: %s and account %s", name, cmd.getZoneName(), cmd.getAccountName()));
}
List<com.vmware.nsx_policy.model.LocaleServices> localeServices = getTier0LocalServices(tier0Gateway);
String tier0GatewayPath = TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway;
@ -224,6 +239,7 @@ public class NsxResource implements ServerResource {
.setResourceType(TIER_1_RESOURCE_TYPE)
.setPoolAllocation(ROUTING.name())
.setHaMode(ACTIVE_STANDBY.name())
.setFailoverMode(PREEMPTIVE.name())
.setId(name)
.setDisplayName(name)
.setChildren(
@ -231,7 +247,7 @@ public class NsxResource implements ServerResource {
.setLocaleServices(
new com.vmware.nsx_policy.model.LocaleServices.Builder()
.setEdgeClusterPath(localeServices.get(0).getEdgeClusterPath())
.setId(localeServices.get(0).getId())
.setParentPath(TIER_1_GATEWAY_PATH_PREFIX + getTier1GatewayName(cmd))
.setResourceType("LocaleServices")
.build()
).build())).build();
@ -254,16 +270,69 @@ public class NsxResource implements ServerResource {
return new NsxAnswer(cmd, true, null);
}
private Answer executeRequest(CreateNsxSegmentCommand cmd) {
try {
String segmentName = getSegmentName(cmd);
Segments segmentService = (Segments) nsxService.apply(Segments.class);
SegmentSubnet subnet = new SegmentSubnet.Builder()
.setGatewayAddress(cmd.getTierNetwork().getGateway() + "/" + cmd.getTierNetwork().getCidr().split("/")[1]).build();
Segment segment = new Segment.Builder()
.setResourceType(SEGMENT_RESOURCE_TYPE)
.setId(segmentName)
.setDisplayName(segmentName)
.setConnectivityPath(isNull(cmd.getVpcName()) ? TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway
: TIER_1_GATEWAY_PATH_PREFIX + getTier1GatewayName(cmd))
.setAdminState(NsxApiClientUtils.AdminState.UP.name())
.setSubnets(List.of(subnet))
.build();
segmentService.patch(segmentName, segment);
} catch (Exception e) {
LOGGER.error(String.format("Failed to create network: %s", cmd.getTierNetwork().getName()));
return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage()));
}
return new NsxAnswer(cmd, true, null);
}
private NsxAnswer executeRequest(DeleteNsxSegmentCommand cmd) {
try {
String segmentName = getSegmentName(cmd);
Segments segmentService = (Segments) nsxService.apply(Segments.class);
segmentService.delete(segmentName);
} catch (Exception e) {
LOGGER.error(String.format("Failed to delete NSX segment: %s", getSegmentName(cmd)) );
return new NsxAnswer(cmd, new CloudRuntimeException(e.getMessage()));
}
return new NsxAnswer(cmd, true, null);
}
private List<com.vmware.nsx_policy.model.LocaleServices> getTier0LocalServices(String tier0Gateway) {
try {
LocaleServices tier0LocaleServices = (LocaleServices) nsxService.apply(LocaleServices.class);
LocaleServicesListResult result =tier0LocaleServices.list(tier0Gateway, null, false, null, null, null, null);
LocaleServicesListResult result = tier0LocaleServices.list(tier0Gateway, null, false, null, null, null, null);
return result.getResults();
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Failed to fetch locale services for tier gateway %s due to %s", tier0Gateway, e.getMessage()));
}
}
private EdgeCluster getEdgeClusterDetails(String edgeClusterName) {
try {
EdgeClusters edgeClusterService = (EdgeClusters) nsxService.apply(EdgeClusters.class);
return edgeClusterService.get(edgeClusterName);
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Failed to fetch details of edge cluster: %s, due to: %s", edgeClusterName, e.getMessage()));
}
}
private ServiceSegmentListResult listServiceSegments() {
try {
ServiceSegments serviceSegmentSvc = (ServiceSegments) nsxService.apply(ServiceSegments.class);
return serviceSegmentSvc.list(null, null, null, true, null);
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Failed to fetch service segment list due to %s", e.getMessage()));
}
}
private Tier1 getTier1Gateway(String tier1GatewayId) {
try {
Tier1s tier1service = (Tier1s) nsxService.apply(Tier1s.class);
@ -278,6 +347,10 @@ public class NsxResource implements ServerResource {
return cmd.getZoneName() + "-" + cmd.getAccountName() + "-" + cmd.getVpcName();
}
private String getSegmentName(CreateNsxSegmentCommand cmd) {
return cmd.getAccountName() + "-" + cmd.getTierNetwork().getName();
}
@Override
public boolean start() {
return true;

View File

@ -36,8 +36,11 @@ import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.network.Network;
import com.cloud.network.NetworkModel;
import com.cloud.network.Networks;
import com.cloud.network.PhysicalNetworkServiceProvider;
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.DhcpServiceProvider;
@ -84,11 +87,15 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
@Inject
DataCenterDao dataCenterDao;
@Inject
NetworkDao networkDao;
@Inject
AgentManager agentManager;
@Inject
ResourceManager resourceManager;
@Inject
PhysicalNetworkDao physicalNetworkDao;
@Inject
NetworkModel networkModel;
private static final Logger LOGGER = Logger.getLogger(NsxElement.class);
@ -97,12 +104,21 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
private static Map<Network.Service, Map<Network.Capability, String>> initCapabilities() {
Map<Network.Service, Map<Network.Capability, String>> capabilities = new HashMap<>();
Map<Network.Capability, String> dhcpCapabilities = Map.of(Network.Capability.DhcpAccrossMultipleSubnets, "true");
capabilities.put(Network.Service.Dhcp, dhcpCapabilities);
Map<Network.Capability, String> dnsCapabilities = new HashMap<>();
dnsCapabilities.put(Network.Capability.AllowDnsSuffixModification, "true");
capabilities.put(Network.Service.Dns, dnsCapabilities);
capabilities.put(Network.Service.Connectivity, null);
// capabilities.put(Network.Service.Connectivity, null);
capabilities.put(Network.Service.StaticNat, null);
Map<Network.Capability, String> sourceNatCapabilities = new HashMap<>();
sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true");
sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount");
capabilities.put(Network.Service.SourceNat, sourceNatCapabilities);
return capabilities;
}
@Override
@ -172,12 +188,14 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
@Override
public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException {
return false;
return canHandle(network, Network.Service.Connectivity);
}
@Override
public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
return false;
Account account = accountMgr.getAccount(network.getAccountId());
NetworkVO networkVO = networkDao.findById(network.getId());
return nsxService.deleteNetwork(account.getAccountName(), networkVO);
}
@Override
@ -192,7 +210,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
@Override
public boolean canEnableIndividualServices() {
return false;
return true;
}
@Override
@ -357,5 +375,17 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
return false;
}
protected boolean canHandle(Network network, Network.Service service) {
LOGGER.debug("Checking if Nsx Element can handle service " + service.getName() + " on network "
+ network.getDisplayText());
if (!networkModel.isProviderForNetwork(getProvider(), network.getId())) {
LOGGER.debug("Nsx Element is not a provider for network " + network.getDisplayText());
return false;
}
return true;
}
private final Function<Long, DataCenterVO> zoneFunction = zoneId -> { return dataCenterDao.findById(zoneId); };
}

View File

@ -16,24 +16,36 @@
// under the License.
package org.apache.cloudstack.service;
import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import com.cloud.dc.DataCenter;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.deploy.DeploymentPlan;
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.NetworkProfile;
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.vpc.VpcVO;
import com.cloud.offering.NetworkOffering;
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;
import com.cloud.vm.ReservationContext;
import com.cloud.vm.VirtualMachineProfile;
import org.apache.cloudstack.NsxAnswer;
import org.apache.cloudstack.agent.api.CreateNsxSegmentCommand;
import org.apache.log4j.Logger;
import javax.inject.Inject;
@ -43,6 +55,12 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr
@Inject
NetworkOfferingServiceMapDao networkOfferingServiceMapDao;
@Inject
NsxControllerUtils nsxControllerUtils;
@Inject
DataCenterDao zoneDao;
@Inject
AccountDao accountDao;
private static final Networks.TrafficType[] TrafficTypes = {Networks.TrafficType.Guest};
@ -56,12 +74,39 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr
PhysicalNetwork physicalNetwork) {
return networkType == DataCenter.NetworkType.Advanced && isMyTrafficType(offering.getTrafficType())
&& isMyIsolationMethod(physicalNetwork) && networkOfferingServiceMapDao.isProviderForNetworkOffering(
offering.getId(), Network.Provider.Tungsten);
offering.getId(), Network.Provider.Nsx);
}
@Override
public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) {
return null;
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, owner);
if (network == null) {
return null;
}
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.NSX);
network.setState(Network.State.Allocated);
return network;
}
@Override
@ -73,7 +118,38 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr
@Override
public Network implement(Network network, NetworkOffering offering, DeployDestination dest,
ReservationContext context) {
return null;
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.NSX.toUri("nsx"));
try {
long zoneId = network.getDataCenterId();
DataCenter zone = zoneDao.findById(zoneId);
if (isNull(zone)) {
throw new CloudRuntimeException(String.format("Failed to find zone with id: %s", zoneId));
}
createNsxSegment(implemented, zone);
} catch (Exception ex) {
throw new CloudRuntimeException("unable to create NSX network " + network.getUuid() + "due to: " + ex.getMessage());
}
return implemented;
}
@Override
@ -112,4 +188,25 @@ public class NsxGuestNetworkGuru extends GuestNetworkGuru implements NetworkMigr
public void commitMigration(NicProfile nic, Network network, VirtualMachineProfile vm, ReservationContext src, ReservationContext dst) {
}
private void createNsxSegment(NetworkVO networkVO, DataCenter zone) {
String vpcName = 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();
}
Account account = accountDao.findById(networkVO.getAccountId());
if (isNull(account)) {
throw new CloudRuntimeException(String.format("Unable to find account with id: %s", networkVO.getAccountId()));
}
CreateNsxSegmentCommand command = new CreateNsxSegmentCommand(zone.getName(), zone.getId(),
account.getAccountName(), networkVO.getAccountId(), vpcName, networkVO);
NsxAnswer answer = nsxControllerUtils.sendNsxCommand(command, zone.getId());
if (!answer.getResult()) {
throw new CloudRuntimeException("can not create NSX network");
}
}
}

View File

@ -16,8 +16,10 @@
// under the License.
package org.apache.cloudstack.service;
import com.cloud.network.dao.NetworkVO;
import org.apache.cloudstack.NsxAnswer;
import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand;
import org.apache.cloudstack.agent.api.DeleteNsxSegmentCommand;
import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
import javax.inject.Inject;
@ -38,4 +40,10 @@ public class NsxServiceImpl implements NsxService {
NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxTier1GatewayCommand, zoneId);
return result.getResult();
}
public boolean deleteNetwork(String accountName, NetworkVO network) {
DeleteNsxSegmentCommand deleteNsxSegmentCommand = new DeleteNsxSegmentCommand(accountName, network);
NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxSegmentCommand, network.getDataCenterId());
return result.getResult();
}
}

View File

@ -40,10 +40,25 @@ public class NsxApiClientUtils {
LB_XLARGE
}
public enum TYPE {
ROUTED,
NATTED
}
public enum HAMode {
ACTIVE_STANDBY,
ACTIVE_ACTIVE
}
public enum FailoverMode {
PREEMPTIVE,
NON_PREEMPTIVE
}
public enum AdminState {
UP,
DOWN
}
public static ApiClient createApiClient(String hostname, String port, String username, char[] password) {
String controllerUrl = String.format("https://%s:%s", hostname, port);
HttpConfiguration.SslConfiguration.Builder sslConfigBuilder = new HttpConfiguration.SslConfiguration.Builder();

View File

@ -1375,6 +1375,14 @@
"label.not.found": "Not found",
"label.not.suitable": "Not suitable",
"label.notifications": "Notifications",
"label.nsx.provider": "NSX Provider",
"label.nsx.provider.name": "NSX provider name",
"label.nsx.provider.hostname": "NSX provider hostname",
"label.nsx.provider.port": "NSX provider port",
"label.nsx.provider.username": "NSX provider username",
"label.nsx.provider.password": "NSX provider password",
"label.nsx.provider.edgecluster": "NSX provider edge cluster",
"label.nsx.provider.tier0gateway": "NSX provider tier-0 gateway",
"label.num.cpu.cores": "# of CPU cores",
"label.number": "#Rule",
"label.numretries": "Number of retries",
@ -2752,6 +2760,7 @@
"message.host.dedication.released": "Host dedication released.",
"message.info.cloudian.console": "Cloudian Management Console should open in another window.",
"message.installwizard.cloudstack.helptext.website": " * Project website:\t ",
"message.infra.setup.nsx.description": "This zone must contain an NSX provider because the isolation method is NSX",
"message.infra.setup.tungsten.description": "This zone must contain a Tungsten-Fabric provider because the isolation method is TF",
"message.installwizard.cloudstack.helptext.document": " * Documentation:\t ",
"message.installwizard.cloudstack.helptext.header": "\nYou can find more information about Apache CloudStack™ on the pages listed below.\n",

View File

@ -480,6 +480,11 @@ export default {
this.stepData.isTungstenZone = true
this.stepData.tungstenPhysicalNetworkId = physicalNetworkReturned.id
}
if (physicalNetwork.isolationMethod === 'NSX' &&
physicalNetwork.traffics.findIndex(traffic => traffic.type === 'public' || traffic.type === 'guest') > -1) {
this.stepData.isNsxZone = true
this.stepData.tungstenPhysicalNetworkId = physicalNetworkReturned.id
}
} else {
this.stepData.physicalNetworkReturned = this.stepData.physicalNetworkItem['createPhysicalNetwork' + index]
}
@ -965,6 +970,8 @@ export default {
if (this.stepData.isTungstenZone) {
await this.stepCreateTungstenFabricPublicNetwork()
} else if (this.stepData.isNsxZone) {
await this.stepAddNsxController()
} else {
await this.stepConfigureStorageTraffic()
}
@ -1035,6 +1042,28 @@ export default {
this.setStepStatus(STATUS_FAILED)
}
},
async stepAddNsxController () {
try {
if (!this.stepData.stepMove.includes('addNsxController')) {
const providerParams = {}
providerParams.name = this.prefillContent?.name || ''
providerParams.nsxproviderhostname = this.prefillContent?.nsxHostname || ''
providerParams.nsxproviderport = this.prefillContent?.nsxPort || ''
providerParams.username = this.prefillContent?.username || ''
providerParams.password = this.prefillContent?.password || ''
providerParams.zoneid = this.stepData.zoneReturned.id
providerParams.tier0gateway = this.prefillContent?.tier0Gateway || ''
providerParams.edgecluster = this.prefillContent?.edgeCluster || ''
await this.addNsxController(providerParams)
this.stepData.stepMove.push('addNsxController')
}
} catch (e) {
this.messageError = e
this.processStatus = STATUS_FAILED
this.setStepStatus(STATUS_FAILED)
}
},
async stepConfigureStorageTraffic () {
let targetNetwork = false
this.prefillContent.physicalNetworks.forEach(physicalNetwork => {
@ -2177,6 +2206,16 @@ export default {
})
})
},
addNsxController (args) {
return new Promise((resolve, reject) => {
api('addNsxController', {}, 'POST', args).then(json => {
resolve()
}).catch(error => {
const message = error.response.headers['x-description']
reject(message)
})
})
},
configTungstenFabricService (args) {
return new Promise((resolve, reject) => {
api('configTungstenFabricService', {}, 'POST', args).then(json => {

View File

@ -74,6 +74,18 @@
:isFixError="isFixError"
/>
<static-inputs-form
v-if="steps && steps[currentStep].formKey === 'nsx'"
@nextPressed="nextPressed"
@backPressed="handleBack"
@fieldsChanged="fieldsChanged"
@submitLaunchZone="submitLaunchZone"
:fields="nsxFields"
:prefillContent="prefillContent"
:description="nsxSetupDescription"
:isFixError="isFixError"
/>
<static-inputs-form
v-if="steps && steps[currentStep].formKey === 'pod'"
@nextPressed="nextPressed"
@ -189,6 +201,16 @@ export default {
}
return isTungsten
},
isNsxZone () {
let isNsx = false
if (!this.prefillContent.physicalNetworks) {
isNsx = false
} else {
const nsxIdx = this.prefillContent.physicalNetworks.findIndex(network => network.isolationMethod === 'NSX')
isNsx = nsxIdx > -1
}
return isNsx
},
allSteps () {
const steps = []
steps.push({
@ -201,6 +223,12 @@ export default {
formKey: 'tungsten'
})
}
if (this.isNsxZone) {
steps.push({
title: 'label.nsx.provider',
formKey: 'nsx'
})
}
if (this.havingNetscaler) {
steps.push({
title: 'label.netScaler',
@ -347,6 +375,53 @@ export default {
}
]
},
nsxFields () {
const fields = [
{
title: 'label.nsx.provider.name',
key: 'name',
placeHolder: 'message.installwizard.tooltip.nsx.provider.name',
required: true
},
{
title: 'label.nsx.provider.hostname',
key: 'nsxHostname',
placeHolder: 'message.installwizard.tooltip.nsx.provider.hostname',
required: true
},
{
title: 'label.nsx.provider.port',
key: 'nsxPort',
placeHolder: 'message.installwizard.tooltip.nsx.provider.port',
required: false
},
{
title: 'label.nsx.provider.username',
key: 'username',
placeHolder: 'message.installwizard.tooltip.nsx.provider.username',
required: true
},
{
title: 'label.nsx.provider.password',
key: 'password',
placeHolder: 'message.installwizard.tooltip.nsx.provider.password',
required: true
},
{
title: 'label.nsx.provider.edgecluster',
key: 'edgeCluster',
placeHolder: 'message.installwizard.tooltip.nsx.provider.edgecluster',
required: true
},
{
title: 'label.nsx.provider.tier0gateway',
key: 'tier0Gateway',
placeHolder: 'message.installwizard.tooltip.nsx.provider.tier0gateway',
required: true
}
]
return fields
},
guestTrafficFields () {
const fields = [
{
@ -416,6 +491,7 @@ export default {
},
podSetupDescription: 'message.add.pod.during.zone.creation',
tungstenSetupDescription: 'message.infra.setup.tungsten.description',
nsxSetupDescription: 'message.infra.setup.nsx.description',
netscalerSetupDescription: 'label.please.specify.netscaler.info',
storageTrafficDescription: 'label.zonewizard.traffictype.storage',
podFields: [
@ -459,6 +535,7 @@ export default {
created () {
this.physicalNetworks = this.prefillContent.physicalNetworks
this.steps = this.filteredSteps()
console.log(this.isNsxZone)
this.currentStep = this.prefillContent?.networkStep || 0
if (this.stepChild && this.stepChild !== '') {
this.currentStep = this.steps.findIndex(item => item.formKey === this.stepChild)

View File

@ -66,7 +66,7 @@
<a-select-option value="VSP"> VSP </a-select-option>
<a-select-option value="VCS"> VCS </a-select-option>
<a-select-option value="TF"> TF </a-select-option>
<a-select-option value="NSX"> NSX </a-select-option>
<a-select-option v-if="hypervisor === 'VMware'" value="NSX"> NSX </a-select-option>
<template #suffixIcon>
<a-tooltip