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

dev.galasa.docker.internal.DockerManagerImpl 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.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import javax.validation.constraints.NotNull;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.annotations.Component;

import dev.galasa.ManagerException;
import dev.galasa.artifact.IArtifactManager;
import dev.galasa.docker.DockerContainer;
import dev.galasa.docker.DockerContainerConfig;
import dev.galasa.docker.DockerManagerException;
import dev.galasa.docker.DockerProvisionException;
import dev.galasa.docker.DockerVolume;
import dev.galasa.docker.DockerEngine;
import dev.galasa.docker.IDockerContainer;
import dev.galasa.docker.IDockerContainerConfig;
import dev.galasa.docker.IDockerManager;
import dev.galasa.docker.IDockerVolume;
import dev.galasa.docker.IDockerEngine;
import dev.galasa.docker.internal.properties.DockerPropertiesSingleton;
import dev.galasa.docker.internal.properties.DockerRegistry;
import dev.galasa.docker.spi.IDockerManagerSpi;
import dev.galasa.framework.spi.AbstractManager;
import dev.galasa.framework.spi.AnnotatedField;
import dev.galasa.framework.spi.ConfigurationPropertyStoreException;
import dev.galasa.framework.spi.GenerateAnnotatedField;
import dev.galasa.framework.spi.IFramework;
import dev.galasa.framework.spi.IManager;
import dev.galasa.framework.spi.ResourceUnavailableException;
import dev.galasa.framework.spi.language.GalasaTest;
import dev.galasa.http.IHttpManager;
import dev.galasa.http.spi.IHttpManagerSpi;

/**
 * Docker manager implementation.
 * 
 * Extracting from the test class the two current annotations of @DockerEngine and @DockerContainer
 * 
 * @DockerEngine - where the containers will be running, set value in CPS (see properties)
 * @DockerContainer - define what container is to be run, image names mus be defined, tag can be set
 * 
 *   
 */
@Component(service = { IManager.class })
public class DockerManagerImpl extends AbstractManager implements IDockerManagerSpi {
    protected final String               NAMESPACE = "docker";
    private final static Log                    logger = LogFactory.getLog(DockerManagerImpl.class);
    private IFramework                          framework;
    private IHttpManagerSpi                   httpManager;
    private IArtifactManager                    artifactManager;
    private IDockerEnvironment                  dockerEnvironment;
    private List            registries = new ArrayList();
    private boolean                             required = false;

    /**
     * Initialies the DockerManager, adding the requirement of the HttpManager
     * 
     * Docker Environment is generated at this stage
     * 
     * @param framework - the galasa framework
     * @param allManagers - list of all the managers
     * @param activeManagers - list of all the active managers

     * @throws ManagerException
     */
    @Override
    public void initialise(@NotNull IFramework framework, @NotNull List allManagers,
            @NotNull List activeManagers, @NotNull GalasaTest galasaTest) throws ManagerException {

        super.initialise(framework, allManagers, activeManagers, galasaTest);

        if(galasaTest.isJava()) {
            List ourFields = findAnnotatedFields(DockerManagerField.class);
            if (!ourFields.isEmpty()) {
                youAreRequired(allManagers, activeManagers, galasaTest);
            }
        }
        try {
            DockerPropertiesSingleton.setCps(framework.getConfigurationPropertyService(NAMESPACE));
        } catch (ConfigurationPropertyStoreException e) {
            throw new DockerManagerException("Failed to set the CPS with the Docker namespace", e);
        }

        this.framework = framework;
        dockerEnvironment = new DockerEnvironment(framework, this);
        logger.info("Docker manager intialised");

    }
    
