All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.galasa.docker.internal.DockerContainerResourceMonitor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright contributors to the Galasa project
 *
 * SPDX-License-Identifier: EPL-2.0
 */
package dev.galasa.docker.internal;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import dev.galasa.docker.internal.json.DockerContainerJSON;
import dev.galasa.framework.spi.ConfigurationPropertyStoreException;
import dev.galasa.framework.spi.FrameworkException;
import dev.galasa.framework.spi.IConfigurationPropertyStoreService;
import dev.galasa.framework.spi.IDynamicStatusStoreService;
import dev.galasa.framework.spi.IFramework;
import dev.galasa.framework.spi.IResourceManagement;
import dev.galasa.framework.spi.utils.GalasaGson;
import dev.galasa.http.HttpClientException;
import dev.galasa.http.HttpClientResponse;
import dev.galasa.http.IHttpClient;
import dev.galasa.http.StandAloneHttpClient;

/**
 * Resource monitor for cleaning up orphaned containers.
 * 
 *   
 */
public class DockerContainerResourceMonitor implements Runnable {
    private final IConfigurationPropertyStoreService cps;
    private final IDynamicStatusStoreService dss;

    private final Log logger = LogFactory.getLog(DockerContainerResourceMonitor.class);

    private GalasaGson gson = new GalasaGson();

    private Map dockerEngines = new HashMap<>();

    public DockerContainerResourceMonitor(IFramework framework, IResourceManagement resourceManagement, IConfigurationPropertyStoreService cps, IDynamicStatusStoreService dss) {
        this.cps = cps;
        this.dss = dss;

        logger.info("Docker container resource monitor intialised");
    }

    @Override
    public void run() {
        logger.info("Docker container resouce check started");

        updateDockerEngines();

        for (String engine : this.dockerEngines.keySet()) {
            List containers = getOrphanedContainers(engine, this.dockerEngines.get(engine));
            logger.info("Engine " + engine + " has " + containers.size() + " orphaned containers found");
            if (containers.size() > 0) {
                killContainers(containers, this.dockerEngines.get(engine));
            }
        }
        logger.info("Docker container resource check finished");
    }

    /**
     * Stops and removed containers from an engines
     * @param containers
     * @param client
     */
    private void killContainers(List containers, IHttpClient client) {
        logger.info("Shutting down orphaned containers");
        try {
            for (String id : containers) {
                HttpClientResponse resp = client.deleteText("/containers/"+id+"?force=true");
                if (resp.getStatusCode() != 204) {
                    logger.error("Something went wrong when removing container: " + resp.getStatusLine());
                    return;
                }
            }
        } catch (HttpClientException e) {
            logger.error("Failed to kill containers.", e);
        }        
    }

    /**
     * Looks at all containers on a Engine, locates Galasa specifics and ensures they have a decicated slot
     * @param engine
     * @param client
     * @return
     */
    private List getOrphanedContainers(String engine, IHttpClient client) {
        List orphanedContainers = new ArrayList<>();
        try {
            HttpClientResponse resp = client.getText("/containers/json?all=true");
            if (resp.getStatusCode() != 200) {
                logger.error("Something went wrong when retrieving containers: " + resp.getStatusLine());
                return orphanedContainers;
            }

            DockerContainerJSON[] activeContainers = gson.fromJson(resp.getContent(), DockerContainerJSON[].class);
            for (DockerContainerJSON container : activeContainers) {
                String runName = container.getLabels().getRunId();
                String slotId = container.getLabels().getSlotId();
                // Other non Galasa pod
                if (runName == null) {
                    continue;
                }

                // Check Slot name against runID. If Null or another run then container orphaned
                if (!runName.equals(dss.get("engine."+engine+".slot."+slotId))) {
                    orphanedContainers.add(container.getId());
                }
            }
        } catch (HttpClientException | FrameworkException e) {
            logger.error("Failed to get containers.", e);
        }
        return orphanedContainers;
    }

    /**
     * Looks at CPS for the docker Engines available
     * @return
     */
    private void updateDockerEngines() {
        try { 
            // This will have to be changed if we support engine clusters
            String[] enginesTags = cps.getProperty("default", "engines").split(",");
            for (String engine : enginesTags) {
                if (this.dockerEngines.get(engine) == null) {
                    String hostname = cps.getProperty("engine", "hostname", engine);
                    String port = cps.getProperty("engine", "port", engine);
    
                    IHttpClient client = StandAloneHttpClient.getHttpClient(3600, logger);
                    client.setURI(new URI(hostname+":"+port));
                    this.dockerEngines.put(engine, client);
                }
            }
        } catch (ConfigurationPropertyStoreException | URISyntaxException e) {
            logger.error("Failed to get Docker engines.", e);
        }
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy