Add support to create and delete nsx tier-1 gateway

This commit is contained in:
Pearl Dsilva 2023-08-28 15:27:32 -04:00
parent 415e61a23f
commit 7575a4da82
10 changed files with 237 additions and 32 deletions

View File

@ -39,6 +39,9 @@ public class NsxProviderVO implements NsxProvider {
@Column(name = "zone_id")
private long zoneId;
@Column(name = "host_id")
private long hostId;
@Column(name = "uuid")
private String uuid;
@ -68,8 +71,9 @@ public class NsxProviderVO implements NsxProvider {
this.uuid = UUID.randomUUID().toString();
}
public NsxProviderVO( long zoneId,String providerName, String hostname, String username, String password, String tier0Gateway, String edgeCluster) {
public NsxProviderVO( long zoneId, long hostId, String providerName, String hostname, String username, String password, String tier0Gateway, String edgeCluster) {
this.zoneId = zoneId;
this.hostId = hostId;
this.uuid = UUID.randomUUID().toString();
this.providerName = providerName;
this.hostname = hostname;
@ -97,6 +101,14 @@ public class NsxProviderVO implements NsxProvider {
this.zoneId = zoneId;
}
public long getHostId() {
return hostId;
}
public void setHostId(long hostId) {
this.hostId = hostId;
}
@Override
public String getUuid() {
return uuid;

View File

@ -185,6 +185,7 @@ CREATE TABLE `cloud`.`nsx_providers` (
`id` bigint unsigned NOT NULL auto_increment COMMENT 'id',
`uuid` varchar(40),
`zone_id` bigint unsigned NOT NULL COMMENT 'Zone ID',
`host_id` bigint unsigned NOT NULL COMMENT 'Host ID',
`provider_name` varchar(40),
`hostname` varchar(255) NOT NULL,
`port` varchar(255),

View File

@ -0,0 +1,8 @@
package org.apache.cloudstack.agent.api;
public class DeleteNsxTier1GatewayCommand extends CreateNsxTier1GatewayCommand {
public DeleteNsxTier1GatewayCommand(String zoneName, Long zoneId, String accountName, Long accountId, String vpcName) {
super(zoneName, zoneId, accountName, accountId, vpcName);
}
}

View File

@ -34,7 +34,7 @@ public class NsxControllerResponse extends BaseResponse {
@SerializedName(ApiConstants.ZONE_ID)
@Param(description = "Zone ID to which the NSX controller is associated with")
private long zoneId;
private String zoneId;
@SerializedName(ApiConstants.ZONE_NAME)
@Param(description = "Zone name to which the NSX controller is associated with")
@ -76,11 +76,11 @@ public class NsxControllerResponse extends BaseResponse {
this.name = name;
}
public long getZoneId() {
public String getZoneId() {
return zoneId;
}
public void setZoneId(long zoneId) {
public void setZoneId(String zoneId) {
this.zoneId = zoneId;
}

View File

@ -27,25 +27,32 @@ import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.PingCommand;
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_policy.infra.Tier1s;
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.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.CreateNsxTier1GatewayCommand;
import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
import org.apache.cloudstack.service.NsxApi;
import org.apache.log4j.Logger;
import javax.naming.ConfigurationException;
import java.util.List;
import java.util.Map;
public class NsxResource implements ServerResource {
private static final Logger s_logger = Logger.getLogger(NsxResource.class);
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_RESOURCE_TYPE = "Tier1";
// private static final String ROUTING = "ROUTING";
@ -88,7 +95,9 @@ public class NsxResource implements ServerResource {
public Answer executeRequest(Command cmd) {
if (cmd instanceof ReadyCommand) {
return executeRequest((ReadyCommand) cmd);
} if (cmd instanceof CreateNsxTier1GatewayCommand) {
} else if (cmd instanceof DeleteNsxTier1GatewayCommand) {
return executeRequest((DeleteNsxTier1GatewayCommand) cmd);
} else if (cmd instanceof CreateNsxTier1GatewayCommand) {
return executeRequest((CreateNsxTier1GatewayCommand) cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
@ -176,6 +185,11 @@ public class NsxResource implements ServerResource {
throw new ConfigurationException("Unable to find zone");
}
tier0Gateway = (String) params.get("tier0Gateway");
if (tier0Gateway == null) {
throw new ConfigurationException("Missing NSX tier0 gateway");
}
edgeCluster = (String) params.get("edgeCluster");
if (edgeCluster == null) {
throw new ConfigurationException("Missing NSX edgeCluster");
@ -190,18 +204,35 @@ public class NsxResource implements ServerResource {
return new ReadyAnswer(cmd);
}
private Service getService(Class serviceClass) {
return nsxApi.getApiClient().createStub(serviceClass);
}
private Answer executeRequest(CreateNsxTier1GatewayCommand cmd) {
String tier0GatewayPath = TIER_0_GATEWAY_PATH_PREFIX + tier0Gateway;
String name = getVpcName(cmd);
Tier1s tier1service = nsxApi.getApiClient().createStub(Tier1s.class);
Tier1 tier1 = new Tier1.Builder()
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;
Tier1s tier1service = (Tier1s) getService(Tier1s.class);
tier1 = new Tier1.Builder()
.setTier0Path(tier0GatewayPath)
.setResourceType(TIER_1_RESOURCE_TYPE)
.setPoolAllocation(ROUTING.name())
.setHaMode(ACTIVE_STANDBY.name())
.setId(name)
.setDisplayName(name)
.build();
.setChildren(
List.of(new ChildLocaleServices.Builder("ChildLocaleServices")
.setLocaleServices(
new com.vmware.nsx_policy.model.LocaleServices.Builder()
.setEdgeClusterPath(localeServices.get(0).getEdgeClusterPath())
.setResourceType("LocaleServices")
.build()
).build())).build();
try {
tier1service.patch(name, tier1);
} catch (Error error) {
@ -211,6 +242,36 @@ public class NsxResource implements ServerResource {
return new NsxAnswer(cmd, true, "");
}
private Answer executeRequest(DeleteNsxTier1GatewayCommand cmd) {
try {
Tier1s tier1service = (Tier1s) getService(Tier1s.class);
tier1service.delete(cmd.getVpcName());
} catch (Exception e) {
return new Answer(cmd, new CloudRuntimeException(e.getMessage()));
}
return new Answer(cmd, true, null);
}
private List<com.vmware.nsx_policy.model.LocaleServices> getTier0LocalServices(String tier0Gateway) {
try {
LocaleServices tier0LocaleServices = (LocaleServices) getService(LocaleServices.class);
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 Tier1 getTier1Gateway(String tier1GatewayId) {
try {
Tier1s tier1service = (Tier1s) getService(Tier1s.class);
return tier1service.get(tier1GatewayId);
} catch (Exception e) {
LOGGER.debug(String.format("NSX Tier-1 gateway with name: %s not found", tier1GatewayId));
}
return null;
}
private String getVpcName(CreateNsxTier1GatewayCommand cmd) {
return cmd.getZoneName() + "-" + cmd.getAccountName() + "-" + cmd.getVpcName();
}

View File

@ -19,7 +19,6 @@ package org.apache.cloudstack.service;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.network.dao.NsxProviderDao;
import com.cloud.network.element.NsxProviderVO;
import org.apache.cloudstack.NsxAnswer;
@ -46,7 +45,8 @@ public class NsxControllerUtils {
throw new InvalidParameterValueException("Failed to find an NSX controller");
}
Answer answer = agentMgr.sendTo(zoneId, Hypervisor.HypervisorType.VMware, cmd);
//Answer answer = agentMgr.sendTo(zoneId, Hypervisor.HypervisorType.VMware, cmd);
Answer answer = agentMgr.easySend(nsxProviderVO.getHostId(), cmd);
if (answer == null || !answer.getResult()) {
s_logger.error("NSX API Command failed");

View File

@ -16,15 +16,24 @@
// under the License.
package org.apache.cloudstack.service;
import com.cloud.agent.AgentManager;
import com.cloud.agent.Listener;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.AgentControlAnswer;
import com.cloud.agent.api.AgentControlCommand;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ConnectionException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.network.Network;
import com.cloud.network.PhysicalNetworkServiceProvider;
import com.cloud.network.element.DhcpServiceProvider;
@ -35,6 +44,7 @@ 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;
@ -44,7 +54,7 @@ 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.network.router.deployment.RouterDeploymentDefinitionBuilder;
import org.apache.cloudstack.StartupNsxCommand;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -58,16 +68,19 @@ import java.util.Objects;
@Component
public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, VpcProvider,
ResourceStateAdapter {
ResourceStateAdapter, Listener {
@Inject
RouterDeploymentDefinitionBuilder routerDeploymentDefinitionBuilder;
@Inject
AccountManager accountMgr;
@Inject
NsxServiceImpl nsxService;
@Inject
DataCenterDao dataCenterDao;
@Inject
AgentManager agentManager;
@Inject
ResourceManager resourceManager;
private static final Logger LOGGER = Logger.getLogger(NsxElement.class);
private final Map<Network.Service, Map<Network.Capability, String>> capabilities = initCapabilities();
@ -160,7 +173,7 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
@Override
public boolean isReady(PhysicalNetworkServiceProvider provider) {
return false;
return true;
}
@Override
@ -180,6 +193,8 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
agentManager.registerForHostEvents(this, true, true, true);
resourceManager.registerResourceStateAdapter(this.getClass().getSimpleName(), this);
return false;
}
@ -200,7 +215,11 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
@Override
public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details, List<String> hostTags) {
return null;
if (!(startup[0] instanceof StartupNsxCommand)) {
return null;
}
host.setType(Host.Type.L2Networking);
return host;
}
@Override
@ -225,8 +244,19 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
}
@Override
public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
return false;
public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException {
DataCenterVO zone = dataCenterDao.findById(vpc.getZoneId());
if (Network.Provider.Nsx.getName().equalsIgnoreCase(zone.getDhcpProvider())) {
if (Objects.isNull(zone)) {
throw new InvalidParameterValueException(String.format("Failed to find zone with id %s", vpc.getZoneId()));
}
Account account = accountMgr.getAccount(vpc.getAccountId());
if (Objects.isNull(account)) {
throw new InvalidParameterValueException(String.format("Failed to find account with id %s", vpc.getAccountId()));
}
return nsxService.deleteVpcNetwork(vpc.getZoneId(), zone.getName(), account.getAccountId(), account.getName(), vpc.getName());
}
return true;
}
@Override
@ -248,4 +278,59 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS
public boolean applyACLItemsToPrivateGw(PrivateGateway gateway, List<? extends NetworkACLItem> rules) throws ResourceUnavailableException {
return false;
}
@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) {
}
@Override
public void processConnect(Host host, StartupCommand cmd, boolean forRebalance) throws ConnectionException {
}
@Override
public boolean processDisconnect(long agentId, Status state) {
return false;
}
@Override
public void processHostAboutToBeRemoved(long hostId) {
}
@Override
public void processHostRemoved(long hostId, long clusterId) {
}
@Override
public boolean isRecurring() {
return false;
}
@Override
public int getTimeout() {
return 0;
}
@Override
public boolean processTimeout(long agentId, long seq) {
return false;
}
}

View File

@ -20,6 +20,8 @@ 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;
@ -97,22 +99,22 @@ public class NsxProviderServiceImpl implements NsxProviderService {
NsxResource nsxResource = new NsxResource();
try {
nsxResource.configure(hostname, hostdetails);
//final Host host = resourceManager.addHost(zoneId, nsxResource, nsxResource.getType(), params);
//if (host != null) {
final Host host = resourceManager.addHost(zoneId, nsxResource, nsxResource.getType(), params);
if (host != null) {
nsxProvider = Transaction.execute((TransactionCallback<NsxProviderVO>) status -> {
NsxProviderVO nsxProviderVO = new NsxProviderVO(zoneId, name, hostname,
NsxProviderVO nsxProviderVO = new NsxProviderVO(zoneId, host.getId(), name, hostname,
username, password, tier0Gateway, edgeCluster);
nsxProviderDao.persist(nsxProviderVO);
// DetailVO detail = new DetailVO(host.getId(), "nsxcontrollerid",
// String.valueOf(nsxProviderVO.getId()));
// hostDetailsDao.persist(detail);
DetailVO detail = new DetailVO(host.getId(), "nsxcontrollerid",
String.valueOf(nsxProviderVO.getId()));
hostDetailsDao.persist(detail);
return nsxProviderVO;
});
// } else {
// throw new CloudRuntimeException("Failed to add NSX controller due to internal error.");
// }
} else {
throw new CloudRuntimeException("Failed to add NSX controller due to internal error.");
}
} catch (ConfigurationException e) {
throw new CloudRuntimeException(e.getMessage());
}
@ -130,7 +132,7 @@ public class NsxProviderServiceImpl implements NsxProviderService {
response.setUuid(nsxProvider.getUuid());
response.setHostname(nsxProvider.getHostname());
response.setPort(nsxProvider.getPort());
response.setZoneId(nsxProvider.getZoneId());
response.setZoneId(zone.getUuid());
response.setZoneName(zone.getName());
response.setTier0Gateway(nsxProvider.getTier0Gateway());
response.setTier0Gateway(nsxProvider.getEdgeCluster());

View File

@ -18,6 +18,7 @@ package org.apache.cloudstack.service;
import org.apache.cloudstack.NsxAnswer;
import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand;
import org.apache.cloudstack.agent.api.DeleteNsxTier1GatewayCommand;
import javax.inject.Inject;
@ -30,4 +31,11 @@ public class NsxServiceImpl implements NsxService {
NsxAnswer result = nsxControllerUtils.sendNsxCommand(createNsxTier1GatewayCommand, zoneId);
return result.getResult();
}
public boolean deleteVpcNetwork(Long zoneId, String zoneName, Long accountId, String accountName, String vpcName) {
DeleteNsxTier1GatewayCommand deleteNsxTier1GatewayCommand =
new DeleteNsxTier1GatewayCommand(zoneName, zoneId, accountName, accountId, vpcName);
NsxAnswer result = nsxControllerUtils.sendNsxCommand(deleteNsxTier1GatewayCommand, zoneId);
return result.getResult();
}
}

View File

@ -1060,6 +1060,34 @@ export default {
{
title: 'Nsx',
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.nsx.controller',