    /**
     * Makes sure that the docker manager is added to the list of active managers, and adds the dependency on http manager.
     * 
     * @param allManagers - list of all the managers
     * @param activeManagers - list of the active managers
     * @throws ManagerException
     */
    @Override
    public void youAreRequired(@NotNull List allManagers, @NotNull List activeManagers, @NotNull GalasaTest galasaTest)
            throws ManagerException {
        this.required = true;

        if (activeManagers.contains(this)) {
			return;
		}
        activeManagers.add(this);
        httpManager = addDependentManager(allManagers, activeManagers, galasaTest, IHttpManagerSpi.class);
        if (httpManager == null) {
            throw new DockerManagerException("The http manager is not available");
        }
        artifactManager = this.addDependentManager(allManagers, activeManagers, galasaTest, IArtifactManager.class);
        if (artifactManager == null) {
            throw new DockerManagerException("The Artifact manager is not available");
        }
    }

    @Override
    public boolean areYouProvisionalDependentOn(@NotNull IManager otherManager) {
        if(otherManager instanceof IHttpManager) {
            return true;
        }
        return false;
    }

    /**
     * Generates the docker containers defined in the annotation inside the test class.
     * 
     * @param field
     * @param annotations
     * @return IDockerContainer
     * @throws DockerManagerException
     */
    @GenerateAnnotatedField(annotation = DockerContainer.class)
    public IDockerContainer generateDockerContainer(Field field, List annotations) throws DockerManagerException {
        DockerContainer annotationContainer = field.getAnnotation(DockerContainer.class);
        return this.provisionContainer(annotationContainer.dockerContainerTag(),
                                        annotationContainer.image(),
                                        annotationContainer.start(),
                                        annotationContainer.dockerEngineTag()); 
    }

    /**
     * Private method to provision the dockerContainer described by the generateDockerContainer() in the provisioned docker environment.
     *  
     * @param dockerContainerTag
     * @param image
     * @param start
     * @return
     * @throws DockerManagerException
     */
    @Override
    public IDockerContainer provisionContainer(String dockerContainerTag, String image, boolean start, String dockerEngineTag) throws DockerManagerException {
        try {
            return dockerEnvironment.provisionDockerContainer(dockerContainerTag, image, start, dockerEngineTag);
        } catch (DockerProvisionException e) {
            throw new DockerManagerException("Failed to provision Docker container tag: "+ dockerContainerTag, e);
        }
    }

    /**
     * Directs to the docker engine where the containers will be provisioned.
     * 
     * @param field
     * @param annotations
     * @return IDockerEngine
     * @throws DockerManagerException
     */
    @GenerateAnnotatedField(annotation = DockerEngine.class)
    public IDockerEngine generateDockerEngine(Field field, List annotations) throws DockerManagerException {
        DockerEngine annotationServer = field.getAnnotation(DockerEngine.class);
        return this.getDockerEngine(annotationServer.dockerEngineTag());
    }

    @GenerateAnnotatedField(annotation = DockerContainerConfig.class)
    public IDockerContainerConfig generateDockerContainerConfig(Field field, List annotations) throws DockerManagerException {
        List volumes = new ArrayList<>();
        DockerContainerConfig config = field.getAnnotation(DockerContainerConfig.class);

        for (DockerVolume volumeAnnotation : config.dockerVolumes()) {
            volumes.add(generateDockerVolumme(volumeAnnotation));
        }
        return new DockerContainerConfigImpl(volumes);
    }

    @GenerateAnnotatedField(annotation =  DockerVolume.class)
    public IDockerVolume generateDockerVolumme(DockerVolume annotation) throws DockerManagerException {
        try {
            return dockerEnvironment.allocateDockerVolume(  annotation.existingVolumeName(), 
                                                            annotation.volumeTag(),
                                                            annotation.mountPath(),
                                                            annotation.dockerEngineTag(),
                                                            annotation.readOnly());
        } catch (DockerProvisionException e) {
            throw new DockerManagerException("Failed to allocate Docker volume", e);
        }
    }

    /**
     * Private method for retrieving the docker sever used by the docker environment
     * 
     * @return
     * @throws DockerManagerException
     */
    private IDockerEngine getDockerEngine(String dockerEngineTag) throws DockerManagerException {
        return dockerEnvironment.getDockerEngineImpl(dockerEngineTag);
    }
    
