blob: 0cdd0f128224809a402164cc1e0e4ff5d99068fb [file] [log] [blame]
// 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.
//
// Automatically generated by addcopyright.py at 01/29/2013
// Apache License, Version 2.0 (the "License"); you may not use this
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//
// Automatically generated by addcopyright.py at 04/03/2012
package com.cloud.baremetal.networkservice;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.log4j.Logger;
import com.cloud.agent.IAgentControl;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.CheckNetworkAnswer;
import com.cloud.agent.api.CheckNetworkCommand;
import com.cloud.agent.api.CheckVirtualMachineAnswer;
import com.cloud.agent.api.CheckVirtualMachineCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.HostVmStateReportEntry;
import com.cloud.agent.api.MaintainAnswer;
import com.cloud.agent.api.MaintainCommand;
import com.cloud.agent.api.MigrateAnswer;
import com.cloud.agent.api.MigrateCommand;
import com.cloud.agent.api.PingCommand;
import com.cloud.agent.api.PingRoutingCommand;
import com.cloud.agent.api.PrepareForMigrationAnswer;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.ReadyAnswer;
import com.cloud.agent.api.ReadyCommand;
import com.cloud.agent.api.RebootAnswer;
import com.cloud.agent.api.RebootCommand;
import com.cloud.agent.api.SecurityGroupRulesCmd;
import com.cloud.agent.api.StartAnswer;
import com.cloud.agent.api.StartCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.StopAnswer;
import com.cloud.agent.api.StopCommand;
import com.cloud.agent.api.baremetal.IpmISetBootDevCommand;
import com.cloud.agent.api.baremetal.IpmISetBootDevCommand.BootDev;
import com.cloud.agent.api.baremetal.IpmiBootorResetCommand;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.baremetal.manager.BaremetalManager;
import com.cloud.configuration.Config;
import com.cloud.host.Host.Type;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.resource.ServerResource;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.script.OutputInterpreter;
import com.cloud.utils.script.Script;
import com.cloud.utils.script.Script2;
import com.cloud.utils.script.Script2.ParamType;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.PowerState;
import com.cloud.vm.dao.VMInstanceDao;
public class BareMetalResourceBase extends ManagerBase implements ServerResource {
private static final Logger s_logger = Logger.getLogger(BareMetalResourceBase.class);
protected String _uuid;
protected String _zone;
protected String _pod;
protected Long hostId;
protected String _cluster;
protected long _memCapacity;
protected long _cpuCapacity;
protected long _cpuNum;
protected String _mac;
protected String _username;
protected String _password;
protected String _ip;
protected boolean _isEchoScAgent;
protected IAgentControl _agentControl;
protected Script2 _pingCommand;
protected Script2 _setPxeBootCommand;
protected Script2 _setDiskBootCommand;
protected Script2 _rebootCommand;
protected Script2 _getStatusCommand;
protected Script2 _powerOnCommand;
protected Script2 _powerOffCommand;
protected Script2 _forcePowerOffCommand;
protected Script2 _bootOrRebootCommand;
protected String _vmName;
protected int ipmiRetryTimes = 5;
protected boolean provisionDoneNotificationOn = false;
protected int isProvisionDoneNotificationTimeout = 1800;
protected ConfigurationDao configDao;
protected VMInstanceDao vmDao;
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
setName(name);
_uuid = (String) params.get("guid");
try {
_memCapacity = Long.parseLong((String) params.get(ApiConstants.MEMORY)) * 1024L * 1024L;
_cpuCapacity = Long.parseLong((String) params.get(ApiConstants.CPU_SPEED));
_cpuNum = Long.parseLong((String) params.get(ApiConstants.CPU_NUMBER));
} catch (NumberFormatException e) {
throw new ConfigurationException(String.format("Unable to parse number of CPU or memory capacity "
+ "or cpu capacity(cpu number = %1$s memCapacity=%2$s, cpuCapacity=%3$s", params.get(ApiConstants.CPU_NUMBER),
params.get(ApiConstants.MEMORY), params.get(ApiConstants.CPU_SPEED)));
}
_zone = (String) params.get("zone");
_pod = (String) params.get("pod");
_cluster = (String) params.get("cluster");
hostId = (Long) params.get("hostId");
_ip = (String) params.get(ApiConstants.PRIVATE_IP);
_mac = (String) params.get(ApiConstants.HOST_MAC);
_username = (String) params.get(ApiConstants.USERNAME);
_password = (String) params.get(ApiConstants.PASSWORD);
_vmName = (String) params.get("vmName");
String echoScAgent = (String) params.get(BaremetalManager.EchoSecurityGroupAgent);
vmDao = (VMInstanceDao) params.get("vmDao");
configDao = (ConfigurationDao) params.get("configDao");
if (_pod == null) {
throw new ConfigurationException("Unable to get the pod");
}
if (_cluster == null) {
throw new ConfigurationException("Unable to get the pod");
}
if (_ip == null) {
throw new ConfigurationException("Unable to get the host address");
}
if (_mac.equalsIgnoreCase("unknown")) {
throw new ConfigurationException("Unable to get the host mac address");
}
if (_mac.split(":").length != 6) {
throw new ConfigurationException("Wrong MAC format(" + _mac
+ "). It must be in format of for example 00:11:ba:33:aa:dd which is not case sensitive");
}
if (_uuid == null) {
throw new ConfigurationException("Unable to get the uuid");
}
if (echoScAgent != null) {
_isEchoScAgent = Boolean.valueOf(echoScAgent);
}
String ipmiIface = "default";
try {
ipmiIface = configDao.getValue(Config.BaremetalIpmiLanInterface.key());
} catch (Exception e) {
s_logger.debug(e.getMessage(), e);
}
try {
ipmiRetryTimes = Integer.parseInt(configDao.getValue(Config.BaremetalIpmiRetryTimes.key()));
} catch (Exception e) {
s_logger.debug(e.getMessage(), e);
}
try {
provisionDoneNotificationOn = Boolean.valueOf(configDao.getValue(Config.BaremetalProvisionDoneNotificationEnabled.key()));
isProvisionDoneNotificationTimeout = Integer.parseInt(configDao.getValue(Config.BaremetalProvisionDoneNotificationTimeout.key()));
} catch (Exception e) {
s_logger.debug(e.getMessage(), e);
}
String injectScript = "scripts/util/ipmi.py";
String scriptPath = Script.findScript("", injectScript);
if (scriptPath == null) {
throw new ConfigurationException("Cannot find ping script " + scriptPath);
}
String pythonPath = "/usr/bin/python";
_pingCommand = new Script2(pythonPath, s_logger);
_pingCommand.add(scriptPath);
_pingCommand.add("ping");
_pingCommand.add("interface=" + ipmiIface);
_pingCommand.add("hostname=" + _ip);
_pingCommand.add("usrname=" + _username);
_pingCommand.add("password=" + _password, ParamType.PASSWORD);
_setPxeBootCommand = new Script2(pythonPath, s_logger);
_setPxeBootCommand.add(scriptPath);
_setPxeBootCommand.add("boot_dev");
_setPxeBootCommand.add("interface=" + ipmiIface);
_setPxeBootCommand.add("hostname=" + _ip);
_setPxeBootCommand.add("usrname=" + _username);
_setPxeBootCommand.add("password=" + _password, ParamType.PASSWORD);
_setPxeBootCommand.add("dev=pxe");
_setDiskBootCommand = new Script2(pythonPath, s_logger);
_setDiskBootCommand.add(scriptPath);
_setDiskBootCommand.add("boot_dev");
_setDiskBootCommand.add("interface=" + ipmiIface);
_setDiskBootCommand.add("hostname=" + _ip);
_setDiskBootCommand.add("usrname=" + _username);
_setDiskBootCommand.add("password=" + _password, ParamType.PASSWORD);
_setDiskBootCommand.add("dev=disk");
_rebootCommand = new Script2(pythonPath, s_logger);
_rebootCommand.add(scriptPath);
_rebootCommand.add("reboot");
_rebootCommand.add("interface=" + ipmiIface);
_rebootCommand.add("hostname=" + _ip);
_rebootCommand.add("usrname=" + _username);
_rebootCommand.add("password=" + _password, ParamType.PASSWORD);
_getStatusCommand = new Script2(pythonPath, s_logger);
_getStatusCommand.add(scriptPath);
_getStatusCommand.add("ping");
_getStatusCommand.add("interface=" + ipmiIface);
_getStatusCommand.add("hostname=" + _ip);
_getStatusCommand.add("usrname=" + _username);
_getStatusCommand.add("password=" + _password, ParamType.PASSWORD);
_powerOnCommand = new Script2(pythonPath, s_logger);
_powerOnCommand.add(scriptPath);
_powerOnCommand.add("power");
_powerOnCommand.add("interface=" + ipmiIface);
_powerOnCommand.add("hostname=" + _ip);
_powerOnCommand.add("usrname=" + _username);
_powerOnCommand.add("password=" + _password, ParamType.PASSWORD);
_powerOnCommand.add("action=on");
_powerOffCommand = new Script2(pythonPath, s_logger);
_powerOffCommand.add(scriptPath);
_powerOffCommand.add("power");
_powerOffCommand.add("interface=" + ipmiIface);
_powerOffCommand.add("hostname=" + _ip);
_powerOffCommand.add("usrname=" + _username);
_powerOffCommand.add("password=" + _password, ParamType.PASSWORD);
_powerOffCommand.add("action=soft");
_forcePowerOffCommand = new Script2(pythonPath, s_logger);
_forcePowerOffCommand.add(scriptPath);
_forcePowerOffCommand.add("power");
_forcePowerOffCommand.add("interface=" + ipmiIface);
_forcePowerOffCommand.add("hostname=" + _ip);
_forcePowerOffCommand.add("usrname=" + _username);
_forcePowerOffCommand.add("password=" + _password, ParamType.PASSWORD);
_forcePowerOffCommand.add("action=off");
_bootOrRebootCommand = new Script2(pythonPath, s_logger);
_bootOrRebootCommand.add(scriptPath);
_bootOrRebootCommand.add("boot_or_reboot");
_bootOrRebootCommand.add("interface=" + ipmiIface);
_bootOrRebootCommand.add("hostname=" + _ip);
_bootOrRebootCommand.add("usrname=" + _username);
_bootOrRebootCommand.add("password=" + _password, ParamType.PASSWORD);
return true;
}
protected boolean doScript(Script cmd) {
return doScript(cmd, null);
}
protected boolean doScript(Script cmd, int retry) {
return doScript(cmd, null, retry);
}
protected boolean doScript(Script cmd, OutputInterpreter interpreter) {
return doScript(cmd, interpreter, ipmiRetryTimes);
}
protected boolean doScript(Script cmd, OutputInterpreter interpreter, int retry) {
String res = null;
while (retry-- > 0) {
if (interpreter == null) {
res = cmd.execute();
} else {
res = cmd.execute(interpreter);
}
if (res != null && res.startsWith("Error: Unable to establish LAN")) {
s_logger.warn("IPMI script timeout(" + cmd.toString() + "), will retry " + retry + " times");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
s_logger.debug("[ignored] interrupted while waiting to retry running script.");
}
continue;
} else if (res == null) {
return true;
} else {
break;
}
}
s_logger.warn("IPMI Scirpt failed due to " + res + "(" + cmd.toString() + ")");
return false;
}
@Override
public boolean start() {
return true;
}
@Override
public boolean stop() {
return true;
}
@Override
public Type getType() {
return com.cloud.host.Host.Type.Routing;
}
protected Map<String, HostVmStateReportEntry> getHostVmStateReport() {
Map<String, HostVmStateReportEntry> states = new HashMap<String, HostVmStateReportEntry>();
if (hostId != null) {
final List<? extends VMInstanceVO> vms = vmDao.listByHostId(hostId);
for (VMInstanceVO vm : vms) {
states.put(
vm.getInstanceName(),
new HostVmStateReportEntry(
vm.getPowerState(), "host-" + hostId
)
);
}
}
return states;
}
@Override
public StartupCommand[] initialize() {
StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.BareMetal,
new HashMap<String, String>());
cmd.setDataCenter(_zone);
cmd.setPod(_pod);
cmd.setCluster(_cluster);
cmd.setGuid(_uuid);
cmd.setName(_ip);
cmd.setPrivateIpAddress(_ip);
cmd.setStorageIpAddress(_ip);
cmd.setVersion(BareMetalResourceBase.class.getPackage().getImplementationVersion());
cmd.setCpus((int) _cpuNum);
cmd.setSpeed(_cpuCapacity);
cmd.setMemory(_memCapacity);
cmd.setPrivateMacAddress(_mac);
cmd.setPublicMacAddress(_mac);
return new StartupCommand[] { cmd };
}
private boolean ipmiPing() {
return doScript(_pingCommand);
}
@Override
public PingCommand getCurrentStatus(long id) {
try {
if (!ipmiPing()) {
Thread.sleep(1000);
if (!ipmiPing()) {
s_logger.warn("Cannot ping ipmi nic " + _ip);
return null;
}
}
} catch (Exception e) {
s_logger.debug("Cannot ping ipmi nic " + _ip, e);
return null;
}
return new PingRoutingCommand(getType(), id, null);
/*
if (hostId != null) {
final List<? extends VMInstanceVO> vms = vmDao.listByHostId(hostId);
if (vms.isEmpty()) {
return new PingRoutingCommand(getType(), id, null);
} else {
VMInstanceVO vm = vms.get(0);
SecurityGroupHttpClient client = new SecurityGroupHttpClient();
HashMap<String, Pair<Long, Long>> nwGrpStates = client.sync(vm.getInstanceName(), vm.getId(), vm.getPrivateIpAddress());
return new PingRoutingWithNwGroupsCommand(getType(), id, null, nwGrpStates);
}
} else {
return new PingRoutingCommand(getType(), id, null);
}
*/
}
protected Answer execute(IpmISetBootDevCommand cmd) {
Script bootCmd = null;
if (cmd.getBootDev() == BootDev.disk) {
bootCmd = _setDiskBootCommand;
} else if (cmd.getBootDev() == BootDev.pxe) {
bootCmd = _setPxeBootCommand;
} else {
throw new CloudRuntimeException("Unknown boot dev " + cmd.getBootDev());
}
String bootDev = cmd.getBootDev().name();
if (!doScript(bootCmd)) {
s_logger.warn("Set " + _ip + " boot dev to " + bootDev + "failed");
return new Answer(cmd, false, "Set " + _ip + " boot dev to " + bootDev + "failed");
}
s_logger.warn("Set " + _ip + " boot dev to " + bootDev + "Success");
return new Answer(cmd, true, "Set " + _ip + " boot dev to " + bootDev + "Success");
}
protected MaintainAnswer execute(MaintainCommand cmd) {
return new MaintainAnswer(cmd, false);
}
protected PrepareForMigrationAnswer execute(PrepareForMigrationCommand cmd) {
return new PrepareForMigrationAnswer(cmd);
}
protected MigrateAnswer execute(MigrateCommand cmd) {
if (!doScript(_powerOffCommand)) {
return new MigrateAnswer(cmd, false, "IPMI power off failed", null);
}
return new MigrateAnswer(cmd, true, "success", null);
}
protected CheckVirtualMachineAnswer execute(final CheckVirtualMachineCommand cmd) {
return new CheckVirtualMachineAnswer(cmd, PowerState.PowerOff, null);
}
protected Answer execute(IpmiBootorResetCommand cmd) {
if (!doScript(_bootOrRebootCommand)) {
return new Answer(cmd, false, "IPMI boot or reboot failed");
}
return new Answer(cmd, true, "Success");
}
protected CheckNetworkAnswer execute(CheckNetworkCommand cmd) {
return new CheckNetworkAnswer(cmd, true, "Success");
}
protected Answer execute(SecurityGroupRulesCmd cmd) {
SecurityGroupHttpClient hc = new SecurityGroupHttpClient();
return hc.call(cmd.getGuestIp(), cmd);
}
@Override
public Answer executeRequest(Command cmd) {
try {
if (cmd instanceof ReadyCommand) {
return execute((ReadyCommand) cmd);
} else if (cmd instanceof StartCommand) {
return execute((StartCommand) cmd);
} else if (cmd instanceof StopCommand) {
return execute((StopCommand) cmd);
} else if (cmd instanceof RebootCommand) {
return execute((RebootCommand) cmd);
} else if (cmd instanceof IpmISetBootDevCommand) {
return execute((IpmISetBootDevCommand) cmd);
} else if (cmd instanceof MaintainCommand) {
return execute((MaintainCommand) cmd);
} else if (cmd instanceof PrepareForMigrationCommand) {
return execute((PrepareForMigrationCommand) cmd);
} else if (cmd instanceof MigrateCommand) {
return execute((MigrateCommand) cmd);
} else if (cmd instanceof CheckVirtualMachineCommand) {
return execute((CheckVirtualMachineCommand) cmd);
} else if (cmd instanceof IpmiBootorResetCommand) {
return execute((IpmiBootorResetCommand) cmd);
} else if (cmd instanceof SecurityGroupRulesCmd) {
return execute((SecurityGroupRulesCmd) cmd);
} else if (cmd instanceof CheckNetworkCommand) {
return execute((CheckNetworkCommand) cmd);
} else {
return Answer.createUnsupportedCommandAnswer(cmd);
}
} catch (Throwable t) {
s_logger.debug(t.getMessage(), t);
return new Answer(cmd, false, t.getMessage());
}
}
protected boolean isPowerOn(String str) {
if (str.startsWith("Chassis Power is on")) {
return true;
} else if (str.startsWith("Chassis Power is off")) {
return false;
} else {
throw new CloudRuntimeException("Cannot parse IPMI power status " + str);
}
}
protected RebootAnswer execute(final RebootCommand cmd) {
String infoStr = "Command not supported in present state";
OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser();
if (!doScript(_rebootCommand, interpreter, 10)) {
if (interpreter.getLines().contains(infoStr)) {
// try again, this error should be temporary
if (!doScript(_rebootCommand, interpreter, 10)) {
return new RebootAnswer(cmd, "IPMI reboot failed", false);
}
} else {
return new RebootAnswer(cmd, "IPMI reboot failed", false);
}
}
return new RebootAnswer(cmd, "reboot succeeded", true);
}
protected StopAnswer execute(final StopCommand cmd) {
boolean success = false;
int count = 0;
Script powerOff = _powerOffCommand;
while (count < 10) {
if (!doScript(powerOff)) {
break;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser();
if (!doScript(_getStatusCommand, interpreter)) {
success = true;
s_logger.warn("Cannot get power status of " + getName() + ", assume VM state changed successfully");
break;
}
if (!isPowerOn(interpreter.getLines())) {
success = true;
break;
} else {
powerOff = _forcePowerOffCommand;
}
count++;
}
return success ? new StopAnswer(cmd, "Success", true) : new StopAnswer(cmd, "IPMI power off failed", false);
}
protected StartAnswer execute(StartCommand cmd) {
VirtualMachineTO vm = cmd.getVirtualMachine();
OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser();
if (!doScript(_getStatusCommand, interpreter)) {
return new StartAnswer(cmd, "Cannot get current power status of " + getName());
}
if (isPowerOn(interpreter.getLines())) {
if (!doScript(_rebootCommand)) {
return new StartAnswer(cmd, "IPMI reboot failed");
}
} else {
if (!doScript(_powerOnCommand)) {
return new StartAnswer(cmd, "IPMI power on failed");
}
}
if (_isEchoScAgent) {
SecurityGroupHttpClient hc = new SecurityGroupHttpClient();
boolean echoRet = hc.echo(vm.getNics()[0].getIp(), TimeUnit.MINUTES.toMillis(30), TimeUnit.MINUTES.toMillis(1));
if (!echoRet) {
return new StartAnswer(cmd, String.format("Call security group agent on vm[%s] timeout", vm.getNics()[0].getIp()));
}
}
if (provisionDoneNotificationOn) {
QueryBuilder<VMInstanceVO> q = QueryBuilder.create(VMInstanceVO.class);
q.and(q.entity().getInstanceName(), SearchCriteria.Op.EQ, vm.getName());
VMInstanceVO vmvo = q.find();
if (vmvo.getLastHostId() == null) {
// this is new created vm
long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(isProvisionDoneNotificationTimeout);
while (timeout > System.currentTimeMillis()) {
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
s_logger.warn(e.getMessage(), e);
}
q = QueryBuilder.create(VMInstanceVO.class);
q.and(q.entity().getInstanceName(), SearchCriteria.Op.EQ, vm.getName());
vmvo = q.find();
if (vmvo == null) {
return new StartAnswer(cmd, String.format("cannot find vm[name:%s] while waiting for baremtal provision done notification", vm.getName()));
}
if (VirtualMachine.State.Running == vmvo.getState()) {
return new StartAnswer(cmd);
}
s_logger.debug(String.format("still wait for baremetal provision done notification for vm[name:%s], current vm state is %s", vmvo.getInstanceName(), vmvo.getState()));
}
return new StartAnswer(cmd, String.format("timeout after %s seconds, no baremetal provision done notification received. vm[name:%s] failed to start", isProvisionDoneNotificationTimeout, vm.getName()));
}
}
s_logger.debug("Start bare metal vm " + vm.getName() + "successfully");
_vmName = vm.getName();
return new StartAnswer(cmd);
}
protected ReadyAnswer execute(ReadyCommand cmd) {
// derived resource should check if the PXE server is ready
s_logger.debug("Bare metal resource " + getName() + " is ready");
return new ReadyAnswer(cmd);
}
@Override
public void disconnected() {
}
@Override
public IAgentControl getAgentControl() {
return _agentControl;
}
@Override
public void setAgentControl(IAgentControl agentControl) {
_agentControl = agentControl;
}
}