/* * Copyright 2000-2012 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.vmware; import com.intellij.openapi.diagnostic.Logger; import java.util.*; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import jetbrains.buildServer.clouds.*; import jetbrains.buildServer.clouds.vmware.settings.VMWareSettings; import jetbrains.buildServer.clouds.vmware.vmrun.VMRun; import jetbrains.buildServer.clouds.vmware.vmrun.VMRunFactory; import jetbrains.buildServer.clouds.vmware.vmrun.remote.server.ClientState; import jetbrains.buildServer.serverSide.AgentDescription; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * @author Eugene Petrenko * Created: 07.12.2009 19:19:16 */ public class VMWareCloudClientEx extends ErrorHolder implements CloudClientEx { private static final Logger LOG = Logger.getInstance(VMWareCloudClientEx.class.getName()); private final ScheduledExecutorService myExecutor; private final Map myHosts = new HashMap(); private final AtomicBoolean myHostsInSync = new AtomicBoolean(false); public VMWareCloudClientEx(final VMWareSettings settings, final VMRunFactory vmRunFactory, @NotNull final ExecutorServiceFactory factory) { myExecutor = factory.createExecutorService("VMRunClients"); //TODO: watch each image in separate thread! //TODO: represent available (image,machine) pairs as permanent instnaces myExecutor.scheduleWithFixedDelay(wrap("Update running VMRunClients", new Runnable() { public void run() { final Collection vmRuns = vmRunFactory.getAvailableRunners(); Set obsoleteKeys = new HashSet(myHosts.keySet()); //TODO: too much work for one lock synchronized (VMWareCloudClientEx.this) { for (VMRun _vmRun : vmRuns) { final VMRun vmRun = new CachedVMRun(_vmRun); try { final String locationId = vmRun.getLocationId(); obsoleteKeys.remove(locationId); if (!myHosts.containsKey(locationId)) { VMRemoteHost host = new VMRemoteHost(vmRun, (ClientState)_vmRun, factory.createExecutorService(vmRun.getLocationId())); myHosts.put(locationId, host); } } catch (Throwable t) { LOG.warn("Failed to communicate with a client. " + t.getMessage()); } } for (String obsoleteKey : obsoleteKeys) { final VMRemoteHost host = myHosts.remove(obsoleteKey); if (host != null) { host.dispose(); } } } myHostsInSync.set(true); } }), 30, 30, TimeUnit.SECONDS); } @Nullable private synchronized VMRemoteHost findHostByImage(@NotNull final CloudImage image) { final VMWareImage img = (VMWareImage)image; return myHosts.get(img.getRemoteHostId()); } @NotNull public CloudInstance startNewInstance(@NotNull final CloudImage image, @NotNull final CloudInstanceUserData tag) throws QuotaException { final VMRemoteHost host = findHostByImage(image); if (host == null) { throw new CloudException("Failed to start image. Image is gone"); } return host.startNewInstance((VMWareImage)image, tag); } public boolean canStartNewInstance(@NotNull final CloudImage image) { final VMRemoteHost host = findHostByImage(image); if (host == null) { throw new CloudException("Failed to start image. Image is gone"); } return host.canStartNewInstance((VMWareImage)image); } public void restartInstance(@NotNull final CloudInstance instance) { } public void terminateInstance(@NotNull final CloudInstance instance) { final VMRemoteHost host = findHostByImage(instance.getImage()); if (host == null) { throw new CloudException("Failed to start image. Image is gone"); } host.terminateInstance((VMWareInstance)instance); } public synchronized void dispose() { for (VMRemoteHost host : myHosts.values()) { host.dispose(); } myHosts.clear(); myExecutor.shutdownNow(); } public synchronized boolean isInitialized() { if (!myHostsInSync.get()) return false; for (VMRemoteHost host : myHosts.values()) { if (!host.isInitialized()) return false; } return true; } @NotNull private synchronized Collection getHosts() { return new ArrayList(myHosts.values()); } public CloudImage findImageById(@NotNull final String imageId) throws CloudException { for (VMRemoteHost host : getHosts()) { final CloudImage image = host.findImageById(imageId); if (image != null) return image; } return null; } public CloudInstance findInstanceByAgent(@NotNull final AgentDescription agent) { final Map map = agent.getDefinedParameters(); final String imageId = map.get(VMWareConstants.WM_IMAGE_ID); final String instanceId = map.get(VMWareConstants.WM_INSTANCE_ID); if (imageId == null || instanceId == null) return null; final CloudImage id = findImageById(imageId); if (id == null) return null; return id.findInstanceById(instanceId); } @NotNull public Collection getImages() throws CloudException { List result = new ArrayList(); for (VMRemoteHost host : getHosts()) { result.addAll(host.getImages()); } return result; } @Nullable public String generateAgentName(@NotNull final AgentDescription agent) { return agent.getDefinedParameters().get(VMWareConstants.VMWARE_NAME_PROPOSAL); } }