| // 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.kvm.resource; |
| |
| import java.io.File; |
| |
| import org.apache.logging.log4j.Logger; |
| import org.apache.logging.log4j.LogManager; |
| import org.libvirt.LibvirtException; |
| import org.libvirt.StoragePool; |
| import org.libvirt.StoragePoolInfo; |
| import org.libvirt.StoragePoolInfo.StoragePoolState; |
| |
| import com.cloud.hypervisor.kvm.storage.KVMStoragePool; |
| import com.cloud.utils.script.OutputInterpreter; |
| import com.cloud.utils.script.OutputInterpreter.AllLinesParser; |
| import com.cloud.utils.script.Script; |
| import com.cloud.agent.properties.AgentProperties; |
| import com.cloud.agent.properties.AgentPropertiesFileHandler; |
| |
| public class KVMHABase { |
| protected Logger logger = LogManager.getLogger(getClass()); |
| private long _timeout = 60000; /* 1 minutes */ |
| protected static String s_heartBeatPath; |
| protected long _heartBeatUpdateTimeout = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.HEARTBEAT_UPDATE_TIMEOUT); |
| protected long _heartBeatUpdateFreq = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.KVM_HEARTBEAT_UPDATE_FREQUENCY); |
| protected long _heartBeatUpdateMaxTries = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.KVM_HEARTBEAT_UPDATE_MAX_TRIES); |
| protected long _heartBeatUpdateRetrySleep = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.KVM_HEARTBEAT_UPDATE_RETRY_SLEEP); |
| |
| public static enum PoolType { |
| PrimaryStorage, SecondaryStorage |
| } |
| |
| public static class HAStoragePool { |
| String poolUuid; |
| String poolIp; |
| String poolMountSourcePath; |
| String mountDestPath; |
| PoolType poolType; |
| KVMStoragePool pool; |
| |
| public HAStoragePool(KVMStoragePool pool, String host, String path, PoolType type) { |
| this.pool = pool; |
| this.poolUuid = pool.getUuid(); |
| this.mountDestPath = pool.getLocalPath(); |
| this.poolIp = host; |
| this.poolMountSourcePath = path; |
| this.poolType = type; |
| } |
| |
| public String getPoolUUID() { |
| return poolUuid; |
| } |
| |
| public void setPoolUUID(String poolUuid) { |
| this.poolUuid = poolUuid; |
| } |
| |
| public String getPoolIp() { |
| return poolIp; |
| } |
| |
| public void setPoolIp(String poolIp) { |
| this.poolIp = poolIp; |
| } |
| |
| public String getPoolMountSourcePath() { |
| return poolMountSourcePath; |
| } |
| |
| public void setPoolMountSourcePath(String poolMountSourcePath) { |
| this.poolMountSourcePath = poolMountSourcePath; |
| } |
| |
| public String getMountDestPath() { |
| return mountDestPath; |
| } |
| |
| public void setMountDestPath(String mountDestPath) { |
| this.mountDestPath = mountDestPath; |
| } |
| |
| public PoolType getType() { |
| return poolType; |
| } |
| |
| public void setType(PoolType type) { |
| this.poolType = type; |
| } |
| |
| public KVMStoragePool getPool() { |
| return pool; |
| } |
| |
| public void setPool(KVMStoragePool pool) { |
| this.pool = pool; |
| } |
| } |
| |
| protected String checkingMountPoint(HAStoragePool pool, String poolName) { |
| String mountSource = pool.getPoolIp() + ":" + pool.getPoolMountSourcePath(); |
| String mountPaths = Script.runSimpleBashScript("cat /proc/mounts | grep " + mountSource); |
| String destPath = pool.getMountDestPath(); |
| |
| if (mountPaths != null) { |
| String token[] = mountPaths.split(" "); |
| String mountType = token[2]; |
| String mountDestPath = token[1]; |
| if (mountType.equalsIgnoreCase("nfs")) { |
| if (poolName != null && !mountDestPath.startsWith(destPath)) { |
| /* we need to mount it under poolName */ |
| Script mount = new Script("/bin/bash", 60000); |
| mount.add("-c"); |
| mount.add("mount " + mountSource + " " + destPath); |
| String result = mount.execute(); |
| if (result != null) { |
| destPath = null; |
| } |
| destroyVMs(destPath); |
| } else if (poolName == null) { |
| destPath = mountDestPath; |
| } |
| } |
| } else { |
| /* Can't find the mount point? */ |
| /* we need to mount it under poolName */ |
| if (poolName != null) { |
| Script mount = new Script("/bin/bash", 60000); |
| mount.add("-c"); |
| mount.add("mount " + mountSource + " " + destPath); |
| String result = mount.execute(); |
| if (result != null) { |
| destPath = null; |
| } |
| |
| destroyVMs(destPath); |
| } |
| } |
| |
| return destPath; |
| } |
| |
| protected String getMountPoint(HAStoragePool storagePool) { |
| |
| StoragePool pool = null; |
| String poolName = null; |
| try { |
| pool = LibvirtConnection.getConnection().storagePoolLookupByUUIDString(storagePool.getPoolUUID()); |
| if (pool != null) { |
| StoragePoolInfo spi = pool.getInfo(); |
| if (spi.state != StoragePoolState.VIR_STORAGE_POOL_RUNNING) { |
| pool.create(0); |
| } else { |
| /* |
| * Sometimes, the mount point is lost, even libvirt thinks |
| * the storage pool still running |
| */ |
| } |
| poolName = pool.getName(); |
| } |
| |
| } catch (LibvirtException e) { |
| logger.debug("Ignoring libvirt error.", e); |
| } finally { |
| try { |
| if (pool != null) { |
| pool.free(); |
| } |
| } catch (LibvirtException e) { |
| logger.debug("Ignoring libvirt error.", e); |
| } |
| } |
| |
| return checkingMountPoint(storagePool, poolName); |
| } |
| |
| protected void destroyVMs(String mountPath) { |
| /* if there are VMs using disks under this mount path, destroy them */ |
| Script cmd = new Script("/bin/bash", _timeout); |
| cmd.add("-c"); |
| cmd.add("ps axu|grep qemu|grep " + mountPath + "* |awk '{print $2}'"); |
| AllLinesParser parser = new OutputInterpreter.AllLinesParser(); |
| String result = cmd.execute(parser); |
| |
| if (result != null) { |
| return; |
| } |
| |
| String pids[] = parser.getLines().split("\n"); |
| for (String pid : pids) { |
| Script.runSimpleBashScript("kill -9 " + pid); |
| } |
| } |
| |
| protected String getHBFile(String mountPoint, String hostIP) { |
| return mountPoint + File.separator + "KVMHA" + File.separator + "hb-" + hostIP; |
| } |
| |
| protected String getHBFolder(String mountPoint) { |
| return mountPoint + File.separator + "KVMHA" + File.separator; |
| } |
| |
| protected String runScriptRetry(String cmdString, OutputInterpreter interpreter) { |
| String result = null; |
| for (int i = 0; i < 3; i++) { |
| Script cmd = new Script("/bin/bash", _timeout); |
| cmd.add("-c"); |
| cmd.add(cmdString); |
| if (interpreter != null) |
| result = cmd.execute(interpreter); |
| else { |
| result = cmd.execute(); |
| } |
| if (result == Script.ERR_TIMEOUT) { |
| continue; |
| } else if (result == null) { |
| break; |
| } |
| } |
| |
| return result; |
| } |
| |
| public Boolean checkingHeartBeat() { |
| // TODO Auto-generated method stub |
| return null; |
| } |
| } |