Add a API to allow adding external hypervisor cluster

This commit is contained in:
Kelven Yang 2010-12-16 09:59:54 -08:00
parent 1e595ddf00
commit 65c094a2c0
6 changed files with 256 additions and 3 deletions

View File

@ -0,0 +1,102 @@
package com.cloud.api.commands;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import com.cloud.api.ApiConstants;
import com.cloud.api.BaseCmd;
import com.cloud.api.Implementation;
import com.cloud.api.Parameter;
import com.cloud.api.ServerApiException;
import com.cloud.api.response.HostResponse;
import com.cloud.api.response.ListResponse;
import com.cloud.exception.DiscoveryException;
import com.cloud.host.Host;
@Implementation(description="Adds a new external cluster", responseObject=HostResponse.class)
public class AddExternalClusterCmd extends BaseCmd {
public static final Logger s_logger = Logger.getLogger(AddExternalClusterCmd.class.getName());
private static final String s_name = "addexternalclusterresponse";
@Parameter(name=ApiConstants.CLUSTER_NAME, type=CommandType.STRING, description="the cluster name")
private String clusterName;
@Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required=true, description="the password for the host")
private String password;
@Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, description="the Pod ID for the host")
private Long podId;
@Parameter(name=ApiConstants.URL, type=CommandType.STRING, required=true, description="the host URL")
private String url;
@Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required=true, description="the username for the host")
private String username;
@Parameter(name=ApiConstants.ZONE_ID, type=CommandType.LONG, required=true, description="the Zone ID for the host")
private Long zoneId;
@Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=false, description="hypervisor type of the host")
private String hypervisor;
public String getClusterName() {
return clusterName;
}
public String getPassword() {
return password;
}
public Long getPodId() {
return podId;
}
public String getUrl() {
return url;
}
public String getUsername() {
return username;
}
public Long getZoneId() {
return zoneId;
}
public String getHypervisor() {
return hypervisor;
}
@Override
public String getCommandName() {
return s_name;
}
@Override
public void execute(){
try {
List<? extends Host> result = _resourceService.discoverExternalCluster(this);
ListResponse<HostResponse> response = new ListResponse<HostResponse>();
List<HostResponse> hostResponses = new ArrayList<HostResponse>();
if (result != null) {
for (Host host : result) {
HostResponse hostResponse = _responseGenerator.createHostResponse(host);
hostResponses.add(hostResponse);
}
} else {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Failed to add external host cluster");
}
response.setResponses(hostResponses);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} catch (DiscoveryException ex) {
s_logger.warn("Exception: ", ex);
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, ex.getMessage());
}
}
}

View File

@ -3,11 +3,20 @@
*/
package com.cloud.org;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
public interface Cluster extends Grouping {
public static enum ClusterType {
CloudManaged,
ExternalManaged;
};
long getId();
String getName();
long getDataCenterId();
long getPodId();
HypervisorType getHypervisorType();
ClusterType getClusterType();
}

View File

