@Override public void release(DockerContainerLocation machine) { lock.readLock().lock(); try { LOG.info("Releasing {}", machine); DynamicCluster cluster = dockerHost.getDockerContainerCluster(); DockerContainer container = machine.getOwner(); if (cluster.removeMember(container)) { LOG.info("Docker Host {}: member {} released", dockerHost.getDockerHostName(), machine); } else { LOG.warn( "Docker Host {}: member {} not found for release", dockerHost.getDockerHostName(), machine); } // Now close and unmange the container try { machine.close(); container.stop(); } catch (Exception e) { LOG.warn("Error stopping container: " + container, e); Exceptions.propagateIfFatal(e); } finally { Entities.unmanage(container); } } finally { lock.readLock().unlock(); } }
@Override public DockerContainerLocation obtain(Map<?, ?> flags) throws NoMachinesAvailableException { lock.readLock().lock(); try { // Lookup entity from context or flags Object context = flags.get(LocationConfigKeys.CALLER_CONTEXT.getName()); if (context == null || !(context instanceof Entity)) { throw new IllegalStateException("Invalid location context: " + context); } Entity entity = (Entity) context; // Flag to configure adding SSHable layer boolean useSsh = entity.config().get(DockerContainer.DOCKER_USE_SSH) && dockerHost.config().get(DockerContainer.DOCKER_USE_SSH); // Configure the entity LOG.info("Configuring entity {} via subnet {}", entity, dockerHost.getSubnetTier()); entity .config() .set( SubnetTier.PORT_FORWARDING_MANAGER, dockerHost.getSubnetTier().getPortForwardManager()); entity.config().set(SubnetTier.PORT_FORWARDER, portForwarder); if (getOwner().config().get(SdnAttributes.SDN_ENABLE)) { SdnAgent agent = getOwner().sensors().get(SdnAgent.SDN_AGENT); if (agent == null) { throw new IllegalStateException("SDN agent entity on " + getOwner() + " is null"); } Map<String, Cidr> networks = agent.sensors().get(SdnAgent.SDN_PROVIDER).sensors().get(SdnProvider.SUBNETS); entity.config().set(SubnetTier.SUBNET_CIDR, networks.get(entity.getApplicationId())); } else { entity.config().set(SubnetTier.SUBNET_CIDR, Cidr.UNIVERSAL); } configureEnrichers(entity); // Add the entity Dockerfile if configured String dockerfile = entity.config().get(DockerAttributes.DOCKERFILE_URL); String entrypoint = entity.config().get(DockerAttributes.DOCKERFILE_ENTRYPOINT_URL); String contextArchive = entity.config().get(DockerAttributes.DOCKERFILE_CONTEXT_URL); String imageId = entity.config().get(DockerAttributes.DOCKER_IMAGE_ID); Optional<String> baseImage = Optional.fromNullable(entity.config().get(DockerAttributes.DOCKER_IMAGE_NAME)); String imageTag = Optional.fromNullable(entity.config().get(DockerAttributes.DOCKER_IMAGE_TAG)) .or("latest"); // TODO incorporate more info final String imageName = DockerUtils.imageName(entity, dockerfile); // Lookup image ID or build new image from Dockerfile LOG.info("ImageName for entity {}: {}", entity, imageName); if (dockerHost.getImageNamed(imageName, imageTag).isPresent()) { // Wait until committed before continuing - Brooklyn may be midway through its creation. waitForImage(imageName); // Look up imageId again imageId = dockerHost.getImageNamed(imageName, imageTag).get(); LOG.info("Found image {} for entity: {}", imageName, imageId); // Skip install phase entity.config().set(SoftwareProcess.SKIP_INSTALLATION, true); } else if (baseImage.isPresent()) { if (useSsh) { // Create an SSHable image from the one configured imageId = dockerHost.layerSshableImageOn(baseImage.get(), imageTag); LOG.info("Created SSHable image from {}: {}", baseImage.get(), imageId); } else { dockerHost.runDockerCommand(String.format("pull %s:%s", baseImage.get(), imageTag)); imageId = dockerHost.getImageNamed(baseImage.get(), imageTag).get(); } entity.config().set(SoftwareProcess.SKIP_INSTALLATION, true); } else { // Otherwise Clocker is going to make an image for the entity once it is installed. insertCallback(entity, SoftwareProcess.POST_INSTALL_COMMAND, DockerCallbacks.commit()); if (Strings.isNonBlank(dockerfile)) { if (imageId != null) { LOG.warn( "Ignoring container imageId {} as dockerfile URL is set: {}", imageId, dockerfile); } Map<String, Object> substitutions = getExtraTemplateSubstitutions(imageName, entity); imageId = dockerHost.buildImage( dockerfile, entrypoint, contextArchive, imageName, useSsh, substitutions); } if (Strings.isBlank(imageId)) { imageId = getOwner().sensors().get(DockerHost.DOCKER_IMAGE_ID); } // Tag the image name and create its latch images.putIfAbsent(imageName, new CountDownLatch(1)); dockerHost.runDockerCommand(String.format("tag -f %s %s:latest", imageId, imageName)); } // Look up hardware ID String hardwareId = entity.config().get(DockerAttributes.DOCKER_HARDWARE_ID); if (Strings.isEmpty(hardwareId)) { hardwareId = getOwner().config().get(DockerAttributes.DOCKER_HARDWARE_ID); } // Create new Docker container in the host cluster LOG.info( "Starting container with imageId {} and hardwareId {} at {}", new Object[] {imageId, hardwareId, machine}); Map<Object, Object> containerFlags = MutableMap.builder() .putAll(flags) .put("useSsh", useSsh) .put("entity", entity) .putIfNotNull("imageId", imageId) .putIfNotNull("hardwareId", hardwareId) .build(); DynamicCluster cluster = dockerHost.getDockerContainerCluster(); Entity added = cluster.addNode(machine, containerFlags); if (added == null) { throw new NoMachinesAvailableException( String.format("Failed to create container at %s", dockerHost.getDockerHostName())); } else { Entities.invokeEffector( (EntityLocal) entity, added, Startable.START, MutableMap.of("locations", ImmutableList.of(machine))) .getUnchecked(); } DockerContainer dockerContainer = (DockerContainer) added; // Save the container attributes dockerContainer.sensors().set(DockerContainer.IMAGE_ID, imageId); dockerContainer.sensors().set(DockerContainer.IMAGE_NAME, imageName); dockerContainer.sensors().set(DockerContainer.HARDWARE_ID, hardwareId); // record SDN application network details if (getOwner().config().get(SdnAttributes.SDN_ENABLE)) { SdnAgent agent = getOwner().sensors().get(SdnAgent.SDN_AGENT); Cidr applicationCidr = agent.sensors().get(SdnAgent.SDN_PROVIDER).getSubnetCidr(entity.getApplicationId()); entity.sensors().set(SdnProvider.APPLICATION_CIDR, applicationCidr); dockerContainer.sensors().set(SdnProvider.APPLICATION_CIDR, applicationCidr); } return dockerContainer.getDynamicLocation(); } finally { lock.readLock().unlock(); } }