Package io.fabric8.container.process

Source Code of io.fabric8.container.process.ProcessManagerController

/**
*  Copyright 2005-2014 Red Hat, Inc.
*
*  Red Hat 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 io.fabric8.container.process;

import com.google.common.collect.ImmutableMap;
import io.fabric8.agent.download.DownloadFuture;
import io.fabric8.agent.download.DownloadManager;
import io.fabric8.agent.download.DownloadManagers;
import io.fabric8.agent.mvn.Parser;
import io.fabric8.agent.utils.AgentUtils;
import io.fabric8.api.Constants;
import io.fabric8.api.Container;
import io.fabric8.api.CreateChildContainerMetadata;
import io.fabric8.api.CreateChildContainerOptions;
import io.fabric8.api.CreateContainerMetadata;
import io.fabric8.api.CreateContainerOptions;
import io.fabric8.api.CreationStateListener;
import io.fabric8.api.EnvironmentVariables;
import io.fabric8.api.FabricService;
import io.fabric8.api.Profile;
import io.fabric8.api.Profiles;
import io.fabric8.api.scr.Configurer;
import io.fabric8.api.scr.support.Strings;
import io.fabric8.utils.Files;
import io.fabric8.utils.Objects;
import io.fabric8.deployer.JavaContainers;
import io.fabric8.process.manager.DownloadStrategy;
import io.fabric8.process.manager.InstallContext;
import io.fabric8.process.manager.InstallOptions;
import io.fabric8.process.manager.InstallTask;
import io.fabric8.process.manager.Installation;
import io.fabric8.process.manager.ProcessController;
import io.fabric8.process.manager.ProcessManager;
import io.fabric8.process.manager.config.JsonHelper;
import io.fabric8.process.manager.config.ProcessConfig;
import io.fabric8.process.manager.support.ApplyConfigurationTask;
import io.fabric8.process.manager.support.CompositeTask;
import io.fabric8.process.manager.support.DownloadResourcesTask;
import io.fabric8.process.manager.support.InstallDeploymentsTask;
import io.fabric8.process.manager.support.JarInstaller;
import io.fabric8.process.manager.support.ProcessUtils;
import io.fabric8.process.manager.support.RemoveFilesTask;
import io.fabric8.service.child.ChildContainerController;
import io.fabric8.service.child.ChildContainers;
import io.fabric8.service.child.JavaContainerEnvironmentVariables;
import org.apache.curator.framework.CuratorFramework;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static io.fabric8.deployer.JavaContainers.registerJolokiaUrl;

/**
* An implementation of {@link io.fabric8.service.child.ChildContainerController} which uses the {@link ProcessManager}.
* Created containers are new JVM processes running on the same physical machine as the parent container (usually located
* in the {@code FABRIC8_HOME/processes} directory).
*/
public class ProcessManagerController implements ChildContainerController {
    private static final transient Logger LOG = LoggerFactory.getLogger(ProcessManagerController.class);

    private final ProcessControllerFactoryService owner;
    private final Configurer configurer;
    private final ProcessManager processManager;
    private final FabricService fabricService;
    private final ExecutorService downloadExecutor = Executors.newSingleThreadExecutor();
    private final CuratorFramework curator;


    public ProcessManagerController(ProcessControllerFactoryService owner, Configurer configurer, ProcessManager processManager, FabricService fabricService, CuratorFramework curator) {
        this.owner = owner;
        this.configurer = configurer;
        this.processManager = processManager;
        this.fabricService = fabricService;
        this.curator = curator;
    }

    @Override
    public CreateChildContainerMetadata create(CreateChildContainerOptions options, CreationStateListener listener) throws Exception {
        CreateChildContainerMetadata metadata = new CreateChildContainerMetadata();

        String containerId = options.getName();
        metadata.setCreateOptions(options);
        metadata.setContainerName(containerId);

        Container container = null;
        try {
            container = fabricService.getContainer(containerId);
        } catch (Exception e) {
            LOG.debug("Could not find container: " + containerId);
        }
        if (container != null) {
            container.setProvisionResult(Container.PROVISION_DOWNLOADING);
        }
        ProcessManager procManager = processManager;
        Map<String,String> initialEnvironmentVariables = new HashMap<String, String>();
        Installation installation = createInstallation(procManager, container, options, metadata, initialEnvironmentVariables);
        if (container != null) {
            container.setProvisionResult(Container.PROVISION_FINALIZING);
        }
        if (installation != null) {
            installation.getController().start();
        }
        return metadata;
    }