    protected IHttpManagerSpi getHttpManager() {
    	return this.httpManager;
    }

    /**
     * Provision generate step. Extracts the docker manager realted annotations and generates the resources
     * 
     * @throws ManagerException
     */
    @Override
    public void provisionGenerate() throws ResourceUnavailableException, ManagerException {
        logger.info("Registering Docker registries");
        registerDockerRegistires();
        logger.info("Finding all Docker related annotations");
        generateDockerFields();
    }

    /**
     * Used in the provision generate step to extract annotations from the test class.
     * 
     * @throws ManagerException
     */
    private void generateDockerFields() throws ResourceUnavailableException, ManagerException {
        List annotatedFields = findAnnotatedFields(DockerManagerField.class);

        for (AnnotatedField annotatedField: annotatedFields) {
            final Field field = annotatedField.getField();
            final List annotations = annotatedField.getAnnotations();

            if (field.getType() == IDockerManager.class) {
                registerAnnotatedField(field, this);
            } else if (field.getType() == IDockerEngine.class) {
                DockerEngine annotation = field.getAnnotation(DockerEngine.class);
                if (annotation != null) {
                    IDockerEngine dockerEngine = generateDockerEngine(field, annotations);
                    registerAnnotatedField(field, dockerEngine);
                }
            } else if (field.getType() == IDockerContainer.class) {
                DockerContainer annotation = field.getAnnotation(DockerContainer.class);
                if (annotation != null) {
                    IDockerContainer dockerContainer = generateDockerContainer(field, annotations);
                    registerAnnotatedField(field, dockerContainer);
                }
            } else if (field.getType() == IDockerContainerConfig.class) {
                DockerContainerConfig annotation = field.getAnnotation(DockerContainerConfig.class);
                if (annotation != null) {
                    IDockerContainerConfig config = generateDockerContainerConfig(field, annotations);
                    registerAnnotatedField(field, config);
                }
            }
        }
        generateAnnotatedFields(DockerManagerField.class);
    }
    
    /**
     * Used in the provision generate step to register all the docker registries from the CPS, if non specified docker hub is registered.
     * 
     * @throws DockerProvisionException
     */
    private void registerDockerRegistires() throws DockerProvisionException {
        try {
            String[] registryIds = DockerRegistry.get();

            for (String id: registryIds) {
                registries.add(new DockerRegistryImpl(framework, this, id));
            }
        } catch (Exception e) {
            throw new DockerProvisionException("Unable to resolve Docker registries: ", e);
        }
    }

    /**
     * Cleans and discards the docker environment, deleting docker containers not flagged to keep running.
     */
    @Override
    public void provisionStop() {
        try {
            dockerEnvironment.discard();
        } catch (DockerManagerException e) {
            logger.error("Unable to discard Docker environment", e);
        }

    }

    /**
     * Gets any container running in the docker environment via the image tag
     * 
     * @throws DockerManagerException
     */
    public IDockerContainer getDockerContainer(String dockerContainerTag) throws DockerManagerException {
        return dockerEnvironment.getDockerContainerImpl(dockerContainerTag);
    }

    /**
     * Frees up any slot in use from a docker container.
     * 
     * @param slot
     * @throws DockerProvisionException
     */
    public void freeDockerSlot(DockerSlotImpl slot) throws DockerProvisionException {
        dockerEnvironment.freeDockerSlot(slot);
    }

    /**
     * Returns a list of all the registered registries used by the docker container.
     * 
     * @return registries
     */
	public List getRegistries() {
		return this.registries;
	}

    @Override
    public @NotNull String getEngineHostname(String dockerEngineTag) throws DockerManagerException {
    	try {
        URI dockerEngine = dockerEnvironment.getDockerEngineImpl(dockerEngineTag).getURI();
        return dockerEngine.getScheme() + "://" + dockerEngine.getHost();
    	} catch (URISyntaxException e) {
    		throw new DockerManagerException("Failed to parse the found URI", e);
    	}
    }

    public IArtifactManager getArtifactManager() {
        return this.artifactManager;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy