/* * * * Copyright 2000-2014 JetBrains s.r.o. * * * * Licensed 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 jetbrains.buildServer.clouds.base; import com.intellij.openapi.diagnostic.Logger; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import jetbrains.buildServer.clouds.*; import jetbrains.buildServer.clouds.base.beans.CloudImageDetails; import jetbrains.buildServer.clouds.base.connector.CloudApiConnector; import jetbrains.buildServer.clouds.base.connector.CloudAsyncTaskExecutor; import jetbrains.buildServer.clouds.base.errors.CloudErrorMap; import jetbrains.buildServer.clouds.base.errors.TypedCloudErrorInfo; import jetbrains.buildServer.clouds.base.errors.UpdatableCloudErrorProvider; import jetbrains.buildServer.clouds.base.tasks.UpdateInstancesTask; import jetbrains.buildServer.clouds.vmware.errors.VmwareErrorMessages; import jetbrains.buildServer.serverSide.AgentDescription; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author Sergey.Pak * Date: 7/22/2014 * Time: 1:49 PM */ public abstract class AbstractCloudClient<G extends AbstractCloudInstance<T>, T extends AbstractCloudImage<G,D>, D extends CloudImageDetails> implements CloudClientEx, UpdatableCloudErrorProvider { private static final Logger LOG = Logger.getInstance(AbstractCloudClient.class.getName()); protected final Map<String, T> myImageMap; protected final UpdatableCloudErrorProvider myErrorProvider; protected final CloudAsyncTaskExecutor myAsyncTaskExecutor; @NotNull protected final CloudApiConnector myApiConnector; protected final CloudClientParameters myParameters; private volatile boolean myIsInitialized = false; public AbstractCloudClient(@NotNull final CloudClientParameters params, @NotNull final CloudApiConnector apiConnector) { myParameters = params; myAsyncTaskExecutor = new CloudAsyncTaskExecutor("Async tasks for cloud " + params.getProfileDescription()); myImageMap = new HashMap<String, T>(); myErrorProvider = new CloudErrorMap(VmwareErrorMessages.getInstance()); myApiConnector = apiConnector; } public boolean isInitialized() { return myIsInitialized; } public void dispose() { myAsyncTaskExecutor.dispose(); } @NotNull public G startNewInstance(@NotNull final CloudImage baseImage, @NotNull final CloudInstanceUserData tag) throws QuotaException { final T image = (T)baseImage; return image.startNewInstance(tag); } public void restartInstance(@NotNull final CloudInstance baseInstance) { final G instance = (G)baseInstance; instance.getImage().restartInstance(instance); } public void terminateInstance(@NotNull final CloudInstance baseInstance) { final G instance = (G)baseInstance; instance.getImage().terminateInstance(instance); } public boolean canStartNewInstance(@NotNull final CloudImage baseImage) { final T image = (T)baseImage; return image.canStartNewInstance(); } public void populateImagesData(@NotNull final Collection<D> imageDetails){ populateImagesData(imageDetails, 60*1000, 60*1000); } public void populateImagesData(@NotNull final Collection<D> imageDetails, long initialDelayMs, long delayMs){ for (D details : imageDetails) { T image = checkAndCreateImage(details); myImageMap.put(image.getName(), image); } final UpdateInstancesTask<G, T, ?> updateInstancesTask = createUpdateInstancesTask(); if (updateInstancesTask == null) { return; } myAsyncTaskExecutor.submit("Populate images data", new Runnable() { public void run() { try { updateInstancesTask.run(); myAsyncTaskExecutor.scheduleWithFixedDelay("Update instances", updateInstancesTask, initialDelayMs, delayMs, TimeUnit.MILLISECONDS); } finally { myIsInitialized = true; LOG.info("Cloud profile '" + myParameters.getProfileDescription() + "' initialized"); } } }); } protected abstract T checkAndCreateImage(@NotNull final D imageDetails); @NotNull protected abstract UpdateInstancesTask<G,T,?> createUpdateInstancesTask(); @Nullable public abstract G findInstanceByAgent(@NotNull final AgentDescription agent); @Nullable public T findImageById(@NotNull final String imageId) throws CloudException { return myImageMap.get(imageId); } @NotNull public Collection<T> getImages() throws CloudException { return Collections.unmodifiableCollection(myImageMap.values()); } public void updateErrors(final TypedCloudErrorInfo... errors) { myErrorProvider.updateErrors(errors); } @Nullable public CloudErrorInfo getErrorInfo() { return myErrorProvider.getErrorInfo(); } }