From 28568e694bbd1bafcfb37ca2d74179dead3ab901 Mon Sep 17 00:00:00 2001 From: Vijayendra Bhamidipati Date: Fri, 27 Apr 2012 16:06:51 -0700 Subject: [PATCH] Bug CS-9919: Support for Nexus Swiches (Cisco Vswitches) Description: This is work in progress. This set of changes will not compile. Checking in for team wide code sync up. Changes are underway to test if VMWareResource can be leveraged to talk to the VSM, instead of creating a new resource for the VSM, like we've been doing up until now. --- .../cloud/network/resource/CiscoNexusVSM.java | 115 ++++++++++++ .../resource/CiscoNexusVSMResource.java | 173 ------------------ .../api/commands/AddCiscoNexusVSMCmd.java | 11 +- .../CiscoNexusVSMDeviceManagerImpl.java | 50 ++++- .../network/element/CiscoNexusVSMElement.java | 5 +- 5 files changed, 169 insertions(+), 185 deletions(-) create mode 100644 core/src/com/cloud/network/resource/CiscoNexusVSM.java delete mode 100644 core/src/com/cloud/network/resource/CiscoNexusVSMResource.java diff --git a/core/src/com/cloud/network/resource/CiscoNexusVSM.java b/core/src/com/cloud/network/resource/CiscoNexusVSM.java new file mode 100644 index 00000000000..51d4a377f34 --- /dev/null +++ b/core/src/com/cloud/network/resource/CiscoNexusVSM.java @@ -0,0 +1,115 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by 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.resource; + +import java.util.Map; +import javax.naming.ConfigurationException; +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.StartupExternalLoadBalancerCommand; +import com.cloud.api.ApiConstants; +import com.cloud.host.Host; +import com.cloud.host.Host.Type; +import com.cloud.resource.ServerResource; +import com.cloud.serializer.GsonHelper; +import com.cloud.utils.NumbersUtil; +import com.google.gson.Gson; + +import com.cloud.utils.ssh.*; +import com.cloud.utils.cisco.n1kv.vsm.CiscoNexusVSMService; +import com.cloud.utils.exception.CloudRuntimeException; + +import org.apache.log4j.Logger; + +class VSMError { + static final int VSM_RESOURCE_EXISTS = 89901; + static final int VSM_RESOURCE_NOT_EXISTS= 89902; + static final int VSM_NO_SERIVCE = 89903; + static final int VSM_OPERATION_NOT_PERMITTED = 89904; +} + +public class CiscoNexusVSM { + + // deployment configuration + private String vsmIpaddr; + private String vsmUsername; + private String vsmPassword; + private String vsmSubsystem; + com.trilead.ssh2.Connection sshConnection; + private String _helloClientCmd = "urn:ietf:params:xml:ns:netconf:base:1.0]]>]]>"; + private String _clientCmd1 = "]]>]]>"; + + private static final Logger s_logger = Logger.getLogger(CiscoNexusVSM.class); + + // interface to interact with Cisco Nexus VSM devices + CiscoNexusVSMService _vsmService; + + Long _timeout = new Long(100000); + //base_response apiCallResult; + + // We need to store the result of the XML-RPC command sent to + // the VSM. For now it's a string. We should make this the appropriate XSD object. + String xml_rpc_response; + + public void setVsmIpaddr(String ipaddr) { + this.vsmIpaddr = ipaddr; + } + + public void setVsmUsername(String username) { + this.vsmUsername = username; + } + + public void setVsmPassword(String password) { + this.vsmPassword = password; + } + + public void setVsmSubsystem(String subsystem) { + this.vsmSubsystem = subsystem; + } + + public CiscoNexusVSM() { + this.vsmSubsystem = "xmlagent"; + } + + public String getVsmIpaddr() { + return vsmIpaddr; + } + + public String getvsmUsername() { + return vsmUsername; + } + + public String getvsmPassword() { + return vsmPassword; + } + + public String getvsmSubsystem() { + return vsmSubsystem; + } + + public CiscoNexusVSM(String username, String ipaddr, String password) { + + } + + public boolean connectToVSM() { + sshConnection = SSHCmdHelper.acquireAuthorizedConnection(this.vsmIpaddr, this.vsmUsername, this.vsmPassword); + if (sshConnection == null) { + return false; + } + return true; + } + +} \ No newline at end of file diff --git a/core/src/com/cloud/network/resource/CiscoNexusVSMResource.java b/core/src/com/cloud/network/resource/CiscoNexusVSMResource.java deleted file mode 100644 index 09111d059b1..00000000000 --- a/core/src/com/cloud/network/resource/CiscoNexusVSMResource.java +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright 2012 Citrix Systems, Inc. Licensed under the -// Apache License, Version 2.0 (the "License"); you may not use this -// file except in compliance with the License. Citrix Systems, Inc. -// reserves all rights not expressly granted by 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.resource; - -import java.util.Map; -import javax.naming.ConfigurationException; -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.StartupExternalLoadBalancerCommand; -import com.cloud.api.ApiConstants; -import com.cloud.host.Host; -import com.cloud.host.Host.Type; -import com.cloud.resource.ServerResource; -import com.cloud.serializer.GsonHelper; -import com.cloud.utils.NumbersUtil; -import com.google.gson.Gson; - -import com.cloud.utils.cisco.n1kv.vsm.CiscoNexusVSMService; - -import org.apache.log4j.Logger; - -class VSMError { - static final int VSM_RESOURCE_EXISTS = 89901; - static final int VSM_RESOURCE_NOT_EXISTS= 89902; - static final int VSM_NO_SERIVCE = 89903; - static final int VSM_OPERATION_NOT_PERMITTED = 89904; -} - -public class CiscoNexusVSMResource implements ServerResource { - - // deployment configuration - private String _name; - //private String _zoneId; - private String _ip; - private String _username; - private String _password; - private Integer _numRetries; - private static final Logger s_logger = Logger.getLogger(CiscoNexusVSMResource.class); - protected Gson _gson; - - // interface to interact with Cisco Nexus VSM devices - CiscoNexusVSMService _vsmService; - - Long _timeout = new Long(100000); - //base_response apiCallResult; - - // We need to store the result of the XML-RPC command sent to - // the VSM. For now it's a string. We should make this the appropriate XSD object. - String xml_rpc_response; - - public CiscoNexusVSMResource() { - _gson = GsonHelper.getGsonLogger(); - } - - - public boolean configure(String name, Map params) throws ConfigurationException { - try { - // What is this name?! Is it a name for the VSM device? What do we set this to?? - // Can't understand why the "Manager" interface needs a String name parameter for - // configure(). - - // Do we need this zone id???? We may need to add other info also, like a/c id etc. - /** - _zoneId = (String) params.get("zoneId"); - if (_zoneId == null) { - throw new ConfigurationException("Unable to find zone Id in the configuration parameters"); - } **/ - - _ip = (String) params.get(ApiConstants.IP_ADDRESS); - if (_ip == null) { - throw new ConfigurationException("Unable to find IP address in the configuration parameters"); - } - - _username = (String) params.get(ApiConstants.USERNAME); - if (_username == null) { - throw new ConfigurationException("Unable to find username in the configuration parameters"); - } - - _password = (String) params.get(ApiConstants.PASSWORD); - if (_password == null) { - throw new ConfigurationException("Unable to find password in the configuration parameters"); - } - - _numRetries = NumbersUtil.parseInt((String) params.get("numretries"), 2); - - // we may want to validate whether the username/password is right.. so we may want to - // issue a login to the VSM. However note that the VSM has a max limit of 8 concurrent - // sessions. We don't want a situation where we are opening concurrent sessions at all. - - return true; - } catch (Exception e) { - throw new ConfigurationException(e.getMessage()); - } - } - - @Override - public IAgentControl getAgentControl() { - return null; - } - - @Override - public void setAgentControl(IAgentControl agentControl) { - return; - } - - - @Override - public void disconnected() { - return; - } - - @Override - public Type getType() { - return Host.Type.ExternalVirtualSwitchSupervisor; - } - - @Override - public PingCommand getCurrentStatus(long id) { - return new PingCommand(Host.Type.ExternalVirtualSwitchSupervisor, id); - } - - @Override - public StartupCommand[] initialize() { - StartupExternalLoadBalancerCommand cmd = new StartupExternalLoadBalancerCommand(); - cmd.setName(_name); - //cmd.setDataCenter(_zoneId); - cmd.setPod(""); - cmd.setPrivateIpAddress(_ip); - cmd.setStorageIpAddress(""); - cmd.setVersion(""); - return new StartupCommand[]{cmd}; - } - - @Override - public Answer executeRequest(Command cmd) { - return executeRequest(cmd, _numRetries); - } - - // We will need to change this executeRequest() function. - - private Answer executeRequest(Command cmd, int numRetries) { - return Answer.createUnsupportedCommandAnswer(cmd); - } - - @Override - public String getName() { - return _name; - } - - @Override - public boolean start() { - return true; - } - - @Override - public boolean stop() { - return true; - } - -} \ No newline at end of file diff --git a/server/src/com/cloud/api/commands/AddCiscoNexusVSMCmd.java b/server/src/com/cloud/api/commands/AddCiscoNexusVSMCmd.java index c136dccc5a5..1b275df3e36 100644 --- a/server/src/com/cloud/api/commands/AddCiscoNexusVSMCmd.java +++ b/server/src/com/cloud/api/commands/AddCiscoNexusVSMCmd.java @@ -54,8 +54,8 @@ public class AddCiscoNexusVSMCmd extends BaseAsyncCmd { @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, required = true, description="IP Address of the Cisco Nexus 1000v VSM appliance.") private String ipaddr; - @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.STRING, required = true, description="Id of the zone in which the Cisco Nexus 1000v VSM appliance.") - private long zoneId; + @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required = true, description="Id of the CloudStack cluster in which the Cisco Nexus 1000v VSM appliance.") + private long clusterId; @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="username to reach the Cisco Nexus 1000v VSM device") private String username; @@ -86,14 +86,17 @@ public class AddCiscoNexusVSMCmd extends BaseAsyncCmd { return vsmName; } - public long getZoneId() { - return zoneId; + public long getClusterId() { + return clusterId; } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// + // NOTE- The uuid that is sent in during the invocation of the API AddCiscoNexusVSM() + // automagically gets translated to the corresponding db id before this execute() method + // is invoked. That's the reason why we don't have any uuid-dbid translation code here. @Override public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException { try { diff --git a/server/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java b/server/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java index cf4bc5445d1..a1c90132c3f 100644 --- a/server/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java +++ b/server/src/com/cloud/network/CiscoNexusVSMDeviceManagerImpl.java @@ -26,12 +26,14 @@ import com.cloud.agent.api.StartupCommand; import com.cloud.api.ApiConstants; import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterIpAddressVO; import com.cloud.dc.DataCenterVO; import com.cloud.dc.Pod; import com.cloud.dc.Vlan.VlanType; import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.HostPodDao; import com.cloud.dc.dao.VlanDao; @@ -44,6 +46,7 @@ import com.cloud.host.Host; import com.cloud.host.HostVO; import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDetailsDao; +import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.ExternalNetworkDeviceManager.NetworkDevice; import com.cloud.network.Network.Service; import com.cloud.network.Networks.TrafficType; @@ -75,6 +78,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.NicDao; import com.cloud.network.dao.CiscoNexusVSMDeviceDao; +import com.cloud.network.resource.CiscoNexusVSM; //public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase implements CiscoNexusVSMDeviceManager, ResourceStateAdapter { public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase { @@ -125,12 +129,49 @@ public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase { NetworkServiceMapDao _ntwkSrvcProviderDao; @Inject protected HostPodDao _podDao = null; - + @Inject + ClusterDao _clusterDao; + private static final org.apache.log4j.Logger s_logger = Logger.getLogger(ExternalLoadBalancerDeviceManagerImpl.class); + // dummy func, will remove later. + private boolean vsmIsReachable(String ipaddress, String username, String password) { + return true; // dummy true for now. + } + @DB - public CiscoNexusVSMDeviceVO addCiscoNexusVSM(long zoneId, String ipaddress, String username, String password, ServerResource resource, String vsmName) { + //public CiscoNexusVSMDeviceVO addCiscoNexusVSM(long clusterId, String ipaddress, String username, String password, ServerResource resource, String vsmName) { + public CiscoNexusVSMDeviceVO addCiscoNexusVSM(long clusterId, String ipaddress, String username, String password, String vsmName) { + // In this function, we associate this VSM with the vCenter + // that is associated with the provided clusterId. + + ClusterVO cluster = _clusterDao.findById(clusterId); + + // Check if the ClusterVO's hypervisor type is "vmware". If not, + // throw an exception. + if (cluster.getHypervisorType() != HypervisorType.VMware) { + InvalidParameterValueException ex = new InvalidParameterValueException("Cluster with specified id is not a VMWare hypervisor cluster"); + throw ex; + } + + // Now we need a reference to the vmWareResource for this cluster. + + + DataCenterVO zone = _dcDao.findById(cluster.getDataCenterId()); + + // Else, check if this VSM is reachable. Use the XML-RPC VSM API Java bindings to talk to + // the VSM. + + // Create a new VSM object. + CiscoNexusVSM vsmObj = new CiscoNexusVSM(ipaddress, username, password); + + if (!vsmObj.connectToVSM()) { + throw new CloudRuntimeException("Couldn't login to the specified VSM"); + } + + // Since we can reached the VSM, and are logged into it, let's add it to the vCenter. + // In this function, we create a record for this Cisco Nexus VSM, in the database. // We also hand off interaction with the actual Cisco Nexus VSM via XML-RPC, to the // Resource Manager. The resource manager invokes the CiscoNexusVSMResource class's @@ -144,10 +185,7 @@ public abstract class CiscoNexusVSMDeviceManagerImpl extends AdapterBase { // Q1) Do we need a zoneUuid to dbzoneId translation? How will the user send in the zoneId? // We get the zoneId as a uuid, so we need to look up the db zoneId. // Ask Frank how to do this lookup. - long dbZoneId = zoneId; - - // Q2) Do we need to have the user send in a "DedicatedUse" parameter? What is it's use - // for Netscaler? + long dbZoneId = clusterId; hostDetails.put(ApiConstants.ZONE_ID, dbZoneId); hostDetails.put(ApiConstants.GUID, UUID.randomUUID().toString()); diff --git a/server/src/com/cloud/network/element/CiscoNexusVSMElement.java b/server/src/com/cloud/network/element/CiscoNexusVSMElement.java index 29a6303c8f1..f4bd8eb8260 100644 --- a/server/src/com/cloud/network/element/CiscoNexusVSMElement.java +++ b/server/src/com/cloud/network/element/CiscoNexusVSMElement.java @@ -174,12 +174,13 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme String vsmusername = cmd.getUsername(); String vsmpassword = cmd.getPassword(); String vsmName = cmd.getVSMName(); - long zoneId = cmd.getZoneId(); + long clusterId = cmd.getClusterId(); // Invoke the addCiscoNexusVSM() function defined in the upper layer (DeviceMgrImpl). // The upper layer function will create a resource of type "host" to represent this VSM. // It will add this VSM to the db. - CiscoNexusVSMDeviceVO vsmDeviceVO = addCiscoNexusVSM(zoneId, vsmipaddress, vsmusername, vsmpassword, (ServerResource) new CiscoNexusVSMResource(), vsmName); + //CiscoNexusVSMDeviceVO vsmDeviceVO = addCiscoNexusVSM(clusterId, vsmipaddress, vsmusername, vsmpassword, (ServerResource) new CiscoNexusVSMResource(), vsmName); + CiscoNexusVSMDeviceVO vsmDeviceVO = addCiscoNexusVSM(clusterId, vsmipaddress, vsmusername, vsmpassword, vsmName); return vsmDeviceVO; }