// 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 com.cloud.hypervisor.hyperv;
import java.net.InetAddress;
import java.net.URI;
import java.net.UnknownHostException;
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.agent.api.Command;
import com.cloud.agent.api.StartupVMMAgentCommand;
import com.cloud.agent.transport.Request;
import com.cloud.alert.AlertManager;
import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterVO;
import com.cloud.dc.dao.ClusterDao;
import com.cloud.exception.DiscoveryException;
import com.cloud.host.Host;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.hyperv.resource.HypervDummyResourceBase;
import com.cloud.resource.Discoverer;
import com.cloud.resource.DiscovererBase;
import com.cloud.resource.ResourceManager;
import com.cloud.resource.ServerResource;
import com.cloud.utils.component.Inject;
import com.cloud.utils.nio.HandlerFactory;
import com.cloud.utils.nio.Link;
import com.cloud.utils.nio.NioClient;
import com.cloud.utils.nio.Task;
import com.cloud.utils.nio.Task.Type;
@Local(value=Discoverer.class)
public class HypervServerDiscoverer extends DiscovererBase implements Discoverer, HandlerFactory{
private static final Logger s_logger = Logger.getLogger(HypervServerDiscoverer.class);
private int _waitTime = 1;
@Inject ClusterDao _clusterDao;
@Inject AlertManager _alertMgr;
@Inject ClusterDetailsDao _clusterDetailsDao;
@Inject HostDao _hostDao = null;
@Inject ResourceManager _resourceMgr;
Link _link;
@SuppressWarnings("static-access")
@Override
public Map<? extends ServerResource, Map<String, String>> find(long dcId, Long podId, Long clusterId, URI url,
String username, String password, List<String> hostTags) throws DiscoveryException {
if(s_logger.isInfoEnabled()) {
s_logger.info("Discover host. dc: " + dcId + ", pod: " + podId + ", cluster: " + clusterId + ", uri host: " + url.getHost());
}
if(podId == null) {
if(s_logger.isInfoEnabled()) {
s_logger.info("No pod is assigned, skipping the discovery in Hyperv discoverer");
}
return null;
}
if (!url.getScheme().equals("http")) {
String msg = "urlString is not http so HypervServerDiscoverer taking care of the discovery for this: " + url;
s_logger.debug(msg);
return null;
}
ClusterVO cluster = _clusterDao.findById(clusterId);
if(cluster == null || cluster.getHypervisorType() != HypervisorType.Hyperv) {
if(s_logger.isInfoEnabled()) {
s_logger.info("invalid cluster id or cluster is not for Hyperv hypervisors");
}
return null;
}
String clusterName = cluster.getName();
try {
String hostname = url.getHost();
InetAddress ia = InetAddress.getByName(hostname);
String agentIp = ia.getHostAddress();
String guid = UUID.nameUUIDFromBytes(agentIp.getBytes()).toString();
String guidWithTail = guid + "-HypervResource";/*tail added by agent.java*/
if (_resourceMgr.findHostByGuid(guidWithTail) != null) {
s_logger.debug("Skipping " + agentIp + " because " + guidWithTail + " is already in the database.");
return null;
}
// bootstrap SCVMM agent to connect back to management server
NioClient _connection = new NioClient("HypervAgentClient", url.getHost(), 9000, 1, this);
_connection.start();
StartupVMMAgentCommand cmd = new StartupVMMAgentCommand(
dcId,
podId,
clusterName,
guid,
InetAddress.getLocalHost().getHostAddress(),
"8250",
HypervServerDiscoverer.class.getPackage().getImplementationVersion());
// send bootstrap command to agent running on SCVMM host
s_logger.info("sending bootstrap request to SCVMM agent on host "+ url.getHost());
Request request = new Request(0, 0, cmd, false);
// :FIXME without sleep link.send failing why??????
Thread.currentThread().sleep(5000);
_link.send(request.toBytes());
//wait for SCVMM agent to connect back
HostVO connectedHost = waitForHostConnect(dcId, podId, clusterId, guidWithTail);
if (connectedHost == null)
{
s_logger.info("SCVMM agent did not connect back after sending bootstrap request");
return null;
}
//disconnect
s_logger.info("SCVMM agent connected back after sending bootstrap request");
_connection.stop();
Map<HypervDummyResourceBase, Map<String, String>> resources = new HashMap<HypervDummyResourceBase, Map<String, String>>();
Map<String, String> details = new HashMap<String, String>();
Map<String, Object> params = new HashMap<String, Object>();
HypervDummyResourceBase resource = new HypervDummyResourceBase();
details.put("url", url.getHost());
details.put("username", username);
details.put("password", password);
resources.put(resource, details);
params.put("zone", Long.toString(dcId));
params.put("pod", Long.toString(podId));
params.put("cluster", Long.toString(clusterId));
resource.configure("Hyperv", params);
return resources;
} catch (ConfigurationException e) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage());
s_logger.warn("Unable to instantiate " + url.getHost(), e);
} catch (UnknownHostException e) {
_alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId, "Unable to add " + url.getHost(), "Error is " + e.getMessage());
s_logger.warn("Unable to instantiate " + url.getHost(), e);
} catch (Exception e) {
s_logger.info("exception " + e.toString());
}
return null;
}
@Override
public void postDiscovery(List<HostVO> hosts, long msId) {
// do nothing
}
@Override
public boolean matchHypervisor(String hypervisor) {
if(hypervisor == null) {
return true;
}
return Hypervisor.HypervisorType.VMware.toString().equalsIgnoreCase(hypervisor);
}
@Override
public Hypervisor.HypervisorType getHypervisorType() {
return Hypervisor.HypervisorType.Hyperv;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
return true;
}
@Override
public Task create(Type type, Link link, byte[] data) {
_link = link;
return new BootStrapTakHandler(type, link, data);
}
private HostVO waitForHostConnect(long dcId, long podId, long clusterId, String guid) {
for (int i = 0; i < _waitTime *2; i++) {
List<HostVO> 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");
return null;
}
// class to handle the bootstrap command from the management server
public class BootStrapTakHandler extends Task {
public BootStrapTakHandler(Task.Type type, Link link, byte[] data) {
super(type, link, data);
s_logger.info("created new BootStrapTakHandler");
}
protected void processRequest(final Link link, final Request request) {
final Command[] cmds = request.getCommands();
Command cmd = cmds[0];
}
@Override
protected void doTask(Task task) throws Exception {
final Type type = task.getType();
s_logger.info("recieved task of type "+type.toString() +" in BootStrapTakHandler");
}
}
}