    @Override
    public void start(Container container) {
        Installation installation = getInstallation(container);
        if (installation != null) {
            try {
                installation.getController().start();
            } catch (Exception e) {
                handleException("Starting container " + container.getId(), e);
            }
        }
    }

    @Override
    public void stop(Container container) {
        Installation installation = getInstallation(container);
        if (installation != null) {
            try {
                installation.getController().stop();
                container.setProvisionResult(Container.PROVISION_STOPPED);
                owner.deleteContainerZooKeeperPaths(installation, container);
            } catch (Exception e) {
                handleException("Stopping container " + container.getId(), e);
            }
        }
    }

    @Override
    public void destroy(Container container) {
        Installation installation = getInstallation(container);
        if (installation != null) {
            try {
                installation.getController().stop();
                owner.deleteContainerZooKeeperPaths(installation, container);
            } catch (Exception e) {
                LOG.info("Failed to stop process for container " + container.getId() + ". " + e, e);
            }
            processManager.uninstall(installation);
        }
    }

    /**
     * A profile may have changed so lets double check that there have been no changes to the installation
     */
    public void updateInstallation(final Container container, final Installation installation) throws Exception {
        Map<String, String> initialEnvironmentVariables = getInstallationProxyPorts(installation);

        CreateContainerMetadata<?> containerMetadata = container.getMetadata();
        if (containerMetadata instanceof CreateChildContainerMetadata) {
            CreateChildContainerMetadata metadata = (CreateChildContainerMetadata) containerMetadata;
            CreateContainerOptions createOptions = metadata.getCreateOptions();
            if (createOptions instanceof CreateChildContainerOptions) {
                CreateChildContainerOptions options = (CreateChildContainerOptions) createOptions;

                // is this an update of existing container or do we need re-installation the container because its version changed?
                // to know that we need to create the container config, and compare with existing
                ProcessContainerConfig config = createProcessContainerConfig(options, initialEnvironmentVariables);

                if (installation.getUrl() != null && !installation.getUrl().toString().equals(config.getUrl())) {
                    // the url has changed so its a full re-installation
                    LOG.info("Re-installing " + container.getId() + " due container distribution url changed to: " + config.getUrl());
                    destroy(container);

                    Installation newInstallation = createInstallation(processManager, container, options, metadata, initialEnvironmentVariables);
                    try {
                        newInstallation.getController().install();
                        start(container);
                    } catch (Exception e) {
                        handleException("Error installing container " + container.getId(), e);
                    }

                } else {

                    LOG.info("Updating container " + container.getId());

                    // need to use a process manager that updates instead of installing
                    ProcessManager procManager = new ProcessManager() {
                        @Override
                        public Installation install(InstallOptions parameters, InstallTask postInstall) throws Exception {
                            updateInstallation(container, installation, parameters, postInstall);
                            return null;
                        }

                        @Override
                        public Installation installJar(InstallOptions parameters, InstallTask postInstall) throws Exception {
                            updateInstallation(container, installation, parameters, null);
                            return null;
                        }

                        @Override
                        public void uninstall(Installation installation) {
                            processManager.uninstall(installation);
                        }

                        @Override
                        public Executor getExecutor() {
                            return processManager.getExecutor();
                        }

                        @Override
                        public List<Installation> listInstallations() {
                            return processManager.listInstallations();
                        }

                        @Override
                        public ImmutableMap<String, Installation> listInstallationMap() {
                            return processManager.listInstallationMap();
                        }

                        @Override
                        public Installation getInstallation(String id) {
                            return processManager.getInstallation(id);
                        }

                        @Override
                        public ProcessConfig loadProcessConfig(InstallOptions options) throws IOException {
                            return processManager.loadProcessConfig(options);
                        }
                    };

                    // reuse create installation with our procManager to do the update
                    createInstallation(procManager, container, options, metadata, initialEnvironmentVariables);
                }
            }
        }
    }

