From 0b7491a9d2fe0885c49ed025cf66da39e917846d Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Thu, 24 Aug 2023 06:35:41 -0400 Subject: [PATCH] add NSX resource , api client, create tier1 gw --- .../java/com/cloud/network/NsxProvider.java | 2 + .../apache/cloudstack/api/ApiConstants.java | 2 +- .../cloud/network/element/NsxProviderVO.java | 12 ++ plugins/network-elements/nsx/pom.xml | 4 +- .../java/org/apache/cloudstack/NsxAnswer.java | 30 +++++ .../apache/cloudstack/StartupNsxCommand.java | 26 ++++ .../api/CreateNsxTier1GatewayCommand.java | 34 +++++ .../cloudstack/agent/api/NsxCommand.java | 69 ++++++++++ .../agent/api/StartupNsxCommand.java | 11 ++ .../api/command/AddNsxControllerCmd.java | 4 + .../api/response/NsxControllerResponse.java | 12 ++ .../cloudstack/resource/NsxResource.java | 123 ++++++++++++++++-- .../org/apache/cloudstack/service/NsxApi.java | 35 +++++ .../service/NsxControllerUtils.java | 42 ++++++ .../apache/cloudstack/service/NsxElement.java | 89 ++++++++++++- .../service/NsxProviderServiceImpl.java | 50 ++++--- .../cloudstack/service/NsxServiceImpl.java | 13 ++ .../cloudstack/utils/NsxApiClientUtils.java | 73 +++++++++++ .../cloudstack/nsx/spring-nsx-context.xml | 4 +- .../infra/network/ServiceProvidersTab.vue | 17 +++ 20 files changed, 618 insertions(+), 34 deletions(-) create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/StartupNsxCommand.java create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/StartupNsxCommand.java create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApi.java create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxControllerUtils.java create mode 100644 plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxApiClientUtils.java diff --git a/api/src/main/java/com/cloud/network/NsxProvider.java b/api/src/main/java/com/cloud/network/NsxProvider.java index 4a6a09c3eeb..136c8f013bb 100644 --- a/api/src/main/java/com/cloud/network/NsxProvider.java +++ b/api/src/main/java/com/cloud/network/NsxProvider.java @@ -21,6 +21,8 @@ import org.apache.cloudstack.api.InternalIdentity; public interface NsxProvider extends InternalIdentity, Identity { String getHostname(); + + String getPort(); String getProviderName(); String getUsername(); long getZoneId(); 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 7b78e02be24..80478a126de 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -812,7 +812,7 @@ public class ApiConstants { public static final String NSX_LOGICAL_SWITCH_PORT = "nsxlogicalswitchport"; public static final String NSX_PROVIDER_HOSTNAME = "nsxproviderhostname"; public static final String NSX_PROVIDER_PORT = "nsxproviderport"; - + public static final String NSX_CONTROLLER_ID = "nsxcontrollerid"; public static final String S3_ACCESS_KEY = "accesskey"; public static final String S3_SECRET_KEY = "secretkey"; public static final String S3_END_POINT = "endpoint"; diff --git a/engine/schema/src/main/java/com/cloud/network/element/NsxProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/NsxProviderVO.java index 3561ed4227f..96eaa0ad3f6 100644 --- a/engine/schema/src/main/java/com/cloud/network/element/NsxProviderVO.java +++ b/engine/schema/src/main/java/com/cloud/network/element/NsxProviderVO.java @@ -48,6 +48,9 @@ public class NsxProviderVO implements NsxProvider { @Column(name = "hostname") private String hostname; + @Column(name = "port") + private String port = "443"; + @Column(name = "username") private String username; @@ -117,6 +120,15 @@ public class NsxProviderVO implements NsxProvider { return hostname; } + public void setPort(String port) { + this.port = port; + } + + @Override + public String getPort() { + return port; + } + public void setHostname(String hostname) { this.hostname = hostname; } diff --git a/plugins/network-elements/nsx/pom.xml b/plugins/network-elements/nsx/pom.xml index cf2934d253f..6a89afc407a 100644 --- a/plugins/network-elements/nsx/pom.xml +++ b/plugins/network-elements/nsx/pom.xml @@ -53,8 +53,8 @@ com.vmware.vapi - vapi-authentication - 2.37.0 + vapi-runtime + 2.40.0 diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.java new file mode 100644 index 00000000000..310e69dff01 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/NsxAnswer.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; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.Command; + +public class NsxAnswer extends Answer { + public NsxAnswer(final Command command, final boolean success, final String details) { + super(command, success, details); + } + + public NsxAnswer(final Command command, final Exception e) { + super(command, e); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/StartupNsxCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/StartupNsxCommand.java new file mode 100644 index 00000000000..8a5ac35e57e --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/StartupNsxCommand.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 StartupNsxCommand extends StartupCommand { + public StartupNsxCommand() { + super(Host.Type.L2Networking); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java new file mode 100644 index 00000000000..eb29f624383 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/CreateNsxTier1GatewayCommand.java @@ -0,0 +1,34 @@ +// 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 CreateNsxTier1GatewayCommand extends NsxCommand { + private String vpcName; + + public CreateNsxTier1GatewayCommand(String zoneName, Long zoneId, String accountName, Long accountId, String vpcName) { + super(zoneName, zoneId, accountName, accountId); + this.vpcName = vpcName; + } + + public String getVpcName() { + return vpcName; + } + + public void setVpcName(String vpcName) { + this.vpcName = vpcName; + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java new file mode 100644 index 00000000000..ec34d611eba --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/NsxCommand.java @@ -0,0 +1,69 @@ +// 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 NsxCommand extends Command { + private String zoneName; + private Long zoneId; + private String accountName; + private Long accountId; + + public NsxCommand(String zoneName, Long zoneId, String accountName, Long accountId) { + this.zoneName = zoneName; + this.zoneId = zoneId; + this.accountName = accountName; + this.accountId = accountId; + } + + public String getZoneName() { + return zoneName; + } + + public void setZoneName(String zoneName) { + this.zoneName = zoneName; + } + + public Long getZoneId() { + return zoneId; + } + + public void setZoneId(Long zoneId) { + this.zoneId = zoneId; + } + + public String getAccountName() { + return accountName; + } + + public void setAccountName(String accountName) { + this.accountName = accountName; + } + + public Long getAccountId() { + return accountId; + } + + public void setAccountId(Long accountId) { + this.accountId = accountId; + } + @Override + public boolean executeInSequence() { + return false; + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/StartupNsxCommand.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/StartupNsxCommand.java new file mode 100644 index 00000000000..193b245c562 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/agent/api/StartupNsxCommand.java @@ -0,0 +1,11 @@ +package org.apache.cloudstack.agent.api; + +import com.cloud.agent.api.StartupCommand; +import com.cloud.host.Host; + +public class StartupNsxCommand extends StartupCommand { + + public StartupNsxCommand() { + super(Host.Type.L2Networking); + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/AddNsxControllerCmd.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/AddNsxControllerCmd.java index 8ff58bbd4c9..d7c695b864c 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/AddNsxControllerCmd.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/command/AddNsxControllerCmd.java @@ -83,6 +83,10 @@ public class AddNsxControllerCmd extends BaseCmd { return hostname; } + public String getPort() { + return port; + } + public String getUsername() { return username; } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/response/NsxControllerResponse.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/response/NsxControllerResponse.java index 1f3a923080d..e7cf8c1ea22 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/response/NsxControllerResponse.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/api/response/NsxControllerResponse.java @@ -41,6 +41,10 @@ public class NsxControllerResponse extends BaseResponse { @Param(description = "NSX controller hostname or IP address") private String hostname; + @SerializedName(ApiConstants.PORT) + @Param(description = "NSX controller port") + private String port; + // TODO: Should Password be returned? @SerializedName(ApiConstants.TIER0_GATEWAY) @@ -85,6 +89,14 @@ public class NsxControllerResponse extends BaseResponse { this.hostname = hostname; } + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + public String getTier0Gateway() { return tier0Gateway; } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java index ff5c0830a61..02c1e86b8a8 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/resource/NsxResource.java @@ -16,14 +16,28 @@ // 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.Answer; -import com.cloud.agent.api.Command; -import com.cloud.agent.api.PingCommand; 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.PingCommand; import com.cloud.host.Host; import com.cloud.resource.ServerResource; -import com.vmware.vapi.cis.authn.SecurityContextFactory; +import com.cloud.utils.exception.CloudRuntimeException; +import com.vmware.nsx_policy.infra.Tier1s; +import com.vmware.nsx_policy.model.ApiError; +import com.vmware.nsx_policy.model.Tier1; +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.service.NsxApi; import org.apache.log4j.Logger; @@ -32,13 +46,20 @@ import java.util.Map; public class NsxResource implements ServerResource { private static final Logger s_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"; private String name; protected String hostname; protected String username; protected String password; protected String guid; + protected String port; protected String tier0Gateway; protected String edgeCluster; + protected String zoneId; + + protected NsxApi nsxApi; @Override public Host.Type getType() { @@ -47,7 +68,15 @@ public class NsxResource implements ServerResource { @Override public StartupCommand[] initialize() { - return new StartupCommand[0]; + StartupNsxCommand sc = new StartupNsxCommand(); + sc.setGuid(guid); + sc.setName(name); + sc.setDataCenter(zoneId); + sc.setPod(""); + sc.setPrivateIpAddress(""); + sc.setStorageIpAddress(""); + sc.setVersion(""); + return new StartupCommand[] {sc}; } @Override @@ -57,7 +86,13 @@ public class NsxResource implements ServerResource { @Override public Answer executeRequest(Command cmd) { - return null; + if (cmd instanceof ReadyCommand) { + return executeRequest((ReadyCommand) cmd); + } if (cmd instanceof CreateNsxTier1GatewayCommand) { + return executeRequest((CreateNsxTier1GatewayCommand) cmd); + } else { + return Answer.createUnsupportedCommandAnswer(cmd); + } } @Override @@ -72,12 +107,11 @@ public class NsxResource implements ServerResource { @Override public void setAgentControl(IAgentControl agentControl) { - } @Override public String getName() { - return null; + return name; } @Override @@ -107,7 +141,78 @@ public class NsxResource implements ServerResource { @Override public boolean configure(String name, Map params) throws ConfigurationException { - return false; + hostname = (String) params.get("hostname"); + if (hostname == null) { + throw new ConfigurationException("Missing NSX hostname from params: " + params); + } + + port = (String) params.get("port"); + if (port == null) { + throw new ConfigurationException("Missing NSX port from params: " + params); + } + + username = (String) params.get("username"); + if (username == null) { + throw new ConfigurationException("Missing NSX username from params: " + params); + } + + password = (String) params.get("password"); + if (password == null) { + throw new ConfigurationException("Missing NSX 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"); + } + + edgeCluster = (String) params.get("edgeCluster"); + if (edgeCluster == null) { + throw new ConfigurationException("Missing NSX edgeCluster"); + } + + nsxApi = new NsxApi(); + nsxApi.setApiClient(createApiClient(hostname, port, username, password.toCharArray())); + return true; + } + + private Answer executeRequest(ReadyCommand cmd) { + return new ReadyAnswer(cmd); + } + + 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() + .setTier0Path(tier0GatewayPath) + .setResourceType(TIER_1_RESOURCE_TYPE) + .setPoolAllocation(ROUTING.name()) + .setHaMode(ACTIVE_STANDBY.name()) + .setId(name) + .setDisplayName(name) + .build(); + try { + tier1service.patch(name, tier1); + } catch (Error error) { + ApiError ae = error.getData()._convertTo(ApiError.class); + return new NsxAnswer(cmd, new CloudRuntimeException(ae.getErrorMessage())); + } + return new NsxAnswer(cmd, true, ""); + } + + private String getVpcName(CreateNsxTier1GatewayCommand cmd) { + return cmd.getZoneName() + "-" + cmd.getAccountName() + "-" + cmd.getVpcName(); } @Override diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApi.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApi.java new file mode 100644 index 00000000000..fe6bca3ceb0 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxApi.java @@ -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.service; + +import com.vmware.vapi.client.ApiClient; +import org.apache.log4j.Logger; + +public class NsxApi { + + private static final Logger S_LOGGER = Logger.getLogger(NsxApi.class); + + ApiClient apiClient; + + public ApiClient getApiClient() { + return apiClient; + } + + public void setApiClient(ApiClient apiClient) { + this.apiClient = apiClient; + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxControllerUtils.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxControllerUtils.java new file mode 100644 index 00000000000..8312835a9fd --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxControllerUtils.java @@ -0,0 +1,42 @@ +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; +import org.apache.cloudstack.agent.api.NsxCommand; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; + +@Component +public class NsxControllerUtils { + private static final Logger s_logger = Logger.getLogger(NsxControllerUtils.class); + + @Inject + AgentManager agentMgr; + @Inject + NsxProviderDao nsxProviderDao; + + public NsxAnswer sendNsxCommand(NsxCommand cmd, long zoneId) throws IllegalArgumentException { + + NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId); + if (nsxProviderVO == null) { + s_logger.error("No NSX controller was found!"); + throw new InvalidParameterValueException("Failed to find an NSX controller"); + } + + Answer answer = agentMgr.sendTo(zoneId, Hypervisor.HypervisorType.VMware, cmd); + + if (answer == null || !answer.getResult()) { + s_logger.error("NSX API Command failed"); + throw new InvalidParameterValueException("Failed API call to NSX controller"); + } + + return (NsxAnswer) answer; + } +} diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java index fc7d090ffd0..13942ae7618 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxElement.java @@ -16,29 +16,58 @@ // under the License. package org.apache.cloudstack.service; +import com.cloud.agent.api.StartupCommand; +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.host.HostVO; import com.cloud.network.Network; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.network.element.DhcpServiceProvider; import com.cloud.network.element.DnsServiceProvider; +import com.cloud.network.element.VpcProvider; +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.ResourceStateAdapter; +import com.cloud.resource.ServerResource; +import com.cloud.resource.UnableDeleteHostException; +import com.cloud.user.Account; +import com.cloud.user.AccountManager; 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.log4j.Logger; import org.springframework.stereotype.Component; +import javax.inject.Inject; import javax.naming.ConfigurationException; -import java.util.HashMap; import java.util.Map; +import java.util.HashMap; +import java.util.List; import java.util.Set; +import java.util.Objects; @Component -public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider { +public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsServiceProvider, VpcProvider, + ResourceStateAdapter { + + @Inject + RouterDeploymentDefinitionBuilder routerDeploymentDefinitionBuilder; + @Inject + AccountManager accountMgr; + @Inject + NsxServiceImpl nsxService; + @Inject + DataCenterDao dataCenterDao; private static final Logger LOGGER = Logger.getLogger(NsxElement.class); private final Map> capabilities = initCapabilities(); @@ -163,4 +192,60 @@ public class NsxElement extends AdapterBase implements DhcpServiceProvider, DnsS public boolean stop() { return false; } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { + return null; + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map details, List hostTags) { + return null; + } + + @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 { + 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.createVpcNetwork(vpc.getZoneId(), zone.getName(), account.getAccountId(), account.getName(), vpc.getName()); + } + return true; + } + + @Override + public boolean shutdownVpc(Vpc vpc, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean createPrivateGateway(PrivateGateway gateway) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean deletePrivateGateway(PrivateGateway privateGateway) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean applyStaticRoutes(Vpc vpc, List routes) throws ResourceUnavailableException { + return false; + } + + @Override + public boolean applyACLItemsToPrivateGw(PrivateGateway gateway, List rules) throws ResourceUnavailableException { + return false; + } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java index c0c658548f2..a99846efac3 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxProviderServiceImpl.java @@ -20,8 +20,6 @@ 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; @@ -41,10 +39,19 @@ import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.command.AddNsxControllerCmd; import org.apache.cloudstack.api.response.NsxControllerResponse; import org.apache.cloudstack.resource.NsxResource; +import org.apache.commons.lang3.StringUtils; import javax.inject.Inject; import javax.naming.ConfigurationException; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + + + public class NsxProviderServiceImpl implements NsxProviderService { @@ -63,19 +70,21 @@ public class NsxProviderServiceImpl implements NsxProviderService { @Override public NsxProvider addProvider(AddNsxControllerCmd cmd) { - Long zoneId = cmd.getZoneId(); - String name = cmd.getName(); - String hostname = cmd.getHostname(); - String username = cmd.getUsername(); - String password = cmd.getPassword(); - String tier0Gateway = cmd.getTier0Gateway(); - String edgeCluster = cmd.getEdgeCluster(); + final Long zoneId = cmd.getZoneId(); + final String name = cmd.getName(); + final String hostname = cmd.getHostname(); + final String port = cmd.getPort() == null || cmd.getPort().equals(StringUtils.EMPTY) ? "443" : cmd.getPort(); + final String username = cmd.getUsername(); + final String password = cmd.getPassword(); + final String tier0Gateway = cmd.getTier0Gateway(); + final String edgeCluster = cmd.getEdgeCluster(); 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("tier0Gateway", tier0Gateway); @@ -87,22 +96,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) status -> { NsxProviderVO nsxProviderVO = new NsxProviderVO(zoneId, 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()); } @@ -118,6 +127,7 @@ public class NsxProviderServiceImpl implements NsxProviderService { NsxControllerResponse response = new NsxControllerResponse(); response.setName(nsxProvider.getProviderName()); response.setHostname(nsxProvider.getHostname()); + response.setPort(nsxProvider.getPort()); response.setZoneId(nsxProvider.getZoneId()); response.setZoneName(zone.getName()); response.setTier0Gateway(nsxProvider.getTier0Gateway()); @@ -130,7 +140,9 @@ public class NsxProviderServiceImpl implements NsxProviderService { List nsxControllersResponseList = new ArrayList<>(); if (zoneId != null) { NsxProviderVO nsxProviderVO = nsxProviderDao.findByZoneId(zoneId); - nsxControllersResponseList.add(createNsxControllerResponse(nsxProviderVO)); + if (Objects.nonNull(nsxProviderVO)) { + nsxControllersResponseList.add(createNsxControllerResponse(nsxProviderVO)); + } } else { List nsxProviderVOList = nsxProviderDao.listAll(); for (NsxProviderVO nsxProviderVO : nsxProviderVOList) { diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java index 57803cc5b60..95e4dbbe917 100644 --- a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/service/NsxServiceImpl.java @@ -16,5 +16,18 @@ // under the License. package org.apache.cloudstack.service; +import org.apache.cloudstack.NsxAnswer; +import org.apache.cloudstack.agent.api.CreateNsxTier1GatewayCommand; + +import javax.inject.Inject; + public class NsxServiceImpl implements NsxService { + @Inject + private NsxControllerUtils nsxControllerUtils; + public boolean createVpcNetwork(Long zoneId, String zoneName, Long accountId, String accountName, String vpcName) { + CreateNsxTier1GatewayCommand createNsxTier1GatewayCommand = + new CreateNsxTier1GatewayCommand(zoneName, zoneId, accountName, accountId, vpcName); + NsxAnswer result = nsxControllerUtils.sendNsxCommand(createNsxTier1GatewayCommand, zoneId); + return result.getResult(); + } } diff --git a/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxApiClientUtils.java b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxApiClientUtils.java new file mode 100644 index 00000000000..c34eb385793 --- /dev/null +++ b/plugins/network-elements/nsx/src/main/java/org/apache/cloudstack/utils/NsxApiClientUtils.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.utils; + +import com.vmware.vapi.bindings.StubConfiguration; +import com.vmware.vapi.cis.authn.SecurityContextFactory; +import com.vmware.vapi.client.ApiClient; +import com.vmware.vapi.client.ApiClients; +import com.vmware.vapi.client.Configuration; +import com.vmware.vapi.core.ExecutionContext.SecurityContext; +import com.vmware.vapi.internal.protocol.RestProtocol; +import com.vmware.vapi.internal.protocol.client.rest.authn.BasicAuthenticationAppender; +import com.vmware.vapi.protocol.HttpConfiguration; +import org.apache.log4j.Logger; + +public class NsxApiClientUtils { + private static final Logger S_LOGGER = Logger.getLogger(NsxApiClientUtils.class); + public static ApiClient apiClient = null; + public static final int RESPONSE_TIMEOUT_SECONDS = 60; + + public enum PoolAllocation { + ROUTING, + LB_SMALL, + LB_MEDIUM, + LB_LARGE, + LB_XLARGE + } + + public enum HAMode { + ACTIVE_STANDBY, + ACTIVE_ACTIVE + } + 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(); + sslConfigBuilder + .disableCertificateValidation() + .disableHostnameVerification(); + HttpConfiguration.SslConfiguration sslConfig = sslConfigBuilder.getConfig(); + + HttpConfiguration httpConfig = new HttpConfiguration.Builder() + .setSoTimeout(RESPONSE_TIMEOUT_SECONDS * 1000) + .setSslConfiguration(sslConfig).getConfig(); + + StubConfiguration stubConfig = new StubConfiguration(); + SecurityContext securityContext = SecurityContextFactory + .createUserPassSecurityContext(username, password); + stubConfig.setSecurityContext(securityContext); + + Configuration.Builder configBuilder = new Configuration.Builder() + .register(Configuration.HTTP_CONFIG_CFG, httpConfig) + .register(Configuration.STUB_CONFIG_CFG, stubConfig) + .register(RestProtocol.REST_REQUEST_AUTHENTICATOR_CFG, new BasicAuthenticationAppender()); + Configuration config = configBuilder.build(); + apiClient = ApiClients.newRestClient(controllerUrl, config); + + return apiClient; + } +} diff --git a/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml index 8ebd1ce6d13..4e45b5fab99 100644 --- a/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml +++ b/plugins/network-elements/nsx/src/main/resources/META-INF/cloudstack/nsx/spring-nsx-context.xml @@ -28,9 +28,11 @@ - + + + diff --git a/ui/src/views/infra/network/ServiceProvidersTab.vue b/ui/src/views/infra/network/ServiceProvidersTab.vue index 4985389ba60..e61acf7b70a 100644 --- a/ui/src/views/infra/network/ServiceProvidersTab.vue +++ b/ui/src/views/infra/network/ServiceProvidersTab.vue @@ -1056,6 +1056,22 @@ export default { columns: ['name', 'tungstenproviderhostname', 'tungstenproviderport', 'tungstengateway', 'tungstenprovidervrouterport', 'tungstenproviderintrospectport'] } ] + }, + { + title: 'Nsx', + details: ['name', 'state', 'id', 'physicalnetworkid', 'servicelist'], + lists: [ + { + title: 'label.nsx.controller', + api: 'listNsxControllers', + mapping: { + zoneid: { + value: (record) => { return record.zoneid } + } + }, + columns: ['name', 'hostname', 'port', 'tier0gateway', 'edgecluster'] + } + ] } ] } @@ -1096,6 +1112,7 @@ 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