| // 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.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.nio.charset.Charset; |
| import java.rmi.RemoteException; |
| import java.security.KeyManagementException; |
| import java.security.KeyStoreException; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.UnrecoverableKeyException; |
| import java.security.cert.CertificateException; |
| import java.security.cert.X509Certificate; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import javax.annotation.PostConstruct; |
| import javax.inject.Inject; |
| import javax.naming.ConfigurationException; |
| |
| import org.apache.cloudstack.storage.command.CopyCommand; |
| import org.apache.commons.codec.binary.Base64; |
| import org.apache.commons.lang.StringEscapeUtils; |
| import org.apache.http.HttpResponse; |
| import org.apache.http.HttpStatus; |
| import org.apache.http.client.ClientProtocolException; |
| import org.apache.http.client.HttpClient; |
| import org.apache.http.client.methods.HttpPost; |
| import org.apache.http.conn.ClientConnectionManager; |
| import org.apache.http.conn.scheme.Scheme; |
| import org.apache.http.conn.scheme.SchemeRegistry; |
| import org.apache.http.conn.ssl.AllowAllHostnameVerifier; |
| import org.apache.http.conn.ssl.SSLSocketFactory; |
| import org.apache.http.conn.ssl.TrustStrategy; |
| import org.apache.http.entity.StringEntity; |
| import org.apache.http.impl.client.DefaultHttpClient; |
| import org.apache.http.impl.conn.BasicClientConnectionManager; |
| import org.apache.http.util.EntityUtils; |
| import org.apache.log4j.Logger; |
| import org.joda.time.Duration; |
| |
| 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.GetVmConfigAnswer; |
| import com.cloud.agent.api.GetVmConfigAnswer.NicDetails; |
| import com.cloud.agent.api.GetVmConfigCommand; |
| import com.cloud.agent.api.HostVmStateReportEntry; |
| import com.cloud.agent.api.ModifyVmNicConfigCommand; |
| 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.PlugNicAnswer; |
| import com.cloud.agent.api.PlugNicCommand; |
| import com.cloud.agent.api.SetupGuestNetworkCommand; |
| import com.cloud.agent.api.StartCommand; |
| import com.cloud.agent.api.StartupCommand; |
| import com.cloud.agent.api.StartupRoutingCommand; |
| import com.cloud.agent.api.StartupStorageCommand; |
| import com.cloud.agent.api.UnPlugNicAnswer; |
| import com.cloud.agent.api.UnPlugNicCommand; |
| import com.cloud.agent.api.UnsupportedAnswer; |
| 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.IpAssocVpcCommand; |
| import com.cloud.agent.api.routing.LoadBalancerConfigCommand; |
| import com.cloud.agent.api.routing.NetworkElementCommand; |
| import com.cloud.agent.api.routing.RemoteAccessVpnCfgCommand; |
| 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.SetMonitorServiceCommand; |
| import com.cloud.agent.api.routing.SetNetworkACLCommand; |
| 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.routing.VpnUsersCfgCommand; |
| import com.cloud.agent.api.to.DataStoreTO; |
| 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.NfsTO; |
| import com.cloud.agent.api.to.NicTO; |
| import com.cloud.agent.api.to.PortForwardingRuleTO; |
| import com.cloud.agent.api.to.StaticNatRuleTO; |
| import com.cloud.agent.api.to.VirtualMachineTO; |
| import com.cloud.agent.resource.virtualnetwork.VRScripts; |
| import com.cloud.agent.resource.virtualnetwork.VirtualRouterDeployer; |
| import com.cloud.agent.resource.virtualnetwork.VirtualRoutingResource; |
| import com.cloud.dc.DataCenter.NetworkType; |
| import com.cloud.exception.InternalErrorException; |
| import com.cloud.host.Host.Type; |
| import com.cloud.hypervisor.Hypervisor; |
| import com.cloud.hypervisor.hyperv.manager.HypervManager; |
| import com.cloud.network.HAProxyConfigurator; |
| import com.cloud.network.LoadBalancerConfigurator; |
| import com.cloud.network.Networks.BroadcastDomainType; |
| 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.ExecutionResult; |
| 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.VirtualMachine; |
| import com.cloud.vm.VirtualMachine.PowerState; |
| import com.cloud.vm.VirtualMachineName; |
| import com.google.gson.Gson; |
| import com.google.gson.reflect.TypeToken; |
| |
| |
| /** |
| * Implementation of dummy resource to be returned from discoverer. |
| **/ |
| public class HypervDirectConnectResource extends ServerResourceBase implements ServerResource, VirtualRouterDeployer { |
| public static final int DEFAULT_AGENT_PORT = 8250; |
| public static final String HOST_VM_STATE_REPORT_COMMAND = "org.apache.cloudstack.HostVmStateReportCommand"; |
| 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 final int _port = DEFAULT_AGENT_PORT; |
| protected final long _opsTimeout = 900000; // 15 minutes time out to time |
| |
| protected final int _retry = 24; |
| protected final int _sleep = 10000; |
| protected static final int DEFAULT_DOMR_SSHPORT = 3922; |
| private String _clusterGuid; |
| |
| // Used by initialize to assert object configured before |
| // initialize called. |
| private boolean _configureCalled = false; |
| |
| private String _username; |
| private String _password; |
| |
| private static HypervManager s_hypervMgr; |
| @Inject |
| HypervManager _hypervMgr; |
| protected VirtualRoutingResource _vrResource; |
| |
| @PostConstruct |
| void init() { |
| s_hypervMgr = _hypervMgr; |
| } |
| |
| @Override |
| public final Type getType() { |
| return Type.Routing; |
| } |
| |
| @Override |
| public final StartupCommand[] initialize() { |
| // assert |
| if (!_configureCalled) { |
| final String errMsg = this.getClass().getName() + " requires configure() be called before" + " initialize()"; |
| s_logger.error(errMsg); |
| } |
| |
| // Create default StartupRoutingCommand, then customise |
| final StartupRoutingCommand defaultStartRoutCmd = |
| new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.Hyperv, RouterPrivateIpStrategy.HostLocal); |
| |
| // 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 + "\""); |
| |
| defaultStartRoutCmd.setVersion(this.getClass().getPackage().getImplementationVersion()); |
| |
| // 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. |
| final Command[] startCmds = requestStartupCommand(new Command[] {defaultStartRoutCmd}); |
| |
| // TODO: may throw, is this okay? |
| final StartupRoutingCommand startCmd = (StartupRoutingCommand)startCmds[0]; |
| |
| // Assert that host identity is consistent with existing values. |
| if (startCmd == null) { |
| final 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())) { |
| final 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())) { |
| final 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())) { |
| final 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())) { |
| final 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())) { |
| final 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())) { |
| final 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) { |
| final String frmtStr = "Host %s (IP %s) sent incorrect Command, " + "second parameter should be a " + "StartupStorageCommand"; |
| final 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) { |
| final PingCommand pingCmd = new PingRoutingCommand(getType(), id, getHostVmStateReport()); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Ping host " + _name + " (IP " + _agentIp + ")"); |
| } |
| |
| final Answer pingAns = 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; |
| } |
| |
| public final ArrayList<Map<String, String>> requestHostVmStateReport() { |
| URI agentUri = null; |
| try { |
| agentUri = new URI("https", null, _agentIp, _port, "/api/HypervResource/" + HOST_VM_STATE_REPORT_COMMAND, null, null); |
| } catch (final URISyntaxException e) { |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| return null; |
| } |
| final String incomingCmd = postHttpRequest("{}", agentUri); |
| |
| if (incomingCmd == null) { |
| return null; |
| } |
| ArrayList<Map<String, String>> result = null; |
| try { |
| result = s_gson.fromJson(incomingCmd, new TypeToken<ArrayList<HashMap<String, String>>>() { |
| }.getType()); |
| } catch (final Exception ex) { |
| final String errMsg = "Failed to deserialize Command[] " + incomingCmd; |
| s_logger.error(errMsg, ex); |
| } |
| s_logger.debug("HostVmStateReportCommand received response " |
| + s_gson.toJson(result)); |
| if (result != null) { |
| if (!result.isEmpty()) { |
| return result; |
| } else { |
| return new ArrayList<Map<String, String>>(); |
| } |
| } |
| return null; |
| } |
| |
| protected HashMap<String, HostVmStateReportEntry> getHostVmStateReport() { |
| final HashMap<String, HostVmStateReportEntry> vmStates = new HashMap<String, HostVmStateReportEntry>(); |
| final ArrayList<Map<String, String>> vmList = requestHostVmStateReport(); |
| if (vmList == null) { |
| return null; |
| } |
| |
| for (final Map<String, String> vmMap : vmList) { |
| final String name = (String)vmMap.keySet().toArray()[0]; |
| vmStates.put(name, new HostVmStateReportEntry(PowerState.valueOf(vmMap.get(name)), _guid)); |
| } |
| return vmStates; |
| } |
| |
| // 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 { |
| final String cmdName = StartupCommand.class.getName(); |
| agentUri = |
| new URI("https", null, _agentIp, _port, |
| "/api/HypervResource/" + cmdName, null, null); |
| } catch (final URISyntaxException e) { |
| // TODO add proper logging |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| return null; |
| } |
| final 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 (final Exception ex) { |
| final 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; |
| final Class<? extends Command> clazz = cmd.getClass(); |
| Answer answer = null; |
| try { |
| final String cmdName = cmd.getClass().getName(); |
| agentUri = |
| new URI("https", null, _agentIp, _port, |
| "/api/HypervResource/" + cmdName, null, null); |
| } catch (final URISyntaxException e) { |
| // TODO add proper logging |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| return null; |
| } |
| if (cmd instanceof NetworkElementCommand) { |
| return _vrResource.executeRequest((NetworkElementCommand)cmd); |
| }if (clazz == CheckSshCommand.class) { |
| answer = execute((CheckSshCommand)cmd); |
| } else if (cmd instanceof NetworkUsageCommand) { |
| answer = execute((NetworkUsageCommand)cmd); |
| } else if (clazz == PingTestCommand.class) { |
| answer = execute((PingTestCommand)cmd); |
| } else if (clazz == PlugNicCommand.class) { |
| answer = execute((PlugNicCommand)cmd); |
| } else if (clazz == UnPlugNicCommand.class) { |
| answer = execute((UnPlugNicCommand)cmd); |
| } else if (clazz == CopyCommand.class) { |
| answer = execute((CopyCommand)cmd); |
| } |
| else { |
| if (clazz == StartCommand.class) { |
| final VirtualMachineTO vmSpec = ((StartCommand)cmd).getVirtualMachine(); |
| if (vmSpec.getType() != VirtualMachine.Type.User) { |
| if (s_hypervMgr != null) { |
| final String secondary = s_hypervMgr.prepareSecondaryStorageStore(Long.parseLong(_zoneId)); |
| if (secondary != null) { |
| ((StartCommand)cmd).setSecondaryStorage(secondary); |
| } |
| } else { |
| s_logger.error("Hyperv manager isn't available. Couldn't check and copy the systemvm iso."); |
| } |
| } |
| } |
| |
| // Send the cmd to hyperv agent. |
| final String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri); |
| if (ansStr == null) { |
| return Answer.createUnsupportedCommandAnswer(cmd); |
| } |
| // Only Answer instances are returned by remote agents. |
| // E.g. see Response.getAnswers() |
| final Answer[] result = s_gson.fromJson(ansStr, Answer[].class); |
| final String logResult = cleanPassword(s_gson.toJson(result)); |
| s_logger.debug("executeRequest received response " + logResult); |
| if (result.length > 0) { |
| return result[0]; |
| } |
| } |
| return answer; |
| } |
| |
| private Answer execute(final CopyCommand cmd) { |
| URI agentUri = null; |
| try { |
| final String cmdName = cmd.getClass().getName(); |
| agentUri = |
| new URI("https", null, _agentIp, _port, |
| "/api/HypervResource/" + cmdName, null, null); |
| } catch (final URISyntaxException e) { |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| return null; |
| } |
| cleanPassword(cmd.getSrcTO().getDataStore()); |
| cleanPassword(cmd.getDestTO().getDataStore()); |
| |
| // Send the cmd to hyperv agent. |
| final String ansStr = postHttpRequest(s_gson.toJson(cmd), agentUri); |
| if (ansStr == null) { |
| return Answer.createUnsupportedCommandAnswer(cmd); |
| } |
| |
| final Answer[] result = s_gson.fromJson(ansStr, Answer[].class); |
| final String logResult = cleanPassword(s_gson.toJson(result)); |
| s_logger.debug("executeRequest received response " + logResult); |
| if (result.length > 0) { |
| return result[0]; |
| } |
| |
| return null; |
| } |
| |
| private void cleanPassword(final DataStoreTO dataStoreTO) { |
| if (dataStoreTO instanceof NfsTO) { |
| final NfsTO nfsTO = (NfsTO)dataStoreTO; |
| final String url = nfsTO.getUrl(); |
| if (url.contains("cifs") && url.contains("password")) { |
| nfsTO.setUrl(url.substring(0, url.indexOf('?'))); |
| } |
| } |
| } |
| |
| private PlugNicAnswer execute(final PlugNicCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource PlugNicCommand " + s_gson.toJson(cmd)); |
| } |
| |
| try { |
| |
| final String vmName = cmd.getVmName(); |
| final NicTO nic = cmd.getNic(); |
| final URI broadcastUri = nic.getBroadcastUri(); |
| if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) { |
| throw new InternalErrorException("Unable to assign a public IP to a VIF on network " + nic.getBroadcastUri()); |
| } |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| int publicNicInfo = -1; |
| publicNicInfo = getVmFreeNicIndex(vmName); |
| if (publicNicInfo > 0) { |
| modifyNicVlan(vmName, vlanId, publicNicInfo, true, cmd.getNic().getName()); |
| return new PlugNicAnswer(cmd, true, "success"); |
| } |
| final String msg = " Plug Nic failed for the vm as it has reached max limit of NICs to be added"; |
| s_logger.warn(msg); |
| return new PlugNicAnswer(cmd, false, msg); |
| |
| } catch (final Exception e) { |
| s_logger.error("Unexpected exception: ", e); |
| return new PlugNicAnswer(cmd, false, "Unable to execute PlugNicCommand due to " + e.toString()); |
| } |
| } |
| |
| |
| private UnPlugNicAnswer execute(final UnPlugNicCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource UnPlugNicCommand " + s_gson.toJson(cmd)); |
| } |
| |
| try { |
| final String vmName = cmd.getVmName(); |
| final NicTO nic = cmd.getNic(); |
| final URI broadcastUri = nic.getBroadcastUri(); |
| if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) { |
| throw new InternalErrorException("Unable to unassign a public IP to a VIF on network " + nic.getBroadcastUri()); |
| } |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| int publicNicInfo = -1; |
| publicNicInfo = getVmNics(vmName, vlanId); |
| if (publicNicInfo > 0) { |
| modifyNicVlan(vmName, "2", publicNicInfo, false, ""); |
| } |
| return new UnPlugNicAnswer(cmd, true, "success"); |
| } catch (final Exception e) { |
| s_logger.error("Unexpected exception: ", e); |
| return new UnPlugNicAnswer(cmd, false, "Unable to execute unPlugNicCommand due to " + e.toString()); |
| } |
| } |
| |
| @Override |
| public ExecutionResult executeInVR(final String routerIP, final String script, final String args) { |
| return executeInVR(routerIP, script, args, Duration.standardSeconds(120L)); |
| } |
| |
| @Override |
| public ExecutionResult executeInVR(final String routerIP, final String script, final String args, final Duration timeout) { |
| Pair<Boolean, String> result; |
| |
| //TODO: Password should be masked, cannot output to log directly |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Run command on VR: " + routerIP + ", script: " + script + " with args: " + args); |
| } |
| |
| try { |
| result = SshHelper.sshExecute(routerIP, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/" + script + " " + args, VRScripts.CONNECTION_TIMEOUT, |
| VRScripts.CONNECTION_TIMEOUT, timeout); |
| } catch (final Exception e) { |
| final String msg = "Command failed due to " + e ; |
| s_logger.error(msg); |
| result = new Pair<Boolean, String>(false, msg); |
| } |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug(script + " execution result: " + result.first().toString()); |
| } |
| return new ExecutionResult(result.first(), result.second()); |
| } |
| |
| @Override |
| public ExecutionResult createFileInVR(final String routerIp, final String filePath, final String fileName, final String content) { |
| final File keyFile = getSystemVMKeyFile(); |
| try { |
| SshHelper.scpTo(routerIp, 3922, "root", keyFile, null, filePath, content.getBytes(Charset.forName("UTF-8")), fileName, null); |
| } catch (final Exception e) { |
| s_logger.warn("Fail to create file " + filePath + fileName + " in VR " + routerIp, e); |
| return new ExecutionResult(false, e.getMessage()); |
| } |
| return new ExecutionResult(true, null); |
| } |
| |
| @Override |
| public ExecutionResult prepareCommand(final NetworkElementCommand cmd) { |
| //Update IP used to access router |
| cmd.setRouterAccessIp(getRouterSshControlIp(cmd)); |
| assert cmd.getRouterAccessIp() != null; |
| |
| if (cmd instanceof IpAssocVpcCommand) { |
| return prepareNetworkElementCommand((IpAssocVpcCommand)cmd); |
| } else if (cmd instanceof IpAssocCommand) { |
| return prepareNetworkElementCommand((IpAssocCommand)cmd); |
| } else if (cmd instanceof SetSourceNatCommand) { |
| return prepareNetworkElementCommand((SetSourceNatCommand)cmd); |
| } else if (cmd instanceof SetupGuestNetworkCommand) { |
| return prepareNetworkElementCommand((SetupGuestNetworkCommand)cmd); |
| } else if (cmd instanceof SetNetworkACLCommand) { |
| return prepareNetworkElementCommand((SetNetworkACLCommand)cmd); |
| } |
| return new ExecutionResult(true, null); |
| } |
| |
| private ExecutionResult prepareNetworkElementCommand(final IpAssocCommand cmd) { |
| try { |
| |
| final IpAddressTO[] ips = cmd.getIpAddresses(); |
| final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); |
| final String controlIp = getRouterSshControlIp(cmd); |
| |
| for (final IpAddressTO ip : ips) { |
| /** |
| * TODO support other networks |
| */ |
| final URI broadcastUri = BroadcastDomainType.fromString(ip.getBroadcastUri()); |
| if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) { |
| throw new InternalErrorException("Unable to assign a public IP to a VIF on network " + ip.getBroadcastUri()); |
| } |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| int publicNicInfo = -1; |
| publicNicInfo = getVmNics(routerName, vlanId); |
| |
| boolean addVif = false; |
| if (ip.isAdd() && publicNicInfo == -1) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Plug new NIC to associate" + controlIp + " to " + ip.getPublicIp()); |
| } |
| addVif = true; |
| } |
| |
| if (addVif) { |
| final Pair<Integer, String> nicdevice = findRouterFreeEthDeviceIndex(controlIp); |
| publicNicInfo = nicdevice.first(); |
| if (publicNicInfo > 0) { |
| modifyNicVlan(routerName, vlanId, nicdevice.second()); |
| // After modifying the vnic on VR, check the VR VNics config in the host and get the device position |
| publicNicInfo = getVmNics(routerName, vlanId); |
| // As a new nic got activated in the VR. add the entry in the NIC's table. |
| networkUsage(controlIp, "addVif", "eth" + publicNicInfo); |
| } |
| else { |
| // we didn't find any eth device available in VR to configure the ip range with new VLAN |
| final String msg = "No Nic is available on DomR VIF to associate/disassociate IP with."; |
| s_logger.error(msg); |
| throw new InternalErrorException(msg); |
| } |
| ip.setNicDevId(publicNicInfo); |
| ip.setNewNic(addVif); |
| } else { |
| ip.setNicDevId(publicNicInfo); |
| } |
| } |
| } catch (final Throwable e) { |
| s_logger.error("Unexpected exception: " + e.toString() + " will shortcut rest of IPAssoc commands", e); |
| return new ExecutionResult(false, e.toString()); |
| } |
| return new ExecutionResult(true, null); |
| } |
| |
| protected ExecutionResult prepareNetworkElementCommand(final SetupGuestNetworkCommand cmd) { |
| final NicTO nic = cmd.getNic(); |
| final String domrName = |
| cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); |
| |
| try { |
| final URI broadcastUri = nic.getBroadcastUri(); |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| final int ethDeviceNum = getVmNics(domrName, vlanId); |
| if (ethDeviceNum > 0) { |
| nic.setDeviceId(ethDeviceNum); |
| } else { |
| return new ExecutionResult(false, "Prepare SetupGuestNetwork failed due to unable to find the nic"); |
| } |
| } catch (final Exception e) { |
| final String msg = "Prepare SetupGuestNetwork failed due to " + e.toString(); |
| s_logger.warn(msg, e); |
| return new ExecutionResult(false, msg); |
| } |
| return new ExecutionResult(true, null); |
| } |
| |
| |
| private ExecutionResult prepareNetworkElementCommand(final IpAssocVpcCommand cmd) { |
| final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); |
| |
| try { |
| final IpAddressTO[] ips = cmd.getIpAddresses(); |
| for (final IpAddressTO ip : ips) { |
| final URI broadcastUri = BroadcastDomainType.fromString(ip.getBroadcastUri()); |
| if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) { |
| throw new InternalErrorException("Invalid Broadcast URI " + ip.getBroadcastUri()); |
| } |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| int publicNicInfo = -1; |
| publicNicInfo = getVmNics(routerName, vlanId); |
| if (publicNicInfo < 0) { |
| if (ip.isAdd()) { |
| throw new InternalErrorException("Failed to find DomR VIF to associate/disassociate IP with."); |
| } else { |
| s_logger.debug("VIF to deassociate IP with does not exist, return success"); |
| continue; |
| } |
| } |
| |
| ip.setNicDevId(publicNicInfo); |
| } |
| } catch (final Exception e) { |
| s_logger.error("Prepare Ip Assoc failure on applying one ip due to exception: ", e); |
| return new ExecutionResult(false, e.toString()); |
| } |
| |
| return new ExecutionResult(true, null); |
| } |
| |
| protected ExecutionResult prepareNetworkElementCommand(final SetSourceNatCommand cmd) { |
| final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); |
| final IpAddressTO pubIp = cmd.getIpAddress(); |
| |
| try { |
| final String broadcastUri = pubIp.getBroadcastUri(); |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| final int ethDeviceNum = getVmNics(routerName, vlanId); |
| if (ethDeviceNum > 0) { |
| pubIp.setNicDevId(ethDeviceNum); |
| } else { |
| return new ExecutionResult(false, "Prepare Ip SNAT failed due to unable to find the nic"); |
| } |
| } catch (final Exception e) { |
| final String msg = "Prepare Ip SNAT failure due to " + e.toString(); |
| s_logger.error(msg, e); |
| return new ExecutionResult(false, e.toString()); |
| } |
| return new ExecutionResult(true, null); |
| } |
| |
| private ExecutionResult prepareNetworkElementCommand(final SetNetworkACLCommand cmd) { |
| final NicTO nic = cmd.getNic(); |
| final String routerName = |
| cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); |
| |
| try { |
| final URI broadcastUri = nic.getBroadcastUri(); |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| final int ethDeviceNum = getVmNics(routerName, vlanId); |
| if (ethDeviceNum > 0) { |
| nic.setDeviceId(ethDeviceNum); |
| } else { |
| return new ExecutionResult(false, "Prepare SetNetworkACL failed due to unable to find the nic"); |
| } |
| } catch (final Exception e) { |
| final String msg = "Prepare SetNetworkACL failed due to " + e.toString(); |
| s_logger.error(msg, e); |
| return new ExecutionResult(false, msg); |
| } |
| return new ExecutionResult(true, null); |
| } |
| |
| @Override |
| public ExecutionResult cleanupCommand(final NetworkElementCommand cmd) { |
| return new ExecutionResult(true, null); |
| } |
| |
| protected Answer execute(final RemoteAccessVpnCfgCommand cmd) { |
| final String controlIp = getRouterSshControlIp(cmd); |
| final StringBuffer argsBuf = new StringBuffer(); |
| if (cmd.isCreate()) { |
| argsBuf.append(" -r ").append(cmd.getIpRange()).append(" -p ").append(cmd.getPresharedKey()).append(" -s ").append(cmd.getVpnServerIp()).append(" -l ").append(cmd.getLocalIp()) |
| .append(" -c "); |
| |
| } else { |
| argsBuf.append(" -d ").append(" -s ").append(cmd.getVpnServerIp()); |
| } |
| argsBuf.append(" -C ").append(cmd.getLocalCidr()); |
| argsBuf.append(" -i ").append(cmd.getPublicInterface()); |
| |
| try { |
| final String command = String.format("%s%s %s", "/opt/cloud/bin/", VRScripts.VPN_L2TP, argsBuf.toString()); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Executing " + command); |
| } |
| |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| if (!result.first()) { |
| s_logger.error("RemoteAccessVpnCfg command on domR failed, message: " + result.second()); |
| |
| return new Answer(cmd, false, "RemoteAccessVpnCfg command failed due to " + result.second()); |
| } |
| |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("RemoteAccessVpnCfg command on domain router " + argsBuf.toString() + " completed"); |
| } |
| |
| } catch (final Throwable e) { |
| if (e instanceof RemoteException) { |
| s_logger.warn(e.getMessage()); |
| } |
| |
| final String msg = "RemoteAccessVpnCfg command failed due to " + e.getMessage(); |
| s_logger.error(msg, e); |
| return new Answer(cmd, false, msg); |
| } |
| |
| return new Answer(cmd); |
| } |
| |
| protected Answer execute(final VpnUsersCfgCommand cmd) { |
| |
| final String controlIp = getRouterSshControlIp(cmd); |
| for (final VpnUsersCfgCommand.UsernamePassword userpwd : cmd.getUserpwds()) { |
| final StringBuffer argsBuf = new StringBuffer(); |
| if (!userpwd.isAdd()) { |
| argsBuf.append(" -U ").append(userpwd.getUsername()); |
| } else { |
| argsBuf.append(" -u ").append(userpwd.getUsernamePassword()); |
| } |
| |
| try { |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Executing /opt/cloud/bin/vpn_lt2p.sh "); |
| } |
| |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/opt/cloud/bin/vpn_l2tp.sh " + argsBuf.toString()); |
| |
| if (!result.first()) { |
| s_logger.error("VpnUserCfg command on domR failed, message: " + result.second()); |
| |
| return new Answer(cmd, false, "VpnUserCfg command failed due to " + result.second()); |
| } |
| } catch (final Throwable e) { |
| if (e instanceof RemoteException) { |
| s_logger.warn(e.getMessage()); |
| } |
| |
| final String msg = "VpnUserCfg command failed due to " + e.getMessage(); |
| s_logger.error(msg, e); |
| return new Answer(cmd, false, msg); |
| } |
| } |
| |
| return new Answer(cmd); |
| } |
| private SetStaticRouteAnswer execute(final SetStaticRouteCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource SetStaticRouteCommand: " + s_gson.toJson(cmd)); |
| } |
| |
| boolean endResult = true; |
| |
| final String controlIp = getRouterSshControlIp(cmd); |
| String args = ""; |
| final String[] results = new String[cmd.getStaticRoutes().length]; |
| int i = 0; |
| |
| // Extract and build the arguments for the command to be sent to the VR. |
| final String[] rules = cmd.generateSRouteRules(); |
| final StringBuilder sb = new StringBuilder(); |
| |
| for (int j = 0; j < rules.length; j++) { |
| sb.append(rules[j]).append(','); |
| } |
| args += " -a " + sb.toString(); |
| |
| final String command = String.format("%s%s %s", "/opt/cloud/bin/", VRScripts.VPC_STATIC_ROUTE, args); |
| |
| // Send over the command for execution, via ssh, to the VR. |
| try { |
| final Pair<Boolean, String> result = |
| SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| 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 (final 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(final CheckS2SVpnConnectionsCommand cmd) { |
| final StringBuilder cmdline = new StringBuilder(); |
| cmdline.append("/opt/cloud/bin/"); |
| cmdline.append(VRScripts.S2SVPN_CHECK); |
| |
| 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) + cmdline.toString()); |
| } |
| |
| Pair<Boolean, String> result; |
| try { |
| final String controlIp = getRouterSshControlIp(cmd); |
| for (final String ip : cmd.getVpnIps()) { |
| cmdline.append(" "); |
| cmdline.append(ip); |
| } |
| |
| result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, cmdline.toString()); |
| |
| 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 (final Throwable e) { |
| final 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(final Site2SiteVpnCfgCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource Site2SiteVpnCfgCommand " + s_gson.toJson(cmd)); |
| } |
| |
| final 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<Boolean, String> result; |
| try { |
| final String command = String.format("%s%s %s", "/opt/cloud/bin/", VRScripts.S2SVPN_IPSEC, args); |
| result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| 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 (final Throwable e) { |
| final 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(final SetSourceNatCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource SetSourceNatCommand " + s_gson.toJson(cmd)); |
| } |
| |
| final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); |
| final String routerIp = getRouterSshControlIp(cmd); |
| final IpAddressTO pubIp = cmd.getIpAddress(); |
| try { |
| final int ethDeviceNum = findRouterEthDeviceIndex(routerName, routerIp, pubIp.getVifMacAddress()); |
| String args = ""; |
| args += " -A "; |
| args += " -l "; |
| args += pubIp.getPublicIp(); |
| |
| args += " -c "; |
| args += "eth" + ethDeviceNum; |
| |
| final String command = String.format("%s%s %s", "/opt/cloud/bin/", VRScripts.VPC_SOURCE_NAT, args); |
| |
| final Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| if (!result.first()) { |
| final 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 (final Exception e) { |
| final String msg = "Ip SNAT failure due to " + e.toString(); |
| s_logger.error(msg, e); |
| return new SetSourceNatAnswer(cmd, false, msg); |
| } |
| } |
| |
| protected Answer execute(final SetPortForwardingRulesCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource SetPortForwardingRulesCommand: " + s_gson.toJson(cmd)); |
| } |
| |
| final String controlIp = getRouterSshControlIp(cmd); |
| String args = ""; |
| final String[] results = new String[cmd.getRules().length]; |
| int i = 0; |
| |
| boolean endResult = true; |
| for (final 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 { |
| final Pair<Boolean, String> 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 (final 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(final CheckRouterCommand cmd) { |
| final String command = String.format("%s%s", "/opt/cloud/bin/", VRScripts.RVR_CHECK); |
| |
| 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) + command); |
| } |
| |
| Pair<Boolean, String> result; |
| try { |
| |
| final String controlIp = getRouterSshControlIp(cmd); |
| result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| 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 (final Throwable e) { |
| final 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(final 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; |
| final String[] results = new String[cmd.getRules().length]; |
| int i = 0; |
| boolean endResult = true; |
| for (final 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 { |
| final String controlIp = getRouterSshControlIp(cmd); |
| final Pair<Boolean, String> 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 (final 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(final PingTestCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource PingTestCommand: " + s_gson.toJson(cmd)); |
| } |
| final String controlIp = cmd.getRouterIp(); |
| final String args = " -c 1 -n -q " + cmd.getPrivateIp(); |
| try { |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, "/bin/ping" + args); |
| if (result.first()) { |
| return new Answer(cmd); |
| } |
| } catch (final 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); |
| final List<IpAliasTO> revokedIpAliasTOs = cmd.getDeleteIpAliasTos(); |
| final List<IpAliasTO> activeIpAliasTOs = cmd.getCreateIpAliasTos(); |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing deleteIpAlias command: " + s_gson.toJson(cmd)); |
| } |
| final StringBuilder args = new StringBuilder(); |
| for (final IpAliasTO ipAliasTO : revokedIpAliasTOs) { |
| args.append(ipAliasTO.getAlias_count()); |
| args.append(":"); |
| args.append(ipAliasTO.getRouterip()); |
| args.append(":"); |
| args.append(ipAliasTO.getNetmask()); |
| args.append("-"); |
| } |
| args.append("- "); |
| for (final IpAliasTO ipAliasTO : activeIpAliasTOs) { |
| args.append(ipAliasTO.getAlias_count()); |
| args.append(":"); |
| args.append(ipAliasTO.getRouterip()); |
| args.append(":"); |
| args.append(ipAliasTO.getNetmask()); |
| args.append("-"); |
| } |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /root/deleteIpAlias " + args); |
| } |
| |
| try { |
| final String controlIp = getRouterSshControlIp(cmd); |
| final Pair<Boolean, String> 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 (final Throwable e) { |
| final 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); |
| } |
| |
| final File keyFile = getSystemVMKeyFile(); |
| |
| final String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); |
| final String controlIp = getRouterSshControlIp(cmd); |
| |
| assert controlIp != null; |
| |
| final LoadBalancerConfigurator cfgtr = new HAProxyConfigurator(); |
| final String[] config = cfgtr.generateConfiguration(cmd); |
| |
| final String[][] rules = cfgtr.generateFwRules(cmd); |
| final String tmpCfgFilePath = "/tmp/" + routerIp.replace('.', '_') + ".cfg"; |
| final StringBuilder tmpCfgFileContents = new StringBuilder(); |
| for (int i = 0; i < config.length; i++) { |
| tmpCfgFileContents.append(config[i]); |
| tmpCfgFileContents.append("\n"); |
| } |
| |
| try { |
| SshHelper.scpTo(controlIp, DEFAULT_DOMR_SSHPORT, "root", keyFile, null, "/tmp/", tmpCfgFileContents.toString().getBytes(Charset.forName("UTF-8")), routerIp.replace('.', '_') + |
| ".cfg", null); |
| |
| try { |
| final String[] addRules = rules[LoadBalancerConfigurator.ADD]; |
| final String[] removeRules = rules[LoadBalancerConfigurator.REMOVE]; |
| final 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<Boolean, String> 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 unable to copy haproxy configuration file"); |
| } |
| |
| final String command = String.format("%s%s %s", "/root/", VRScripts.LB, args); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Run command on domain router " + routerIp + command); |
| } |
| |
| result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| if (!result.first()) { |
| final 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 (final Throwable e) { |
| s_logger.error("Unexpected exception: " + e.toString(), e); |
| return new Answer(cmd, false, "LoadBalancerConfigCommand failed due to " + e.getMessage()); |
| } |
| } |
| |
| protected Answer execute(final SavePasswordCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| |
| s_logger.info("Executing resource SavePasswordCommand. vmName: " + cmd.getVmName() + ", vmIp: " + cmd.getVmIpAddress() + ", password: " + |
| StringUtils.getMaskedPasswordForDisplay(cmd.getPassword())); |
| } |
| |
| final String controlIp = getRouterSshControlIp(cmd); |
| final String password = cmd.getPassword(); |
| final String vmIpAddress = cmd.getVmIpAddress(); |
| |
| // Run save_password_to_domr.sh |
| final String command = String.format("%s%s %s %s %s %s", "/opt/cloud/bin/", VRScripts.PASSWORD, "-v", vmIpAddress, "-p", password); |
| |
| if (s_logger.isDebugEnabled()) { |
| final String debugCommand = String.format("%s%s %s %s %s %s", "/opt/cloud/bin/", VRScripts.PASSWORD, "-v", vmIpAddress, "-p", StringUtils.getMaskedPasswordForDisplay(cmd.getPassword())); |
| s_logger.debug("Run command on domain router " + controlIp + debugCommand); |
| } |
| |
| try { |
| |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| 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 (final Throwable e) { |
| final 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(final SetFirewallRulesCommand cmd) { |
| final String controlIp = getRouterSshControlIp(cmd); |
| final String[] results = new String[cmd.getRules().length]; |
| final FirewallRuleTO[] allrules = cmd.getRules(); |
| final FirewallRule.TrafficType trafficType = allrules[0].getTrafficType(); |
| final String egressDefault = cmd.getAccessDetail(NetworkElementCommand.FIREWALL_EGRESS_DEFAULT); |
| |
| final 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 "; |
| } |
| } |
| |
| final StringBuilder sb = new StringBuilder(); |
| final 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<Boolean, String> 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 (final 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(final VmDataCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource VmDataCommand: " + s_gson.toJson(cmd)); |
| } |
| final String controlIp = getRouterSshControlIp(cmd); |
| final Map<String, List<String[]>> data = new HashMap<String, List<String[]>>(); |
| data.put(cmd.getVmIpAddress(), cmd.getVmData()); |
| |
| String json = new Gson().toJson(data); |
| s_logger.debug("VM data JSON IS:" + json); |
| |
| json = Base64.encodeBase64String(json.getBytes(Charset.forName("UTF-8"))); |
| final String command = String.format("%s%s %s %s", "/opt/cloud/bin/", VRScripts.VMDATA, "-d", json); |
| |
| try { |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| 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()); |
| } |
| |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("vm_data command on domain router " + controlIp + " completed"); |
| } |
| } catch (final Throwable e) { |
| final String msg = "VmDataCommand failed due to " + e.getMessage(); |
| s_logger.error(msg, e); |
| return new Answer(cmd, false, msg); |
| } |
| return new Answer(cmd); |
| } |
| |
| protected Answer execute(final 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"; |
| } |
| |
| final String command = String.format("%s%s %s", "/root/", VRScripts.DHCP, args); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + command); |
| } |
| |
| try { |
| final String controlIp = getRouterSshControlIp(cmd); |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| 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 (final Throwable e) { |
| final 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); |
| final List<IpAliasTO> ipAliasTOs = cmd.getIpAliasList(); |
| final StringBuilder args = new StringBuilder(); |
| for (final IpAliasTO ipaliasto : ipAliasTOs) { |
| args.append(ipaliasto.getAlias_count()); |
| args.append(":"); |
| args.append(ipaliasto.getRouterip()); |
| args.append(":"); |
| args.append(ipaliasto.getNetmask()); |
| args.append("-"); |
| } |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Run command on domR " + cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP) + ", /root/createIpAlias " + args); |
| } |
| |
| try { |
| final String controlIp = getRouterSshControlIp(cmd); |
| final Pair<Boolean, String> 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 (final Throwable e) { |
| final 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)); |
| } |
| final String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); |
| final String controlIp = getRouterSshControlIp(cmd); |
| |
| assert controlIp != null; |
| |
| final List<DhcpTO> dhcpTos = cmd.getIps(); |
| final StringBuilder args = new StringBuilder(); |
| for (final DhcpTO dhcpTo : dhcpTos) { |
| args.append(dhcpTo.getRouterIp()); |
| args.append(":"); |
| args.append(dhcpTo.getGateway()); |
| args.append(":"); |
| args.append(dhcpTo.getNetmask()); |
| args.append(":"); |
| args.append(dhcpTo.getStartIpOfSubnet()); |
| args.append("-"); |
| } |
| |
| try { |
| final String command = String.format("%s%s %s", "/root/", VRScripts.DHCP, args); |
| |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| 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 (final Throwable e) { |
| final String msg = "Dnsmasqconfig command failed due to " + e.getMessage(); |
| s_logger.error(msg, e); |
| return new Answer(cmd, false, msg); |
| } |
| |
| return new Answer(cmd); |
| } |
| |
| // |
| // 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(final String domrName, final String routerIp, final String mac) throws Exception { |
| |
| s_logger.info("findRouterEthDeviceIndex. mac: " + mac); |
| |
| // TODO : this is a temporary very inefficient solution, will refactor it later |
| final Pair<Boolean, String> 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 |
| final long startTick = System.currentTimeMillis(); |
| while (System.currentTimeMillis() - startTick < 15000) { |
| if (result.first()) { |
| final String[] tokens = result.second().split("\\s+"); |
| for (final String token : tokens) { |
| if (!("all".equalsIgnoreCase(token) || "default".equalsIgnoreCase(token) || "lo".equalsIgnoreCase(token))) { |
| final 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); |
| } |
| final Pair<Boolean, String> 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..."); |
| |
| } |
| |
| return -1; |
| } |
| |
| private Pair<Integer, String> findRouterFreeEthDeviceIndex(final String routerIp) throws Exception { |
| |
| s_logger.info("findRouterFreeEthDeviceIndex. mac: "); |
| |
| // TODO : this is a temporary very inefficient solution, will refactor it later |
| final Pair<Boolean, String> result = SshHelper.sshExecute(routerIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, |
| "ip address | grep DOWN| cut -f2 -d :"); |
| |
| // 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 |
| final long startTick = System.currentTimeMillis(); |
| while (System.currentTimeMillis() - startTick < 15000) { |
| if (result.first() && !result.second().isEmpty()) { |
| final String[] tokens = result.second().split("\\n"); |
| for (final 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); |
| //TODO: don't check for eth0,1,2, as they will be empty by default. |
| //String cmd = String.format("ip address show %s ", token); |
| final 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); |
| } |
| final Pair<Boolean, String> 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().length() > 0) { |
| return new Pair<Integer, String>(Integer.parseInt(token.trim().substring(3)), result2.second().trim()) ; |
| } |
| } |
| } |
| } |
| |
| //s_logger.warn("can not find intereface associated with mac: , guest OS may still at loading state, retry..."); |
| |
| } |
| |
| return new Pair<Integer, String>(-1, ""); |
| } |
| |
| protected Answer execute(final IpAssocCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource IPAssocCommand: " + s_gson.toJson(cmd)); |
| } |
| |
| int i = 0; |
| final String[] results = new String[cmd.getIpAddresses().length]; |
| |
| try { |
| |
| final IpAddressTO[] ips = cmd.getIpAddresses(); |
| final String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME); |
| final String controlIp = getRouterSshControlIp(cmd); |
| for (final 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 (final 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 int getVmFreeNicIndex(final String vmName) { |
| final GetVmConfigCommand vmConfig = new GetVmConfigCommand(vmName); |
| URI agentUri = null; |
| int nicposition = -1; |
| try { |
| final String cmdName = GetVmConfigCommand.class.getName(); |
| agentUri = |
| new URI("https", null, _agentIp, _port, |
| "/api/HypervResource/" + cmdName, null, null); |
| } catch (final URISyntaxException e) { |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| } |
| final String ansStr = postHttpRequest(s_gson.toJson(vmConfig), agentUri); |
| final Answer[] result = s_gson.fromJson(ansStr, Answer[].class); |
| s_logger.debug("GetVmConfigCommand response received " |
| + s_gson.toJson(result)); |
| if (result.length > 0) { |
| final GetVmConfigAnswer ans = (GetVmConfigAnswer)result[0]; |
| final List<NicDetails> nics = ans.getNics(); |
| for (final NicDetails nic : nics) { |
| if (nic.getState() == false) { |
| nicposition = nics.indexOf(nic); |
| break; |
| } |
| } |
| } |
| return nicposition; |
| } |
| |
| protected int getVmNics(final String vmName, String vlanid) { |
| final GetVmConfigCommand vmConfig = new GetVmConfigCommand(vmName); |
| URI agentUri = null; |
| int nicposition = -1; |
| if(vlanid.equalsIgnoreCase("untagged")) { |
| vlanid = "-1"; |
| } |
| try { |
| final String cmdName = GetVmConfigCommand.class.getName(); |
| agentUri = |
| new URI("https", null, _agentIp, _port, |
| "/api/HypervResource/" + cmdName, null, null); |
| } catch (final URISyntaxException e) { |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| } |
| final String ansStr = postHttpRequest(s_gson.toJson(vmConfig), agentUri); |
| final Answer[] result = s_gson.fromJson(ansStr, Answer[].class); |
| s_logger.debug("executeRequest received response " |
| + s_gson.toJson(result)); |
| if (result.length > 0) { |
| final GetVmConfigAnswer ans = (GetVmConfigAnswer)result[0]; |
| final List<NicDetails> nics = ans.getNics(); |
| for (final NicDetails nic : nics) { |
| nicposition++; |
| if (nicposition > 1 && nic.getVlanid().equals(vlanid)) { |
| break; |
| } |
| } |
| } |
| return nicposition; |
| } |
| |
| protected void modifyNicVlan(final String vmName, final String vlanId, final String macAddress) { |
| final ModifyVmNicConfigCommand modifynic = new ModifyVmNicConfigCommand(vmName, vlanId, macAddress); |
| URI agentUri = null; |
| try { |
| final String cmdName = ModifyVmNicConfigCommand.class.getName(); |
| agentUri = |
| new URI("https", null, _agentIp, _port, |
| "/api/HypervResource/" + cmdName, null, null); |
| } catch (final URISyntaxException e) { |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| } |
| final String ansStr = postHttpRequest(s_gson.toJson(modifynic), agentUri); |
| final Answer[] result = s_gson.fromJson(ansStr, Answer[].class); |
| s_logger.debug("executeRequest received response " |
| + s_gson.toJson(result)); |
| if (result.length > 0) { |
| } |
| } |
| |
| protected void modifyNicVlan(final String vmName, final String vlanId, final int pos, final boolean enable, final String switchLabelName) { |
| final ModifyVmNicConfigCommand modifyNic = new ModifyVmNicConfigCommand(vmName, vlanId, pos, enable); |
| modifyNic.setSwitchLableName(switchLabelName); |
| URI agentUri = null; |
| try { |
| final String cmdName = ModifyVmNicConfigCommand.class.getName(); |
| agentUri = |
| new URI("https", null, _agentIp, _port, |
| "/api/HypervResource/" + cmdName, null, null); |
| } catch (final URISyntaxException e) { |
| final String errMsg = "Could not generate URI for Hyper-V agent"; |
| s_logger.error(errMsg, e); |
| } |
| final String ansStr = postHttpRequest(s_gson.toJson(modifyNic), agentUri); |
| final Answer[] result = s_gson.fromJson(ansStr, Answer[].class); |
| s_logger.debug("executeRequest received response " |
| + s_gson.toJson(result)); |
| if (result.length > 0) { |
| } |
| } |
| |
| protected void assignPublicIpAddress(final String vmName, final String privateIpAddress, final String publicIpAddress, final boolean add, final boolean firstIP, |
| final boolean sourceNat, final String broadcastId, final String vlanGateway, final String vlanNetmask, final String vifMacAddress) throws Exception { |
| |
| final URI broadcastUri = BroadcastDomainType.fromString(broadcastId); |
| if (BroadcastDomainType.getSchemeValue(broadcastUri) != BroadcastDomainType.Vlan) { |
| throw new InternalErrorException("Unable to assign a public IP to a VIF on network " + broadcastId); |
| } |
| final String vlanId = BroadcastDomainType.getValue(broadcastUri); |
| |
| int publicNicInfo = -1; |
| publicNicInfo = getVmNics(vmName, vlanId); |
| |
| boolean addVif = false; |
| if (add && publicNicInfo == -1) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Plug new NIC to associate" + privateIpAddress + " to " + publicIpAddress); |
| } |
| addVif = true; |
| } else if (!add && firstIP) { |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Unplug NIC " + publicNicInfo); |
| } |
| } |
| |
| if (addVif) { |
| final Pair<Integer, String> nicdevice = findRouterFreeEthDeviceIndex(privateIpAddress); |
| publicNicInfo = nicdevice.first(); |
| if (publicNicInfo > 0) { |
| modifyNicVlan(vmName, vlanId, nicdevice.second()); |
| // After modifying the vnic on VR, check the VR VNics config in the host and get the device position |
| publicNicInfo = getVmNics(vmName, vlanId); |
| // As a new nic got activated in the VR. add the entry in the NIC's table. |
| networkUsage(privateIpAddress, "addVif", "eth" + publicNicInfo); |
| } |
| else { |
| // we didn't find any eth device available in VR to configure the ip range with new VLAN |
| final String msg = "No Nic is available on 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 "; |
| } |
| final String cidrSize = Long.toString(NetUtils.getCidrSize(vlanNetmask)); |
| args += " -l "; |
| args += publicIpAddress + "/" + cidrSize; |
| |
| args += " -c "; |
| |
| args += "eth" + publicNicInfo; |
| args += " -g "; |
| args += vlanGateway; |
| |
| if (addVif) { |
| args += " -n "; |
| } |
| |
| final String command = String.format("%s%s %s","/opt/cloud/bin/", VRScripts.IPASSOC ,args); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Run command on domain router " + privateIpAddress + command); |
| } |
| |
| final Pair<Boolean, String> result = |
| SshHelper.sshExecute(privateIpAddress, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| 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(final GetDomRVersionCmd cmd) { |
| final String command = String.format("%s%s", "/opt/cloud/bin/", VRScripts.VERSION); |
| |
| 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) + command); |
| } |
| |
| Pair<Boolean, String> result; |
| try { |
| final String controlIp = getRouterSshControlIp(cmd); |
| result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| 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 (final Throwable e) { |
| final String msg = "GetDomRVersionCmd failed due to " + e; |
| s_logger.error(msg, e); |
| return new GetDomRVersionAnswer(cmd, msg); |
| } |
| final 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(final NetworkElementCommand cmd) { |
| final String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP); |
| final String routerGuestIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_GUEST_IP); |
| final 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(final 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")) { |
| networkUsage(cmd.getPrivateIP(), "create", null); |
| final NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, "true", 0L, 0L); |
| return answer; |
| } |
| final long[] stats = getNetworkStats(cmd.getPrivateIP()); |
| |
| final NetworkUsageAnswer answer = new NetworkUsageAnswer(cmd, "", stats[0], stats[1]); |
| return answer; |
| } |
| |
| private long[] getNetworkStats(final String privateIP) { |
| final String result = networkUsage(privateIP, "get", null); |
| final long[] stats = new long[2]; |
| if (result != null) { |
| try { |
| final String[] splitResult = result.split(":"); |
| int i = 0; |
| while (i < splitResult.length - 1) { |
| stats[0] += Long.parseLong(splitResult[i++]); |
| stats[1] += Long.parseLong(splitResult[i++]); |
| } |
| } catch (final Throwable e) { |
| s_logger.warn("Unable to parse return from script return of network usage command: " + e.toString(), e); |
| } |
| } |
| return stats; |
| } |
| |
| protected Answer execute(final SetMonitorServiceCommand cmd) { |
| if (s_logger.isInfoEnabled()) { |
| s_logger.info("Executing resource SetMonitorServiceCommand: " + s_gson.toJson(cmd)); |
| } |
| |
| final String controlIp = getRouterSshControlIp(cmd); |
| final String config = cmd.getConfiguration(); |
| final String args = String.format(" %s %s", "-c", config); |
| |
| final String command = String.format("%s%s %s", "/opt/cloud/bin/", VRScripts.MONITOR_SERVICE, args); |
| |
| try { |
| final Pair<Boolean, String> result = SshHelper.sshExecute(controlIp, DEFAULT_DOMR_SSHPORT, "root", getSystemVMKeyFile(), null, command); |
| |
| if (!result.first()) { |
| final String msg= "monitor_service.sh failed on domain router " + controlIp + " failed " + result.second(); |
| s_logger.error(msg); |
| return new Answer(cmd, false, msg); |
| } |
| |
| return new Answer(cmd); |
| |
| } catch (final Throwable e) { |
| s_logger.error("Unexpected exception: " + e.toString(), e); |
| return new Answer(cmd, false, "SetMonitorServiceCommand failed due to " + e); |
| } |
| } |
| |
| protected CheckSshAnswer execute(final CheckSshCommand cmd) { |
| final String vmName = cmd.getName(); |
| final String privateIp = cmd.getIp(); |
| final int cmdPort = cmd.getPort(); |
| |
| if (s_logger.isDebugEnabled()) { |
| s_logger.debug("Ping command port, " + privateIp + ":" + cmdPort); |
| } |
| |
| try { |
| final 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 (final 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); |
| } |
| |
| final Pair<Boolean, String> 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 (final 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; |
| } |
| |
| public File getSystemVMKeyFile() { |
| final 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 |
| // 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. |
| String logMessage = StringEscapeUtils.unescapeJava(jsonCmd); |
| logMessage = cleanPassword(logMessage); |
| s_logger.debug("POST request to " + agentUri.toString() |
| + " with contents " + logMessage); |
| |
| // Create request |
| HttpClient httpClient = null; |
| final TrustStrategy easyStrategy = new TrustStrategy() { |
| @Override |
| public boolean isTrusted(final X509Certificate[] chain, final String authType) |
| throws CertificateException { |
| return true; |
| } |
| }; |
| |
| try { |
| final SSLSocketFactory sf = new SSLSocketFactory(easyStrategy, new AllowAllHostnameVerifier()); |
| final SchemeRegistry registry = new SchemeRegistry(); |
| registry.register(new Scheme("https", DEFAULT_AGENT_PORT, sf)); |
| final ClientConnectionManager ccm = new BasicClientConnectionManager(registry); |
| httpClient = new DefaultHttpClient(ccm); |
| } catch (final KeyManagementException e) { |
| s_logger.error("failed to initialize http client " + e.getMessage()); |
| } catch (final UnrecoverableKeyException e) { |
| s_logger.error("failed to initialize http client " + e.getMessage()); |
| } catch (final NoSuchAlgorithmException e) { |
| s_logger.error("failed to initialize http client " + e.getMessage()); |
| } catch (final KeyStoreException e) { |
| s_logger.error("failed to initialize http client " + e.getMessage()); |
| } |
| |
| String result = null; |
| |
| // TODO: are there timeout settings and worker thread settings to tweak? |
| try { |
| final HttpPost request = new HttpPost(agentUri); |
| |
| // JSON encode command |
| // Assumes command sits comfortably in a string, i.e. not used for |
| // large data transfers |
| final StringEntity cmdJson = new StringEntity(jsonCmd); |
| request.addHeader("content-type", "application/json"); |
| request.setEntity(cmdJson); |
| s_logger.debug("Sending cmd to " + agentUri.toString() |
| + " cmd data:" + logMessage); |
| final HttpResponse response = httpClient.execute(request); |
| |
| // Unsupported commands will not route. |
| if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) { |
| final String errMsg = "Failed to send : HTTP error code : " + response.getStatusLine().getStatusCode(); |
| s_logger.error(errMsg); |
| final String unsupportMsg = "Unsupported command " + agentUri.getPath() + ". Are you sure you got the right type of" + " server?"; |
| final 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) { |
| final 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()); |
| final String logResult = cleanPassword(StringEscapeUtils.unescapeJava(result)); |
| s_logger.debug("POST response is " + logResult); |
| } |
| } catch (final ClientProtocolException protocolEx) { |
| // Problem with HTTP message exchange |
| s_logger.error(protocolEx); |
| } catch (final 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. */ |
| |
| if (params != null) { |
| _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; |
| } |
| |
| _vrResource = new VirtualRoutingResource(this); |
| if (!_vrResource.configure(name, new HashMap<String, Object>())) { |
| throw new ConfigurationException("Unable to configure VirtualRoutingResource"); |
| } |
| 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 |
| } |
| |
| protected String connect(final String vmName, final String ipAddress, final int port) { |
| final 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 <= _opsTimeout || --retry > 0) { |
| s_logger.info("Trying to connect to " + ipAddress); |
| try (SocketChannel sch = SocketChannel.open();) { |
| sch.configureBlocking(true); |
| sch.socket().setSoTimeout(5000); |
| // we need to connect to the control ip address to check the status of the system vm |
| final InetSocketAddress addr = new InetSocketAddress(ipAddress, port); |
| sch.connect(addr); |
| return null; |
| } catch (final 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 (final InterruptedException ex) { |
| s_logger.debug("[ignored] interupted while waiting to retry connecting to vm after exception: "+e.getLocalizedMessage()); |
| } |
| } |
| } |
| |
| try { |
| Thread.sleep(1000); |
| } catch (final InterruptedException ex) { |
| s_logger.debug("[ignored] interupted while connecting to vm."); |
| } |
| } |
| |
| s_logger.info("Unable to logon to " + ipAddress); |
| |
| return "Unable to connect"; |
| } |
| |
| public static String cleanPassword(final String logString) { |
| String cleanLogString = null; |
| if (logString != null) { |
| cleanLogString = logString; |
| final String[] temp = logString.split(","); |
| int i = 0; |
| if (temp != null) { |
| while (i < temp.length) { |
| temp[i] = StringUtils.cleanString(temp[i]); |
| i++; |
| } |
| final List<String> stringList = new ArrayList<String>(); |
| Collections.addAll(stringList, temp); |
| cleanLogString = StringUtils.join(stringList, ","); |
| } |
| } |
| return cleanLogString; |
| } |
| } |