diff --git a/agent/bindir/cloud-setup-agent.in b/agent/bindir/cloud-setup-agent.in index 6932672b962..667d130e3bf 100755 --- a/agent/bindir/cloud-setup-agent.in +++ b/agent/bindir/cloud-setup-agent.in @@ -100,6 +100,10 @@ if __name__ == '__main__': if bridgeType: glbEnv.bridgeType = bridgeType + hypervisorType = old_config.getEntry("hypervisor.type").lower() + if hypervisorType: + glbEnv.hypervisorType = hypervisorType + (options, args) = parser.parse_args() if options.auto is None: userInputs = getUserInputs() diff --git a/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java b/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java index e8cb10b770a..92928ae22dc 100644 --- a/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java +++ b/api/src/org/apache/cloudstack/api/command/admin/cluster/AddClusterCmd.java @@ -63,7 +63,7 @@ public class AddClusterCmd extends BaseCmd { required=true, description="the Zone ID for the cluster") private Long zoneId; - @Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=true, description="hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Simulator") + @Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=true, description="hypervisor type of the cluster: XenServer,KVM,VMware,Hyperv,BareMetal,Docker,Simulator") private String hypervisor; @Parameter(name=ApiConstants.CLUSTER_TYPE, type=CommandType.STRING, required=true, description="type of the cluster: CloudManaged, ExternalManaged") diff --git a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java index bba90bf2c2a..afdbbb9ec9f 100644 --- a/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java +++ b/api/src/org/apache/cloudstack/api/command/user/template/RegisterTemplateCmd.java @@ -57,7 +57,7 @@ public class RegisterTemplateCmd extends BaseCmd { @Parameter(name=ApiConstants.DISPLAY_TEXT, type=CommandType.STRING, required=true, description="the display text of the template. This is usually used for display purposes.", length=4096) private String displayText; - @Parameter(name=ApiConstants.FORMAT, type=CommandType.STRING, required=true, description="the format for the template. Possible values include QCOW2, RAW, and VHD.") + @Parameter(name=ApiConstants.FORMAT, type=CommandType.STRING, description="the format for the template. Possible values include QCOW2, RAW, and VHD.") private String format; @Parameter(name=ApiConstants.HYPERVISOR, type=CommandType.STRING, required=true, description="the target hypervisor for the template") diff --git a/plugins/hypervisors/docker/pom.xml b/plugins/hypervisors/docker/pom.xml index 4ede673c6ec..1f7a430af11 100755 --- a/plugins/hypervisors/docker/pom.xml +++ b/plugins/hypervisors/docker/pom.xml @@ -15,7 +15,7 @@ org.apache.cloudstack cloudstack-plugins - 4.4.0-SNAPSHOT + 4.3.0 ../../pom.xml @@ -23,6 +23,10 @@ libvirt-org http://libvirt.org/maven2 + + ceph-com + http://ceph.com/maven + @@ -40,9 +44,9 @@ ${cs.libvirt-java.version} - org.apache.cloudstack - cloud-plugin-network-ovs - ${project.version} + com.ceph + rados + ${cs.rados-java.version} net.java.dev.jna @@ -58,6 +62,7 @@ org.apache.maven.plugins maven-dependency-plugin + 2.5.1 copy-dependencies @@ -75,6 +80,7 @@ org.apache.maven.plugins maven-surefire-plugin + 2.14 **/Qemu*.java diff --git a/plugins/hypervisors/docker/src/com/cloud/hypervisor/docker/resource/DockerResource.java b/plugins/hypervisors/docker/src/com/cloud/hypervisor/docker/resource/DockerResource.java index 501df0df7eb..6c11e9a63a3 100644 --- a/plugins/hypervisors/docker/src/com/cloud/hypervisor/docker/resource/DockerResource.java +++ b/plugins/hypervisors/docker/src/com/cloud/hypervisor/docker/resource/DockerResource.java @@ -21,17 +21,17 @@ import com.cloud.resource.ServerResourceBase; @Local(value = {ServerResource.class}) public class DockerResource extends ServerResourceBase implements ServerResource { - private static final Logger s_logger = Logger.getLogger(DockerResource.class); + private static final Logger s_logger = Logger.getLogger(DockerResource.class); - @Override + @Override public boolean configure(String name, Map params) throws ConfigurationException { - return true; - } - - @Override - public Answer executeRequest(Command cmd) { - try { - if (cmd instanceof StopCommand) { + return true; + } + + @Override + public Answer executeRequest(Command cmd) { + try { + if (cmd instanceof StopCommand) { return execute((StopCommand)cmd); } else if (cmd instanceof RebootCommand) { return execute((RebootCommand)cmd); @@ -44,72 +44,68 @@ public class DockerResource extends ServerResourceBase implements ServerResource } catch (final IllegalArgumentException e) { return new Answer(cmd, false, e.getMessage()); } - } - - protected Answer execute(StopCommand cmd) { - - } - - private Answer execute(RebootCommand cmd) { - - } - - protected StartAnswer execute(StartCommand cmd) { - - } - - @Override - public void setName(String name) { - // TODO Auto-generated method stub - - } + } - @Override - public void setConfigParams(Map params) { - // TODO Auto-generated method stub - - } + protected Answer execute(StopCommand cmd) { + return null; + } - @Override - public Map getConfigParams() { - // TODO Auto-generated method stub - return null; - } + private Answer execute(RebootCommand cmd) { + return null; + } - @Override - public int getRunLevel() { - // TODO Auto-generated method stub - return 0; - } + protected StartAnswer execute(StartCommand cmd) { + return null; + } - @Override - public void setRunLevel(int level) { - // TODO Auto-generated method stub - - } + @Override + public Map getConfigParams() { + // TODO Auto-generated method stub + return null; + } - @Override - public Type getType() { - // TODO Auto-generated method stub - return null; - } + @Override + public int getRunLevel() { + // TODO Auto-generated method stub + return 0; + } - @Override - public StartupCommand[] initialize() { - // TODO Auto-generated method stub - return null; - } + @Override + public void setConfigParams(Map arg0) { + // TODO Auto-generated method stub + } - @Override - public PingCommand getCurrentStatus(long id) { - // TODO Auto-generated method stub - return null; - } + @Override + public void setName(String arg0) { + // TODO Auto-generated method stub + } - @Override - protected String getDefaultScriptsDir() { - // TODO Auto-generated method stub - return null; - } - + @Override + public void setRunLevel(int arg0) { + // TODO Auto-generated method stub + } + + @Override + public PingCommand getCurrentStatus(long arg0) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Type getType() { + // TODO Auto-generated method stub + return null; + } + + @Override + public StartupCommand[] initialize() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected String getDefaultScriptsDir() { + // TODO Auto-generated method stub + return null; + } } diff --git a/plugins/pom.xml b/plugins/pom.xml index 86308bc06df..86a7ba839ab 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -42,6 +42,7 @@ hypervisors/baremetal hypervisors/ucs hypervisors/hyperv + hypervisors/docker network-elements/elastic-loadbalancer network-elements/ovs network-elements/juniper-contrail diff --git a/python/lib/cloudutils/globalEnv.py b/python/lib/cloudutils/globalEnv.py index 867aa17670d..9f202122099 100644 --- a/python/lib/cloudutils/globalEnv.py +++ b/python/lib/cloudutils/globalEnv.py @@ -42,3 +42,5 @@ class globalEnv: self.distribution = None # bridgeType self.bridgeType = "native" + # hypervisorType + self.hypervisorType = None diff --git a/python/lib/cloudutils/serviceConfig.py b/python/lib/cloudutils/serviceConfig.py index d7c7e78c3ab..7c5c32b6f4d 100755 --- a/python/lib/cloudutils/serviceConfig.py +++ b/python/lib/cloudutils/serviceConfig.py @@ -384,6 +384,10 @@ class nfsConfig(serviceCfgBase): self.serviceName = "Nfs" def config(self): + # Docker + if self.syscfg.env.hypervisorType == "docker": + return True + # end Docker try: if not os.path.exists("/etc/nfsmount.conf"): return True @@ -412,6 +416,9 @@ class securityPolicyConfigUbuntu(serviceCfgBase): self.serviceName = "Apparmor" def config(self): + # Docker + if self.syscfg.env.hypervisorType == "docker": + return True try: cmd = bash("service apparmor status") if not cmd.isSuccess() or cmd.getStdout() == "": @@ -532,6 +539,9 @@ class libvirtConfigUbuntu(serviceCfgBase): cfo.replace_or_add_line("libvirtd_opts=","libvirtd_opts='-l -d'") def config(self): + # Docker + if self.syscfg.env.hypervisorType == "docker": + return True try: self.setupLiveMigration() @@ -568,6 +578,9 @@ class firewallConfigUbuntu(serviceCfgBase): ports = "22 1798 16509".split() for p in ports: bash("ufw allow %s"%p) + #Docker + bash("ufw allow 5555") + #end Docker bash("ufw allow proto tcp from any to any port 5900:6100") bash("ufw allow proto tcp from any to any port 49152:49216") self.syscfg.svo.stopService("ufw") @@ -678,7 +691,12 @@ class cloudAgentConfig(serviceCfgBase): cfo.addEntry("guid", str(self.syscfg.env.uuid)) if cfo.getEntry("local.storage.uuid") == "": cfo.addEntry("local.storage.uuid", str(bash("uuidgen").getStdout())) - cfo.addEntry("resource", "com.cloud.hypervisor.kvm.resource.LibvirtComputingResource") + # Docker + if self.syscfg.env.hypervisorType == "docker": + cfo.addEntry("resource", "com.cloud.hypervisor.docker.resource.DockerResource") + else: + cfo.addEntry("resource", "com.cloud.hypervisor.kvm.resource.LibvirtComputingResource") + # end Docker cfo.save() self.syscfg.svo.stopService("cloudstack-agent") diff --git a/server/src/com/cloud/hypervisor/kvm/discoverer/DockerServerDiscoverer.java b/server/src/com/cloud/hypervisor/kvm/discoverer/DockerServerDiscoverer.java index d7ce7c20099..7b031d5f5b5 100644 --- a/server/src/com/cloud/hypervisor/kvm/discoverer/DockerServerDiscoverer.java +++ b/server/src/com/cloud/hypervisor/kvm/discoverer/DockerServerDiscoverer.java @@ -1,18 +1,218 @@ package com.cloud.hypervisor.kvm.discoverer; +import java.net.InetAddress; +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + import javax.ejb.Local; +import javax.naming.ConfigurationException; import org.apache.log4j.Logger; +import com.cloud.configuration.Config; +import com.cloud.dc.ClusterVO; +import com.cloud.exception.DiscoveredWithErrorException; +import com.cloud.exception.DiscoveryException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; import com.cloud.hypervisor.Hypervisor; +import com.cloud.network.PhysicalNetworkSetupInfo; import com.cloud.resource.Discoverer; +import com.cloud.resource.ServerResource; +import com.cloud.utils.ssh.SSHCmdHelper; @Local(value = Discoverer.class) public class DockerServerDiscoverer extends LibvirtServerDiscoverer { private static final Logger s_logger = Logger.getLogger(DockerServerDiscoverer.class); + private String _hostIp; + private final int _waitTime = 5; /* wait for 5 minutes */ + private String _dockerPrivateNic; + private String _dockerPublicNic; + private String _dockerGuestNic; @Override public Hypervisor.HypervisorType getHypervisorType() { return Hypervisor.HypervisorType.Docker; } + + @Override + public boolean configure(String name, Map params) throws ConfigurationException { + _dockerPrivateNic = _configDao.getValue(Config.KvmPrivateNetwork.key()); + if (_dockerPrivateNic == null) { + _dockerPrivateNic = "cloudbr0"; + } + + _dockerPublicNic = _configDao.getValue(Config.KvmPublicNetwork.key()); + if (_dockerPublicNic == null) { + _dockerPublicNic = _dockerPrivateNic; + } + + _dockerGuestNic = _configDao.getValue(Config.KvmGuestNetwork.key()); + if (_dockerGuestNic == null) { + _dockerGuestNic = _dockerPrivateNic; + } + + _hostIp = _configDao.getValue("host"); + if (_hostIp == null) { + throw new ConfigurationException("Can't get host IP"); + } + _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); + return true; + } + + @Override + public Map> find(long dcId, Long podId, Long clusterId, URI uri, + String username, String password, List hostTags) throws DiscoveryException { + ClusterVO cluster = _clusterDao.findById(clusterId); + if (cluster == null || cluster.getHypervisorType() != getHypervisorType()) { + if (s_logger.isInfoEnabled()) + s_logger.info("invalid cluster id or cluster is not for " + getHypervisorType() + " hypervisors"); + return null; + } + + Map> resources = new HashMap>(); + Map details = new HashMap(); + if (!uri.getScheme().equals("http")) { + String msg = "urlString is not http so we're not taking care of the discovery for this: " + uri; + s_logger.debug(msg); + return null; + } + com.trilead.ssh2.Connection sshConnection = null; + String agentIp = null; + + try { + String hostname = uri.getHost(); + InetAddress ia = InetAddress.getByName(hostname); + agentIp = ia.getHostAddress(); + String guid = UUID.nameUUIDFromBytes(agentIp.getBytes()).toString(); + String guidWithTail = guid + "-LibvirtComputingResource";/* + * tail + * added by + * agent + * .java + */ + if (_resourceMgr.findHostByGuid(guidWithTail) != null) { + s_logger.debug("Skipping " + agentIp + " because " + guidWithTail + " is already in the database."); + return null; + } + + sshConnection = new com.trilead.ssh2.Connection(agentIp, 22); + sshConnection.connect(null, 60000, 60000); + if (!sshConnection.authenticateWithPassword(username, password)) { + s_logger.debug("Failed to authenticate"); + throw new DiscoveredWithErrorException("Authentication error"); + } + + List netInfos = _networkMgr.getPhysicalNetworkInfo(dcId, getHypervisorType()); + String dockerPrivateNic = null; + String dockerPublicNic = null; + String dockerGuestNic = null; + + for (PhysicalNetworkSetupInfo info : netInfos) { + if (info.getPrivateNetworkName() != null) { + dockerPrivateNic = info.getPrivateNetworkName(); + } + if (info.getPublicNetworkName() != null) { + dockerPublicNic = info.getPublicNetworkName(); + } + if (info.getGuestNetworkName() != null) { + dockerGuestNic = info.getGuestNetworkName(); + } + } + + if (dockerPrivateNic == null && dockerPublicNic == null && dockerGuestNic == null) { + dockerPrivateNic = _dockerPrivateNic; + dockerPublicNic = _dockerPublicNic; + dockerGuestNic = _dockerGuestNic; + } + + if (dockerPublicNic == null) { + dockerPublicNic = (dockerGuestNic != null) ? dockerGuestNic : dockerPrivateNic; + } + + if (dockerPrivateNic == null) { + dockerPrivateNic = (dockerPublicNic != null) ? dockerPublicNic : dockerGuestNic; + } + + if (dockerGuestNic == null) { + dockerGuestNic = (dockerPublicNic != null) ? dockerPublicNic : dockerPrivateNic; + } + + String parameters = " -m " + _hostIp + " -z " + dcId + " -p " + podId + " -c " + clusterId + " -g " + guid + + " -a"; + + parameters += " --pubNic=" + dockerPublicNic; + parameters += " --prvNic=" + dockerPrivateNic; + parameters += " --guestNic=" + dockerGuestNic; + + SSHCmdHelper.sshExecuteCmd(sshConnection, "cloudstack-setup-agent " + parameters, 3); + + KvmDummyResourceBase kvmResource = new KvmDummyResourceBase(); + Map params = new HashMap(); + + params.put("zone", Long.toString(dcId)); + params.put("pod", Long.toString(podId)); + params.put("cluster", Long.toString(clusterId)); + params.put("guid", guid); + params.put("agentIp", agentIp); + kvmResource.configure("kvm agent", params); + resources.put(kvmResource, details); + + HostVO connectedHost = waitForHostConnect(dcId, podId, clusterId, guidWithTail); + if (connectedHost == null) + return null; + + details.put("guid", guidWithTail); + + // place a place holder guid derived from cluster ID + if (cluster.getGuid() == null) { + cluster.setGuid(UUID.nameUUIDFromBytes(String.valueOf(clusterId).getBytes()).toString()); + _clusterDao.update(clusterId, cluster); + } + + // save user name and password + _hostDao.loadDetails(connectedHost); + Map hostDetails = connectedHost.getDetails(); + hostDetails.put("password", password); + hostDetails.put("username", username); + _hostDao.saveDetails(connectedHost); + return resources; + } catch (DiscoveredWithErrorException e) { + throw e; + } catch (Exception e) { + String msg = " can't setup agent, due to " + e.toString() + " - " + e.getMessage(); + s_logger.warn(msg); + } finally { + if (sshConnection != null) + sshConnection.close(); + } + + return null; + } + + private HostVO waitForHostConnect(long dcId, long podId, long clusterId, String guid) { + for (int i = 0; i < _waitTime * 2; i++) { + List hosts = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.Routing, clusterId, podId, dcId); + for (HostVO host : hosts) { + if (host.getGuid().equalsIgnoreCase(guid)) { + return host; + } + } + try { + Thread.sleep(30000); + } catch (InterruptedException e) { + s_logger.debug("Failed to sleep: " + e.toString()); + } + } + s_logger.debug("Timeout, to wait for the host connecting to mgt svr, assuming it is failed"); + List hosts = _resourceMgr.findHostByGuid(dcId, guid); + if (hosts.size() == 1) { + return hosts.get(0); + } else { + return null; + } + } } diff --git a/server/src/com/cloud/template/HypervisorTemplateAdapter.java b/server/src/com/cloud/template/HypervisorTemplateAdapter.java index 32f1287faea..7659b6250ee 100755 --- a/server/src/com/cloud/template/HypervisorTemplateAdapter.java +++ b/server/src/com/cloud/template/HypervisorTemplateAdapter.java @@ -118,17 +118,16 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { @Override public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException { TemplateProfile profile = super.prepare(cmd); - String url = profile.getUrl(); - String path = null; - try { - URL str = new URL(url); - path = str.getPath(); - } catch (MalformedURLException ex) { - throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is invalid"); - } - -// Don't check with Docker template - if (!cmd.getHypervisor().equals(Hypervisor.HypervisorType.Docker)) { +// Don't check with Docker template + if (!HypervisorType.getType(cmd.getHypervisor()).equals(HypervisorType.Docker)) { + String url = profile.getUrl(); + String path = null; + try { + URL str = new URL(url); + path = str.getPath(); + } catch (MalformedURLException ex) { + throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is invalid"); + } try { checkFormat(cmd.getFormat(), url); } catch (InvalidParameterValueException ex) { @@ -139,8 +138,8 @@ public class HypervisorTemplateAdapter extends TemplateAdapterBase { // Check that the resource limit for secondary storage won't be exceeded _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(cmd.getEntityOwnerId()), ResourceType.secondary_storage, UriUtils.getRemoteSize(url)); - } profile.setUrl(url); + } return profile; } diff --git a/server/src/com/cloud/template/TemplateAdapterBase.java b/server/src/com/cloud/template/TemplateAdapterBase.java index c75c1e4137b..510be910fe2 100755 --- a/server/src/com/cloud/template/TemplateAdapterBase.java +++ b/server/src/com/cloud/template/TemplateAdapterBase.java @@ -187,9 +187,12 @@ public abstract class TemplateAdapterBase extends AdapterBase implements Templat featured = Boolean.FALSE; } - ImageFormat imgfmt = ImageFormat.valueOf(format.toUpperCase()); - if (imgfmt == null) { - throw new IllegalArgumentException("Image format is incorrect " + format + ". Supported formats are " + EnumUtils.listValues(ImageFormat.values())); + ImageFormat imgfmt = ImageFormat.TAR; + if (!hypervisorType.equals(HypervisorType.Docker)) { + imgfmt = ImageFormat.valueOf(format.toUpperCase()); + if (imgfmt == null) { + throw new IllegalArgumentException("Image format is incorrect " + format + ". Supported formats are " + EnumUtils.listValues(ImageFormat.values())); + } } // Check that the resource limit for templates/ISOs won't be exceeded