    public static Map<String, String> getInstallationProxyPorts(Installation installation) {
        Map<String,String> initialEnvironmentVariables = new HashMap<String, String>();
        ProcessConfig currentConfig = getProcessConfig(installation);
        if (currentConfig != null) {
            // lets preserve the ports allocated
            Map<String, String> environment = currentConfig.getEnvironment();
            for (Map.Entry<String, String> entry : environment.entrySet()) {
                String key = entry.getKey();
                if (key.endsWith("_PROXY_PORT")) {
                    String value = entry.getValue();
                    initialEnvironmentVariables.put(key, value);
                }
            }
        }
        return initialEnvironmentVariables;
    }

    protected void updateInstallation(Container container, final Installation installation, InstallOptions parameters, InstallTask postInstall) throws Exception {
        ProcessConfig processConfig = processManager.loadProcessConfig(parameters);
        processConfig.setName(parameters.getName());
        ProcessConfig oldConfig = getProcessConfig(installation);

        String id = installation.getId();
        File installDir = installation.getInstallDir();
        InstallContext installContext = new InstallContext(parameters.getContainer(), installDir, true);

        if (processConfig != null && !oldConfig.equals(processConfig)) {
            installContext.addRestartReason("Environment Variables");
            if (LOG.isDebugEnabled()) {
                LOG.debug("Requires restart as config has changed: OLD: " + JsonHelper.toJson(oldConfig) + " and NEW: " + JsonHelper.toJson(processConfig));
            }
            // need to resolve the environment variables first
            resolveEnvironmentVariables(processConfig.getEnvironment());
            // make sure to update the process config
            JsonHelper.saveProcessConfig(processConfig, installDir);
            // need to update environment on the controller also, so it uses the updated environments when restarting
            installation.getController().getConfig().setEnvironment(processConfig.getEnvironment());
        }

        if (postInstall != null) {
            postInstall.install(installContext, processConfig, id, installDir);
        } else {
            // lets do the Jar thing...
            JarInstaller installer = new JarInstaller(parameters, processManager.getExecutor());
            installer.install(installContext, processConfig, id, installDir);
        }

        installContext.updateContainerChecksums();

        if (installContext.isRestartRequired()) {
            LOG.info("Restarting " + container.getId() + " due to profile changes: " + installContext.getRestartReasons());
            ProcessController controller = installation.getController();
            if (controller != null && container != null && container.isAlive()) {
                controller.restart();
            }
        }
    }

    protected void resolveEnvironmentVariables(Map<String, String> environmentVariables) {
        JolokiaAgentHelper.substituteEnvironmentVariableExpressions(environmentVariables, environmentVariables, fabricService, curator, true);
        // in case there's any current system environment variables to replace
        // such as the operating system PATH or FABRIC8_JAVA8_HOME when not using docker containers
        JolokiaAgentHelper.substituteEnvironmentVariableExpressions(environmentVariables, System.getenv(), null, null, true);
    }

    protected static ProcessConfig getProcessConfig(Installation installation) {
        ProcessController controller = installation.getController();
        return controller.getConfig();
    }

    protected ProcessContainerConfig createProcessContainerConfig(CreateChildContainerOptions options, Map<String, String> initialEnvironmentVariables) throws Exception {
        Map<String, String> environmentVariables = ChildContainers.getEnvironmentVariables(fabricService, options);
        Set<Map.Entry<String, String>> initialEntries = initialEnvironmentVariables.entrySet();
        for (Map.Entry<String, String> entry : initialEntries) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (!environmentVariables.containsKey(key)) {
                environmentVariables.put(key, value);
            }
        }
        ProcessContainerConfig processConfig = doCreateProcessContainerConfig(options, environmentVariables);
        resolveEnvironmentVariables(environmentVariables);

