Java tutorial
/** * Copyright (C) 2009-2015 Dell, Inc. * See annotations for authorship information * * ==================================================================== * 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 org.dasein.cloud.compute; import org.dasein.cloud.CloudException; import org.dasein.cloud.CloudProvider; import org.dasein.cloud.InternalException; import org.dasein.cloud.OperationNotSupportedException; import org.dasein.cloud.ProviderContext; import org.dasein.cloud.Requirement; import org.dasein.cloud.ResourceStatus; import org.dasein.cloud.Tag; import org.dasein.cloud.identity.ServiceAction; import org.dasein.cloud.util.*; import org.dasein.util.CalendarWrapper; import org.dasein.util.Jiterator; import org.dasein.util.JiteratorPopulator; import org.dasein.util.PopulatorThread; import org.dasein.util.uom.storage.Gigabyte; import org.dasein.util.uom.storage.Megabyte; import org.dasein.util.uom.storage.Storage; import org.dasein.util.uom.time.Day; import org.dasein.util.uom.time.TimePeriod; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.*; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * Default implementation of virtual machine support for clouds with very little support. * <p>Created by George Reese: 1/29/13 6:11 PM</p> * * @author George Reese * @version 2013.04 * @since 2013.04 */ public abstract class AbstractVMSupport<T extends CloudProvider> implements VirtualMachineSupport { private T provider; public AbstractVMSupport(T provider) { this.provider = provider; } @Override @Deprecated public VirtualMachine alterVirtualMachine(@Nonnull String vmId, @Nonnull VMScalingOptions options) throws InternalException, CloudException { throw new OperationNotSupportedException( "VM alternations are not currently supported for " + getProvider().getCloudName()); } @Override @Deprecated public VirtualMachine modifyInstance(@Nonnull String vmId, @Nonnull String[] firewalls) throws InternalException, CloudException { throw new OperationNotSupportedException( "Instance firewall modifications are not currently supported for " + getProvider().getCloudName()); } @Override public @Nonnull VirtualMachine alterVirtualMachineProduct(@Nonnull String virtualMachineId, @Nonnull String productId) throws InternalException, CloudException { throw new OperationNotSupportedException( "VM alternations are not currently supported for " + getProvider().getCloudName()); } @Override public @Nonnull VirtualMachine alterVirtualMachineSize(@Nonnull String virtualMachineId, @Nullable String cpuCount, @Nullable String ramInMB) throws InternalException, CloudException { throw new OperationNotSupportedException( "VM alternations are not currently supported for " + getProvider().getCloudName()); } @Override public @Nonnull VirtualMachine alterVirtualMachineFirewalls(@Nonnull String virtualMachineId, @Nonnull String[] firewalls) throws InternalException, CloudException { throw new OperationNotSupportedException( "Instance firewall modifications are not currently supported for " + getProvider().getCloudName()); } @Override public void cancelSpotDataFeedSubscription() throws CloudException, InternalException { throw new OperationNotSupportedException( "Spot Instances are not supported for " + getProvider().getCloudName()); } @Override public void cancelSpotVirtualMachineRequest(@Nonnull String providerSpotVirtualMachineRequestID) throws CloudException, InternalException { throw new OperationNotSupportedException( "Spot Instances are not supported for " + getProvider().getCloudName()); } @Override public @Nonnull VirtualMachine clone(@Nonnull String vmId, @Nonnull String intoDcId, @Nonnull String name, @Nonnull String description, boolean powerOn, @Nullable String... firewallIds) throws InternalException, CloudException { throw new OperationNotSupportedException( "VM cloning is not currently supported for " + getProvider().getCloudName()); } @Override public @Nonnull SpotVirtualMachineRequest createSpotVirtualMachineRequest( @Nonnull SpotVirtualMachineRequestCreateOptions options) throws CloudException, InternalException { throw new OperationNotSupportedException( "Spot Instances are not supported for " + getProvider().getCloudName()); } public @Nonnull Iterable<SpotVirtualMachineRequest> listSpotVirtualMachineRequests( @Nullable SpotVirtualMachineRequestFilterOptions options) throws CloudException, InternalException { throw new OperationNotSupportedException( "Spot Instances are not supported for " + getProvider().getCloudName()); } @Override @Deprecated public @Nullable VMScalingCapabilities describeVerticalScalingCapabilities() throws CloudException, InternalException { return getCapabilities().getVerticalScalingCapabilities(); } @Override public void disableAnalytics(@Nonnull String vmId) throws InternalException, CloudException { // NO-OP } @Override public void enableAnalytics(@Nonnull String vmId) throws InternalException, CloudException { // NO-OP } @Override public void enableSpotDataFeedSubscription(@Nonnull String bucketName) throws CloudException, InternalException { throw new OperationNotSupportedException( "Spot Instances are not supported for " + getProvider().getCloudName()); } /** * Provides the current provider context for the request in progress. * * @return the current provider context * @throws CloudException no context was defined before making this call */ protected final @Nonnull ProviderContext getContext() throws CloudException { ProviderContext ctx = getProvider().getContext(); if (ctx == null) { throw new CloudException("No context was defined for this request"); } return ctx; } @Override @Deprecated public @Nonnegative int getCostFactor(@Nonnull VmState state) throws CloudException, InternalException { return getCapabilities().getCostFactor(state); } @Override public @Nullable String getPassword(@Nonnull String vmId) throws InternalException, CloudException { return null; } @Override public @Nullable String getUserData(@Nonnull String vmId) throws InternalException, CloudException { return null; } @Override public @Nonnull String getConsoleOutput(@Nonnull String vmId) throws InternalException, CloudException { return ""; } @Override @Deprecated public int getMaximumVirtualMachineCount() throws CloudException, InternalException { return getCapabilities().getMaximumVirtualMachineCount(); } @Override public @Nullable VirtualMachineProduct getProduct(@Nonnull String productId) throws InternalException, CloudException { APITrace.begin(getProvider(), "VM.getProduct"); try { for (Architecture architecture : getCapabilities().listSupportedArchitectures()) { for (VirtualMachineProduct prd : listProducts(architecture)) { if (productId.equals(prd.getProviderProductId())) { return prd; } } } return null; } finally { APITrace.end(); } } /** * @return the current provider governing any operations against this cloud in this support instance */ protected final @Nonnull T getProvider() { return provider; } @Override @Deprecated public @Nonnull String getProviderTermForServer(@Nonnull Locale locale) { try { return getCapabilities().getProviderTermForVirtualMachine(locale); } catch (Exception ignore) { return "virtual machine"; } } @Override public @Nullable VirtualMachine getVirtualMachine(@Nonnull String vmId) throws InternalException, CloudException { for (VirtualMachine vm : listVirtualMachines(null)) { if (vm.getProviderVirtualMachineId().equals(vmId)) { return vm; } } return null; } @Override public @Nonnull VmStatistics getVMStatistics(@Nonnull String vmId, @Nonnegative long from, @Nonnegative long to) throws InternalException, CloudException { return new VmStatistics(); } @Override public @Nonnull Iterable<VmStatistics> getVMStatisticsForPeriod(@Nonnull String vmId, @Nonnegative long from, @Nonnegative long to) throws InternalException, CloudException { return Collections.emptyList(); } @Override @Deprecated public @Nonnull Requirement identifyImageRequirement(@Nonnull ImageClass cls) throws CloudException, InternalException { return getCapabilities().identifyImageRequirement(cls); } @Override @Deprecated public @Nonnull Requirement identifyPasswordRequirement() throws CloudException, InternalException { return getCapabilities().identifyPasswordRequirement(Platform.UNKNOWN); } @Override @Deprecated public @Nonnull Requirement identifyPasswordRequirement(Platform platform) throws CloudException, InternalException { return getCapabilities().identifyPasswordRequirement(platform); } @Override @Deprecated public @Nonnull Requirement identifyRootVolumeRequirement() throws CloudException, InternalException { return getCapabilities().identifyRootVolumeRequirement(); } @Override @Deprecated public @Nonnull Requirement identifyShellKeyRequirement() throws CloudException, InternalException { return getCapabilities().identifyShellKeyRequirement(Platform.UNKNOWN); } @Override @Deprecated public @Nonnull Requirement identifyShellKeyRequirement(Platform platform) throws CloudException, InternalException { return getCapabilities().identifyShellKeyRequirement(platform); } @Override @Deprecated public @Nonnull Requirement identifyStaticIPRequirement() throws CloudException, InternalException { return getCapabilities().identifyStaticIPRequirement(); } @Override @Deprecated public @Nonnull Requirement identifyVlanRequirement() throws CloudException, InternalException { return getCapabilities().identifyVlanRequirement(); } @Override @Deprecated public boolean isAPITerminationPreventable() throws CloudException, InternalException { return getCapabilities().isAPITerminationPreventable(); } @Override @Deprecated public boolean isBasicAnalyticsSupported() throws CloudException, InternalException { return getCapabilities().isBasicAnalyticsSupported(); } @Override @Deprecated public boolean isExtendedAnalyticsSupported() throws CloudException, InternalException { return getCapabilities().isExtendedAnalyticsSupported(); } @Override @Deprecated public boolean isUserDataSupported() throws CloudException, InternalException { return getCapabilities().isUserDataSupported(); } static private final ExecutorService launchPool = Executors.newCachedThreadPool(); /** * Launches a virtual machine asynchronously from a cached thread pool. All errors are pulled out from the * the {@link java.util.concurrent.Future} result. * * @param withLaunchOptions the launch options to use in launching the virtual machine * @return the unique ID of the launched virtual machine */ protected Future<String> launchAsync(final @Nonnull VMLaunchOptions withLaunchOptions) { return launchPool.submit(new Callable<String>() { @Override public String call() throws Exception { return launch(withLaunchOptions).getProviderVirtualMachineId(); } }); } // the default implementation does parallel launches and throws an exception only if it is unable to launch any virtual machines @Override public @Nonnull Iterable<String> launchMany(final @Nonnull VMLaunchOptions withLaunchOptions, final @Nonnegative int count) throws CloudException, InternalException { if (count < 1) { throw new InternalException( "Invalid attempt to launch less than 1 virtual machine (requested " + count + ")."); } if (count == 1) { return Collections.singleton(launch(withLaunchOptions).getProviderVirtualMachineId()); } final List<Future<String>> results = new ArrayList<Future<String>>(); MachineImage image = null; ComputeServices services = getProvider().getComputeServices(); if (services != null) { MachineImageSupport support = services.getImageSupport(); if (support != null) { image = support.getImage(withLaunchOptions.getMachineImageId()); } } NamingConstraints c = NamingConstraints.getHostNameInstance(image == null || image.getPlatform().equals(Platform.UNKNOWN) || image.getPlatform().equals(Platform.WINDOWS)); String baseHost = c.convertToValidName(withLaunchOptions.getHostName(), Locale.US); if (baseHost == null) { baseHost = withLaunchOptions.getHostName(); } for (int i = 1; i <= count; i++) { String hostName = c.incrementName(baseHost, i); String friendlyName = withLaunchOptions.getFriendlyName() + "-" + i; VMLaunchOptions options = withLaunchOptions .copy(hostName == null ? withLaunchOptions.getHostName() + "-" + i : hostName, friendlyName); results.add(launchAsync(options)); } PopulatorThread<String> populator = new PopulatorThread<String>(new JiteratorPopulator<String>() { @Override public void populate(@Nonnull Jiterator<String> iterator) throws Exception { List<Future<String>> original = results; List<Future<String>> copy = new ArrayList<Future<String>>(); Exception exception = null; boolean loaded = false; while (!original.isEmpty()) { for (Future<String> result : original) { if (result.isDone()) { try { iterator.push(result.get()); loaded = true; } catch (Exception e) { exception = e; } } else { copy.add(result); } } original = copy; // copy has to be a new list else we'll get into concurrently modified list state copy = new ArrayList<Future<String>>(); } if (exception != null && !loaded) { throw exception; } } }); populator.populate(); return populator.getResult(); } @Override @Deprecated public @Nonnull VirtualMachine launch(@Nonnull String fromMachineImageId, @Nonnull VirtualMachineProduct product, @Nonnull String dataCenterId, @Nonnull String name, @Nonnull String description, @Nullable String withKeypairId, @Nullable String inVlanId, boolean withAnalytics, boolean asSandbox, @Nullable String... firewallIds) throws InternalException, CloudException { VMLaunchOptions options = VMLaunchOptions.getInstance(product.getProviderProductId(), fromMachineImageId, name, name, description); options.inDataCenter(dataCenterId); if (withKeypairId != null) { options.withBootstrapKey(withKeypairId); } if (inVlanId != null) { options.inVlan(null, dataCenterId, inVlanId); } if (withAnalytics) { options.withExtendedAnalytics(); } if (firewallIds != null) { options.behindFirewalls(firewallIds); } return launch(options); } @Override @Deprecated public @Nonnull VirtualMachine launch(@Nonnull String fromMachineImageId, @Nonnull VirtualMachineProduct product, @Nonnull String dataCenterId, @Nonnull String name, @Nonnull String description, @Nullable String withKeypairId, @Nullable String inVlanId, boolean withAnalytics, boolean asSandbox, @Nullable String[] firewallIds, @Nullable Tag... tags) throws InternalException, CloudException { VMLaunchOptions options = VMLaunchOptions.getInstance(product.getProviderProductId(), fromMachineImageId, name, name, description); options.inDataCenter(dataCenterId); if (withKeypairId != null) { options.withBootstrapKey(withKeypairId); } if (inVlanId != null) { options.inVlan(null, dataCenterId, inVlanId); } if (withAnalytics) { options.withExtendedAnalytics(); } if (firewallIds != null) { options.behindFirewalls(firewallIds); } if (tags != null) { Map<String, Object> metaData = new HashMap<String, Object>(); for (Tag tag : tags) { metaData.put(tag.getKey(), tag.getValue()); } options.withMetaData(metaData); } return launch(options); } @Override public @Nonnull Iterable<String> listFirewalls(@Nonnull String vmId) throws InternalException, CloudException { return Collections.emptyList(); } /** * <p> * Identifies a resource file that potentially contains VM product definitions for one or more clouds and/or * a default set of products. This helps this abstract base class implement some default configuration file * based behaviors for clouds that do not provide mechanisms for looking up VM products such as AWS or clouds * that don't have a concept of products like vCloud. If your cloud provides product lookups (like OpenStack), * then you can happily ignore this method and override {@link #listProducts(Architecture)} to do the proper * lookup. * </p> * <p> * The best way to take advantage of this feature is simply to create a resource file, place it in the application * CLASSPATH, and then set the {@link ProviderContext#getCustomProperties()} so it has a "vmproducts" * property that points to the resource file to use for that specific cloud connection. * </p> * <p> * The format of the resource file is as follows: * <p/> * </p> * <pre> * [ * { * "provider":"default", * "cloud":"default", * "products":[ * { * "architectures":["I32", "I64"], * "id":"t1.micro", * "name":"Micro Instance (t1.micro)", * "description":"Micro Instance (t1.micro)", * "cpuCount":1, * "rootVolumeSizeInGb":1, * "ramSizeInMb":512 * }, * } * ] * </pre> * <p> * The core element is a list of cloud/product definitions. Each cloud has a "provider", "cloud", * and "products" attribute. The provider is either "default" or a match to the value for * {@link ProviderContext#getProviderName()}. The cloud is similarly either "default" or a match to the * value for {@link ProviderContext#getCloudName()}. The implementation of {@link #listProducts(Architecture)} * in this base class will attempt to match the cloud name and provider name or look for a default. * </p> * <p> * Here's what happens in practice: * </p> * <p> * If your implementation has over-ridden {@link #listProducts(Architecture)}, then that logic prevails and * all of this is ignored (for that cloud implementation). * </p> * <p> * If your implementation is under the package something.whatever.<b>cloudname</b> (the important part is the last part * of the package name) and you have not specified ANY kind of properties, the default {@link #listProducts(Architecture)} * will look for a vmproducts.json file as the resource org.dasein.cloud.<b>cloudname</b>.vmproducts.json. If it exists, * it will be used. * </p> * <p> * If you specify a custom property with your connection called "vmproducts", then the * default {@link #listProducts(Architecture)} method will look for a resource matching the value specified * in that property. * </p> * <p> * If no custom property is set, but there is a system property (@{@link System#getProperties()}) called * "dasein.vmproducts.<b>cloudname</b>" and look for a resource matching the value specified in that * property. * </p> * <p> * If you do absolutely nothing (or if the property file specified above doesn't actually exist), * Dasein Cloud will load the default vmproducts.json packages with dasein-cloud-core under * the resource org.dasein.cloud.std.vmproducts.json. * </p> * * @return a resource file location with a vmproducts JSON definition * @throws CloudException no context has been set for loading the products */ protected @Nonnull String getVMProductsResource() throws CloudException { Properties p = getContext().getCustomProperties(); String value = null; if (p != null) { value = p.getProperty("vmproducts"); } if (value == null) { String[] parts = getProvider().getClass().getPackage().getName().split("\\."); String impl; if (parts.length < 1) { impl = getProvider().getClass().getPackage().getName(); } else { impl = parts[parts.length - 1]; } value = System.getProperty("dasein.vmproducts." + impl); if (value == null) { value = "/org/dasein/cloud/" + impl + "/vmproducts.json"; } } return value; } @Override public @Nonnull Iterable<VirtualMachineProduct> listProducts(@Nonnull String machineImageId) throws InternalException, CloudException { return listProducts(VirtualMachineProductFilterOptions.getInstance()); } @Override final public Iterable<VirtualMachineProduct> listProducts(@Nonnull VirtualMachineProductFilterOptions options) throws InternalException, CloudException { List<VirtualMachineProduct> products = new ArrayList<VirtualMachineProduct>(); for (Architecture arch : getCapabilities().listSupportedArchitectures()) { mergeProductLists(products, this.listProducts(options, arch)); } return products; } /** * Merge product iterable into the list, using providerProductId as a unique key * @param to * the target list * @param from * the source iterable */ private void mergeProductLists(List<VirtualMachineProduct> to, Iterable<VirtualMachineProduct> from) { List<VirtualMachineProduct> copy = new ArrayList<VirtualMachineProduct>(to); for (VirtualMachineProduct productFrom : from) { boolean found = false; for (VirtualMachineProduct productTo : copy) { if (productTo.getProviderProductId().equalsIgnoreCase(productFrom.getProviderProductId())) { found = true; break; } } if (!found) { to.add(productFrom); } } } @Override final public @Nonnull Iterable<VirtualMachineProduct> listProducts(@Nonnull Architecture architecture) throws InternalException, CloudException { return this.listProducts(null, architecture); } @Override public @Nonnull Iterable<VirtualMachineProduct> listProducts( @Nonnull VirtualMachineProductFilterOptions options, @Nullable Architecture architecture) throws InternalException, CloudException { APITrace.begin(getProvider(), "VM.listProducts"); try { String cacheName = "productsALL"; if (architecture != null) { cacheName = "products" + architecture.name(); } Cache<VirtualMachineProduct> cache = Cache.getInstance(getProvider(), cacheName, VirtualMachineProduct.class, CacheLevel.REGION_ACCOUNT, new TimePeriod<Day>(1, TimePeriod.DAY)); Iterable<VirtualMachineProduct> products = cache.get(getContext()); if (products != null) { return products; } List<VirtualMachineProduct> list = new ArrayList<VirtualMachineProduct>(); try { String resource = getVMProductsResource(); InputStream input = AbstractVMSupport.class.getResourceAsStream(resource); if (input == null) { input = AbstractVMSupport.class.getResourceAsStream("/org/dasein/cloud/std/vmproducts.json"); } if (input == null) { return Collections.emptyList(); } BufferedReader reader = new BufferedReader(new InputStreamReader(input)); StringBuilder json = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { json.append(line); json.append("\n"); } JSONArray arr = new JSONArray(json.toString()); JSONObject toCache = null; for (int i = 0; i < arr.length(); i++) { JSONObject productSet = arr.getJSONObject(i); String cloud, provider; if (productSet.has("cloud")) { cloud = productSet.getString("cloud"); } else { continue; } if (productSet.has("provider")) { provider = productSet.getString("provider"); } else { continue; } if (!productSet.has("products")) { continue; } if (toCache == null || (provider.equals("default") && cloud.equals("default"))) { toCache = productSet; } if (provider.equalsIgnoreCase(getProvider().getProviderName()) && cloud.equalsIgnoreCase(getProvider().getCloudName())) { toCache = productSet; break; } } if (toCache == null) { return Collections.emptyList(); } JSONArray plist = toCache.getJSONArray("products"); for (int i = 0; i < plist.length(); i++) { JSONObject product = plist.getJSONObject(i); boolean supported = false; // If architecture is specified, check if product matches if (architecture != null && product.has("architectures")) { JSONArray architectures = product.getJSONArray("architectures"); for (int j = 0; j < architectures.length(); j++) { String a = architectures.getString(j); if (architecture.name().equals(a)) { supported = true; break; } } if (!supported) { continue; } } else { // No architecture specified, flip the flag - all architectures allowed supported = true; } if (product.has("excludesRegions")) { JSONArray regions = product.getJSONArray("excludesRegions"); for (int j = 0; j < regions.length(); j++) { String r = regions.getString(j); if (r.equals(getContext().getRegionId())) { supported = false; break; } } } if (!supported) { continue; } VirtualMachineProduct prd = toProduct(product); if (prd != null) { if (options != null) { // Filter supplied, add matches only. if (options.matches(prd)) { list.add(prd); } } else { // No filter supplied, add all survived. list.add(prd); } } } cache.put(getContext(), list); } catch (IOException e) { throw new InternalException(e); } catch (JSONException e) { throw new InternalException(e); } return list; } finally { APITrace.end(); } } @Override public Iterable<SpotPriceHistory> listSpotPriceHistories(SpotPriceHistoryFilterOptions options) throws CloudException, InternalException { throw new OperationNotSupportedException( "Spot Instances are not supported for " + getProvider().getCloudName()); } @Override @Deprecated public Iterable<Architecture> listSupportedArchitectures() throws InternalException, CloudException { return getCapabilities().listSupportedArchitectures(); /* Cache<Architecture> cache = Cache.getInstance(getProvider(), "architectures", Architecture.class, CacheLevel.REGION_ACCOUNT, new TimePeriod<Week>(1, TimePeriod.WEEK)); Iterable<Architecture> architectures = cache.get(getContext()); if( architectures == null ) { ArrayList<Architecture> list = new ArrayList<Architecture>(); Collections.addAll(list, Architecture.values()); architectures = list; cache.put(getContext(), architectures); } return architectures; */ } @Override public @Nonnull Iterable<ResourceStatus> listVirtualMachineStatus() throws InternalException, CloudException { List<ResourceStatus> status = new ArrayList<ResourceStatus>(); for (VirtualMachine vm : listVirtualMachines()) { status.add(new ResourceStatus(vm.getProviderVirtualMachineId(), vm.getCurrentState())); } return status; } @Override public @Nonnull Iterable<VirtualMachine> listVirtualMachines() throws InternalException, CloudException { return Collections.<VirtualMachine>emptyList(); } @Override public @Nonnull Iterable<VirtualMachine> listVirtualMachines(@Nullable VMFilterOptions options) throws InternalException, CloudException { if (options == null) { return listVirtualMachines(); } List<VirtualMachine> vms = new ArrayList<VirtualMachine>(); for (VirtualMachine vm : listVirtualMachines()) { if (options.matches(vm)) { vms.add(vm); } } return vms; } @Override public void pause(@Nonnull String vmId) throws InternalException, CloudException { throw new OperationNotSupportedException( "Pause/unpause is not currently implemented for " + getProvider().getCloudName()); } @Override public void reboot(@Nonnull String vmId) throws CloudException, InternalException { VirtualMachine vm = getVirtualMachine(vmId); if (vm == null) { throw new CloudException("No such virtual machine: " + vmId); } stop(vmId); long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 5L); while (timeout > System.currentTimeMillis()) { try { vm = getVirtualMachine(vmId); } catch (Throwable ignore) { } if (vm == null) { return; } if (vm.getCurrentState().equals(VmState.STOPPED)) { start(vmId); return; } } } @Override public void resume(@Nonnull String vmId) throws CloudException, InternalException { throw new OperationNotSupportedException( "Resume/suspend is not currently implemented for " + getProvider().getCloudName()); } @Override public void start(@Nonnull String vmId) throws InternalException, CloudException { throw new OperationNotSupportedException( "Start/stop is not currently implemented for " + getProvider().getCloudName()); } @Override public final void stop(@Nonnull String vmId) throws InternalException, CloudException { stop(vmId, false); long timeout = System.currentTimeMillis() + (CalendarWrapper.MINUTE * 5L); while (timeout > System.currentTimeMillis()) { try { Thread.sleep(10000L); } catch (InterruptedException ignore) { } try { VirtualMachine vm = getVirtualMachine(vmId); if (vm == null || VmState.TERMINATED.equals(vm.getCurrentState()) || VmState.STOPPED.equals(vm.getCurrentState())) { return; } } catch (Throwable ignore) { // ignore } } stop(vmId, true); } @Override public void stop(@Nonnull String vmId, boolean force) throws InternalException, CloudException { throw new OperationNotSupportedException( "Start/stop is not currently implemented for " + getProvider().getCloudName()); } @Override @Deprecated public final boolean supportsAnalytics() throws CloudException, InternalException { return (getCapabilities().isBasicAnalyticsSupported() || getCapabilities().isExtendedAnalyticsSupported()); } @Override @Deprecated public boolean supportsPauseUnpause(@Nonnull VirtualMachine vm) { try { VirtualMachineCapabilities c = getCapabilities(); VmState s = vm.getCurrentState(); return (c.canPause(s) || c.canUnpause(s)); } catch (Exception ignore) { return false; } } @Override @Deprecated public boolean supportsStartStop(@Nonnull VirtualMachine vm) { try { VirtualMachineCapabilities c = getCapabilities(); VmState s = vm.getCurrentState(); return (c.canStart(s) || c.canStop(s)); } catch (Exception ignore) { return false; } } @Override @Deprecated public boolean supportsSuspendResume(@Nonnull VirtualMachine vm) { try { VirtualMachineCapabilities c = getCapabilities(); VmState s = vm.getCurrentState(); return (c.canSuspend(s) || c.canResume(s)); } catch (Exception ignore) { return false; } } @Override public void suspend(@Nonnull String vmId) throws CloudException, InternalException { throw new OperationNotSupportedException( "Resume/suspend is not currently implemented for " + getProvider().getCloudName()); } @Override public void terminate(@Nonnull String vmId) throws CloudException, InternalException { terminate(vmId, null); } @Override public void unpause(@Nonnull String vmId) throws CloudException, InternalException { throw new OperationNotSupportedException( "Pause/unpause is not currently implemented for " + getProvider().getCloudName()); } @Override public void updateTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException { // NO-OP } @Override public void updateTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException { for (String id : vmIds) { updateTags(id, tags); } } @Override public void removeTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException { // NO-OP } @Override public void removeTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException { for (String id : vmIds) { removeTags(id, tags); } } @Override public void setTags(@Nonnull String vmId, @Nonnull Tag... tags) throws CloudException, InternalException { setTags(new String[] { vmId }, tags); } @Override public void setTags(@Nonnull String[] vmIds, @Nonnull Tag... tags) throws CloudException, InternalException { for (String id : vmIds) { Tag[] collectionForDelete = TagUtils.getTagsForDelete(getVirtualMachine(id).getTags(), tags); if (collectionForDelete.length != 0) { removeTags(id, collectionForDelete); } updateTags(id, tags); } } @Override public @Nonnull String[] mapServiceAction(@Nonnull ServiceAction action) { return new String[0]; } private @Nullable VirtualMachineProduct toProduct(@Nonnull JSONObject json) throws InternalException { VirtualMachineProduct prd = new VirtualMachineProduct(); try { if (json.has("id")) { prd.setProviderProductId(json.getString("id")); } else { return null; } if (json.has("name")) { prd.setName(json.getString("name")); } else { prd.setName(prd.getProviderProductId()); } if (json.has("description")) { prd.setDescription(json.getString("description")); } else { prd.setDescription(prd.getName()); } if (json.has("cpuCount")) { prd.setCpuCount(json.getInt("cpuCount")); } else { prd.setCpuCount(1); } if (json.has("rootVolumeSizeInGb")) { prd.setRootVolumeSize(new Storage<Gigabyte>(json.getInt("rootVolumeSizeInGb"), Storage.GIGABYTE)); } else { prd.setRootVolumeSize(new Storage<Gigabyte>(1, Storage.GIGABYTE)); } if (json.has("ramSizeInMb")) { prd.setRamSize(new Storage<Megabyte>(json.getInt("ramSizeInMb"), Storage.MEGABYTE)); } else { prd.setRamSize(new Storage<Megabyte>(512, Storage.MEGABYTE)); } if (json.has("standardHourlyRates")) { JSONArray rates = json.getJSONArray("standardHourlyRates"); for (int i = 0; i < rates.length(); i++) { JSONObject rate = rates.getJSONObject(i); if (rate.has("rate")) { prd.setStandardHourlyRate((float) rate.getDouble("rate")); } } } } catch (JSONException e) { throw new InternalException(e); } return prd; } @Override public @Nullable Iterable<VirtualMachineStatus> getVMStatus(@Nullable String... vmIds) throws InternalException, CloudException { throw new OperationNotSupportedException( "Virtual Machine Status is not currently implemented for " + getProvider().getCloudName()); } @Override public @Nullable Iterable<VirtualMachineStatus> getVMStatus(@Nullable VmStatusFilterOptions filterOptions) throws InternalException, CloudException { throw new OperationNotSupportedException( "Virtual Machine Status is not currently implemented for " + getProvider().getCloudName()); } }