/* * Copyright (c) 2015 EMC Corporation * All Rights Reserved */ package com.emc.storageos.services.util; import com.emc.storageos.model.property.PropertyConstants; import com.emc.vipr.model.sys.ipreconfig.ClusterIpInfo; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Scanner; public class PlatformUtils { private static final Logger log = LoggerFactory.getLogger(PlatformUtils.class); private static final String GET_OVF_PROPERTY_CMD = "/etc/getovfproperties"; private static final String GENISO_CMD = "/opt/storageos/bin/geniso"; private static final String IS_VAPP = "--is-vapp"; private static final String SYSTOOL_CMD = "/etc/systool"; private static final String IS_APPLIANCE = "--test"; private static final String GET_VDCPROPS = "--getvdcprops"; private static final String IS_APPLIANCE_OUTPUT = "Ok"; private static final String VDCPROP_SITEIDS = "site_ids"; private static final long CMD_TIMEOUT = 120 * 1000; private static final long CMD_PARTITION_TIMEOUT = 600 * 1000; // 10 min private static String PID_DIR = "/var/run/storageos/"; // matches <svcname>.pid, <svcname>-debug.pid, <svcname>-coverage.pid which contains pid private static final String PID_FILENAME_PATTERN = "%s(-(coverage|debug))?.pid"; private static final String PRODUCT_IDENT_PATH = "/opt/storageos/etc/product"; private static volatile Boolean isVMwareVapp; private static volatile Boolean isAppliance; /* * Get local configuration by reading ovfenv partition and detecting real h/w * * @return local configuration */ public static Configuration getLocalConfiguration() { Configuration conf = new Configuration(); // read ovfenv properties from ovfenv partition String[] props = getOvfenvPropertyStrings(); Map<String, String> propMap = new HashMap<String, String>(); for (String s : props) { if(s.contains(PropertyConstants.DELIMITER)) { if (s.split(PropertyConstants.DELIMITER).length == 2) { propMap.put(s.split(PropertyConstants.DELIMITER)[0], s.split(PropertyConstants.DELIMITER)[1]); }else if(s.split(PropertyConstants.DELIMITER).length == 1) { propMap.put(s.split(PropertyConstants.DELIMITER)[0],""); }else { log.error("ovf properties file contain line in unexpected format : {}", s); } } } // load major properties (network info etc.) conf.loadFromPropertyMap(propMap); // Update local conf to reflect the current memory size, CPU count, disk(data) size and network interface conf.getHwConfig().put(PropertyConstants.PROPERTY_KEY_MEMORY_SIZE, ServerProbe.getInstance().getMemorySize()); conf.getHwConfig().put(PropertyConstants.PROPERTY_KEY_CPU_CORE, ServerProbe.getInstance().getCpuCoreNum()); String diskName = propMap.get(PropertyConstants.PROPERTY_KEY_DISK); if (diskName == null) { diskName = PropertyConstants.DATA_DISK_DEFAULT; } conf.getHwConfig().put(PropertyConstants.PROPERTY_KEY_DISK, diskName); conf.getHwConfig().put(PropertyConstants.PROPERTY_KEY_DISK_CAPACITY, ServerProbe.getInstance().getDiskCapacity(diskName)); String netif = propMap.get(PropertyConstants.PROPERTY_KEY_NETIF); if (netif == null) { netif = PropertyConstants.NETIF_DEFAULT; } conf.getHwConfig().put(PropertyConstants.PROPERTY_KEY_NETIF, netif); log.info("Local found config: {}", conf.toString()); return conf; } public static int diskHasViprPartitions(String disk) { final String[] cmds = { "/etc/mkdisk.sh", "check", disk }; Exec.Result result = Exec.sudo(CMD_PARTITION_TIMEOUT, cmds); if (!result.exitedNormally() || result.getExitValue() != 0) { log.warn("Check disk {} for vipr partition failed with exit value is: {}", disk, result.getExitValue()); } return result.getExitValue(); } public static String[] executeCommand(String[] commands) { StringBuffer output = new StringBuffer(); ArrayList<String> out = new ArrayList<String>(); Process p; try { p = Runtime.getRuntime().exec(commands); p.waitFor(); BufferedReader reader = new BufferedReader(new InputStreamReader( p.getInputStream())); String line = ""; while ((line = reader.readLine()) != null) { output.append(line + "\t"); out.add(line); } reader.close(); } catch (Exception e) { log.error(e.getMessage(), e); } return out.toArray(new String[out.size()]); } /* * Get ovfenv properties * * @return strings of key/value property pairs */ public static String[] getOvfenvPropertyStrings() { final String[] cmds = { "/etc/getovfproperties", "--readCDROM" }; Exec.Result result = Exec.sudo(CMD_TIMEOUT, cmds); if (!result.exitedNormally() || result.getExitValue() != 0) { log.error("Failed to get ovfenv properties with errcode: {}, error: {}", result.getExitValue(), result.getStdError()); } return result.getStdOutput().split("\n"); } /* * Get ovfenv properties * * @return map of key/value property pairs */ public static Map<String, String> getOvfenvProperties() { final String[] cmds = { GET_OVF_PROPERTY_CMD, "--readCDROM" }; Exec.Result result = Exec.sudo(CMD_TIMEOUT, cmds); if (!result.exitedNormally() || result.getExitValue() != 0) { log.error("Failed to get properties from ovfenv device directly with errcode: {}, error: {}", result.getExitValue(), result.getStdError()); throw new IllegalStateException("Failed to get properties from ovfenv device directly"); } String[] props = result.getStdOutput().split("\n"); Map<String, String> propMap = new HashMap<String, String>(); for (String s : props) { String [] kvpairs = s.split(PropertyConstants.DELIMITER); if (kvpairs.length == 2) { propMap.put(s.split(PropertyConstants.DELIMITER)[0], s.split(PropertyConstants.DELIMITER)[1]); } } return propMap; } /** * Generate key/value pairs string for ovfenv properties * * @param ipinfo * @param nodeid * @param node_count * @return */ public static String genOvfenvPropertyKVString(ClusterIpInfo ipinfo, String nodeid, int node_count) { // Compose cluster configuration key/value properties string StringBuffer clusterprops = new StringBuffer(); clusterprops.append(ipinfo.toString()); clusterprops.append(PropertyConstants.NODE_COUNT_KEY).append(PropertyConstants.DELIMITER).append(node_count).append("\n"); clusterprops.append(PropertyConstants.NODE_ID_KEY).append(PropertyConstants.DELIMITER).append(nodeid).append("\n"); return clusterprops.toString(); } /** * Generate ovfenv ISO image which will be then saved to ovfenv partition * * @param ovfenvPropKVStr ovfenv key/value property string * @param isoFilePath the path of the ovfenv ISO */ public static void genOvfenvIsoImage(String ovfenvPropKVStr, String isoFilePath) { byte[] bOvfenvPropKVStr = ovfenvPropKVStr.getBytes(); String propFilePath = "/tmp/ovf-env.properties"; File propFile = new File(propFilePath); try { FileUtils.writePlainFile(propFilePath, bOvfenvPropKVStr); } catch (Exception e1) { propFile.delete(); log.error("Write to prop file failed with exception: {}", e1.getMessage()); throw new IllegalStateException("Failed to generate ovfenv prop file."); } try { File isoFile = new File(isoFilePath); String[] genISOImageCommand = { GENISO_CMD, "--label", "CDROM", "-f", propFilePath, "-o", isoFilePath, "ovf-env.properties", "4096" }; Exec.Result result = Exec.sudo(CMD_TIMEOUT, genISOImageCommand); if (!result.exitedNormally() || result.getExitValue() != 0) { log.error("Generating ISO image failed with exit value: {}, error: {}", result.getExitValue(), result.getStdError()); throw new IllegalStateException("Failed to generate ISO image."); } } catch (Exception e) { throw e; } finally { propFile.delete(); } } /** * Probe ovfenv parition * * @return ovfenv partition */ public static String probeOvfenvPartition() { final String[] cmds = { GET_OVF_PROPERTY_CMD, "--probe-ovfenv-partition" }; Exec.Result result = Exec.sudo(CMD_TIMEOUT, cmds); if (!result.exitedNormally() || result.getExitValue() != 0) { log.error("Failed to get ovfenv device with errcode: {}, error: {}", result.getExitValue(), result.getStdError()); throw new IllegalStateException("Failed to get ovfenv device"); } String ovfenv_partition = result.getStdOutput().split("\n")[0]; log.info("Probed ovfenv partition {}", ovfenv_partition); return ovfenv_partition; } /** * Check if current deployment is VMWare vapp * * @return true if it is VMWare vapp, otherwise false */ public static boolean isVMwareVapp() { if (isVMwareVapp != null) { log.info("Return value {} from cached result", isVMwareVapp.booleanValue()); return isVMwareVapp.booleanValue(); } final String[] cmd = { GET_OVF_PROPERTY_CMD, IS_VAPP }; Exec.Result result = Exec.sudo(CMD_TIMEOUT, cmd); if (!result.exitedNormally()) { log.error("Failed to check if it's vApp {}", result.getStdError()); throw new IllegalStateException("Failed to check platform"); } if (result.getExitValue() == 0) { log.info("Current platform is VMware vApp"); isVMwareVapp = Boolean.TRUE; return isVMwareVapp.booleanValue(); } log.info("The exit value of platform check: {}", result.getExitValue()); isVMwareVapp = Boolean.FALSE; return isVMwareVapp.booleanValue(); } /** * Check if current deployment is an appliance * * @return true if it is an appliance, otherwise false(e.g.: devkit) */ public static boolean isAppliance() { if (isAppliance != null) { log.info("Return value {} from cached result", isAppliance.booleanValue()); return isAppliance.booleanValue(); } final String[] cmd = { SYSTOOL_CMD, IS_APPLIANCE }; Exec.Result result = Exec.sudo(CMD_TIMEOUT, cmd); if (!result.exitedNormally()) { log.error("Failed to check if it's appliance {}", result.getExitValue()); throw new IllegalStateException("Failed to check if it's appliance"); } log.debug("result={}", result.toString()); if (IS_APPLIANCE_OUTPUT.equals(result.getStdError().trim())) { log.info("It's an appliance"); isAppliance = Boolean.TRUE; return isAppliance.booleanValue(); } log.info("The output of appliance check: {}", result.getStdError()); isAppliance = Boolean.FALSE; return isAppliance.booleanValue(); } /** * Checks if the build is a open source build or emc enterprise build * * @return true if it is an open source build otherwise false. */ public static boolean isOssBuild() { boolean isOssBuild = false; String buildType = System.getProperty("buildType"); if (StringUtils.isNotBlank(buildType) && buildType.equalsIgnoreCase("oss")) { isOssBuild = true; } return isOssBuild; } /** * Checks if the env has multiple DR sites * * @return true if it has multiple DR sites */ public static boolean hasMultipleSites() { boolean hasMultipleSites = false; final String[] cmds = { SYSTOOL_CMD, GET_VDCPROPS }; Exec.Result result = Exec.sudo(CMD_TIMEOUT, cmds); if (!result.exitedNormally() || result.getExitValue() != 0) { log.error("Failed to get vdc properties with errcode: {}, error: {}", result.getExitValue(), result.getStdError()); throw new IllegalStateException("Failed to get vdc properties"); } String[] props = result.getStdOutput().split("\n"); for (String s : props) { String key = s.split(PropertyConstants.DELIMITER)[0]; String value = s.split(PropertyConstants.DELIMITER)[1]; if (!key.equals(VDCPROP_SITEIDS)) continue; if (value.contains(",")) { hasMultipleSites = true; break; } } return hasMultipleSites; } /** * Get service process ID by service name. * * @param svcName service name * @return service process ID */ public static int getServicePid(String svcName) throws FileNotFoundException { String pidFileRegex = String.format(PID_FILENAME_PATTERN, svcName); List<File> files = FileUtils.getFileByRegEx(new File(PID_DIR), pidFileRegex); if (files == null || files.isEmpty()) { log.warn("could not find {} pid file , please check service status", svcName); throw new IllegalStateException("can't find pid file, please check service status"); } try (Scanner scanner = new Scanner(files.get(0))) { return scanner.nextInt(); } } /** * Get product ident. * * @return Product ident */ public static String getProductIdent() throws IOException { byte[] productIdent = FileUtils.readDataFromFile(PRODUCT_IDENT_PATH); return new String(productIdent).trim(); } }