@ -19,6 +19,7 @@ package com.cloud.resource;
import java.util.List;
import com.cloud.api.commands.AddExternalClusterCmd;
import com.cloud.api.commands.AddHostCmd;
import com.cloud.api.commands.AddSecondaryStorageCmd;
import com.cloud.api.commands.CancelMaintenanceCmd;
@ -43,6 +44,19 @@ public interface ResourceService {
Host cancelMaintenance(CancelMaintenanceCmd cmd) throws InvalidParameterValueException;
Host reconnectHost(ReconnectHostCmd cmd) throws AgentUnavailableException;
/**
* We will automatically create a cloud.com cluster to attach to the external cluster and return a hyper host to perform
* host related operation within the cluster
*
* @param cmd
* @return
* @throws IllegalArgumentException
* @throws DiscoveryException
* @throws InvalidParameterValueException
*/
List<? extends Host> discoverExternalCluster(AddExternalClusterCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
List<? extends Host> discoverHosts(AddHostCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
List<? extends Host> discoverHosts(AddSecondaryStorageCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException;
Host maintain(PrepareForMaintenanceCmd cmd) throws InvalidParameterValueException;

View File

@ -73,6 +73,7 @@ import com.cloud.agent.transport.Response;
import com.cloud.alert.AlertManager;
import com.cloud.api.BaseCmd;
import com.cloud.api.ServerApiException;
import com.cloud.api.commands.AddExternalClusterCmd;
import com.cloud.api.commands.AddHostCmd;
import com.cloud.api.commands.AddSecondaryStorageCmd;
import com.cloud.api.commands.CancelMaintenanceCmd;
@ -127,6 +128,7 @@ import com.cloud.network.IPAddressVO;
import com.cloud.network.NetworkManager;
import com.cloud.network.dao.IPAddressDao;
import com.cloud.offering.ServiceOffering;
import com.cloud.org.Cluster;
import com.cloud.resource.Discoverer;
import com.cloud.resource.ResourceService;
import com.cloud.resource.ServerResource;
@ -524,8 +526,6 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
return pcs;
}
protected AgentAttache handleDirectConnect(ServerResource resource, StartupCommand[] startup, Map<String, String> details, boolean old) throws ConnectionException {
if (startup == null) {
return null;
@ -544,6 +544,118 @@ public class AgentManagerImpl implements AgentManager, HandlerFactory, ResourceS
return attache;
}
@Override
public List<? extends Host> discoverExternalCluster(AddExternalClusterCmd cmd)
throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException {
Long dcId = cmd.getZoneId();
Long podId = cmd.getPodId();
String clusterName = cmd.getClusterName();
String url = cmd.getUrl();
String username = cmd.getUsername();
String password = cmd.getPassword();
URI uri = null;
//Check if the zone exists in the system
if (_dcDao.findById(dcId) == null ){
throw new InvalidParameterValueException("Can't find zone by id " + dcId);
}
//Check if the pod exists in the system
if (podId != null) {
if (_podDao.findById(podId) == null ){
throw new InvalidParameterValueException("Can't find pod by id " + podId);
}
//check if pod belongs to the zone
HostPodVO pod = _podDao.findById(podId);
if (!Long.valueOf(pod.getDataCenterId()).equals(dcId)) {
throw new InvalidParameterValueException("Pod " + podId + " doesn't belong to the zone " + dcId);
}
}
// Verify cluster information and create a new cluster if needed
if (clusterName == null || clusterName.isEmpty()) {
throw new InvalidParameterValueException("Please specify cluster name");
}
if(cmd.getHypervisor() == null || cmd.getHypervisor().isEmpty()) {
throw new InvalidParameterValueException("Please specify a hypervisor");
}
Hypervisor.HypervisorType hypervisorType = Hypervisor.HypervisorType.valueOf(cmd.getHypervisor());
if(hypervisorType == null) {
throw new InvalidParameterValueException("Please specify a valid hypervisor name");
}
Discoverer discoverer = getMatchingDiscover(cmd.getHypervisor());
if(discoverer == null) {
throw new InvalidParameterValueException("Please specify a valid hypervisor");
}
long clusterId = 0;
if (clusterName != null) {
ClusterVO cluster = new ClusterVO(dcId, podId, clusterName);
cluster.setHypervisorType(cmd.getHypervisor());
cluster.setClusterType(Cluster.ClusterType.ExternalManaged);
try {
cluster = _clusterDao.persist(cluster);
} catch (Exception e) {
cluster = _clusterDao.findBy(clusterName, podId);
if (cluster == null) {
throw new CloudRuntimeException("Unable to create cluster " + clusterName + " in pod " + podId + " and data center " + dcId, e);
}
}
clusterId = cluster.getId();
}
try {
uri = new URI(UriUtils.encodeURIComponent(url));
if (uri.getScheme() == null) {
throw new InvalidParameterValueException("uri.scheme is null " + url + ", add http:// as a prefix");
} else if (uri.getScheme().equalsIgnoreCase("http")) {
if (uri.getHost() == null || uri.getHost().equalsIgnoreCase("") || uri.getPath() == null || uri.getPath().equalsIgnoreCase("")) {
throw new InvalidParameterValueException("Your host and/or path is wrong. Make sure it's of the format http://hostname/path");
}
}
} catch (URISyntaxException e) {
throw new InvalidParameterValueException(url + " is not a valid uri");
}
List<HostVO> hosts = new ArrayList<HostVO>();
Map<? extends ServerResource, Map<String, String>> resources = null;
try {
resources = discoverer.find(dcId, podId, clusterId, uri, username, password);
} catch(Exception e) {
s_logger.info("Exception in external cluster discovery process with discoverer: " + discoverer.getName());
}
if (resources != null) {
for (Map.Entry<? extends ServerResource, Map<String, String>> entry : resources.entrySet()) {
ServerResource resource = entry.getKey();
AgentAttache attache = simulateStart(resource, entry.getValue(), true);
if (attache != null) {
hosts.add(_hostDao.findById(attache.getId()));
}
discoverer.postDiscovery(hosts, _nodeId);
}
s_logger.info("External cluster has been successfully discovered by " + discoverer.getName());
return hosts;
}
s_logger.warn("Unable to find the server resources at " + url);
throw new DiscoveryException("Unable to add the external cluster");
}
private Discoverer getMatchingDiscover(String hypervisorType) {
Enumeration<Discoverer> en = _discoverers.enumeration();
while (en.hasMoreElements()) {
Discoverer discoverer = en.nextElement();
if(discoverer.matchHypervisor(hypervisorType))
return discoverer;
}
return null;
}
@Override
public List<? extends Host> discoverHosts(AddHostCmd cmd) throws IllegalArgumentException, DiscoveryException, InvalidParameterValueException {
Long dcId = cmd.getZoneId();

View File

@ -19,6 +19,8 @@ package com.cloud.dc;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@ -49,14 +51,19 @@ public class ClusterVO implements Cluster {
@Column(name="hypervisor_type")
String hypervisorType;
@Column(name="cluster_type")
@Enumerated(value=EnumType.STRING)
Cluster.ClusterType clusterType;
public ClusterVO() {
clusterType = Cluster.ClusterType.CloudManaged;
}
public ClusterVO(long dataCenterId, long podId, String name) {
this.dataCenterId = dataCenterId;
this.podId = podId;
this.name = name;
this.clusterType = Cluster.ClusterType.CloudManaged;
}
public long getId() {
@ -75,6 +82,14 @@ public class ClusterVO implements Cluster {
return podId;
}
public Cluster.ClusterType getClusterType() {
return clusterType;
}
public void setClusterType(Cluster.ClusterType clusterType) {
this.clusterType = clusterType;
}
public ClusterVO(long clusterId) {
this.id = clusterId;
}

View File

@ -219,6 +219,7 @@ CREATE TABLE `cloud`.`cluster` (
`pod_id` bigint unsigned NOT NULL COMMENT 'pod id',
`data_center_id` bigint unsigned NOT NULL COMMENT 'data center id',
`hypervisor_type` varchar(255),
`cluster_type` varchar(64) DEFAULT 'CloudManaged',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;