com.oneops.inductor.Config.java Source code

Java tutorial

Introduction

Here is the source code for com.oneops.inductor.Config.java

Source

/*******************************************************************************
 *  
 *   Copyright 2015 Walmart, Inc.
 *  
 *   Licensed 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.oneops.inductor;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;

import com.oneops.cms.domain.CmsWorkOrderSimpleBase;
import com.oneops.cms.simple.domain.CmsActionOrderSimple;
import com.oneops.cms.simple.domain.CmsWorkOrderSimple;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Config {

    private static Logger logger = Logger.getLogger(Config.class);

    // Value from spring+inductor.properties
    private @Value("${packer_home}") String circuitDir;

    private @Value("${amq.in_queue}") String inQueue;

    private @Value("${retry_count:3}") int retryCount;

    // allows use of public or private ip
    private @Value("${ip_attribute}") String ipAttribute;

    private @Value("${data_dir}") String dataDir;

    private @Value("${mgmt_domain}") String mgmtDomain;

    private @Value("${perf_collector_cert_location:unset}") String perfCollectorCertLocation;

    private @Value("${mgmt_url}") String mgmtUrl;

    private @Value("${mgmt_cert:unset}") String mgmtCert;

    private @Value("${min_free_space_mb:50}") int minFreeSpaceMB;

    // For backwards compliance (using PPC.ignoreUnresolvablePlaceholders)
    // missing autowired values default to a String, hense this dns value
    // to boolean inside init.
    private @Value("${dns}") String dnsEnabled;

    private boolean dnsDisabled = false;

    private @Value("${dns_config_file}") String dnsConfigFile;

    // Added to debug compute add - prevents compute::delete on
    // compute::add (install_base/remote) failure
    private @Value("${debug_mode}") String debugMode;

    // Enable jmx metrics
    private @Value("${enable_jmx:true}") boolean isJMXEnabled;

    // Enable auto shutdown
    private @Value("${autoShutDown:false}") boolean isAutoShutDown;

    private @Value("${initial_user:unset}") String initialUser;

    private @Value("${local_max_consumers:10}") int localMaxConsumers;

    // rsync timeout. Default value is 30 sec
    private @Value("${rsync_timeout:30}") int rsyncTimeout;

    /**
     * The list of clouds which are marked to be in stub mode.
     * Inductor will mark those work-order and action orders execution result as
     * per <value>stubResultCode</value>
     */
    @Value("#{'${stub.clouds:}'.toLowerCase().split(',')}")
    private List<String> stubbedCloudsList;

    /**
     * The list of clouds, whose resources are already decommissioned or removed.
     * Inductor will mark those work-order (no action orders) execution result as
     * success (0) regardless of the execution outcome for the clouds listed in
     * this (shutdown.clouds) inductor property. Spring EPL default value is empty string.
     */
    @Value("#{'${shutdown.clouds:}'.toLowerCase().split(',')}")
    private List<String> clouds;

    /**
     * Default to fail; Config should be provided to make the resultCode '1' as failure.
     */
    @Value("${stubResultCode:1}")
    private int stubResultCode;

    /**
     * How long should inductor wait before returning a stubbed response ?
     * Defaults to 5 seconds
     */
    @Value("${stub.responseTimeInSeconds:5}")
    private int stubResponseTimeInSeconds;

    @Value("${autoShutDownThreshold:99.99}")
    private double autoShutDownThreshold;
    /**
     * List of bom classes, whose process result status needs to keep intact.
     * By default <b>bom.Fqdn</b>,<b>bom.Lb</b> are added to this list as it
     * doesn't have any openstack hypervisor dependency.
     */
    @Value("#{'${shutdown.skipClasses:bom.Fqdn,bom.Lb}'.toLowerCase().split(',')}")
    private List<String> bomClasses;

    /**
     * List of rfc actions for which the result need to be processed.
     * <b>DELETE</b>action is added by default.
     */
    @Value("#{'${shutdown.rfcActions:DELETE}'.toLowerCase().split(',')}")
    private List<String> rfcActions;

    /**
     * Timeout  value for command execution for shutdown clouds.
     * Default value is set as 10 sec.
     */
    @Value("${shutdown.cmdTimeout:10}")
    private long cmdTimeout;

    /**
     * Additional env variables to be used for workorder exec. The value can
     * be file location or a string containing multiple ENV_NAME=VALUE entries.
     * Entries are separated by newline (file) or ',' (string). Right now this
     * configuration is used only for local workorders.
     */
    @Value("${env_vars:}")
    private String env;

    /**
     * Env vars read from {@link #env}. This will get initialized in ${@link #init()}
     */
    private Map<String, String> envVars;

    private String publicKey = "";

    private String dnsKey = null;

    private String dnsSecret = null;

    private String ipAddr = null;

    private String mgmtCertContent = null;

    private String perfCollectorCertContent = null;

    /**
     * init - configuration / defaults
     */
    public void init() {

        // Read env vars.
        envVars = readEnvVars(env);

        // null checks due to spring ignoreUnresolvablePlaceholders not working
        // on junit tests
        if (mgmtDomain == null) {
            mgmtDomain = getMgmtDomainFromFile();
        }

        // Read mgmt certificate file content
        mgmtCertContent = readCertFile(mgmtCert);

        perfCollectorCertContent = readCertFile(perfCollectorCertLocation);

        // defaults for some backwards compliance
        if (circuitDir == null) {
            circuitDir = "/opt/oneops/inductor";
        }

        if (dataDir == null || dataDir.equals("${data_dir}")) {
            dataDir = "/opt/oneops/tmp";
        }
        if (ipAttribute == null || ipAttribute.equals("${ip_attribute}")) {
            ipAttribute = "public_ip";
        }

        if (dnsEnabled == null || dnsEnabled.equalsIgnoreCase("off") || dnsEnabled.equalsIgnoreCase("false")) {
            dnsDisabled = true;
        }
        if (dnsConfigFile == null || dnsConfigFile.equals("${dns_config_file}")) {
            dnsConfigFile = "/opt/oneops/inductor/global/dns.conf";
        }
        if (debugMode == null) {
            debugMode = "off";
        }
        // Sets the IP for logging.
        ipAddr = getInductorIPv4Addr();
        if (ipAddr == null) {
            ipAddr = "N/A";
        }

        getGlobalDnsConfFromFile();

        Map<String, String> env = System.getenv();
        String envPackerDir = env.get("PACKER_DIR");
        if (envPackerDir != null) {
            circuitDir = envPackerDir;
        }

        if (clouds == null) {
            clouds = new ArrayList<>();
        }

        // Remove the empty default
        clouds.remove("");
        if (!clouds.isEmpty()) {
            logger.info("*** " + this.toString());
        }

    }

    /**
     * get mgmt domain so computes know how to talk to daq
     */
    private String getMgmtDomainFromFile() {
        String outFile = "/opt/oneops/domain";
        String block = "";
        String thisLine;
        BufferedReader br;
        try {
            br = new BufferedReader(new FileReader(outFile));
            while ((thisLine = br.readLine()) != null) {
                block += thisLine;
            }
            br.close();
        } catch (IOException e) {
            logger.error("cannot read /opt/oneops/domain");
        }
        return block;
    }

    /**
     * Read the given cert file.
     *
     * @param certFile cert file path
     * @return string containing content of the file.
     */
    private String readCertFile(String certFile) {
        if (certFile == null || "unset".equals(certFile))
            return null;

        String block = "";
        try (BufferedReader br = new BufferedReader(new FileReader(certFile))) {
            String line;
            while ((line = br.readLine()) != null) {
                block += line + "\r\n";
            }
        } catch (Exception e) {
            logger.error("Cannot read " + certFile, e);
            return null;
        }
        return block;
    }

    /**
     * get mgmt domain so computes know how to talk to daq
     */
    private void getGlobalDnsConfFromFile() {
        String thisLine;
        BufferedReader br;
        logger.info("using dns config: " + dnsConfigFile);
        try {
            br = new BufferedReader(new FileReader(dnsConfigFile));
            int count = 0;
            while ((thisLine = br.readLine()) != null) {
                if (count == 0) {
                    dnsKey = thisLine.replaceAll("\n", "");
                    logger.info("using " + InductorConstants.DEFAULT_DOMAIN + " key:" + dnsKey);
                } else if (count == 1) {
                    dnsSecret = thisLine.replaceAll("\n", "");
                    logger.info("using " + InductorConstants.DEFAULT_DOMAIN + " secret:" + dnsSecret);
                }
                count++;
            }
        } catch (FileNotFoundException e) {
            logger.info("not a public inductor - missing: " + dnsConfigFile);
        } catch (IOException e) {
            logger.info("cannot read " + dnsConfigFile);
        }
    }

    /**
     * Retruns the inductor IP address (IPV4 address). If there are multiple
     * NICs/IfAddresses, it selects the first one. Openstack VMs normally has
     * only one network interface (eth0).
     * 
     * @return IPV4 address of inductor with interface name. Returns
     *         <code>null</code> if it couldn't find anything.
     */
    private String getInductorIPv4Addr() {
        try {
            Enumeration<NetworkInterface> nics = NetworkInterface.getNetworkInterfaces();
            while (nics.hasMoreElements()) {
                NetworkInterface nic = nics.nextElement();
                if (nic.isUp() && !nic.isLoopback()) {
                    Enumeration<InetAddress> addrs = nic.getInetAddresses();
                    while (addrs.hasMoreElements()) {
                        InetAddress add = addrs.nextElement();
                        // Print only IPV4 address
                        if (add instanceof Inet4Address && !add.isLoopbackAddress()) {
                            // Log the first one.
                            String ip = add.getHostAddress() + " (" + nic.getDisplayName() + ")";
                            logger.info("Inductor IP : " + ip);
                            return ip;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.warn("Error getting inductor IP address", e);
            // Skip any errors
        }
        return null;
    }

    public static Logger getLogger() {
        return logger;
    }

    public int getMinFreeSpaceMB() {
        return minFreeSpaceMB;
    }

    public List<String> getClouds() {
        return clouds;
    }

    public List<String> getBomClasses() {
        return bomClasses;
    }

    public List<String> getRfcActions() {
        return rfcActions;
    }

    public List<String> getStubbedCloudsList() {
        return stubbedCloudsList;
    }

    public void setStubbedCloudsList(List<String> stubbedCloudsList) {
        this.stubbedCloudsList = stubbedCloudsList;
    }

    public String getCircuitDir() {
        return circuitDir;
    }

    public String getInQueue() {
        return inQueue;
    }

    public int getRetryCount() {
        return retryCount;
    }

    public String getIpAttribute() {
        return ipAttribute;
    }

    public String getDataDir() {
        return dataDir;
    }

    public String getMgmtDomain() {
        return mgmtDomain;
    }

    public String getPerfCollectorCertLocation() {
        return perfCollectorCertLocation;
    }

    public String getMgmtUrl() {
        return mgmtUrl;
    }

    public String getMgmtCert() {
        return mgmtCert;
    }

    public String getDnsEnabled() {
        return dnsEnabled;
    }

    public boolean isDnsDisabled() {
        return dnsDisabled;
    }

    public String getDnsConfigFile() {
        return dnsConfigFile;
    }

    public String getDebugMode() {
        return debugMode;
    }

    public String getInitialUser() {
        return initialUser;
    }

    public int getLocalMaxConsumers() {
        return localMaxConsumers;
    }

    public int getRsyncTimeout() {
        return rsyncTimeout;
    }

    public String getPublicKey() {
        return publicKey;
    }

    public String getDnsKey() {
        return dnsKey;
    }

    public String getDnsSecret() {
        return dnsSecret;
    }

    public String getIpAddr() {
        return ipAddr;
    }

    public String getMgmtCertContent() {
        return mgmtCertContent;
    }

    public String getPerfCollectorCertContent() {
        return perfCollectorCertContent;
    }

    public String getEnv() {
        return env;
    }

    public void setEnv(String env) {
        this.env = env;
    }

    /**
     * Get the env vars key-value map.
     *
     * @return map containing env name and value.
     */
    public Map<String, String> getEnvVars() {
        return this.envVars;
    }

    /**
     * Helper method to read inductor ${@link #env} and returns an env vars map.
     *
     * @param env env can be a file location or a string containing multiple ENV_NAME=VALUE entries.
     *            Entries are separated by newline (file) or ',' (string).
     * @return env var map.
     */
    private Map<String, String> readEnvVars(String env) {
        Path path = Paths.get(env);
        List<String> kvList;
        if (path.toFile().exists()) {
            try {
                kvList = Files.readAllLines(path);
            } catch (IOException ioe) {
                logger.warn("Error reading env var file: " + path, ioe);
                kvList = Collections.emptyList();
            }
        } else {
            kvList = Arrays.asList(env.trim().split(","));
        }
        return kvList.stream().map(s -> s.split("=")).filter(p -> p.length == 2)
                .collect(Collectors.toMap(p -> p[0].trim(), p -> p[1].trim()));
    }

    /**
      * Checks if the cloud for given wo has been configured as shutdown
      *
      * @param bwo    work order
      * @return <code>true</code> if the wo cloud has configured as shutdown, else return <code>false</code>
      */
    public boolean hasCloudShutdownFor(CmsWorkOrderSimpleBase bwo) {
        if (!clouds.isEmpty()) {
            // Proceed only if it's not null
            if (bwo != null) {
                // Do it only for work orders
                if (bwo instanceof CmsWorkOrderSimple) {
                    CmsWorkOrderSimple wo = CmsWorkOrderSimple.class.cast(bwo);
                    // Do it only for configured rfc actions (DELETE by default)
                    if (rfcActions.contains(wo.getRfcCi().getRfcAction().toLowerCase())) {
                        String cloudName = wo.getCloud().getCiName();
                        // Do it only for the shutdown clouds
                        if (clouds.contains(cloudName.toLowerCase())) {
                            String bomClass = wo.getRfcCi().getCiClassName();
                            // Skip configured bom classes
                            if (!bomClasses.contains(bomClass.toLowerCase())) {
                                return true;
                            }
                        }
                    }

                }
            }

        }
        return false;
    }

    public boolean isCloudStubbed(CmsWorkOrderSimpleBase bwo) {
        boolean stubbedMode = false;
        String cloudName = StringUtils.EMPTY;
        if (!CollectionUtils.isEmpty(stubbedCloudsList)) {
            if (bwo != null) {
                cloudName = getCloud(bwo, cloudName);
                if (StringUtils.isEmpty(cloudName)) {
                    stubbedMode = false;
                } else if (stubbedCloudsList.contains(cloudName.toLowerCase())) {
                    stubbedMode = true;
                }
            }
        }
        if (stubbedMode) {
            logger.warn("Cloud :" + cloudName + " is running in stub mode.");
        }
        return stubbedMode;
    }

    private String getCloud(CmsWorkOrderSimpleBase bwo, String cloudName) {
        if (bwo instanceof CmsWorkOrderSimple) {
            CmsWorkOrderSimple wo = CmsWorkOrderSimple.class.cast(bwo);
            cloudName = wo.getCloud().getCiName();
        } else if (bwo instanceof CmsActionOrderSimple) {
            CmsActionOrderSimple ao = CmsActionOrderSimple.class.cast(bwo);
            cloudName = ao.getCloud().getCiName();
        }
        return cloudName;
    }

    /**
      * Accessor for shutdown clouds
      *
      * @return cloud list
      */
    public List<String> clouds() {
        return this.clouds;
    }

    /**
     * Accessor for bom class
     *
     * @return bom class list
     */
    public List<String> bomClasses() {
        return this.bomClasses;
    }

    /**
     * Accessor for rfc action
     *
     * @return action list
     */
    public List<String> rfcActions() {
        return this.rfcActions;
    }

    /**
     * Accessor for command timeout
     *
     * @return timeout
     */
    public long getCmdTimeout() {
        return cmdTimeout;
    }

    public int getStubResponseTimeInSeconds() {
        return stubResponseTimeInSeconds;
    }

    public int getStubResultCode() {
        return stubResultCode;
    }

    public boolean isJMXEnabled() {
        return isJMXEnabled;
    }

    public void setJMXEnabled(boolean JMXEnabled) {
        isJMXEnabled = JMXEnabled;
    }

    public boolean isAutoShutDown() {
        return isAutoShutDown;
    }

    public void setAutoShutDown(boolean autoShutDown) {
        isAutoShutDown = autoShutDown;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("Config{ ");
        sb.append("ipAddr='").append(ipAddr).append('\'');
        sb.append(", circuitDir='").append(circuitDir).append('\'');
        sb.append(", inQueue='").append(inQueue).append('\'');
        sb.append(", retryCount=").append(retryCount);
        sb.append(", ipAttribute='").append(ipAttribute).append('\'');
        sb.append(", dataDir='").append(dataDir).append('\'');
        sb.append(", mgmtDomain='").append(mgmtDomain).append('\'');
        sb.append(", perfCollectorCertLocation='").append(perfCollectorCertLocation).append('\'');
        sb.append(", mgmtUrl='").append(mgmtUrl).append('\'');
        sb.append(", mgmtCert='").append(mgmtCert).append('\'');
        sb.append(", dnsEnabled='").append(dnsEnabled).append('\'');
        sb.append(", dnsDisabled=").append(dnsDisabled);
        sb.append(", dnsConfigFile='").append(dnsConfigFile).append('\'');
        sb.append(", debugMode='").append(debugMode).append('\'');
        sb.append(", localMaxConsumers=").append(localMaxConsumers);
        sb.append(", rsyncTimeout=").append(rsyncTimeout);
        sb.append(", bomClasses=" + bomClasses);
        sb.append(", rfcActions=" + rfcActions);
        sb.append(", cmdTimeout=" + cmdTimeout);
        sb.append(", autoShutDownThreshold=" + autoShutDownThreshold);
        sb.append(", isJMXEnabled=" + isJMXEnabled);
        sb.append(", isAutoShutDown=" + isAutoShutDown);
        sb.append(", stubbedCloudsList=" + stubbedCloudsList);
        sb.append(", stubResponseTimeInSeconds=" + stubResponseTimeInSeconds);
        sb.append(", stubResultCode=" + stubResultCode);
        sb.append(", env=" + env);
        sb.append('}');
        return sb.toString();
    }

    public double getAutoShutDownThreshold() {
        return autoShutDownThreshold;
    }
}