diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index 0821c81f71a..8d841d8fd1b 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -1222,8 +1222,11 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
public void updateVolumeDiskChain(long volumeId, String path, String chainInfo) {
VolumeVO vol = _volsDao.findById(volumeId);
boolean needUpdate = false;
+ // Volume path is not getting updated in the DB, need to find reason and fix the issue.
+ if (vol.getPath() == null)
+ return;
if(!vol.getPath().equalsIgnoreCase(path))
- needUpdate = true;
+ needUpdate = true;
if(chainInfo != null && (vol.getChainInfo() == null || !chainInfo.equalsIgnoreCase(vol.getChainInfo())))
needUpdate = true;
diff --git a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs
index 9b00c828104..1b9e073e2d0 100644
--- a/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs
+++ b/plugins/hypervisors/hyperv/DotNet/ServerResource/HypervResource/WmiCalls.cs
@@ -167,6 +167,7 @@ namespace HypervResource
int memSize = vmInfo.maxRam / 1048576;
string errMsg = vmName;
var diskDrives = vmInfo.disks;
+ var bootArgs = vmInfo.bootArgs;
// assert
errMsg = vmName + ": missing disk information, array empty or missing, agent expects *at least* one disk for a VM";
@@ -283,34 +284,93 @@ namespace HypervResource
AddDiskDriveToVm(newVm, vhdFile, ideCtrllr, driveResourceType);
}
- // add nics
- foreach (var nic in nicInfo)
+ // Add the Nics to the VM in the deviceId order.
+ for (int i = 0; i <= 2; i++)
{
- string mac = nic.mac;
- string vlan = null;
- string isolationUri = nic.isolationUri;
- if (isolationUri != null && isolationUri.StartsWith("vlan://") && !isolationUri.Equals("vlan://untagged"))
+ foreach (var nic in nicInfo)
{
- vlan = isolationUri.Substring("vlan://".Length);
- int tmp;
- if (!int.TryParse(vlan, out tmp))
+
+ int nicid = nic.deviceId;
+ string mac = nic.mac;
+ string vlan = null;
+ string isolationUri = nic.isolationUri;
+ if (isolationUri != null && isolationUri.StartsWith("vlan://") && !isolationUri.Equals("vlan://untagged"))
{
- // TODO: double check exception type
- errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid);
- var ex = new WmiException(errMsg);
- logger.Error(errMsg, ex);
- throw ex;
+ vlan = isolationUri.Substring("vlan://".Length);
+ int tmp;
+ if (!int.TryParse(vlan, out tmp))
+ {
+ // TODO: double check exception type
+ errMsg = string.Format("Invalid VLAN value {0} for on vm {1} for nic uuid {2}", isolationUri, vmName, nic.uuid);
+ var ex = new WmiException(errMsg);
+ logger.Error(errMsg, ex);
+ throw ex;
+ }
+ }
+
+ if (nicid == i)
+ {
+ CreateNICforVm(newVm, mac, vlan);
+ break;
}
}
- CreateNICforVm(newVm, mac, vlan);
+ }
+
+ // pass the boot args for the VM using KVP component.
+ // We need to pass the boot args to system vm's to get them configured with cloudstack configuration.
+ // Add new user data
+ var vm = WmiCallsV2.GetComputerSystem(vmName);
+ if (bootArgs != null)
+ {
+
+ String bootargs = bootArgs;
+ WmiCallsV2.AddUserData(vm, bootargs);
+
+
+ // Get existing KVP
+ //var vmSettings = WmiCallsV2.GetVmSettings(vm);
+ //var kvpInfo = WmiCallsV2.GetKvpSettings(vmSettings);
+ //logger.DebugFormat("Boot Args presisted on the VM are ", kvpInfo);
+ //WmiCallsV2.AddUserData(vm, bootargs);
+
+ // Verify key added to subsystem
+ //kvpInfo = WmiCallsV2.GetKvpSettings(vmSettings);
+
+ // HostExchangesItems are embedded objects in the sense that the object value is stored and not a reference to the object.
+ //kvpProps = kvpInfo.HostExchangeItems;
+
+ }
+ // call patch systemvm iso only for systemvms
+ if (vmName.StartsWith("r-"))
+ {
+ patchSystemVmIso(vmName);
}
logger.DebugFormat("Starting VM {0}", vmName);
SetState(newVm, RequiredState.Enabled);
+
+ // we need to reboot to get the hv kvp daemon get started vr gets configured.
+ if (vmName.StartsWith("r-"))
+ {
+ System.Threading.Thread.Sleep(90000);
+ SetState(newVm, RequiredState.Reboot);
+ // wait for the second boot and then return with suces
+ System.Threading.Thread.Sleep(50000);
+ }
logger.InfoFormat("Started VM {0}", vmName);
return newVm;
}
+ /// this method is to add a dvd drive and attach the systemvm iso.
+ ///
+
+ public static void patchSystemVmIso(String vmName)
+ {
+ ComputerSystem vmObject = WmiCalls.GetComputerSystem(vmName);
+ AddDiskDriveToVm(vmObject, "", "1", IDE_ISO_DRIVE);
+ WmiCalls.AttachIso(vmName, "c:\\systemvm.iso");
+ }
+
///
/// Create a disk and attach it to the vm
///
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
index e22f284b6e4..6d6dc1f413d 100644
--- a/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
+++ b/plugins/hypervisors/hyperv/src/com/cloud/hypervisor/hyperv/resource/HypervDirectConnectResource.java
@@ -16,11 +16,18 @@
// under the License.
package com.cloud.hypervisor.hyperv.resource;
+import java.io.File;
import java.io.IOException;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.channels.SocketChannel;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.UUID;
import javax.naming.ConfigurationException;
@@ -35,20 +42,67 @@ import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;
import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CheckRouterAnswer;
+import com.cloud.agent.api.CheckRouterCommand;
+import com.cloud.agent.api.CheckS2SVpnConnectionsAnswer;
+import com.cloud.agent.api.CheckS2SVpnConnectionsCommand;
import com.cloud.agent.api.Command;
+import com.cloud.agent.api.GetDomRVersionAnswer;
+import com.cloud.agent.api.GetDomRVersionCmd;
+import com.cloud.agent.api.NetworkUsageAnswer;
+import com.cloud.agent.api.NetworkUsageCommand;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.PingRoutingCommand;
+import com.cloud.agent.api.PingTestCommand;
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.agent.api.check.CheckSshAnswer;
+import com.cloud.agent.api.check.CheckSshCommand;
+import com.cloud.agent.api.routing.CreateIpAliasCommand;
+import com.cloud.agent.api.routing.DeleteIpAliasCommand;
+import com.cloud.agent.api.routing.DhcpEntryCommand;
+import com.cloud.agent.api.routing.DnsMasqConfigCommand;
+import com.cloud.agent.api.routing.IpAliasTO;
+import com.cloud.agent.api.routing.IpAssocAnswer;
+import com.cloud.agent.api.routing.IpAssocCommand;
+import com.cloud.agent.api.routing.LoadBalancerConfigCommand;
+import com.cloud.agent.api.routing.NetworkElementCommand;
+import com.cloud.agent.api.routing.SavePasswordCommand;
+import com.cloud.agent.api.routing.SetFirewallRulesAnswer;
+import com.cloud.agent.api.routing.SetFirewallRulesCommand;
+import com.cloud.agent.api.routing.SetPortForwardingRulesAnswer;
+import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
+import com.cloud.agent.api.routing.SetSourceNatAnswer;
+import com.cloud.agent.api.routing.SetSourceNatCommand;
+import com.cloud.agent.api.routing.SetStaticNatRulesAnswer;
+import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
+import com.cloud.agent.api.routing.SetStaticRouteAnswer;
+import com.cloud.agent.api.routing.SetStaticRouteCommand;
+import com.cloud.agent.api.routing.Site2SiteVpnCfgCommand;
+import com.cloud.agent.api.routing.VmDataCommand;
+import com.cloud.agent.api.to.DhcpTO;
+import com.cloud.agent.api.to.FirewallRuleTO;
+import com.cloud.agent.api.to.IpAddressTO;
+import com.cloud.agent.api.to.PortForwardingRuleTO;
+import com.cloud.agent.api.to.StaticNatRuleTO;
+import com.cloud.dc.DataCenter.NetworkType;
import com.cloud.host.Host.Type;
import com.cloud.hypervisor.Hypervisor;
+import com.cloud.network.HAProxyConfigurator;
+import com.cloud.network.LoadBalancerConfigurator;
import com.cloud.network.Networks.RouterPrivateIpStrategy;
+import com.cloud.network.rules.FirewallRule;
import com.cloud.resource.ServerResource;
import com.cloud.resource.ServerResourceBase;
import com.cloud.serializer.GsonHelper;
+import com.cloud.utils.Pair;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.utils.ssh.SshHelper;
+import com.cloud.vm.VirtualMachineName;
import com.google.gson.Gson;
/**
@@ -68,6 +122,11 @@ public class HypervDirectConnectResource extends ServerResourceBase implements
private String _guid;
private String _agentIp;
private int _port = DEFAULT_AGENT_PORT;
+ protected final long _ops_timeout = 900000; // 15 minutes time out to time
+
+ protected final int _retry = 24;
+ protected final int _sleep = 10000;
+ protected final int DEFAULT_DOMR_SSHPORT = 3922;
private String _clusterGuid;
@@ -296,6 +355,8 @@ public class HypervDirectConnectResource extends ServerResourceBase implements
// Using java.net.URI, see
// http://docs.oracle.com/javase/1.5.0/docs/api/java/net/URI.html
URI agentUri = null;
+ Class extends Command> clazz = cmd.getClass();
+ Answer answer = null;
try {
String cmdName = cmd.getClass().getName();
agentUri =
@@ -307,10 +368,53 @@ public class HypervDirectConnectResource extends ServerResourceBase implements
s_logger.error(errMsg, e);
return null;
}
- String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri);
+ if (clazz == CheckSshCommand.class) {
+ answer = execute((CheckSshCommand) cmd);
+ } else if (clazz == GetDomRVersionCmd.class) {
+ answer = execute((GetDomRVersionCmd)cmd);
+ } else if (cmd instanceof NetworkUsageCommand) {
+ answer = execute((NetworkUsageCommand) cmd);
+ } else if (clazz == IpAssocCommand.class) {
+ answer = execute((IpAssocCommand) cmd);
+ } else if (clazz == DnsMasqConfigCommand.class) {
+ return execute((DnsMasqConfigCommand) cmd);
+ } else if (clazz == CreateIpAliasCommand.class) {
+ return execute((CreateIpAliasCommand) cmd);
+ } else if (clazz == DhcpEntryCommand.class) {
+ answer = execute((DhcpEntryCommand) cmd);
+ } else if (clazz == VmDataCommand.class) {
+ answer = execute((VmDataCommand) cmd);
+ } else if (clazz == SavePasswordCommand.class) {
+ answer = execute((SavePasswordCommand) cmd);
+ } else if (clazz == SetFirewallRulesCommand.class) {
+ answer = execute((SetFirewallRulesCommand)cmd);
+ } else if (clazz == LoadBalancerConfigCommand.class) {
+ answer = execute((LoadBalancerConfigCommand) cmd);
+ } else if (clazz == DeleteIpAliasCommand.class) {
+ return execute((DeleteIpAliasCommand) cmd);
+ } else if (clazz == PingTestCommand.class) {
+ answer = execute((PingTestCommand) cmd);
+ } else if (clazz == SetStaticNatRulesCommand.class) {
+ answer = execute((SetStaticNatRulesCommand) cmd);
+ } else if (clazz == CheckRouterCommand.class) {
+ answer = execute((CheckRouterCommand) cmd);
+ } else if (clazz == SetPortForwardingRulesCommand.class) {
+ answer = execute((SetPortForwardingRulesCommand) cmd);
+ } else if (clazz == SetSourceNatCommand.class) {
+ answer = execute((SetSourceNatCommand) cmd);
+ } else if (clazz == Site2SiteVpnCfgCommand.class) {
+ answer = execute((Site2SiteVpnCfgCommand) cmd);
+ } else if (clazz == CheckS2SVpnConnectionsCommand.class) {
+ answer = execute((CheckS2SVpnConnectionsCommand) cmd);
+ } else if (clazz == SetStaticRouteCommand.class) {
+ answer = execute((SetStaticRouteCommand) cmd);
+ }
+ else {
+ // Else send the cmd to hyperv agent.
+ String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri);
if (ansStr == null) {
- return null;
+ return Answer.createUnsupportedCommandAnswer(cmd);
}
// Only Answer instances are returned by remote agents.
// E.g. see Response.getAnswers()
@@ -320,9 +424,1176 @@ public class HypervDirectConnectResource extends ServerResourceBase implements
if (result.length > 0) {
return result[0];
}
+ }
+ return answer;
+ }
+
+ private SetStaticRouteAnswer execute(SetStaticRouteCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource SetStaticRouteCommand: " + s_gson.toJson(cmd));
+ }
+
+ boolean endResult = true;
+
+ String controlIp = getRouterSshControlIp(cmd);
+ String args = "";
+ String[] results = new String[cmd.getStaticRoutes().length];
+ int i = 0;
+
+ // Extract and build the arguments for the command to be sent to the VR.
+ String[][] rules = cmd.generateSRouteRules();
+ StringBuilder sb = new StringBuilder();
+ String[] srRules = rules[0];
+ for (int j = 0; j < srRules.length; j++) {
+ sb.append(srRules[j]).append(',');
+ }
+ args += " -a " + sb.toString();
+
+ // Send over the command for execution, via ssh, to the VR.
+ try {
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/opt/cloud/bin/vpc_staticroute.sh " + args);
+
+ if (s_logger.isDebugEnabled())
+ s_logger.debug("Executing script on domain router " + controlIp + ": /opt/cloud/bin/vpc_staticroute.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("SetStaticRouteCommand failure on setting one rule. args: " + args);
+ results[i++] = "Failed";
+ endResult = false;
+ } else {
+ results[i++] = null;
+ }
+ } catch (Throwable e) {
+ s_logger.error("SetStaticRouteCommand(args: " + args + ") failed on setting one rule due to " + e);
+ results[i++] = "Failed";
+ endResult = false;
+ }
+ return new SetStaticRouteAnswer(cmd, endResult, results);
+
+ }
+
+ protected CheckS2SVpnConnectionsAnswer execute(CheckS2SVpnConnectionsCommand cmd) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Executing resource CheckS2SVpnConnectionsCommand: " + s_gson.toJson(cmd));
+ s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /opt/cloud/bin/checkbatchs2svpn.sh ");
+ }
+
+ Pair result;
+ try {
+ String controlIp = getRouterSshControlIp(cmd);
+ String cmdline = "/opt/cloud/bin/checkbatchs2svpn.sh ";
+ for (String ip : cmd.getVpnIps()) {
+ cmdline += " " + ip;
+ }
+
+ result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, cmdline);
+
+ if (!result.first()) {
+ s_logger.error("check site-to-site vpn connections command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " failed, message: "
+ + result.second());
+
+ return new CheckS2SVpnConnectionsAnswer(cmd, false, result.second());
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("check site-to-site vpn connections command on domain router " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " completed");
+ }
+ } catch (Throwable e) {
+ String msg = "CheckS2SVpnConnectionsCommand failed due to " + e;
+ s_logger.error(msg, e);
+ return new CheckS2SVpnConnectionsAnswer(cmd, false, "CheckS2SVpnConneciontsCommand failed");
+ }
+ return new CheckS2SVpnConnectionsAnswer(cmd, true, result.second());
+ }
+
+ protected Answer execute(Site2SiteVpnCfgCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource Site2SiteVpnCfgCommand " + s_gson.toJson(cmd));
+ }
+
+ String routerIp = getRouterSshControlIp(cmd);
+
+ String args = "";
+ if (cmd.isCreate()) {
+ args += " -A";
+ args += " -l ";
+ args += cmd.getLocalPublicIp();
+ args += " -n ";
+ args += cmd.getLocalGuestCidr();
+ args += " -g ";
+ args += cmd.getLocalPublicGateway();
+ args += " -r ";
+ args += cmd.getPeerGatewayIp();
+ args += " -N ";
+ args += cmd.getPeerGuestCidrList();
+ args += " -e ";
+ args += "\"" + cmd.getEspPolicy() + "\"";
+ args += " -i ";
+ args += "\"" + cmd.getIkePolicy() + "\"";
+ args += " -t ";
+ args += Long.toString(cmd.getIkeLifetime());
+ args += " -T ";
+ args += Long.toString(cmd.getEspLifetime());
+ args += " -s ";
+ args += "\"" + cmd.getIpsecPsk() + "\"";
+ args += " -d ";
+ if (cmd.getDpd()) {
+ args += "1";
+ } else {
+ args += "0";
+ }
+ } else {
+ args += " -D";
+ args += " -r ";
+ args += cmd.getPeerGatewayIp();
+ args += " -n ";
+ args += cmd.getLocalGuestCidr();
+ args += " -N ";
+ args += cmd.getPeerGuestCidrList();
+ }
+
+ Pair result;
+ try {
+ result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/opt/cloud/bin/ipsectunnel.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("Setup site2site VPN " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " failed, message: " + result.second());
+
+ return new Answer(cmd, false, "Setup site2site VPN falied due to " + result.second());
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("setup site 2 site vpn on router " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " completed");
+ }
+ } catch (Throwable e) {
+ String msg = "Setup site2site VPN falied due to " + e.getMessage();
+ s_logger.error(msg, e);
+ return new Answer(cmd, false, "Setup site2site VPN failed due to " + e.getMessage());
+ }
+ return new Answer(cmd, true, result.second());
+ }
+
+ protected SetSourceNatAnswer execute(SetSourceNatCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource SetSourceNatCommand " + s_gson.toJson(cmd));
+ }
+
+ String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
+ String routerIp = getRouterSshControlIp(cmd);
+ IpAddressTO pubIp = cmd.getIpAddress();
+ try {
+ int ethDeviceNum = findRouterEthDeviceIndex(routerName, routerIp, pubIp.getVifMacAddress());
+ String args = "";
+ args += " -A ";
+ args += " -l ";
+ args += pubIp.getPublicIp();
+
+ args += " -c ";
+ args += "eth" + ethDeviceNum;
+
+ Pair result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/opt/cloud/bin/vpc_snat.sh " + args);
+
+ if (!result.first()) {
+ String msg = "SetupGuestNetworkCommand on domain router " + routerIp + " failed. message: " + result.second();
+ s_logger.error(msg);
+
+ return new SetSourceNatAnswer(cmd, false, msg);
+ }
+
+ return new SetSourceNatAnswer(cmd, true, "success");
+ } catch (Exception e) {
+ String msg = "Ip SNAT failure due to " + e.toString();
+ s_logger.error(msg, e);
+ return new SetSourceNatAnswer(cmd, false, msg);
+ }
+ }
+
+ //
+ // find mac address of a specified ethx device
+ // ip address show ethx | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2
+ // returns
+ // eth0:xx.xx.xx.xx
+
+ //
+ // list IP with eth devices
+ // ifconfig ethx |grep -B1 "inet addr" | awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }'
+ // | awk -F: '{ print $1 ": " $3 }'
+ //
+ // returns
+ // eth0:xx.xx.xx.xx
+ //
+ //
+
+ private int findRouterEthDeviceIndex(String domrName, String routerIp, String mac) throws Exception {
+
+ s_logger.info("findRouterEthDeviceIndex. mac: " + mac);
+
+ // TODO : this is a temporary very inefficient solution, will refactor it later
+ Pair result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "ls /proc/sys/net/ipv4/conf");
+
+ // when we dynamically plug in a new NIC into virtual router, it may take time to show up in guest OS
+ // we use a waiting loop here as a workaround to synchronize activities in systems
+ long startTick = System.currentTimeMillis();
+ while (System.currentTimeMillis() - startTick < 15000) {
+ if (result.first()) {
+ String[] tokens = result.second().split("\\s+");
+ for (String token : tokens) {
+ if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) {
+ String cmd = String.format("ip address show %s | grep link/ether | sed -e 's/^[ \t]*//' | cut -d' ' -f2", token);
+
+ if (s_logger.isDebugEnabled())
+ s_logger.debug("Run domr script " + cmd);
+ Pair result2 = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ // TODO need to find the dev index inside router based on IP address
+ cmd);
+ if (s_logger.isDebugEnabled())
+ s_logger.debug("result: " + result2.first() + ", output: " + result2.second());
+
+ if (result2.first() && result2.second().trim().equalsIgnoreCase(mac.trim()))
+ return Integer.parseInt(token.substring(3));
+ }
+ }
+ }
+
+ s_logger.warn("can not find intereface associated with mac: " + mac + ", guest OS may still at loading state, retry...");
+
+ try {
+ Thread.currentThread().sleep(1000);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ return -1;
+ }
+
+ protected Answer execute(SetPortForwardingRulesCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource SetPortForwardingRulesCommand: " + s_gson.toJson(cmd));
+ }
+
+ String controlIp = getRouterSshControlIp(cmd);
+ String args = "";
+ String[] results = new String[cmd.getRules().length];
+ int i = 0;
+
+ boolean endResult = true;
+ for (PortForwardingRuleTO rule : cmd.getRules()) {
+ args += rule.revoked() ? " -D " : " -A ";
+ args += " -P " + rule.getProtocol().toLowerCase();
+ args += " -l " + rule.getSrcIp();
+ args += " -p " + rule.getStringSrcPortRange();
+ args += " -r " + rule.getDstIp();
+ args += " -d " + rule.getStringDstPortRange();
+
+ try {
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/root/firewall.sh " + args);
+
+ if (s_logger.isDebugEnabled())
+ s_logger.debug("Executing script on domain router " + controlIp + ": /root/firewall.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("SetPortForwardingRulesCommand failure on setting one rule. args: " + args);
+ results[i++] = "Failed";
+ endResult = false;
+ } else {
+ results[i++] = null;
+ }
+ } catch (Throwable e) {
+ s_logger.error("SetPortForwardingRulesCommand(args: " + args + ") failed on setting one rule due to " + e.getMessage());
+ results[i++] = "Failed";
+ endResult = false;
+ }
+ }
+
+ return new SetPortForwardingRulesAnswer(cmd, results, endResult);
+ }
+
+ protected Answer execute(CheckRouterCommand cmd) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Executing resource CheckRouterCommand: " + s_gson.toJson(cmd));
+ s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /opt/cloud/bin/checkrouter.sh ");
+ }
+
+ Pair result;
+ try {
+
+ String controlIp = getRouterSshControlIp(cmd);
+ result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/opt/cloud/bin/checkrouter.sh ");
+
+ if (!result.first()) {
+ s_logger.error("check router command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " failed, message: " + result.second());
+
+ return new CheckRouterAnswer(cmd, "CheckRouter failed due to " + result.second());
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("check router command on domain router " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " completed");
+ }
+ } catch (Throwable e) {
+ String msg = "CheckRouterCommand failed due to " + e.getMessage();
+ s_logger.error(msg, e);
+ return new CheckRouterAnswer(cmd, msg);
+ }
+ return new CheckRouterAnswer(cmd, result.second(), true);
+ }
+
+ protected Answer execute(SetStaticNatRulesCommand cmd) {
+
+ if (cmd.getVpcId() != null) {
+ //return SetVPCStaticNatRules(cmd);
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource SetFirewallRuleCommand: " + s_gson.toJson(cmd));
+ }
+
+ String args = null;
+ String[] results = new String[cmd.getRules().length];
+ int i = 0;
+ boolean endResult = true;
+ for (StaticNatRuleTO rule : cmd.getRules()) {
+ // 1:1 NAT needs instanceip;publicip;domrip;op
+ args = rule.revoked() ? " -D " : " -A ";
+
+ args += " -l " + rule.getSrcIp();
+ args += " -r " + rule.getDstIp();
+
+ if (rule.getProtocol() != null) {
+ args += " -P " + rule.getProtocol().toLowerCase();
+ }
+
+ args += " -d " + rule.getStringSrcPortRange();
+ args += " -G ";
+
+ try {
+ String controlIp = getRouterSshControlIp(cmd);
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/root/firewall.sh " + args);
+
+ if (s_logger.isDebugEnabled())
+ s_logger.debug("Executing script on domain router " + controlIp + ": /root/firewall.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("SetStaticNatRulesCommand failure on setting one rule. args: " + args);
+ results[i++] = "Failed";
+ endResult = false;
+ } else {
+ results[i++] = null;
+ }
+ } catch (Throwable e) {
+ s_logger.error("SetStaticNatRulesCommand (args: " + args + ") failed on setting one rule due to " + e.getMessage());
+ results[i++] = "Failed";
+ endResult = false;
+ }
+ }
+ return new SetStaticNatRulesAnswer(cmd, results, endResult);
+ }
+
+ protected Answer execute(PingTestCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource PingTestCommand: " + s_gson.toJson(cmd));
+ }
+ String controlIp = cmd.getRouterIp();
+ String args = " -c 1 -n -q " + cmd.getPrivateIp();
+ try {
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/bin/ping" + args);
+ if (result.first())
+ return new Answer(cmd);
+ } catch (Exception e) {
+ s_logger.error("Unable to execute ping command on DomR (" + controlIp + "), domR may not be ready yet. failure due to "
+ + e.getMessage());
+ }
+ return new Answer(cmd, false, "PingTestCommand failed");
+ }
+
+ protected Answer execute(final DeleteIpAliasCommand cmd) {
+ cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
+ List revokedIpAliasTOs = cmd.getDeleteIpAliasTos();
+ List activeIpAliasTOs = cmd.getCreateIpAliasTos();
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing deleteIpAlias command: " + s_gson.toJson(cmd));
+ }
+ String args = "";
+ for (IpAliasTO ipAliasTO : revokedIpAliasTOs) {
+ args = args + ipAliasTO.getAlias_count() + ":" + ipAliasTO.getRouterip() + ":" + ipAliasTO.getNetmask() + "-";
+ }
+ args = args + "- ";
+ for (IpAliasTO ipAliasTO : activeIpAliasTOs) {
+ args = args + ipAliasTO.getAlias_count() + ":" + ipAliasTO.getRouterip() + ":" + ipAliasTO.getNetmask() + "-";
+ }
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /root/deleteIpAlias " + args);
+ }
+
+ try {
+ String controlIp = getRouterSshControlIp(cmd);
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/root/deleteIpAlias.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("deleteIpAlias command on domr " + controlIp + " failed, message: " + result.second());
+
+ return new Answer(cmd, false, "deleteIpAlias failed due to " + result.second());
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("deleteIpAlias command on domain router " + controlIp + " completed");
+ }
+
+ } catch (Throwable e) {
+ String msg = "deleteIpAlias failed due to " + e.getMessage();
+ s_logger.error(msg, e);
+ return new Answer(cmd, false, msg);
+ }
+
+ return new Answer(cmd);
+ }
+
+ protected Answer execute(final LoadBalancerConfigCommand cmd) {
+
+ if (cmd.getVpcId() != null) {
+ //return VPCLoadBalancerConfig(cmd);
+ }
+
+ File keyFile = getSystemVMKeyFile();
+
+ String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
+ String controlIp = getRouterSshControlIp(cmd);
+
+ assert (controlIp != null);
+
+ LoadBalancerConfigurator cfgtr = new HAProxyConfigurator();
+ String[] config = cfgtr.generateConfiguration(cmd);
+
+ String[][] rules = cfgtr.generateFwRules(cmd);
+ String tmpCfgFilePath = "/tmp/" + routerIp.replace('.', '_') + ".cfg";
+ String tmpCfgFileContents = "";
+ for (int i = 0; i < config.length; i++) {
+ tmpCfgFileContents += config[i];
+ tmpCfgFileContents += "\n";
+ }
+
+ try {
+ SshHelper.scpTo(controlIp, DEFAULT_DOMR_SSHPORT, "root", keyFile, null, "/tmp/", tmpCfgFileContents.getBytes(), routerIp.replace('.', '_') + ".cfg", null);
+
+ try {
+ String[] addRules = rules[LoadBalancerConfigurator.ADD];
+ String[] removeRules = rules[LoadBalancerConfigurator.REMOVE];
+ String[] statRules = rules[LoadBalancerConfigurator.STATS];
+
+ String args = "";
+ args += "-i " + routerIp;
+ args += " -f " + tmpCfgFilePath;
+
+ StringBuilder sb = new StringBuilder();
+ if (addRules.length > 0) {
+ for (int i = 0; i < addRules.length; i++) {
+ sb.append(addRules[i]).append(',');
+ }
+
+ args += " -a " + sb.toString();
+ }
+
+ sb = new StringBuilder();
+ if (removeRules.length > 0) {
+ for (int i = 0; i < removeRules.length; i++) {
+ sb.append(removeRules[i]).append(',');
+ }
+
+ args += " -d " + sb.toString();
+ }
+
+ sb = new StringBuilder();
+ if (statRules.length > 0) {
+ for (int i = 0; i < statRules.length; i++) {
+ sb.append(statRules[i]).append(',');
+ }
+
+ args += " -s " + sb.toString();
+ }
+
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "scp " + tmpCfgFilePath
+ + " /etc/haproxy/haproxy.cfg.new");
+
+ if (!result.first()) {
+ s_logger.error("Unable to copy haproxy configuration file");
+ return new Answer(cmd, false, "LoadBalancerConfigCommand failed due to uanble to copy haproxy configuration file");
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run command on domain router " + routerIp + ", /root/loadbalancer.sh " + args);
+ }
+
+ result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/root/loadbalancer.sh " + args);
+
+ if (!result.first()) {
+ String msg = "LoadBalancerConfigCommand on domain router " + routerIp + " failed. message: " + result.second();
+ s_logger.error(msg);
+
+ return new Answer(cmd, false, msg);
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("LoadBalancerConfigCommand on domain router " + routerIp + " completed");
+ }
+ } finally {
+ SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "rm " + tmpCfgFilePath);
+ }
+
+ return new Answer(cmd);
+ } catch (Throwable e) {
+ s_logger.error("Unexpected exception: " + e.toString(), e);
+ return new Answer(cmd, false, "LoadBalancerConfigCommand failed due to " + e.getMessage());
+ }
+ }
+
+ protected Answer execute(SavePasswordCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+
+ s_logger.info("Executing resource SavePasswordCommand. vmName: " + cmd.getVmName() + ", vmIp: " + cmd.getVmIpAddress() + ", password: "
+ + StringUtils.getMaskedPasswordForDisplay(cmd.getPassword()));
+ }
+
+ String controlIp = getRouterSshControlIp(cmd);
+ final String password = cmd.getPassword();
+ final String vmIpAddress = cmd.getVmIpAddress();
+
+ // Run save_password_to_domr.sh
+ String args = " -v " + vmIpAddress;
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run command on domain router " + controlIp + ", /root/savepassword.sh " + args + " -p " + StringUtils.getMaskedPasswordForDisplay(cmd.getPassword()));
+ }
+
+ args += " -p " + password;
+
+ try {
+
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/root/savepassword.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("savepassword command on domain router " + controlIp + " failed, message: " + result.second());
+
+ return new Answer(cmd, false, "SavePassword failed due to " + result.second());
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("savepassword command on domain router " + controlIp + " completed");
+ }
+
+ } catch (Throwable e) {
+ String msg = "SavePasswordCommand failed due to " + e;
+ s_logger.error(msg, e);
+ return new Answer(cmd, false, msg);
+ }
+ return new Answer(cmd);
+ }
+
+ protected SetFirewallRulesAnswer execute(SetFirewallRulesCommand cmd) {
+ String controlIp = getRouterSshControlIp(cmd);
+ String[] results = new String[cmd.getRules().length];
+ FirewallRuleTO[] allrules = cmd.getRules();
+ FirewallRule.TrafficType trafficType = allrules[0].getTrafficType();
+ String egressDefault = cmd.getAccessDetail(NetworkElementCommand.FIREWALL_EGRESS_DEFAULT);
+
+ String[][] rules = cmd.generateFwRules();
+ String args = "";
+ args += " -F ";
+ if (trafficType == FirewallRule.TrafficType.Egress){
+ args+= " -E ";
+ if (egressDefault.equals("true")) {
+ args+= " -P 1 ";
+ } else if (egressDefault.equals("System")) {
+ args+= " -P 2 ";
+ } else {
+ args+= " -P 0 ";
+ }
+ }
+
+ StringBuilder sb = new StringBuilder();
+ String[] fwRules = rules[0];
+ if (fwRules.length > 0) {
+ for (int i = 0; i < fwRules.length; i++) {
+ sb.append(fwRules[i]).append(',');
+ }
+ args += " -a " + sb.toString();
+ }
+
+ try {
+ Pair result = null;
+
+ if (trafficType == FirewallRule.TrafficType.Egress){
+ result = SshHelper.sshExecute(controlIp,
+ DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(),
+ null, "/root/firewallRule_egress.sh " + args);
+ } else {
+ result = SshHelper.sshExecute(controlIp,
+ DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(),
+ null, "/root/firewall_rule.sh " + args);
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ if (trafficType == FirewallRule.TrafficType.Egress){
+ s_logger.debug("Executing script on domain router " + controlIp
+ + ": /root/firewallRule_egress.sh " + args);
+ } else {
+ s_logger.debug("Executing script on domain router " + controlIp
+ + ": /root/firewall_rule.sh " + args);
+ }
+ }
+
+
+ if (!result.first()) {
+ s_logger.error("SetFirewallRulesCommand failure on setting one rule. args: "
+ + args);
+ //FIXME - in the future we have to process each rule separately; now we temporarily set every rule to be false if single rule fails
+ for (int i=0; i < results.length; i++) {
+ results[i] = "Failed";
+ }
+
+ return new SetFirewallRulesAnswer(cmd, false, results);
+ }
+ } catch (Throwable e) {
+ s_logger.error("SetFirewallRulesCommand(args: " + args
+ + ") failed on setting one rule due to "
+ ,e);
+ //FIXME - in the future we have to process each rule separately; now we temporarily set every rule to be false if single rule fails
+ for (int i=0; i < results.length; i++) {
+ results[i] = "Failed";
+ }
+ return new SetFirewallRulesAnswer(cmd, false, results);
+ }
+
+ return new SetFirewallRulesAnswer(cmd, true, results);
+ }
+
+
+ protected Answer execute(VmDataCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource VmDataCommand: " + s_gson.toJson(cmd));
+ }
+
+ String routerPrivateIpAddress = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
+ String controlIp = getRouterSshControlIp(cmd);
+
+ String vmIpAddress = cmd.getVmIpAddress();
+ List vmData = cmd.getVmData();
+ String[] vmDataArgs = new String[vmData.size() * 2 + 4];
+ vmDataArgs[0] = "routerIP";
+ vmDataArgs[1] = routerPrivateIpAddress;
+ vmDataArgs[2] = "vmIP";
+ vmDataArgs[3] = vmIpAddress;
+ int i = 4;
+ for (String[] vmDataEntry : vmData) {
+ String folder = vmDataEntry[0];
+ String file = vmDataEntry[1];
+ String contents = (vmDataEntry[2] != null) ? vmDataEntry[2] : "none";
+
+ vmDataArgs[i] = folder + "," + file;
+ vmDataArgs[i + 1] = contents;
+ i += 2;
+ }
+
+ String content = encodeDataArgs(vmDataArgs);
+ String tmpFileName = UUID.randomUUID().toString();
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run vm_data command on domain router " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", data: " + content);
+ }
+
+ try {
+ SshHelper.scpTo(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/tmp", content.getBytes(), tmpFileName, null);
+
+ try {
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/root/userdata.py " + tmpFileName);
+
+ if (!result.first()) {
+ s_logger.error("vm_data command on domain router " + controlIp + " failed. messge: " + result.second());
+ return new Answer(cmd, false, "VmDataCommand failed due to " + result.second());
+ }
+ } finally {
+
+ SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "rm /tmp/" + tmpFileName);
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("vm_data command on domain router " + controlIp + " completed");
+ }
+
+ } catch (Throwable e) {
+ String msg = "VmDataCommand failed due to " + e;
+ s_logger.error(msg, e);
+ return new Answer(cmd, false, msg);
+ }
+ return new Answer(cmd);
+ }
+
+ private String encodeDataArgs(String[] dataArgs) {
+ StringBuilder sb = new StringBuilder();
+
+ for (String arg : dataArgs) {
+ sb.append(arg);
+ sb.append("\n");
+ }
+
+ return sb.toString();
+ }
+
+
+ protected Answer execute(DhcpEntryCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource DhcpEntryCommand: " + s_gson.toJson(cmd));
+ }
+
+ // ssh -p 3922 -o StrictHostKeyChecking=no -i $cert root@$domr "/root/edithosts.sh $mac $ip $vm $dfltrt $ns $staticrt" >/dev/null
+
+ String args = " -m " + cmd.getVmMac();
+ if (cmd.getVmIpAddress() != null) {
+ args += " -4 " + cmd.getVmIpAddress();
+ }
+ args += " -h " + cmd.getVmName();
+
+ if (cmd.getDefaultRouter() != null) {
+ args += " -d " + cmd.getDefaultRouter();
+ }
+
+ if (cmd.getDefaultDns() != null) {
+ args += " -n " + cmd.getDefaultDns();
+ }
+
+ if (cmd.getStaticRoutes() != null) {
+ args += " -s " + cmd.getStaticRoutes();
+ }
+
+ if (cmd.getVmIp6Address() != null) {
+ args += " -6 " + cmd.getVmIp6Address();
+ args += " -u " + cmd.getDuid();
+ }
+
+ if (!cmd.isDefault()) {
+ args += " -N";
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /root/edithosts.sh " + args);
+ }
+
+ try {
+ String controlIp = getRouterSshControlIp(cmd);
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/root/edithosts.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("dhcp_entry command on domR " + controlIp + " failed, message: " + result.second());
+
+ return new Answer(cmd, false, "DhcpEntry failed due to " + result.second());
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("dhcp_entry command on domain router " + controlIp + " completed");
+ }
+
+ } catch (Throwable e) {
+ String msg = "DhcpEntryCommand failed due to " + e;
+ s_logger.error(msg, e);
+ return new Answer(cmd, false, msg);
+ }
+
+ return new Answer(cmd);
+ }
+
+ protected Answer execute(final CreateIpAliasCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing createIpAlias command: " + s_gson.toJson(cmd));
+ }
+ cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
+ List ipAliasTOs = cmd.getIpAliasList();
+ String args="";
+ for (IpAliasTO ipaliasto : ipAliasTOs) {
+ args = args + ipaliasto.getAlias_count()+":"+ipaliasto.getRouterip()+":"+ipaliasto.getNetmask()+"-";
+ }
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /root/createIpAlias " + args);
+ }
+
+ try {
+ String controlIp = getRouterSshControlIp(cmd);
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/root/createIpAlias.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("CreateIpAlias command on domr " + controlIp + " failed, message: " + result.second());
+
+ return new Answer(cmd, false, "createipAlias failed due to " + result.second());
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("createIpAlias command on domain router " + controlIp + " completed");
+ }
+
+ } catch (Throwable e) {
+ String msg = "createIpAlias failed due to " + e;
+ s_logger.error(msg, e);
+ return new Answer(cmd, false, msg);
+ }
+
+ return new Answer(cmd);
+ }
+
+ protected Answer execute(final DnsMasqConfigCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing dnsmasqConfig command: " + s_gson.toJson(cmd));
+ }
+ String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
+ String controlIp = getRouterSshControlIp(cmd);
+
+ assert(controlIp != null);
+
+ List dhcpTos = cmd.getIps();
+ String args ="";
+ for(DhcpTO dhcpTo : dhcpTos) {
+ args = args + dhcpTo.getRouterIp()+":"+dhcpTo.getGateway()+":"+dhcpTo.getNetmask()+":"+dhcpTo.getStartIpOfSubnet()+"-";
+ }
+ //File keyFile = mgr.getSystemVMKeyFile();
+
+ try {
+ Pair result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/root/dnsmasq.sh " + args);
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run command on domain router " + routerIp + ", /root/dnsmasq.sh");
+ }
+
+ if (!result.first()) {
+ s_logger.error("Unable update dnsmasq config file");
+ return new Answer(cmd, false, "dnsmasq config update failed due to: " + result.second());
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("dnsmasq config command on domain router " + routerIp + " completed");
+ }
+ }catch (Throwable e) {
+ String msg = "Dnsmasqconfig command failed due to " + e.getMessage();
+ s_logger.error(msg, e);
+ return new Answer(cmd, false, msg);
+ }
+
+ return new Answer(cmd);
+ }
+
+ protected Answer execute(IpAssocCommand cmd) {
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource IPAssocCommand: " + s_gson.toJson(cmd));
+ }
+
+ int i = 0;
+ String[] results = new String[cmd.getIpAddresses().length];
+
+ try {
+
+ IpAddressTO[] ips = cmd.getIpAddresses();
+ String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
+ String controlIp = getRouterSshControlIp(cmd);
+ for (IpAddressTO ip : ips) {
+ assignPublicIpAddress(routerName, controlIp, ip.getPublicIp(), ip.isAdd(), ip.isFirstIP(), ip.isSourceNat(), ip.getBroadcastUri(), ip.getVlanGateway(), ip.getVlanNetmask(),ip.getVifMacAddress());
+ results[i++] = ip.getPublicIp() + " - success";
+ }
+
+ for (; i < cmd.getIpAddresses().length; i++) {
+ results[i++] = IpAssocAnswer.errorResult;
+ }
+ } catch (Throwable e) {
+ s_logger.error("Unexpected exception: " + e.toString() + " will shortcut rest of IPAssoc commands", e);
+
+ for (; i < cmd.getIpAddresses().length; i++) {
+ results[i++] = IpAssocAnswer.errorResult;
+ }
+ }
+
+ return new IpAssocAnswer(cmd, results);
+ }
+
+ protected void assignPublicIpAddress(final String vmName, final String privateIpAddress, final String publicIpAddress, final boolean add, final boolean firstIP,
+ final boolean sourceNat, final String vlanId, final String vlanGateway, final String vlanNetmask, final String vifMacAddress) throws Exception {
+
+ //String publicNeworkName = HypervisorHostHelper.getPublicNetworkNamePrefix(vlanId);
+ //Pair publicNicInfo = vmMo.getNicDeviceIndex(publicNeworkName);
+
+ if (s_logger.isDebugEnabled()) {
+ //s_logger.debug("Find public NIC index, public network name: " + publicNeworkName + ", index: " + publicNicInfo.first());
+ }
+
+ boolean addVif = false;
+ boolean removeVif = false;
+ if (add ) { // && publicNicInfo.first().intValue() == -1) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Plug new NIC to associate" + privateIpAddress + " to " + publicIpAddress);
+ }
+
+ addVif = true;
+ } else if (!add && firstIP) {
+ removeVif = true;
+
+ if (s_logger.isDebugEnabled()) {
+ //s_logger.debug("Unplug NIC " + publicNicInfo.first());
+ }
+ }
+
+/* if (addVif) {
+ plugPublicNic(vmMo, vlanId, vifMacAddress);
+ publicNicInfo = vmMo.getNicDeviceIndex(publicNeworkName);
+ if (publicNicInfo.first().intValue() >= 0) {
+ networkUsage(privateIpAddress, "addVif", "eth" + publicNicInfo.first());
+ }
+ }
+*/
+/* if (publicNicInfo.first().intValue() < 0) {
+ String msg = "Failed to find DomR VIF to associate/disassociate IP with.";
+ s_logger.error(msg);
+ throw new InternalErrorException(msg);
+ }
+*/
+ String args = null;
+
+ if (add) {
+ args = " -A ";
+ } else {
+ args = " -D ";
+ }
+
+ if (sourceNat) {
+ args += " -s ";
+ }
+ if (firstIP) {
+ args += " -f ";
+ }
+ String cidrSize = Long.toString(NetUtils.getCidrSize(vlanNetmask));
+ args += " -l ";
+ args += publicIpAddress + "/" + cidrSize;
+
+ args += " -c ";
+ args += "eth" +"2"; // currently hardcoding to eth 2 (which is default public ipd)//publicNicInfo.first();
+
+ args += " -g ";
+ args += vlanGateway;
+
+ if (addVif) {
+ args += " -n ";
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Run command on domain router " + privateIpAddress + ", /opt/cloud/bin/ipassoc.sh " + args);
+ }
+
+ Pair result = SshHelper.sshExecute(privateIpAddress, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/ipassoc.sh " + args);
+
+ if (!result.first()) {
+ s_logger.error("ipassoc command on domain router " + privateIpAddress + " failed. message: " + result.second());
+ throw new Exception("ipassoc failed due to " + result.second());
+ }
+
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("ipassoc command on domain router " + privateIpAddress + " completed");
+ }
+ }
+
+ protected Answer execute(GetDomRVersionCmd cmd) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Executing resource GetDomRVersionCmd: " + s_gson.toJson(cmd));
+ s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /opt/cloud/bin/get_template_version.sh ");
+ }
+
+ Pair result;
+ try {
+ String controlIp = getRouterSshControlIp(cmd);
+ result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null,
+ "/opt/cloud/bin/get_template_version.sh ");
+
+ if (!result.first()) {
+ s_logger.error("GetDomRVersionCmd on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " failed, message: " + result.second());
+
+ return new GetDomRVersionAnswer(cmd, "GetDomRVersionCmd failed due to " + result.second());
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("GetDomRVersionCmd on domain router " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + " completed");
+ }
+ } catch (Throwable e) {
+ String msg = "GetDomRVersionCmd failed due to " + e;
+ s_logger.error(msg, e);
+ return new GetDomRVersionAnswer(cmd, msg);
+ }
+ String[] lines = result.second().split("&");
+ if (lines.length != 2) {
+ return new GetDomRVersionAnswer(cmd, result.second());
+ }
+ return new GetDomRVersionAnswer(cmd, result.second(), lines[0], lines[1]);
+ }
+
+
+ private static String getRouterSshControlIp(NetworkElementCommand cmd) {
+ String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
+ String routerGuestIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP);
+ String zoneNetworkType = cmd.getAccessDetail(NetworkElementCommand.ZONE_NETWORK_TYPE);
+
+ if(routerGuestIp != null && zoneNetworkType != null && NetworkType.valueOf(zoneNetworkType) == NetworkType.Basic) {
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("In Basic zone mode, use router's guest IP for SSH control. guest IP : " + routerGuestIp);
+
+ return routerGuestIp;
+ }
+
+ if(s_logger.isDebugEnabled())
+ s_logger.debug("Use router's private IP for SSH control. IP : " + routerIp);
+ return routerIp;
+ }
+
+ protected Answer execute(NetworkUsageCommand cmd) {
+ if ( cmd.isForVpc() ) {
+ //return VPCNetworkUsage(cmd);
+ }
+ if (s_logger.isInfoEnabled()) {
+ s_logger.info("Executing resource NetworkUsageCommand "+ s_gson.toJson(cmd));
+ }
+ if(cmd.getOption()!=null && cmd.getOption().equals("create") ){
+ String result = networkUsage(cmd.getPrivateIP(), "create", null);
+ NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, "true", 0L, 0L);
+ return answer;
+ }
+ long[] stats = getNetworkStats(cmd.getPrivateIP());
+
+ NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, "", stats[0], stats[1]);
+ return answer;
+ }
+ private long[] getNetworkStats(String privateIP) {
+ String result = networkUsage(privateIP, "get", null);
+ long[] stats = new long[2];
+ if (result != null) {
+ try {
+ String[] splitResult = result.split(":");
+ int i = 0;
+ while (i < splitResult.length - 1) {
+ stats[0] += (new Long(splitResult[i++])).longValue();
+ stats[1] += (new Long(splitResult[i++])).longValue();
+ }
+ } catch (Throwable e) {
+ s_logger.warn("Unable to parse return from script return of network usage command: " + e.toString(), e);
+ }
+ }
+ return stats;
+ }
+
+
+ protected CheckSshAnswer execute(CheckSshCommand cmd) {
+ String vmName = cmd.getName();
+ String privateIp = cmd.getIp();
+ int cmdPort = cmd.getPort();
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Ping command port, " + privateIp + ":" + cmdPort);
+ }
+
+ try {
+ String result = connect(cmd.getName(), privateIp, cmdPort);
+ if (result != null) {
+ s_logger.error("Can not ping System vm " + vmName + "due to:" + result);
+ return new CheckSshAnswer(cmd, "Can not ping System vm " + vmName + "due to:" + result);
+ }
+ } catch (Exception e) {
+ s_logger.error("Can not ping System vm " + vmName + "due to exception");
+ return new CheckSshAnswer(cmd, e);
+ }
+
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Ping command port succeeded for vm " + vmName);
+ }
+
+ if (VirtualMachineName.isValidRouterName(vmName)) {
+ if (s_logger.isDebugEnabled()) {
+ s_logger.debug("Execute network usage setup command on " + vmName);
+ }
+ networkUsage(privateIp, "create", null);
+ }
+
+ return new CheckSshAnswer(cmd);
+ }
+
+
+ protected String networkUsage(final String privateIpAddress, final String option, final String ethName) {
+ String args = null;
+ if (option.equals("get")) {
+ args = "-g";
+ } else if (option.equals("create")) {
+ args = "-c";
+ } else if (option.equals("reset")) {
+ args = "-r";
+ } else if (option.equals("addVif")) {
+ args = "-a";
+ args += ethName;
+ } else if (option.equals("deleteVif")) {
+ args = "-d";
+ args += ethName;
+ }
+
+ try {
+ if (s_logger.isTraceEnabled()) {
+ s_logger.trace("Executing /opt/cloud/bin/netusage.sh " + args + " on DomR " + privateIpAddress);
+ }
+
+ Pair result = SshHelper.sshExecute(privateIpAddress, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/netusage.sh " + args);
+
+ if (!result.first()) {
+ return null;
+ }
+
+ return result.second();
+ } catch (Throwable e) {
+ s_logger.error("Unable to execute NetworkUsage command on DomR (" + privateIpAddress + "), domR may not be ready yet. failure due to "
+ + e);
+ }
+
return null;
}
+ private File getSystemVMPatchIsoFile() {
+ // locate systemvm.iso
+ URL url = this.getClass().getClassLoader().getResource("vms/systemvm.iso");
+ File isoFile = null;
+ if (url != null) {
+ isoFile = new File(url.getPath());
+ }
+
+ if(isoFile == null || !isoFile.exists()) {
+ isoFile = new File("/usr/share/cloudstack-common/vms/systemvm.iso");
+ }
+
+ assert(isoFile != null);
+ if(!isoFile.exists()) {
+ s_logger.error("Unable to locate systemvm.iso in your setup at " + isoFile.toString());
+ }
+ return isoFile;
+ }
+
+ public File getSystemVMKeyFile() {
+ URL url = this.getClass().getClassLoader().getResource("scripts/vm/systemvm/id_rsa.cloud");
+ File keyFile = null;
+ if ( url != null ){
+ keyFile = new File(url.getPath());
+ }
+ if (keyFile == null || !keyFile.exists()) {
+ keyFile = new File("/usr/share/cloudstack-common/scripts/vm/systemvm/id_rsa.cloud");
+ }
+ assert(keyFile != null);
+ if(!keyFile.exists()) {
+ s_logger.error("Unable to locate id_rsa.cloud in your setup at " + keyFile.toString());
+ }
+ return keyFile;
+ }
+
+
public static String postHttpRequest(final String jsonCmd,
final URI agentUri) {
// Using Apache's HttpClient for HTTP POST
@@ -450,5 +1721,53 @@ public class HypervDirectConnectResource extends ServerResourceBase implements
public void setRunLevel(final int level) {
// TODO Auto-generated method stub
}
+ protected String connect(final String vmName, final String ipAddress, final int port) {
+ long startTick = System.currentTimeMillis();
+
+ // wait until we have at least been waiting for _ops_timeout time or
+ // at least have tried _retry times, this is to coordinate with system
+ // VM patching/rebooting time that may need
+ int retry = _retry;
+ while (System.currentTimeMillis() - startTick <= _ops_timeout || --retry > 0) {
+ SocketChannel sch = null;
+ try {
+ s_logger.info("Trying to connect to " + ipAddress);
+ sch = SocketChannel.open();
+ sch.configureBlocking(true);
+ sch.socket().setSoTimeout(5000);
+
+ InetSocketAddress addr = new InetSocketAddress(ipAddress, port);
+ sch.connect(addr);
+ return null;
+ } catch (IOException e) {
+ s_logger.info("Could not connect to " + ipAddress + " due to " + e.toString());
+ if (e instanceof ConnectException) {
+ // if connection is refused because of VM is being started,
+ // we give it more sleep time
+ // to avoid running out of retry quota too quickly
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException ex) {
+ }
+ }
+ } finally {
+ if (sch != null) {
+ try {
+ sch.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ s_logger.info("Unable to logon to " + ipAddress);
+
+ return "Unable to connect";
+ }
}
diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
index d916d454422..b304a008a09 100644
--- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
+++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
@@ -186,6 +186,7 @@ public class CloudStackPrimaryDataStoreLifeCycleImpl implements PrimaryDataStore
Object localStorage = dsInfos.get("localStorage");
if (localStorage != null) {
hostPath = hostPath.replaceFirst("/", "");
+ hostPath = hostPath.replace("+"," ");
}
String userInfo = uri.getUserInfo();
int port = uri.getPort();
diff --git a/systemvm/patches/debian/config/etc/init.d/cloud-early-config b/systemvm/patches/debian/config/etc/init.d/cloud-early-config
index d44f94d7d17..d4bf0eb3d92 100755
--- a/systemvm/patches/debian/config/etc/init.d/cloud-early-config
+++ b/systemvm/patches/debian/config/etc/init.d/cloud-early-config
@@ -130,12 +130,11 @@ get_boot_params() {
vmware)
vmtoolsd --cmd 'machine.id.get' > /var/cache/cloud/cmdline
;;
- virtualpc)
- # Hyper-V is recognized as virtualpc hypervisor type. Boot args are passed in the NTFS data-disk
- mkdir -p $EXTRA_MOUNT
- mount -t ntfs /dev/sdb1 $EXTRA_MOUNT
- cp -f $EXTRA_MOUNT/cmdline /var/cache/cloud/cmdline
- umount $EXTRA_MOUNT
+ virtualpc|hyperv)
+ # Hyper-V is recognized as virtualpc hypervisor type. Boot args are passed using KVP Daemon
+ #waiting for the hv_kvp_daemon to start up
+ #sleep 30 need to fix the race condition of hv_kvp_daemon and cloud-early-config
+ cp -f /var/opt/hyperv/.kvp_pool_0 /var/cache/cloud/cmdline
;;
esac
@@ -157,6 +156,10 @@ patch() {
cdrom_dev=/dev/cdrom
elif [ -e /dev/cdrom1 ]; then
cdrom_dev=/dev/cdrom1
+ elif [ -e /dev/cdrom2 ]; then
+ cdrom_dev=/dev/cdrom2
+ elif [ -e /dev/cdrom3 ]; then
+ cdrom_dev=/dev/cdrom3
fi
[ -f /var/cache/cloud/authorized_keys ] && privkey=/var/cache/cloud/authorized_keys
@@ -718,7 +721,7 @@ setup_dnsmasq() {
[ $ETH0_IP ] && echo "dhcp-option=6,$NS" >> /etc/dnsmasq.conf
[ $ETH0_IP6 ] && echo "dhcp-option=option6:dns-server,$NS6" >> /etc/dnsmasq.conf
#adding the name data-server to the /etc/hosts for allowing the access to user-data service and ssh-key reset in every subnet.
- //removing the existing entires to avoid duplicates on restarts.
+#removing the existing entires to avoid duplicates on restarts.
sed -i '/data-server/d' /etc/hosts
if [ -n "$ETH0_IP" ]
then