You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by de...@apache.org on 2013/10/02 11:20:22 UTC
[02/31] A plugin for Hyper-V control is available for CloudStack. The
plugin implements basic VM control;
however, its architecture allows additional functionality to be easily added.
Incorporating the plugin in CloudStack will allow the community to
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/conf/log4j-cloud.xml.in
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/conf/log4j-cloud.xml.in b/plugins/hypervisors/hyperv/conf/log4j-cloud.xml.in
new file mode 100644
index 0000000..fdbba19
--- /dev/null
+++ b/plugins/hypervisors/hyperv/conf/log4j-cloud.xml.in
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+ <!-- ================================= -->
+ <!-- Preserve messages in a local file -->
+ <!-- ================================= -->
+
+ <!-- A time/date based rolling appender -->
+ <appender name="FILE" class="org.apache.log4j.rolling.RollingFileAppender">
+ <param name="Append" value="true"/>
+ <param name="Threshold" value="INFO"/>
+ <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
+ <param name="FileNamePattern" value="@AGENTLOG@.%d{yyyy-MM-dd}.gz"/>
+ <param name="ActiveFileName" value="@AGENTLOG@"/>
+ </rollingPolicy>
+ <layout class="org.apache.log4j.EnhancedPatternLayout">
+ <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{3}] (%t:%x) %m%n"/>
+ </layout>
+ </appender>
+
+ <!-- ============================== -->
+ <!-- Append messages to the console -->
+ <!-- ============================== -->
+
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <param name="Threshold" value="INFO"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{ISO8601}{GMT} %-5p [%c{3}] (%t:%x) %m%n"/>
+ </layout>
+ </appender>
+
+ <!-- ================ -->
+ <!-- Limit categories -->
+ <!-- ================ -->
+
+ <category name="com.cloud">
+ <priority value="INFO"/>
+ </category>
+
+ <category name="com.cloud.agent.metrics">
+ <priority value="INFO"/>
+ </category>
+
+ <category name="com.cloud.agent.resource.computing.ComputingResource$StorageMonitorTask">
+ <priority value="INFO"/>
+ </category>
+
+ <!-- Limit the org.apache category to INFO as its DEBUG is verbose -->
+ <category name="org.apache">
+ <priority value="INFO"/>
+ </category>
+
+ <category name="org">
+ <priority value="INFO"/>
+ </category>
+
+ <category name="net">
+ <priority value="INFO"/>
+ </category>
+
+ <!-- ======================= -->
+ <!-- Setup the Root category -->
+ <!-- ======================= -->
+
+ <root>
+ <level value="INFO"/>
+ <appender-ref ref="CONSOLE"/>
+ <appender-ref ref="FILE"/>
+ </root>
+
+</log4j:configuration>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/conf/log4j.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/conf/log4j.xml b/plugins/hypervisors/hyperv/conf/log4j.xml
new file mode 100644
index 0000000..1e97ce9
--- /dev/null
+++ b/plugins/hypervisors/hyperv/conf/log4j.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+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.
+-->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+
+ <!-- ================================= -->
+ <!-- Preserve messages in a local file -->
+ <!-- ================================= -->
+
+ <!-- A time/date based rolling appender -->
+ <appender name="FILE" class="org.apache.log4j.rolling.RollingFileAppender">
+ <param name="Append" value="true"/>
+ <param name="Threshold" value="TRACE"/>
+ <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy">
+ <param name="FileNamePattern" value="log/@AGENTLOG@.%d{yyyy-MM-dd}.gz"/>
+ <param name="ActiveFileName" value="log/@AGENTLOG@"/>
+ </rollingPolicy>
+ <layout class="org.apache.log4j.EnhancedPatternLayout">
+ <param name="ConversionPattern" value="%d{ISO8601} %-5p [%c{3}] (%t:%x) %m%n"/>
+ </layout>
+ </appender>
+
+ <!-- ============================== -->
+ <!-- Append messages to the console -->
+ <!-- ============================== -->
+
+ <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+ <param name="Target" value="System.out"/>
+ <param name="Threshold" value="TRACE"/>
+
+ <layout class="org.apache.log4j.PatternLayout">
+ <param name="ConversionPattern" value="%d{ISO8601}{GMT} %-5p [%c{3}] (%t:%x) %m%n"/>
+ </layout>
+ </appender>
+
+ <!-- ================ -->
+ <!-- Limit categories -->
+ <!-- ================ -->
+
+ <category name="com.cloud">
+ <priority value="TRACE"/>
+ </category>
+
+ <category name="com.cloud.agent.metrics">
+ <priority value="TRACE"/>
+ </category>
+
+ <category name="com.cloud.agent.resource.computing.ComputingResource$StorageMonitorTask">
+ <priority value="TRACE"/>
+ </category>
+
+ <!-- Limit the org.apache category to TRACE as its DEBUG is verbose -->
+ <category name="org.apache">
+ <priority value="TRACE"/>
+ </category>
+
+ <category name="org">
+ <priority value="TRACE"/>
+ </category>
+
+ <category name="net">
+ <priority value="TRACE"/>
+ </category>
+
+ <!-- ======================= -->
+ <!-- Setup the Root category -->
+ <!-- ======================= -->
+
+ <root>
+ <level value="TRACE"/>
+ <appender-ref ref="CONSOLE"/>
+ <appender-ref ref="FILE"/>
+ </root>
+
+</log4j:configuration>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/pom.xml b/plugins/hypervisors/hyperv/pom.xml
new file mode 100644
index 0000000..e9f0371
--- /dev/null
+++ b/plugins/hypervisors/hyperv/pom.xml
@@ -0,0 +1,158 @@
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>cloud-plugin-hypervisor-hyperv</artifactId>
+ <name>Apache CloudStack Plugin - Hypervisor Hyper-V</name>
+ <parent>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloudstack-plugins</artifactId>
+ <version>4.3.0-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <properties>
+ <skipTests>true</skipTests>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-agent</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty</artifactId>
+ <version>6.1.26</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-utils</artifactId>
+ <version>${project.version}</version>
+ <classifier>tests</classifier>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <defaultGoal>install</defaultGoal>
+ <sourceDirectory>src</sourceDirectory>
+ <testSourceDirectory>test</testSourceDirectory>
+ <resources>
+ <resource>
+ <directory>conf</directory>
+ </resource>
+ </resources>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ <configuration>
+ <executable>java</executable>
+ <mainClass>com.cloud.agent.AgentShell</mainClass>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.12</version>
+ <configuration>
+ <!-- Exclude tests that require an agent, they appear under a different profile -->
+ <excludes>
+ <exclude>**/HypervDirectConnectResourceTest.*</exclude>
+ </excludes>
+ <includes>
+ <include>none</include>
+ </includes>
+ <skipTests>${skipTests}</skipTests>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <!-- Hyper-V plugin is built using mono -->
+ <profile>
+ <id>hyperv-agent</id>
+ <activation>
+ <property>
+ <name>hyperv-agent</name>
+ </property>
+ </activation>
+<!-- <dependencies>
+ <dependency>
+ <groupId>org.apache.cloudstack</groupId>
+ <artifactId>cloud-plugin-hypervisor-hyperv</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ </dependencies> -->
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <executable>bash</executable>
+ <arguments>
+ <argument>./buildagent.sh</argument>
+ </arguments>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.12</version>
+ <configuration>
+ <excludes>
+ <exclude>none</exclude>
+ </excludes>
+ <includes>
+ <include>**/HypervDirectConnectResourceTest.java</include>
+ </includes>
+ <skipTests>${skipTests}</skipTests>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/scripts/dev_extra_setup.sh
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/scripts/dev_extra_setup.sh b/plugins/hypervisors/hyperv/scripts/dev_extra_setup.sh
new file mode 100644
index 0000000..aa77c4b
--- /dev/null
+++ b/plugins/hypervisors/hyperv/scripts/dev_extra_setup.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+mvn -P developer -pl developer -Ddeploydb
+cp client/target/cloud-client-ui-4.2.0-SNAPSHOT/WEB-INF/classes/log4j{-cloud,}.xml
+mysql --user=root --password="" cloud -e "update configuration set value='false' where name='developer';"
+mysql --user=root --password="" cloud -e "INSERT INTO configuration (instance, name,value) VALUE('DEFAULT','system.vm.use.local.storage', 'true');"
+update template_view set url='http://10.70.176.29/pub/systemvmtemplate-2013-07-04-master-hyperv.vhd' where name='SystemVM Template (HyperV)';
+export MAVEN_OPTS="-XX:MaxPermSize=256m -Xmx1g"
+mvn -pl :cloud-client-ui jetty:run
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java
new file mode 100644
index 0000000..11df222
--- /dev/null
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/discoverer/HypervServerDiscoverer.java
@@ -0,0 +1,467 @@
+// 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.discoverer;
+
+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.inject.Inject;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.Listener;
+import com.cloud.agent.api.AgentControlAnswer;
+import com.cloud.agent.api.AgentControlCommand;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ReadyCommand;
+import com.cloud.agent.api.SetupAnswer;
+import com.cloud.agent.api.SetupCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupRoutingCommand;
+import com.cloud.alert.AlertManager;
+import com.cloud.dc.ClusterDetailsDao;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.exception.AgentUnavailableException;
+import com.cloud.exception.ConnectionException;
+import com.cloud.exception.DiscoveryException;
+import com.cloud.exception.OperationTimedoutException;
+import com.cloud.host.Host;
+import com.cloud.host.HostEnvironment;
+import com.cloud.host.HostVO;
+import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.hypervisor.hyperv.resource.HypervDirectConnectResource;
+import com.cloud.resource.Discoverer;
+import com.cloud.resource.DiscovererBase;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ResourceStateAdapter;
+import com.cloud.resource.ServerResource;
+import com.cloud.resource.UnableDeleteHostException;
+
+/**
+ * Methods to discover and managem a Hyper-V agent. Prepares a
+ * HypervDirectConnectResource corresponding to the agent on a Hyper-V
+ * hypervisor and manages its lifecycle.
+ */
+@Local(value = Discoverer.class)
+public class HypervServerDiscoverer extends DiscovererBase implements
+ Discoverer, Listener, ResourceStateAdapter {
+ private static final Logger s_logger = Logger
+ .getLogger(HypervServerDiscoverer.class);
+
+ @Inject
+ private HostDao _hostDao = null;
+ @Inject
+ private ClusterDao _clusterDao;
+ @Inject
+ private ClusterDetailsDao _clusterDetailsDao;
+ @Inject
+ private ResourceManager _resourceMgr;
+ @Inject
+ private HostPodDao _podDao;
+ @Inject
+ private DataCenterDao _dcDao;
+
+ // TODO: AgentManager and AlertManager not being used to transmit info,
+ // may want to reconsider.
+ @Inject
+ private AgentManager _agentMgr;
+ @Inject
+ private AlertManager _alertMgr;
+
+ // Listener interface methods
+
+ @Override
+ public final boolean processAnswers(final long agentId, final long seq,
+ final Answer[] answers) {
+ return false;
+ }
+
+ @Override
+ public final boolean processCommands(final long agentId, final long seq,
+ final Command[] commands) {
+ return false;
+ }
+
+ @Override
+ public final AgentControlAnswer processControlCommand(final long agentId,
+ final AgentControlCommand cmd) {
+ return null;
+ }
+
+ @Override
+ public final void processConnect(final Host agent,
+ final StartupCommand cmd, final boolean forRebalance)
+ throws ConnectionException {
+ // Limit the commands we can process
+ if (!(cmd instanceof StartupRoutingCommand)) {
+ return;
+ }
+
+ StartupRoutingCommand startup = (StartupRoutingCommand) cmd;
+
+ // assert
+ if (startup.getHypervisorType() != HypervisorType.Hyperv) {
+ s_logger.debug("Not Hyper-V hypervisor, so moving on.");
+ return;
+ }
+
+ long agentId = agent.getId();
+ HostVO host = _hostDao.findById(agentId);
+
+ // Our Hyper-V machines are not participating in pools, and the pool id
+ // we provide them is not persisted.
+ // This means the pool id can vary.
+ ClusterVO cluster = _clusterDao.findById(host.getClusterId());
+ if (cluster.getGuid() == null) {
+ cluster.setGuid(startup.getPool());
+ _clusterDao.update(cluster.getId(), cluster);
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Setting up host " + agentId);
+ }
+
+ HostEnvironment env = new HostEnvironment();
+ SetupCommand setup = new SetupCommand(env);
+ if (!host.isSetup()) {
+ setup.setNeedSetup(true);
+ }
+
+ try {
+ SetupAnswer answer = (SetupAnswer) _agentMgr.send(agentId, setup);
+ if (answer != null && answer.getResult()) {
+ host.setSetup(true);
+ // TODO: clean up magic numbers below
+ host.setLastPinged((System.currentTimeMillis() >> 10) - 5 * 60);
+ _hostDao.update(host.getId(), host);
+ if (answer.needReconnect()) {
+ throw new ConnectionException(false,
+ "Reinitialize agent after setup.");
+ }
+ return;
+ } else {
+ String reason = answer.getDetails();
+ if (reason == null) {
+ reason = " details were null";
+ }
+ s_logger.warn("Unable to setup agent " + agentId + " due to "
+ + reason);
+ }
+ // Error handling borrowed from XcpServerDiscoverer, may need to be
+ // updated.
+ } catch (AgentUnavailableException e) {
+ s_logger.warn("Unable to setup agent " + agentId
+ + " because it became unavailable.", e);
+ } catch (OperationTimedoutException e) {
+ s_logger.warn("Unable to setup agent " + agentId
+ + " because it timed out", e);
+ }
+ throw new ConnectionException(true, "Reinitialize agent after setup.");
+ }
+
+ @Override
+ public final boolean processDisconnect(final long agentId,
+ final Status state) {
+ return false;
+ }
+
+ @Override
+ public final boolean isRecurring() {
+ return false;
+ }
+
+ @Override
+ public final int getTimeout() {
+ return 0;
+ }
+
+ @Override
+ public final boolean processTimeout(final long agentId, final long seq) {
+ return false;
+ }
+
+ // End Listener implementation
+
+ // Returns server component used by server manager to operate the plugin.
+ // Server component is a ServerResource. If a connected agent is used, the
+ // ServerResource is
+ // ignored in favour of another created in response to
+ @Override
+ public final Map<? extends ServerResource, Map<String, String>> find(
+ final long dcId, final Long podId, final Long clusterId,
+ final URI uri, final String username, final String password,
+ final List<String> hostTags) throws DiscoveryException {
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Discover host. dc(zone): " + dcId + ", pod: "
+ + podId + ", cluster: " + clusterId + ", uri host: "
+ + uri.getHost());
+ }
+
+ // Assertions
+ if (podId == null) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("No pod is assigned, skipping the discovery in"
+ + " Hyperv discoverer");
+ }
+ return null;
+ }
+ ClusterVO cluster = _clusterDao.findById(clusterId); // ClusterVO exists
+ // in the
+ // database
+ if (cluster == null) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("No cluster in database for cluster id "
+ + clusterId);
+ }
+ return null;
+ }
+ if (cluster.getHypervisorType() != HypervisorType.Hyperv) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Cluster " + clusterId
+ + "is not for Hyperv hypervisors");
+ }
+ return null;
+ }
+ 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;
+ }
+
+ try {
+ String hostname = uri.getHost();
+ InetAddress ia = InetAddress.getByName(hostname);
+ String agentIp = ia.getHostAddress();
+ String uuidSeed = agentIp;
+ String guidWithTail = calcServerResourceGuid(uuidSeed)
+ + "-HypervResource";
+
+ if (_resourceMgr.findHostByGuid(guidWithTail) != null) {
+ s_logger.debug("Skipping " + agentIp + " because "
+ + guidWithTail + " is already in the database.");
+ return null;
+ }
+
+ s_logger.info("Creating"
+ + HypervDirectConnectResource.class.getName()
+ + " HypervDummyResourceBase for zone/pod/cluster " + dcId
+ + "/" + podId + "/" + clusterId);
+
+ // Some Hypervisors organise themselves in pools.
+ // The startup command tells us what pool they are using.
+ // In the meantime, we have to place a GUID corresponding to the
+ // pool in the database
+ // This GUID may change.
+ if (cluster.getGuid() == null) {
+ cluster.setGuid(UUID.nameUUIDFromBytes(
+ String.valueOf(clusterId).getBytes()).toString());
+ _clusterDao.update(clusterId, cluster);
+ }
+
+ // Settings required by all server resources managing a hypervisor
+ Map<String, Object> params = new HashMap<String, Object>();
+ params.put("zone", Long.toString(dcId));
+ params.put("pod", Long.toString(podId));
+ params.put("cluster", Long.toString(clusterId));
+ params.put("guid", guidWithTail);
+ params.put("ipaddress", agentIp);
+
+ // Hyper-V specific settings
+ Map<String, String> details = new HashMap<String, String>();
+ details.put("url", uri.getHost());
+ details.put("username", username);
+ details.put("password", password);
+ details.put("cluster.guid", cluster.getGuid());
+
+ params.putAll(details);
+
+ HypervDirectConnectResource resource =
+ new HypervDirectConnectResource();
+ resource.configure(agentIp, params);
+
+ // Assert
+ // TODO: test by using bogus URL and bogus virtual path in URL
+ ReadyCommand ping = new ReadyCommand();
+ Answer pingAns = resource.executeRequest(ping);
+ if (pingAns == null || !pingAns.getResult()) {
+ String errMsg =
+ "Agent not running, or no route to agent on at "
+ + uri;
+ s_logger.debug(errMsg);
+ throw new DiscoveryException(errMsg);
+ }
+
+ Map<HypervDirectConnectResource, Map<String, String>> resources =
+ new HashMap<HypervDirectConnectResource,
+ Map<String, String>>();
+ resources.put(resource, details);
+
+ // TODO: does the resource have to create a connection?
+ return resources;
+ } catch (ConfigurationException e) {
+ _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId,
+ "Unable to add " + uri.getHost(),
+ "Error is " + e.getMessage());
+ s_logger.warn("Unable to instantiate " + uri.getHost(), e);
+ } catch (UnknownHostException e) {
+ _alertMgr.sendAlert(AlertManager.ALERT_TYPE_HOST, dcId, podId,
+ "Unable to add " + uri.getHost(),
+ "Error is " + e.getMessage());
+ s_logger.warn("Unable to instantiate " + uri.getHost(), e);
+ } catch (Exception e) {
+ String msg = " can't setup agent, due to " + e.toString() + " - "
+ + e.getMessage();
+ s_logger.warn(msg);
+ }
+ return null;
+ }
+
+ /**
+ * Encapsulate GUID calculation in public method to allow access to test
+ * programs. Works by converting a string to a GUID using
+ * UUID.nameUUIDFromBytes
+ *
+ * @param uuidSeed
+ * string to use to generate GUID
+ *
+ * @return GUID in form of a string.
+ */
+ public static String calcServerResourceGuid(final String uuidSeed) {
+ String guid = UUID.nameUUIDFromBytes(uuidSeed.getBytes()).toString();
+ return guid;
+ }
+
+ // Adapter implementation: (facilitates plug in loading)
+ // Required because Discoverer extends Adapter
+ // Overrides Adapter.configure to always return true
+ // Inherit Adapter.getName
+ // Inherit Adapter.stop
+ // Inherit Adapter.start
+ @Override
+ public final boolean configure(final String name,
+ final Map<String, Object> params) throws ConfigurationException {
+ super.configure(name, params);
+
+ // TODO: allow timeout on we HTTPRequests to be configured
+ _agentMgr.registerForHostEvents(this, true, false, true);
+ _resourceMgr.registerResourceStateAdapter(this.getClass()
+ .getSimpleName(), this);
+ return true;
+ }
+
+ // end of Adapter
+
+ @Override
+ public void postDiscovery(final List<HostVO> hosts, final long msId)
+ throws DiscoveryException {
+ }
+
+ @Override
+ public final Hypervisor.HypervisorType getHypervisorType() {
+ return Hypervisor.HypervisorType.Hyperv;
+ }
+
+ // TODO: verify that it is okay to return true on null hypervisor
+ @Override
+ public final boolean matchHypervisor(final String hypervisor) {
+ if (hypervisor == null) {
+ return true;
+ }
+ return Hypervisor.HypervisorType.Hyperv.toString().equalsIgnoreCase(
+ hypervisor);
+ }
+
+ // end of Discoverer
+
+ // ResourceStateAdapter
+ @Override
+ public final HostVO createHostVOForConnectedAgent(final HostVO host,
+ final StartupCommand[] cmd) {
+ return null;
+ }
+
+ // TODO: add test for method
+ @Override
+ public final HostVO createHostVOForDirectConnectAgent(final HostVO host,
+ final StartupCommand[] startup, final ServerResource resource,
+ final Map<String, String> details, final List<String> hostTags) {
+ StartupCommand firstCmd = startup[0];
+ if (!(firstCmd instanceof StartupRoutingCommand)) {
+ return null;
+ }
+
+ StartupRoutingCommand ssCmd = ((StartupRoutingCommand) firstCmd);
+ if (ssCmd.getHypervisorType() != HypervisorType.Hyperv) {
+ return null;
+ }
+
+ s_logger.info("Host: " + host.getName()
+ + " connected with hypervisor type: " + HypervisorType.Hyperv
+ + ". Checking CIDR...");
+
+ HostPodVO pod = _podDao.findById(host.getPodId());
+ DataCenterVO dc = _dcDao.findById(host.getDataCenterId());
+
+ _resourceMgr.checkCIDR(pod, dc, ssCmd.getPrivateIpAddress(),
+ ssCmd.getPrivateNetmask());
+
+ return _resourceMgr.fillRoutingHostVO(host, ssCmd,
+ HypervisorType.Hyperv, details, hostTags);
+ }
+
+ // TODO: add test for method
+ @Override
+ public final DeleteHostAnswer deleteHost(final HostVO host,
+ final boolean isForced, final boolean isForceDeleteStorage)
+ throws UnableDeleteHostException {
+ // assert
+ if (host.getType() != Host.Type.Routing
+ || host.getHypervisorType() != HypervisorType.Hyperv) {
+ return null;
+ }
+ _resourceMgr.deleteRoutingHost(host, isForced, isForceDeleteStorage);
+ return new DeleteHostAnswer(true);
+ }
+
+ @Override
+ public final boolean stop() {
+ _resourceMgr.unregisterResourceStateAdapter(this.getClass()
+ .getSimpleName());
+ return super.stop();
+ }
+ // end of ResourceStateAdapter
+
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java
new file mode 100644
index 0000000..8b79cae
--- /dev/null
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/guru/HypervGuru.java
@@ -0,0 +1,68 @@
+// 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.guru;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.hypervisor.HypervisorGuru;
+import com.cloud.hypervisor.HypervisorGuruBase;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.dao.GuestOSDao;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+
+/**
+ * Implementation of Hypervisor guru for Hyper-V.
+ **/
+@Local(value = HypervisorGuru.class)
+public class HypervGuru extends HypervisorGuruBase implements HypervisorGuru {
+
+ @Inject
+ private GuestOSDao _guestOsDao;
+
+ @Override
+ public final HypervisorType getHypervisorType() {
+ return HypervisorType.Hyperv;
+ }
+ /**
+ * Prevent direct creation.
+ */
+ protected HypervGuru() {
+ super();
+ }
+
+ @Override
+ public final VirtualMachineTO implement(
+ VirtualMachineProfile vm) {
+ VirtualMachineTO to = toVirtualMachineTO(vm);
+
+ // Determine the VM's OS description
+ GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine()
+ .getGuestOSId());
+ to.setOs(guestOS.getDisplayName());
+
+ return to;
+ }
+
+ @Override
+ public final boolean trackVmHostChange() {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/1d0a931d/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
new file mode 100644
index 0000000..e22f284
--- /dev/null
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
@@ -0,0 +1,454 @@
+// 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.resource;
+
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.PingRoutingCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupRoutingCommand;
+import com.cloud.agent.api.StartupStorageCommand;
+import com.cloud.agent.api.UnsupportedAnswer;
+import com.cloud.agent.api.StartupRoutingCommand.VmState;
+import com.cloud.host.Host.Type;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.network.Networks.RouterPrivateIpStrategy;
+import com.cloud.resource.ServerResource;
+import com.cloud.resource.ServerResourceBase;
+import com.cloud.serializer.GsonHelper;
+import com.google.gson.Gson;
+
+/**
+ * Implementation of dummy resource to be returned from discoverer.
+ **/
+
+public class HypervDirectConnectResource extends ServerResourceBase implements
+ ServerResource {
+ public static final int DEFAULT_AGENT_PORT = 8250;
+ private static final Logger s_logger = Logger
+ .getLogger(HypervDirectConnectResource.class.getName());
+
+ private static final Gson s_gson = GsonHelper.getGson();
+ private String _zoneId;
+ private String _podId;
+ private String _clusterId;
+ private String _guid;
+ private String _agentIp;
+ private int _port = DEFAULT_AGENT_PORT;
+
+ private String _clusterGuid;
+
+ // Used by initialize to assert object configured before
+ // initialize called.
+ private boolean _configureCalled = false;
+
+ private String _username;
+ private String _password;
+
+ @Override
+ public final Type getType() {
+ return Type.Routing;
+ }
+
+ @Override
+ public final StartupCommand[] initialize() {
+ // assert
+ if (!_configureCalled) {
+ String errMsg =
+ this.getClass().getName()
+ + " requires configure() be called before"
+ + " initialize()";
+ s_logger.error(errMsg);
+ }
+
+ // Create default StartupRoutingCommand, then customise
+ StartupRoutingCommand defaultStartRoutCmd =
+ new StartupRoutingCommand(0, 0, 0, 0, null,
+ Hypervisor.HypervisorType.Hyperv,
+ RouterPrivateIpStrategy.HostLocal,
+ new HashMap<String, VmState>());
+
+ // Identity within the data centre is decided by CloudStack kernel,
+ // and passed via ServerResource.configure()
+ defaultStartRoutCmd.setDataCenter(_zoneId);
+ defaultStartRoutCmd.setPod(_podId);
+ defaultStartRoutCmd.setCluster(_clusterId);
+ defaultStartRoutCmd.setGuid(_guid);
+ defaultStartRoutCmd.setName(_name);
+ defaultStartRoutCmd.setPrivateIpAddress(_agentIp);
+ defaultStartRoutCmd.setStorageIpAddress(_agentIp);
+ defaultStartRoutCmd.setPool(_clusterGuid);
+
+ s_logger.debug("Generated StartupRoutingCommand for _agentIp \""
+ + _agentIp + "\"");
+
+ // TODO: does version need to be hard coded.
+ defaultStartRoutCmd.setVersion("4.2.0");
+
+ // Specifics of the host's resource capacity and network configuration
+ // comes from the host itself. CloudStack sanity checks network
+ // configuration
+ // and uses capacity info for resource allocation.
+ Command[] startCmds =
+ requestStartupCommand(new Command[] {defaultStartRoutCmd});
+
+ // TODO: may throw, is this okay?
+ StartupRoutingCommand startCmd = (StartupRoutingCommand) startCmds[0];
+
+ // Assert that host identity is consistent with existing values.
+ if (startCmd == null) {
+ String errMsg =
+ String.format("Host %s (IP %s)"
+ + "did not return a StartupRoutingCommand",
+ _name, _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+ if (!startCmd.getDataCenter().equals(
+ defaultStartRoutCmd.getDataCenter())) {
+ String errMsg =
+ String.format(
+ "Host %s (IP %s) changed zone/data center. Was "
+ + defaultStartRoutCmd.getDataCenter()
+ + " NOW its " + startCmd.getDataCenter(),
+ _name, _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+ if (!startCmd.getPod().equals(defaultStartRoutCmd.getPod())) {
+ String errMsg =
+ String.format("Host %s (IP %s) changed pod. Was "
+ + defaultStartRoutCmd.getPod() + " NOW its "
+ + startCmd.getPod(), _name, _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+ if (!startCmd.getCluster().equals(defaultStartRoutCmd.getCluster())) {
+ String errMsg =
+ String.format("Host %s (IP %s) changed cluster. Was "
+ + defaultStartRoutCmd.getCluster() + " NOW its "
+ + startCmd.getCluster(), _name, _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+ if (!startCmd.getGuid().equals(defaultStartRoutCmd.getGuid())) {
+ String errMsg =
+ String.format("Host %s (IP %s) changed guid. Was "
+ + defaultStartRoutCmd.getGuid() + " NOW its "
+ + startCmd.getGuid(), _name, _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+ if (!startCmd.getPrivateIpAddress().equals(
+ defaultStartRoutCmd.getPrivateIpAddress())) {
+ String errMsg =
+ String.format("Host %s (IP %s) IP address. Was "
+ + defaultStartRoutCmd.getPrivateIpAddress()
+ + " NOW its " + startCmd.getPrivateIpAddress(),
+ _name, _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+ if (!startCmd.getName().equals(defaultStartRoutCmd.getName())) {
+ String errMsg =
+ String.format(
+ "Host %s (IP %s) name. Was " + startCmd.getName()
+ + " NOW its "
+ + defaultStartRoutCmd.getName(), _name,
+ _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+
+ // Host will also supply details of an existing StoragePool if it has
+ // been configured with one.
+ //
+ // NB: if the host was configured
+ // with a local storage pool, CloudStack may not be able to use it
+ // unless
+ // it is has service offerings configured to recognise this storage
+ // type.
+ StartupStorageCommand storePoolCmd = null;
+ if (startCmds.length > 1) {
+ storePoolCmd = (StartupStorageCommand) startCmds[1];
+ // TODO: is this assertion required?
+ if (storePoolCmd == null) {
+ String frmtStr =
+ "Host %s (IP %s) sent incorrect Command, "
+ + "second parameter should be a "
+ + "StartupStorageCommand";
+ String errMsg = String.format(frmtStr, _name, _agentIp);
+ s_logger.error(errMsg);
+ // TODO: valid to return null, or should we throw?
+ return null;
+ }
+ s_logger.info("Host " + _name + " (IP " + _agentIp
+ + ") already configured with a storeage pool, details "
+ + s_gson.toJson(startCmds[1]));
+ } else {
+ s_logger.info("Host " + _name + " (IP " + _agentIp
+ + ") already configured with a storeage pool, details ");
+ }
+ return new StartupCommand[] {startCmd, storePoolCmd};
+ }
+
+ @Override
+ public final PingCommand getCurrentStatus(final long id) {
+ PingCommand pingCmd = new PingRoutingCommand(getType(), id, null);
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Ping host " + _name + " (IP " + _agentIp + ")");
+ }
+
+ Answer pingAns = this.executeRequest(pingCmd);
+
+ if (pingAns == null || !pingAns.getResult()) {
+ s_logger.info("Cannot ping host " + _name + " (IP " + _agentIp
+ + "), pingAns (blank means null) is:" + pingAns);
+ return null;
+ }
+ return pingCmd;
+ }
+
+ // TODO: Is it valid to return NULL, or should we throw on error?
+ // Returns StartupCommand with fields revised with values known only to the
+ // host
+ public final Command[] requestStartupCommand(final Command[] cmd) {
+ // Set HTTP POST destination URI
+ // Using java.net.URI, see
+ // http://docs.oracle.com/javase/1.5.0/docs/api/java/net/URI.html
+ URI agentUri = null;
+ try {
+ String cmdName = StartupCommand.class.getName();
+ agentUri =
+ new URI("http", null, _agentIp, _port,
+ "/api/HypervResource/" + cmdName, null, null);
+ } catch (URISyntaxException e) {
+ // TODO add proper logging
+ String errMsg = "Could not generate URI for Hyper-V agent";
+ s_logger.error(errMsg, e);
+ return null;
+ }
+ String incomingCmd = postHttpRequest(s_gson.toJson(cmd), agentUri);
+
+ if (incomingCmd == null) {
+ return null;
+ }
+ Command[] result = null;
+ try {
+ result = s_gson.fromJson(incomingCmd, Command[].class);
+ } catch (Exception ex) {
+ String errMsg = "Failed to deserialize Command[] " + incomingCmd;
+ s_logger.error(errMsg, ex);
+ }
+ s_logger.debug("requestStartupCommand received response "
+ + s_gson.toJson(result));
+ if (result.length > 0) {
+ return result;
+ }
+ return null;
+ }
+
+ // TODO: Is it valid to return NULL, or should we throw on error?
+ @Override
+ public final Answer executeRequest(final Command cmd) {
+ // Set HTTP POST destination URI
+ // Using java.net.URI, see
+ // http://docs.oracle.com/javase/1.5.0/docs/api/java/net/URI.html
+ URI agentUri = null;
+ try {
+ String cmdName = cmd.getClass().getName();
+ agentUri =
+ new URI("http", null, _agentIp, _port,
+ "/api/HypervResource/" + cmdName, null, null);
+ } catch (URISyntaxException e) {
+ // TODO add proper logging
+ String errMsg = "Could not generate URI for Hyper-V agent";
+ s_logger.error(errMsg, e);
+ return null;
+ }
+ String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri);
+
+ if (ansStr == null) {
+ return null;
+ }
+ // Only Answer instances are returned by remote agents.
+ // E.g. see Response.getAnswers()
+ Answer[] result = s_gson.fromJson(ansStr, Answer[].class);
+ s_logger.debug("executeRequest received response "
+ + s_gson.toJson(result));
+ if (result.length > 0) {
+ return result[0];
+ }
+ return null;
+ }
+
+ public static String postHttpRequest(final String jsonCmd,
+ final URI agentUri) {
+ // Using Apache's HttpClient for HTTP POST
+ // Java-only approach discussed at on StackOverflow concludes with
+ // comment to use Apache HttpClient
+ // http://stackoverflow.com/a/2793153/939250, but final comment is to
+ // use Apache.
+ s_logger.debug("POST request to" + agentUri.toString()
+ + " with contents" + jsonCmd);
+
+ // Create request
+ HttpClient httpClient = new DefaultHttpClient();
+ String result = null;
+
+ // TODO: are there timeout settings and worker thread settings to tweak?
+ try {
+ HttpPost request = new HttpPost(agentUri);
+
+ // JSON encode command
+ // Assumes command sits comfortably in a string, i.e. not used for
+ // large data transfers
+ StringEntity cmdJson = new StringEntity(jsonCmd);
+ request.addHeader("content-type", "application/json");
+ request.setEntity(cmdJson);
+ s_logger.debug("Sending cmd to " + agentUri.toString()
+ + " cmd data:" + jsonCmd);
+ HttpResponse response = httpClient.execute(request);
+
+ // Unsupported commands will not route.
+ if (response.getStatusLine().getStatusCode()
+ == HttpStatus.SC_NOT_FOUND) {
+ String errMsg =
+ "Failed to send : HTTP error code : "
+ + response.getStatusLine().getStatusCode();
+ s_logger.error(errMsg);
+ String unsupportMsg =
+ "Unsupported command "
+ + agentUri.getPath()
+ + ". Are you sure you got the right type of"
+ + " server?";
+ Answer ans = new UnsupportedAnswer(null, unsupportMsg);
+ s_logger.error(ans);
+ result = s_gson.toJson(new Answer[] {ans});
+ } else if (response.getStatusLine().getStatusCode()
+ != HttpStatus.SC_OK) {
+ String errMsg =
+ "Failed send to " + agentUri.toString()
+ + " : HTTP error code : "
+ + response.getStatusLine().getStatusCode();
+ s_logger.error(errMsg);
+ return null;
+ } else {
+ result = EntityUtils.toString(response.getEntity());
+ s_logger.debug("POST response is" + result);
+ }
+ } catch (ClientProtocolException protocolEx) {
+ // Problem with HTTP message exchange
+ s_logger.error(protocolEx);
+ } catch (IOException connEx) {
+ // Problem with underlying communications
+ s_logger.error(connEx);
+ } finally {
+ httpClient.getConnectionManager().shutdown();
+ }
+ return result;
+ }
+
+ @Override
+ protected final String getDefaultScriptsDir() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ // NB: 'params' can come from one of two places.
+ // For a new host, HypervServerDiscoverer.find().
+ // For an existing host, DiscovererBase.reloadResource().
+ // In the later case, the params Map is populated with predefined keys
+ // and custom keys from the database that were passed out by the find()
+ // call.
+ // the custom keys go by the variable name 'details'.
+ // Thus, in find(), you see that 'details' are added to the params Map.
+ @Override
+ public final boolean configure(final String name,
+ final Map<String, Object> params) throws ConfigurationException {
+ /* todo: update, make consistent with the xen server equivalent. */
+ _guid = (String) params.get("guid");
+ _zoneId = (String) params.get("zone");
+ _podId = (String) params.get("pod");
+ _clusterId = (String) params.get("cluster");
+ _agentIp = (String) params.get("ipaddress"); // was agentIp
+ _name = name;
+
+ _clusterGuid = (String) params.get("cluster.guid");
+ _username = (String) params.get("url");
+ _password = (String) params.get("password");
+ _username = (String) params.get("username");
+
+ _configureCalled = true;
+ return true;
+ }
+
+ @Override
+ public void setName(final String name) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public void setConfigParams(final Map<String, Object> params) {
+ // TODO Auto-generated method stub
+ }
+
+ @Override
+ public final Map<String, Object> getConfigParams() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public final int getRunLevel() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public void setRunLevel(final int level) {
+ // TODO Auto-generated method stub
+ }
+
+}