mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Add a API to allow adding external hypervisor cluster
This commit is contained in:
parent
1e595ddf00
commit
65c094a2c0
102
api/src/com/cloud/api/commands/AddExternalClusterCmd.java
Normal file
102
api/src/com/cloud/api/commands/AddExternalClusterCmd.java
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user