Java tutorial
/* The MIT License * * Copyright (c) 2010-2015 Danila A. (atmakin.dv@gmail.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ package io.cyberstock.tcdop.server.integration.teamcity; import com.intellij.openapi.diagnostic.Logger; import io.cyberstock.tcdop.model.DOIntegrationMode; import io.cyberstock.tcdop.model.DOSettings; import io.cyberstock.tcdop.model.error.DOError; import io.cyberstock.tcdop.server.integration.digitalocean.DOAsyncClientService; import io.cyberstock.tcdop.server.integration.digitalocean.storage.CloudImageStorage; import io.cyberstock.tcdop.server.integration.digitalocean.impl.DOAsyncClientServiceWrapper; import jetbrains.buildServer.clouds.*; import jetbrains.buildServer.serverSide.AgentDescription; import jetbrains.buildServer.serverSide.impl.auth.SecuredBuildAgent; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import sun.reflect.generics.reflectiveObjects.NotImplementedException; import java.util.Collection; import java.util.Collections; import java.util.UUID; import java.util.concurrent.ExecutorService; /** * Created by beolnix on 24/05/15. */ public class DOCloudClient implements CloudClientEx { // dependencies @NotNull private final DOSettings settings; @NotNull private final DOAsyncClientService client; @NotNull private final CloudImageStorage imageStorage; @NotNull private final ExecutorService executorService; // State private CloudErrorInfo cloudErrorInfo = null; // constants private static final Logger LOG = Logger.getInstance(DOCloudClient.class.getName()); DOCloudClient(@NotNull DOSettings settings, @NotNull DOAsyncClientService client, @NotNull CloudImageStorage imageStorage, @NotNull ExecutorService executorService) { this.settings = settings; this.client = client; this.imageStorage = imageStorage; this.executorService = executorService; } public void setCloudErrorInfo(CloudErrorInfo cloudErrorInfo) { LOG.error("Error occured: " + cloudErrorInfo.getMessage()); this.cloudErrorInfo = cloudErrorInfo; } @NotNull public CloudInstance startNewInstance(@NotNull CloudImage cloudImage, @NotNull CloudInstanceUserData cloudInstanceUserData) throws QuotaException { LOG.info("Launch new instance in Digital Ocean with cloudImage: " + cloudImage.getName()); DOCloudImage DOCloudImage = (DOCloudImage) cloudImage; try { DOCloudInstance instance = client.initializeInstance(DOCloudImage, settings); imageStorage.countNewInstance(); return instance; } catch (DOError e) { setCloudErrorInfo(new CloudErrorInfo("Can't create new instance", e.getMessage(), e)); throw new RuntimeException(e); } } public void restartInstance(@NotNull CloudInstance cloudInstance) { LOG.info("DO Instance restart is triggered for: " + cloudInstance.toString()); client.restartInstance((DOCloudInstance) cloudInstance); } public void terminateInstance(@NotNull CloudInstance cloudInstance) { LOG.info("DO Instance termination is triggered for: " + cloudInstance.toString()); client.terminateInstance((DOCloudInstance) cloudInstance); } public void dispose() { imageStorage.shutdownStorage(); executorService.shutdown(); } public boolean isInitialized() { return imageStorage.isInitialized(); } @Nullable public CloudImage findImageById(@NotNull String s) throws CloudException { // LOG.debug("DO find image by id is triggered: " + s); if (DOIntegrationMode.PREPARED_IMAGE.equals(settings.getMode())) { DOCloudImage cloudImage = imageStorage.getImageById(s); if (cloudImage == null) { // LOG.debug("DO cloud image not found for id: " + s); return null; } else { // LOG.debug("DO cloud image found: " + cloudImage.toString()); } if (settings.getImageName().equals(cloudImage.getName())) { // LOG.debug("DO cloud image is correct. Find Image by id returns successful result: " + cloudImage.toString()); return cloudImage; } else { LOG.error("DO cloud image name isn't equal to pre-configured: " + cloudImage.getName()); return null; } } else { // LOG.error("DO Mode: " + settings.getMode() + " isn't supported yet."); throw new NotImplementedException(); } } @Nullable public CloudInstance findInstanceByAgent(@NotNull AgentDescription agentDescription) { LOG.debug("Find instance by agent is triggered."); String agentIPv4 = ((SecuredBuildAgent) agentDescription).getHostAddress(); if (StringUtils.isEmpty(agentIPv4)) { LOG.error("Agent ipv4 is empty."); return null; } else { LOG.debug("Agent ipv4 is: " + agentIPv4); } Collection<DOCloudImage> images = imageStorage.getImagesList(); for (DOCloudImage image : images) { for (CloudInstance instance : image.getInstances()) { if (instance.getNetworkIdentity().equals(agentIPv4)) { LOG.debug("Instance with the same ipv4 has been found: " + instance.toString()); return instance; } else { LOG.debug("Instance " + instance.getInstanceId() + " has another ipv4: " + instance.getNetworkIdentity()); } } } LOG.error("Instance with ipv4: " + agentIPv4 + " hasn't been found."); return null; } @NotNull public Collection<? extends CloudImage> getImages() throws CloudException { // LOG.debug("DO get images triggered"); if (DOIntegrationMode.PREPARED_IMAGE.equals(settings.getMode())) { Collection<DOCloudImage> images = imageStorage.getImagesList(); // LOG.debug(images.size() + " images found, trying to identify image with name: " + settings.getImageName()); for (DOCloudImage cloudImage : images) { if (cloudImage != null && settings.getImageName().equals(cloudImage.getName())) { // LOG.debug("Image found: " + cloudImage.toString()); return Collections.singleton(cloudImage); } else { // LOG.debug("Image " + cloudImage.getName() + " skipped."); } } } else { LOG.error(settings.getMode() + " Mode isn't supported yet"); throw new NotImplementedException(); } // LOG.debug("Image with name " + settings.getImageName() + " hasn't been found."); return Collections.EMPTY_LIST; } @Nullable public CloudErrorInfo getErrorInfo() { return cloudErrorInfo; } public boolean canStartNewInstance(@NotNull CloudImage cloudImage) { LOG.debug("Can start new instance? is triggered"); if (settings.getInstancesLimit() > imageStorage.getInstancesCount() && cloudErrorInfo == null) { LOG.debug("new instance can be started. Limit: " + settings.getInstancesLimit() + "; current: " + imageStorage.getInstancesCount()); return true; } else { LOG.error("new instance can NOT be started. Limit: " + settings.getInstancesLimit() + "; current: " + imageStorage.getInstancesCount()); if (cloudErrorInfo != null) { LOG.error("Cloud error info: " + cloudErrorInfo.getDetailedMessage()); } return false; } } @Nullable public String generateAgentName(@NotNull AgentDescription agentDescription) { String agentName = settings.getDropletNamePrefix() + "_AGENT_" + UUID.randomUUID(); LOG.debug("Agent name generation is triggered. Generated name is: " + agentName); return agentName; } }