- Support to patch SystemVMs - VMWare

- Remove attaching systemvm.iso to systemVMs
- Modify / Refactor VMware start command to copy patch related files to the systemvms
- cleanup
This commit is contained in:
Pearl Dsilva 2021-12-14 18:25:07 +05:30
parent 4481c9925a
commit 239ee80a88
4 changed files with 136 additions and 15 deletions

View File

@ -48,6 +48,10 @@ import java.util.stream.Collectors;
import javax.naming.ConfigurationException;
import javax.xml.datatype.XMLGregorianCalendar;
import com.cloud.agent.api.PatchSystemVmAnswer;
import com.cloud.agent.api.PatchSystemVmCommand;
import com.cloud.resource.ServerResourceBase;
import com.cloud.utils.FileUtil;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.storage.command.CopyCommand;
import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
@ -362,9 +366,10 @@ import com.vmware.vim25.VmConfigSpec;
import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec;
import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec;
public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService, VirtualRouterDeployer {
public class VmwareResource extends ServerResourceBase implements StoragePoolResource, ServerResource, VmwareHostService, VirtualRouterDeployer {
private static final Logger s_logger = Logger.getLogger(VmwareResource.class);
public static final String VMDK_EXTENSION = ".vmdk";
public static final String BASEPATH = "/usr/share/cloudstack-common/vms/";
private static final Random RANDOM = new Random(System.nanoTime());
@ -594,7 +599,9 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
answer = execute((SetupPersistentNetworkCommand) cmd);
} else if (clz == GetVmVncTicketCommand.class) {
answer = execute((GetVmVncTicketCommand) cmd);
} else {
} else if (clz == PatchSystemVmCommand.class) {
answer = execute((PatchSystemVmCommand) cmd);
} else {
answer = Answer.createUnsupportedCommandAnswer(cmd);
}
@ -634,6 +641,68 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return answer;
}
private ExecutionResult getSystemVmVersionAndChecksum(String controlIp) {
ExecutionResult result;
try {
result = executeInVR(controlIp, VRScripts.VERSION, null);
if (!result.isSuccess()) {
String errMsg = String.format("GetSystemVMVersionCmd on %s failed, message %s", controlIp, result.getDetails());
s_logger.error(errMsg);
throw new CloudRuntimeException(errMsg);
}
} catch (final Exception e) {
final String msg = "GetSystemVMVersionCmd failed due to " + e;
s_logger.error(msg, e);
throw new CloudRuntimeException(msg, e);
}
return result;
}
private Answer execute(PatchSystemVmCommand cmd) {
String controlIp = getRouterSshControlIp(cmd);
String sysVMName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
String homeDir = System.getProperty("user.home");
File pemFile = new File(homeDir + "/.ssh/id_rsa");
ExecutionResult result = getSystemVmVersionAndChecksum(controlIp);
try {
FileUtil.scpPatchFiles(controlIp, "/home/cloud", DefaultDomRSshPort, pemFile, newSrcFiles, BASEPATH);
} catch (CloudRuntimeException e) {
return new PatchSystemVmAnswer(cmd, e.getMessage());
}
final String[] lines = result.getDetails().split("&");
// TODO: do we fail, or patch anyway??
if (lines.length != 2) {
return new PatchSystemVmAnswer(cmd, result.getDetails());
}
String scriptChecksum = lines[1].trim();
String checksum = calculateCurrentChecksum(sysVMName).trim();
if (!org.apache.commons.lang3.StringUtils.isEmpty(checksum) && checksum.equals(scriptChecksum)) {
if (!cmd.isForced()) {
String msg = String.format("No change in the scripts checksum, not patching systemVM %s", sysVMName);
s_logger.info(msg);
return new PatchSystemVmAnswer(cmd, msg, lines[0], lines[1]);
}
}
Pair<Boolean, String> patchResult = null;
try {
patchResult = SshHelper.sshExecute(controlIp, DefaultDomRSshPort, "root",
pemFile, null, "/home/cloud/patch-sysvms.sh", 10000, 10000, 60000);
} catch (Exception e) {
return new PatchSystemVmAnswer(cmd, e.getMessage());
}
if (patchResult.first()) {
return new PatchSystemVmAnswer(cmd, String.format("Successfully patched systemVM %s ", sysVMName), lines[0], lines[1]);
}
return new PatchSystemVmAnswer(cmd, patchResult.second());
}
private Answer execute(SetupPersistentNetworkCommand cmd) {
VmwareHypervisorHost host = getHyperHost(getServiceContext());
String hostname = null;
@ -2100,7 +2169,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo,
String.format("[%s] systemvm/%s", secDsMo.getName(), mgr.getSystemVMIsoFileNameOnDatastore()), secDsMo.getMor(), true, true, ideUnitNumber++, i + 1);
null, secDsMo.getMor(), true, true, ideUnitNumber++, i + 1);
deviceConfigSpecArray[i].setDevice(isoInfo.first());
if (isoInfo.second()) {
if (s_logger.isDebugEnabled())
@ -2485,6 +2554,29 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
startAnswer.setIqnToData(iqnToData);
if (vmSpec.getType() != VirtualMachine.Type.User) {
String controlIp = getControlIp(nics);
// check if the router is up?
for (int count = 0; count < 60; count++) {
final boolean result = _vrResource.connect(controlIp, 1, 5000);
if (result) {
break;
}
}
try {
String homeDir = System.getProperty("user.home");
File pemFile = new File(homeDir + "/.ssh/id_rsa");
FileUtil.scpPatchFiles(controlIp, "/home/cloud", DefaultDomRSshPort, pemFile, newSrcFiles, BASEPATH);
// TODO: May want to remove this when cert patching logic is moved
Thread.sleep(10000);
} catch (Exception e) {
String errMsg = "Failed to scp files to system VM. Patching of systemVM failed";
s_logger.error(errMsg, e);
return new StartAnswer(cmd, String.format("%s due to: %s", errMsg, e.getMessage()));
}
}
// Since VM was successfully powered-on, if there was an existing VM in a different cluster that was unregistered, delete all the files associated with it.
if (existingVmName != null && existingVmFileLayout != null) {
List<String> vmDatastoreNames = new ArrayList<String>();
@ -3886,6 +3978,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
private String getControlIp(NicTO[] nicTOs) {
String controlIpAddress = null;
for (NicTO nic : nicTOs) {
if ((TrafficType.Management == nic.getType() || TrafficType.Control == nic.getType()) && nic.getIp() != null) {
controlIpAddress = nic.getIp();
break;
}
}
return controlIpAddress;
}
private VirtualMachineMO takeVmFromOtherHyperHost(VmwareHypervisorHost hyperHost, String vmName) throws Exception {
VirtualMachineMO vmMo = hyperHost.findVmOnPeerHyperHost(vmName);
@ -6973,6 +7076,11 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
return _name;
}
@Override
protected String getDefaultScriptsDir() {
return null;
}
@Override
public boolean start() {
return true;

View File

@ -25,10 +25,8 @@ import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase;
import com.cloud.resource.CommandWrapper;
import com.cloud.resource.ResourceWrapper;
import com.cloud.utils.ExecutionResult;
import com.cloud.utils.FileUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.ssh.SshHelper;
import com.xensource.xenapi.Connection;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
@ -44,12 +42,13 @@ public class CitrixPatchSystemVmCommandWrapper extends CommandWrapper<PatchSyste
public Answer execute(PatchSystemVmCommand command, CitrixResourceBase serverResource) {
final String controlIp = command.getAccessDetail(NetworkElementCommand.ROUTER_IP);
final String sysVMName = command.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
final Connection conn = serverResource.getConnection();
ExecutionResult result;
try {
result = getSystemVmVersionAndChecksum(serverResource, controlIp);
FileUtil.scpPatchFiles(controlIp, "/home/cloud", sshPort, pemFile, serverResource.newSrcFiles, CitrixResourceBase.BASEPATH);
serverResource.copyPatchFilesToVR(controlIp, "/home/cloud");
//FileUtil.scpPatchFiles(controlIp, "/home/cloud", sshPort, pemFile, serverResource.newSrcFiles, CitrixResourceBase.BASEPATH);
} catch (CloudRuntimeException e) {
return new PatchSystemVmAnswer(command, e.getMessage());
}
@ -70,18 +69,18 @@ public class CitrixPatchSystemVmCommandWrapper extends CommandWrapper<PatchSyste
return new PatchSystemVmAnswer(command, msg, lines[0], lines[1]);
}
}
Pair<Boolean, String> patchResult = null;
String patchResult = null;
try {
patchResult = SshHelper.sshExecute(controlIp, sshPort, "root",
pemFile, null, "/home/cloud/patch-sysvms.sh", 10000, 10000, 60000);
patchResult = serverResource.callHostPlugin(conn, "vmops", "runPatchScriptInDomr", "domrip", controlIp);
} catch (Exception e) {
return new PatchSystemVmAnswer(command, e.getMessage());
}
if (patchResult.first()) {
if (patchResult.startsWith("succ#")) {
return new PatchSystemVmAnswer(command, String.format("Successfully patched systemVM %s ", sysVMName), lines[0], lines[1]);
}
return new PatchSystemVmAnswer(command, patchResult.second());
return new PatchSystemVmAnswer(command, patchResult.substring(5));
}

View File

@ -248,6 +248,19 @@ def createFileInDomr(session, args):
txt = 'fail#' + txt
return txt
@echo
def runPatchScriptInDomr(session, args):
domrip = args['domrip']
txt=""
try:
target = "root@" + domrip
txt = util.pread2(['ssh','-p','3922','-i','/root/.ssh/id_rsa.cloud', target, "/bin/bash","/home/cloud/patch-sysvms.sh"])
txt = 'succ#' + txt
except:
logging.debug("failed to run patch script in systemVM with IP: " + domrip)
txt = 'fail#' + txt
return txt
@echo
def deleteFile(session, args):
file_path = args["filepath"]
@ -1590,4 +1603,5 @@ if __name__ == "__main__":
"cleanup_rules":cleanup_rules,
"createFileInDomr":createFileInDomr,
"kill_copy_process":kill_copy_process,
"secureCopyToHost":secureCopyToHost})
"secureCopyToHost":secureCopyToHost,
"runPatchScriptInDomr": runPatchScriptInDomr})

View File

@ -4874,7 +4874,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
@Override
public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) {
public boolean finalizeStart(VirtualMachineProfile profile, long hostId, Commands cmds, ReservationContext context) {
UserVmVO vm = _vmDao.findById(profile.getId());
Answer[] answersToCmds = cmds.getAnswers();