        return processConfig;
    }

    protected Installation createInstallation(ProcessManager procManager, Container container, CreateChildContainerOptions options, CreateChildContainerMetadata metadata, Map<String, String> initialEnvironmentVariables) throws Exception {
        String containerId = options.getName();
        Map<String, String> environmentVariables = ChildContainers.getEnvironmentVariables(fabricService, options);
        Set<Map.Entry<String, String>> initialEntries = initialEnvironmentVariables.entrySet();
        for (Map.Entry<String, String> entry : initialEntries) {
            String key = entry.getKey();
            String value = entry.getValue();
            if (!environmentVariables.containsKey(key)) {
                environmentVariables.put(key, value);
            }
        }
        ProcessContainerConfig processConfig = createProcessContainerConfig(options, environmentVariables);
        if (container != null) {
            registerPorts(options, processConfig, container, environmentVariables);
        }
        resolveEnvironmentVariables(environmentVariables);
        publishZooKeeperValues(options, processConfig, container, environmentVariables);

        if (container != null) {
            String type = processConfig.getProcessName();
            if (type != null) {
                container.setType(type);
            }
        }

        Installation installation = null;
        try {
            if (ChildContainers.isJavaContainer(fabricService, options)) {
                LOG.debug("Java container detected - installing jar. Configuration: ", options);
                JavaContainerConfig javaConfig = createJavaContainerConfig(options);
                InstallOptions parameters = createJavaInstallOptions(container, metadata, options, javaConfig, environmentVariables);
                String layout = javaConfig.getOverlayFolder();
                InstallTask postInstall = createCommonPostInstal(options, environmentVariables, layout);
                Objects.notNull(parameters, "JavaInstall parameters");
                installation = procManager.installJar(parameters, postInstall);
            } else {
                LOG.debug("Process container detected - installing process. Configuration: ", options);
                InstallOptions parameters = createProcessInstallOptions(container, metadata, options, processConfig, environmentVariables);
                InstallTask postInstall = createProcessPostInstall(container, options, processConfig, environmentVariables);
                Objects.notNull(parameters, "process parameters");
                installation = procManager.install(parameters, postInstall);
            }
        } catch (Exception e) {
            handleException("Creating container " + containerId, e);
        }
        LOG.info("Creating process container with environment vars: " + environmentVariables);

        String defaultHost = fabricService.getCurrentContainer().getLocalHostname();
        if (Strings.isNullOrBlank(defaultHost)) {
            defaultHost = "localhost";
        }
        String jolokiaUrl = JolokiaAgentHelper.findJolokiaUrlFromEnvironmentVariables(environmentVariables, defaultHost);
        if (!Strings.isNullOrBlank(jolokiaUrl)) {
            registerJolokiaUrl(container, jolokiaUrl);
        }
        if (container != null) {
            processConfig = createProcessContainerConfig(options, environmentVariables);
            String httpUrl = processConfig.getContainerHttpUrl();
            if (httpUrl != null && !Objects.equal(container.getHttpUrl(), httpUrl)) {
                container.setHttpUrl(httpUrl);
            }
            String type = processConfig.getProcessName();
            if (type != null) {
                container.setType(type);
            }
        }
        return installation;
    }

    protected InstallOptions createJavaInstallOptions(Container container, CreateChildContainerMetadata metadata, CreateChildContainerOptions options, JavaContainerConfig javaConfig, Map<String, String> environmentVariables) throws Exception {
        boolean isJavaContainer = true;
        javaConfig.updateEnvironmentVariables(environmentVariables, isJavaContainer);
        Set<String> profileIds = options.getProfiles();
        String versionId = options.getVersion();
        JolokiaAgentHelper.updateSystemPropertiesEnvironmentVariable(environmentVariables, fabricService, versionId, profileIds);
        configureInstallOptionsJolokia(container.getId(), environmentVariables, javaConfig, isJavaContainer);

        Map<String, File> jarsFromProfiles = extractJarsFromProfiles(container, options);

        InstallOptions.InstallOptionsBuilder builder = InstallOptions.builder();
        if(javaConfig.getJarUrl() != null) {
            builder.url(javaConfig.getJarUrl());
        }
        builder.container(container);
        if(javaConfig.getJvmArguments() != null) {
            builder.jvmOptionsString(javaConfig.getJvmArguments());
        }
        builder.jarFiles(jarsFromProfiles);
        builder.id(options.getName());
        builder.environment(environmentVariables);
        String mainClass = environmentVariables.get(JavaContainerEnvironmentVariables.FABRIC8_JAVA_MAIN);
        String name = "java";
        if (!Strings.isNullOrBlank(mainClass)) {
            name += " " + mainClass;
        }
        builder.name(name);
        builder.downloadStrategy(createDownloadStrategy());
        metadata.setContainerType(name);
        builder.mainClass(mainClass);
        return builder.build();
    }

    protected DownloadStrategy createDownloadStrategy() throws MalformedURLException {
        // lets check we're in an active profile and not in a test case that has no profile
        if (fabricService != null) {
            Container container = fabricService.getCurrentContainer();
            if (container != null) {
                final DownloadManager downloadManager = DownloadManagers.createDownloadManager(fabricService, downloadExecutor);
                return new DownloadStrategy() {
                    @Override
                    public File downloadContent(URL sourceUrl, File installDir) throws IOException {
                        DownloadFuture future = downloadManager.download(sourceUrl.toString());
                        File file = AgentUtils.waitForFileDownload(future);
                        if (file != null && file.exists() && file.isFile()) {
                            // now lest copy it to the install dir
                            File newFile = new File(installDir, file.getName());
                            Files.copy(file, newFile);
                            return newFile;
                        } else {
                            throw new IOException("Could not download " + sourceUrl);
                        }
                    }
                };
            }
        }
        return null;
    }

    protected JavaContainerConfig createJavaContainerConfig(CreateChildContainerOptions options) throws Exception {
        JavaContainerConfig javaConfig = new JavaContainerConfig();
        Map<String, ?> javaContainerConfig = Profiles.getOverlayConfiguration(fabricService, options.getProfiles(), options.getVersion(), Constants.JAVA_CONTAINER_PID);
        configurer.configure(javaContainerConfig, javaConfig);
        return javaConfig;
    }

    protected Map<String, File> extractJarsFromProfiles(Container container, CreateChildContainerOptions installOptions) throws Exception {
        List<Profile> profiles = Profiles.getProfiles(fabricService, installOptions.getProfiles(), installOptions.getVersion());
        Map<String, File> javaArtifacts = JavaContainers.getJavaContainerArtifactsFiles(fabricService, profiles, downloadExecutor);
        // no longer required ??
        //setProvisionList(container, javaArtifacts);
        return javaArtifacts;
    }

    protected void configureInstallOptionsJolokia(String containerId, Map<String, String> environmentVariables, JavaContainerConfig javaConfig, boolean isJavaContainer) {
        if (JolokiaAgentHelper.hasJolokiaAgent(environmentVariables)) {
            String JOLOKIA_PROXY_PORT_ENV = "FABRIC8_JOLOKIA_PROXY_PORT";
            String portText = environmentVariables.get(JOLOKIA_PROXY_PORT_ENV);
            Integer portObject = null;
            if (portText != null) {
                try {
                    portObject = Integer.parseInt(portText);
                } catch (NumberFormatException e) {
                    LOG.warn("Ignoring bad port number for " + JOLOKIA_PROXY_PORT_ENV + " value '" + portText + ". " + e, e);
                }
            }
            int jolokiaPort = (portObject != null) ? portObject : owner.createJolokiaPort(containerId);
            environmentVariables.put(JOLOKIA_PROXY_PORT_ENV, "" + jolokiaPort);
            JolokiaAgentHelper.substituteEnvironmentVariables(javaConfig, environmentVariables, isJavaContainer,
                    JolokiaAgentHelper.getJolokiaPortOverride(jolokiaPort), JolokiaAgentHelper.getJolokiaAgentIdOverride(fabricService.getEnvironment()));
        } else {
            JolokiaAgentHelper.substituteEnvironmentVariables(javaConfig, environmentVariables, isJavaContainer,
                    JolokiaAgentHelper.getJolokiaAgentIdOverride(fabricService.getEnvironment()));
        }
    }

    protected InstallOptions createProcessInstallOptions(Container container, CreateChildContainerMetadata metadata, CreateChildContainerOptions options, ProcessContainerConfig configObject, Map<String, String> environmentVariables) throws Exception {
        return configObject.createProcessInstallOptions(fabricService, container, metadata, options, environmentVariables, createDownloadStrategy());
    }

    private ProcessContainerConfig doCreateProcessContainerConfig(CreateChildContainerOptions options, Map<String, String> environmentVariables) throws Exception {
        Set<String> profileIds = options.getProfiles();
        String versionId = options.getVersion();
        Map<String, String> configuration = Profiles.getOverlayConfiguration(fabricService, profileIds, versionId, Constants.PROCESS_CONTAINER_PID);
        JolokiaAgentHelper.substituteEnvironmentVariableExpressions(configuration, environmentVariables, fabricService, curator, true);
        ProcessContainerConfig configObject = new ProcessContainerConfig();
        configurer.configure(configuration, configObject);
        return configObject;
    }

    protected InstallTask createProcessPostInstall(Container container, CreateChildContainerOptions options, ProcessContainerConfig configObject, Map<String, String> environmentVariables) throws Exception {
        // lets see if there's a template configuration
        Set<String> profileIds = options.getProfiles();
        String versionId = options.getVersion();
        List<Profile> profiles = Profiles.getProfiles(fabricService, profileIds, versionId);
        String layout = configObject.getOverlayFolder();
        String[] postUnpackRemoveFiles = configObject.getPostUnpackRemoveFiles();
        InstallTask answer = createCommonPostInstal(options, environmentVariables, layout);
        if (postUnpackRemoveFiles != null && postUnpackRemoveFiles.length > 0) {
            answer = CompositeTask.combine(answer, new RemoveFilesTask(postUnpackRemoveFiles));
        }

        if (!configObject.isInternalAgent()) {
            Map<String, File> javaArtifacts = JavaContainers.getJavaContainerArtifactsFiles(fabricService, profiles, downloadExecutor);
            if (!javaArtifacts.isEmpty()) {
                Map<String, String> contextPathConfiguration = Profiles.getOverlayConfiguration(fabricService, profileIds, versionId, Constants.WEB_CONTEXT_PATHS_PID);

                Map<String, String> locationToContextPathMap = new HashMap<String, String>();
                // lets map the the locations to context paths

                Set<String> locations = javaArtifacts.keySet();
                for (String location : locations) {
                    Parser parser = null;
                    try {
                        parser = Parser.parsePathWithSchemePrefix(location);
                    } catch (MalformedURLException e) {
                        // ignore
                    }
                    if (parser != null) {
                        String key = parser.getGroup() + "/" + parser.getArtifact();
                        String value = contextPathConfiguration.get(key);
                        if (value != null) {
                            locationToContextPathMap.put(location, value);
                        }
                    }
                }
                Set<Map.Entry<String, String>> contextPathEntries = contextPathConfiguration.entrySet();
                for (Map.Entry<String, String> contextPathEntry : contextPathEntries) {
                    String groupIdAndArtifactId = contextPathEntry.getKey();
                    String contextPath = contextPathEntry.getValue();
                    if (!locationToContextPathMap.containsValue(contextPath)) {
                        LOG.warn("Properties file " +  Constants.WEB_CONTEXT_PATHS_PID
                                + " for profile(s) " + profileIds
                                + " has unmatched contextPath mapping to " + contextPath
                                + " for group id and artifact id key " + groupIdAndArtifactId
                                + " when has matched values: " + locationToContextPathMap.values());
                    }
                }
                answer = CompositeTask.combine(answer, new InstallDeploymentsTask(javaArtifacts, locationToContextPathMap));
                setProvisionList(container, javaArtifacts);
            }
        }
        return answer;
    }

    protected InstallTask createCommonPostInstal(CreateChildContainerOptions options, Map<String, String> environmentVariables, String layout) {
        Set<String> profileIds = options.getProfiles();
        String versionId = options.getVersion();
        List<Profile> profiles = Profiles.getProfiles(fabricService, profileIds, versionId);
        InstallTask answer = null;
        if (layout != null) {
            Map<String, String> configuration = ProcessUtils.getProcessLayout(fabricService, profiles, layout);
            if (configuration != null && !configuration.isEmpty()) {
                Map variables = Profiles.getOverlayConfiguration(fabricService, profileIds, versionId, Constants.TEMPLATE_VARIABLES_PID);
                if (variables == null) {
                    variables = new HashMap();
                } else {
                    JolokiaAgentHelper.substituteEnvironmentVariableExpressions(variables, environmentVariables, fabricService, curator, true);
                }
                variables.putAll(environmentVariables);
                LOG.info("Using template variables for MVEL: " + variables);
                answer = new ApplyConfigurationTask(configuration, variables);
            }
        }
        Map<String, String> overlayResources = Profiles.getOverlayConfiguration(fabricService, profileIds, versionId, Constants.PROCESS_CONTAINER_OVERLAY_RESOURCES_PID);
        if (overlayResources != null && !overlayResources.isEmpty()) {
            answer = CompositeTask.combine(answer, new DownloadResourcesTask(overlayResources));
        }
        return answer;
    }

    protected void setProvisionList(Container container, Map<String, File> javaArtifacts) {
        if (container != null) {
            List<String> provisionList = new ArrayList<String>();
            for (String name : javaArtifacts.keySet()) {
                int idx = name.indexOf(":mvn:");
                if (idx > 0) {
                    name = name.substring(idx + 1);
                }
                provisionList.add(name);
            }
            Collections.sort(provisionList);
            container.setProvisionList(provisionList);
        }
    }

    /**
     * Generates mappings from logical ports to physically allocated dynamic ports and exposes them as environment variables
     */
    protected void registerPorts(CreateChildContainerOptions options, ProcessContainerConfig processConfig, Container container, Map<String, String> environmentVariables) {
        String containerId = options.getName();
        Map<String, Object> exposedPorts = new HashMap<String, Object>();
        Map<String, Integer> internalPorts = new HashMap<String, Integer>();
        Map<String, Integer> externalPorts = new HashMap<String, Integer>();

        // lets use the root container to find which ports are allocated as the contianer isn't created yet
        Set<Integer> usedPortByHost = fabricService.getPortService().findUsedPortByHost(fabricService.getCurrentContainer());
        Map<String, String> emptyMap = new HashMap<String, String>();

        Set<String> profileIds = options.getProfiles();
        String versionId = options.getVersion();
        Map<String, String> ports = Profiles.getOverlayConfiguration(fabricService, profileIds, versionId, Constants.PORTS_PID);
        SortedMap<Integer, String> sortedInternalPorts = new TreeMap<Integer, String>();

        for (Map.Entry<String, String> portEntry : ports.entrySet()) {
            String portName = portEntry.getKey();
            String portText = portEntry.getValue();
            if (portText != null && !io.fabric8.utils.Strings.isNullOrBlank(portText)) {
                Integer port = null;
                try {
                    port = Integer.parseInt(portText);
                } catch (NumberFormatException e) {
                    LOG.warn("Ignoring bad port number for " + portName + " value '" + portText + "' in PID: " + Constants.PORTS_PID);
                }
                if (port != null) {
                    sortedInternalPorts.put(port, portName);
                    internalPorts.put(portName, port);
                    exposedPorts.put(portText + "/tcp", emptyMap);
                } else {
                    LOG.info("No port for " + portName);
                }
            }
        }

        String jolokiaUrl = null;
        Container currentContainer = fabricService.getCurrentContainer();
        String listenHost = currentContainer.getLocalIp();
        if (Strings.isNullOrBlank(listenHost)) {
            listenHost = currentContainer.getLocalHostname();
        }
        if (Strings.isNullOrBlank(listenHost)) {
            listenHost = "localhost";
        }
        if (!environmentVariables.containsKey(EnvironmentVariables.FABRIC8_LISTEN_ADDRESS)) {
            environmentVariables.put(EnvironmentVariables.FABRIC8_LISTEN_ADDRESS, listenHost);
        }

        Set<String> disableDynamicPorts = new HashSet<String>();
        String[] dynamicPortArray = processConfig.getDisableDynamicPorts();
        if (dynamicPortArray != null) {
            disableDynamicPorts.addAll(Arrays.asList(dynamicPortArray));
        }

        // lets create the ports in sorted order
        for (Map.Entry<Integer, String> entry : sortedInternalPorts.entrySet()) {
            Integer port = entry.getKey();
            String portName = entry.getValue();
            int externalPort = port;
            environmentVariables.put("FABRIC8_" + portName + "_PORT", "" + port);
            String proxyPortEnvName = "FABRIC8_" + portName + "_PROXY_PORT";

            // lets allow the proxy ports to be defined from the outside as an environment variable
            Integer currentProxyPort = null;
            String currentExternalPortText = environmentVariables.get(proxyPortEnvName);
            if (currentExternalPortText != null) {
                try {
                    currentProxyPort = Integer.parseInt(currentExternalPortText);
                } catch (NumberFormatException e) {
                    LOG.warn("Could not parse env var " + proxyPortEnvName + " of " + currentExternalPortText + " as a number: " + e, e);
                }
            }
            if (currentProxyPort != null) {
                externalPort = currentProxyPort;
            } else {
                if (!disableDynamicPorts.contains(portName)) {
                    externalPort = owner.createExternalPort(containerId, portName, usedPortByHost, options);
                }
                environmentVariables.put(proxyPortEnvName, "" + externalPort);
            }
            externalPorts.put(portName, externalPort);
            if (portName.equals(JolokiaAgentHelper.JOLOKIA_PORT_NAME)) {
                jolokiaUrl = "http://" + listenHost + ":" + externalPort + "/jolokia/";
                LOG.info("Found Jolokia URL: " + jolokiaUrl);
            }
        }
        if (processConfig.isCreateLocalContainerAddress()) {
            environmentVariables.put(EnvironmentVariables.FABRIC8_LOCAL_CONTAINER_ADDRESS, owner.createContainerLocalAddress(containerId, options));
        }

        if (jolokiaUrl != null) {
            registerJolokiaUrl(container, jolokiaUrl);
        }
    }

    protected void publishZooKeeperValues(CreateChildContainerOptions options, ProcessContainerConfig processConfig, Container container, Map<String, String> environmentVariables) {
        Map<String, Map<String, String>> publishConfigurations = Profiles.getOverlayFactoryConfigurations(fabricService, options.getProfiles(), options.getVersion(), ZooKeeperPublishConfig.PROCESS_CONTAINER_ZK_PUBLISH_PID);
        Set<Map.Entry<String, Map<String, String>>> entries = publishConfigurations.entrySet();
        for (Map.Entry<String, Map<String, String>> entry : entries) {
            String configName = entry.getKey();
            Map<String, String> exportConfig = entry.getValue();

            if (exportConfig != null && !exportConfig.isEmpty()) {
                JolokiaAgentHelper.substituteEnvironmentVariableExpressions(exportConfig, environmentVariables, fabricService, curator, true);
                ZooKeeperPublishConfig config = new ZooKeeperPublishConfig();
                try {
                    configurer.configure(exportConfig, config);
                    config.publish(curator, options, processConfig, container, environmentVariables);
                } catch (Exception e) {
                    LOG.warn("Failed to publish configuration " + configName + " of " + config + " due to: " + e, e);
                }
            }
        }
    }


    protected Installation getInstallation(Container container) {
        return processManager.getInstallation(container.getId());
    }

    protected void handleException(String message, Exception cause) {
        throw new RuntimeException(message + ". " + cause, cause);
    }

}
TOP

Related Classes of io.fabric8.container.process.ProcessManagerController

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.