mirror of https://github.com/apache/jclouds.git
implemented image extension
This commit is contained in:
parent
a238d63578
commit
05212b75fa
|
@ -25,8 +25,8 @@ import static org.jclouds.compute.config.ComputeServiceProperties.RESOURCENAME_D
|
||||||
import static org.jclouds.util.Preconditions2.checkNotEmpty;
|
import static org.jclouds.util.Preconditions2.checkNotEmpty;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
@ -39,6 +39,7 @@ import org.jclouds.Constants;
|
||||||
import org.jclouds.aws.util.AWSUtils;
|
import org.jclouds.aws.util.AWSUtils;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
|
@ -69,12 +70,13 @@ import org.jclouds.scriptbuilder.functions.InitAdminAccess;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.ImmutableMultimap.Builder;
|
import com.google.common.collect.ImmutableMultimap.Builder;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,12 +103,13 @@ public class EC2ComputeService extends BaseComputeService {
|
||||||
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
||||||
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
|
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, EC2Client ec2Client,
|
||||||
ConcurrentMap<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap) {
|
ConcurrentMap<RegionAndName, KeyPair> credentialsMap, @Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
|
||||||
|
Optional<ImageExtension> imageExtension) {
|
||||||
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
|
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
|
||||||
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
|
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
|
||||||
initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
|
initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
|
||||||
executor);
|
executor, imageExtension);
|
||||||
this.ec2Client = ec2Client;
|
this.ec2Client = ec2Client;
|
||||||
this.credentialsMap = credentialsMap;
|
this.credentialsMap = credentialsMap;
|
||||||
this.securityGroupMap = securityGroupMap;
|
this.securityGroupMap = securityGroupMap;
|
||||||
|
|
|
@ -33,6 +33,7 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.Constants;
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
|
@ -103,12 +104,12 @@ public class NovaComputeService extends BaseComputeService {
|
||||||
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
|
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
|
||||||
LoadingCache<ZoneAndName, KeyPair> keyPairCache,
|
LoadingCache<ZoneAndName, KeyPair> keyPairCache,
|
||||||
Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId,
|
Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId,
|
||||||
GroupNamingConvention.Factory namingConvention) {
|
GroupNamingConvention.Factory namingConvention, Optional<ImageExtension> imageExtension) {
|
||||||
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy, stopNodeStrategy,
|
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
|
||||||
templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated, nodeSuspended,
|
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
||||||
initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
|
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
|
||||||
executor);
|
timeouts, executor, imageExtension);
|
||||||
this.novaClient = checkNotNull(novaClient, "novaClient");
|
this.novaClient = checkNotNull(novaClient, "novaClient");
|
||||||
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
|
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
|
||||||
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
|
this.keyPairCache = checkNotNull(keyPairCache, "keyPairCache");
|
||||||
|
@ -134,7 +135,7 @@ public class NovaComputeService extends BaseComputeService {
|
||||||
if (securityGroupClient.isPresent()) {
|
if (securityGroupClient.isPresent()) {
|
||||||
for (String group : groups) {
|
for (String group : groups) {
|
||||||
for (SecurityGroup securityGroup : Iterables.filter(securityGroupClient.get().listSecurityGroups(),
|
for (SecurityGroup securityGroup : Iterables.filter(securityGroupClient.get().listSecurityGroups(),
|
||||||
SecurityGroupPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
|
SecurityGroupPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
|
||||||
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, securityGroup.getName());
|
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, securityGroup.getName());
|
||||||
logger.debug(">> deleting securityGroup(%s)", zoneAndName);
|
logger.debug(">> deleting securityGroup(%s)", zoneAndName);
|
||||||
securityGroupClient.get().deleteSecurityGroup(securityGroup.getId());
|
securityGroupClient.get().deleteSecurityGroup(securityGroup.getId());
|
||||||
|
@ -152,7 +153,7 @@ public class NovaComputeService extends BaseComputeService {
|
||||||
for (String group : groups) {
|
for (String group : groups) {
|
||||||
for (Map<String, KeyPair> wrapper : keyPairClient.get().listKeyPairs()) {
|
for (Map<String, KeyPair> wrapper : keyPairClient.get().listKeyPairs()) {
|
||||||
for (KeyPair pair : Iterables.filter(wrapper.values(),
|
for (KeyPair pair : Iterables.filter(wrapper.values(),
|
||||||
KeyPairPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
|
KeyPairPredicates.nameMatches(namingConvention.create().containsGroup(group)))) {
|
||||||
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName());
|
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, pair.getName());
|
||||||
logger.debug(">> deleting keypair(%s)", zoneAndName);
|
logger.debug(">> deleting keypair(%s)", zoneAndName);
|
||||||
keyPairClient.get().deleteKeyPair(pair.getName());
|
keyPairClient.get().deleteKeyPair(pair.getName());
|
||||||
|
@ -162,7 +163,7 @@ public class NovaComputeService extends BaseComputeService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyPairCache.invalidate(ZoneAndName.fromZoneAndName(zoneId,
|
keyPairCache.invalidate(ZoneAndName.fromZoneAndName(zoneId,
|
||||||
namingConvention.create().sharedNameForGroup(group)));
|
namingConvention.create().sharedNameForGroup(group)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -174,5 +175,7 @@ public class NovaComputeService extends BaseComputeService {
|
||||||
public NovaTemplateOptions templateOptions() {
|
public NovaTemplateOptions templateOptions() {
|
||||||
return NovaTemplateOptions.class.cast(super.templateOptions());
|
return NovaTemplateOptions.class.cast(super.templateOptions());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.openstack.nova.v1_1.compute;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
|
import org.jclouds.compute.domain.CloneImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.Image;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplateBuilder;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class NovaImageExtension implements ImageExtension {
|
||||||
|
|
||||||
|
private final NovaClient novaClient;
|
||||||
|
private final Function<ImageInZone, Image> imageInZoneToImage;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public NovaImageExtension(NovaClient novaClient, Function<ImageInZone, Image> imageInZoneToImage) {
|
||||||
|
this.novaClient = checkNotNull(novaClient);
|
||||||
|
this.imageInZoneToImage = imageInZoneToImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
|
||||||
|
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
|
||||||
|
Server server = novaClient.getServerClientForZone(zoneAndId.getZone()).getServer(zoneAndId.getId());
|
||||||
|
if (server == null)
|
||||||
|
throw new NoSuchElementException("Cannot find server with id: " + zoneAndId);
|
||||||
|
CloneImageTemplate template = new ImageTemplateBuilder.CloneImageTemplateBuilder().nodeId(id).name(name).build();
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Image createImage(ImageTemplate template) {
|
||||||
|
checkState(template instanceof CloneImageTemplate,
|
||||||
|
" openstack-nova only supports creating images through cloning.");
|
||||||
|
CloneImageTemplate cloneTemplate = (CloneImageTemplate) template;
|
||||||
|
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(cloneTemplate.getSourceNodeId());
|
||||||
|
String newImageId = novaClient.getServerClientForZone(zoneAndId.getZone()).createImageFromServer(
|
||||||
|
cloneTemplate.getName(), zoneAndId.getId());
|
||||||
|
org.jclouds.openstack.nova.v1_1.domain.Image newImage = checkNotNull(findImage(ZoneAndId.fromZoneAndId(
|
||||||
|
zoneAndId.getZone(), newImageId)));
|
||||||
|
return imageInZoneToImage.apply(new ImageInZone(newImage, zoneAndId.getZone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteImage(String id) {
|
||||||
|
ZoneAndId zoneAndId = ZoneAndId.fromSlashEncoded(id);
|
||||||
|
try {
|
||||||
|
this.novaClient.getImageClientForZone(zoneAndId.getZone()).deleteImage(zoneAndId.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private org.jclouds.openstack.nova.v1_1.domain.Image findImage(final ZoneAndId zoneAndId) {
|
||||||
|
return Iterables.tryFind(novaClient.getImageClientForZone(zoneAndId.getZone()).listImagesInDetail(),
|
||||||
|
new Predicate<org.jclouds.openstack.nova.v1_1.domain.Image>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(org.jclouds.openstack.nova.v1_1.domain.Image input) {
|
||||||
|
return input.getId().equals(zoneAndId.getId());
|
||||||
|
}
|
||||||
|
}).orNull();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeService;
|
import org.jclouds.compute.ComputeService;
|
||||||
import org.jclouds.compute.ComputeServiceAdapter;
|
import org.jclouds.compute.ComputeServiceAdapter;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
|
@ -46,6 +47,7 @@ import org.jclouds.domain.LoginCredentials;
|
||||||
import org.jclouds.functions.IdentityFunction;
|
import org.jclouds.functions.IdentityFunction;
|
||||||
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeService;
|
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeService;
|
||||||
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
|
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
|
||||||
|
import org.jclouds.openstack.nova.v1_1.compute.NovaImageExtension;
|
||||||
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded;
|
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded;
|
||||||
import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware;
|
import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorInZoneToHardware;
|
||||||
import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage;
|
import org.jclouds.openstack.nova.v1_1.compute.functions.ImageInZoneToImage;
|
||||||
|
@ -69,6 +71,7 @@ import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndRe
|
||||||
import org.jclouds.predicates.RetryablePredicate;
|
import org.jclouds.predicates.RetryablePredicate;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
|
@ -135,6 +138,9 @@ public class NovaComputeServiceContextModule extends
|
||||||
|
|
||||||
bind(new TypeLiteral<CacheLoader<ZoneAndName, KeyPair>>() {
|
bind(new TypeLiteral<CacheLoader<ZoneAndName, KeyPair>>() {
|
||||||
}).to(CreateUniqueKeyPair.class);
|
}).to(CreateUniqueKeyPair.class);
|
||||||
|
|
||||||
|
bind(new TypeLiteral<ImageExtension>() {
|
||||||
|
}).to(NovaImageExtension.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -206,4 +212,9 @@ public class NovaComputeServiceContextModule extends
|
||||||
}, locations);
|
}, locations);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||||
|
return Optional.of(i.getInstance(ImageExtension.class));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -31,6 +31,7 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.Constants;
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
|
@ -54,6 +55,7 @@ import org.jclouds.scriptbuilder.functions.InitAdminAccess;
|
||||||
import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions;
|
import org.jclouds.trmk.vcloud_0_8.compute.options.TerremarkVCloudTemplateOptions;
|
||||||
import org.jclouds.trmk.vcloud_0_8.compute.strategy.CleanupOrphanKeys;
|
import org.jclouds.trmk.vcloud_0_8.compute.strategy.CleanupOrphanKeys;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
|
|
||||||
|
@ -78,12 +80,13 @@ public class TerremarkVCloudComputeService extends BaseComputeService {
|
||||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
|
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
|
||||||
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
|
||||||
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys) {
|
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, CleanupOrphanKeys cleanupOrphanKeys,
|
||||||
|
Optional<ImageExtension> imageExtension) {
|
||||||
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
|
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
|
||||||
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
||||||
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
|
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
|
||||||
timeouts, executor);
|
timeouts, executor, imageExtension);
|
||||||
this.cleanupOrphanKeys = cleanupOrphanKeys;
|
this.cleanupOrphanKeys = cleanupOrphanKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import org.jclouds.domain.Location;
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
|
|
||||||
import com.google.common.annotations.Beta;
|
import com.google.common.annotations.Beta;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.inject.ImplementedBy;
|
import com.google.inject.ImplementedBy;
|
||||||
|
@ -345,5 +346,14 @@ public interface ComputeService {
|
||||||
* @see #runScriptOnNode(String, String, RunScriptOptions)
|
* @see #runScriptOnNode(String, String, RunScriptOptions)
|
||||||
*/
|
*/
|
||||||
ExecResponse runScriptOnNode(String id, String runScript);
|
ExecResponse runScriptOnNode(String id, String runScript);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link ImageExtension} for this provider if it implements it.
|
||||||
|
*
|
||||||
|
* @return an optional of the {@link ImageExtension} or {@link Optional#absent()} if not
|
||||||
|
* implemented
|
||||||
|
*/
|
||||||
|
@Beta
|
||||||
|
Optional<ImageExtension> getImageExtension();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.compute;
|
||||||
|
|
||||||
|
import org.jclouds.compute.domain.Image;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An extension to compute service to allow for the manipulation of {@link Image}s. Implementation
|
||||||
|
* is optional by providers.
|
||||||
|
*
|
||||||
|
* @author David Alves
|
||||||
|
*/
|
||||||
|
public interface ImageExtension {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build an ImageTemplate from a running node, to use later to create a new {@link Image}.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* name to give the new image
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* node to base the template on
|
||||||
|
* @return an image template that can be used to create a new image
|
||||||
|
*/
|
||||||
|
ImageTemplate buildImageTemplateFromNode(String name, String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transform the {@link ImageTemplate} on an {@link Image} that can be used to create nodes.
|
||||||
|
*
|
||||||
|
* @param template
|
||||||
|
* template to base the new image on
|
||||||
|
* @return the image that was just built *after* it is registered on the provider
|
||||||
|
*/
|
||||||
|
Image createImage(ImageTemplate template);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an {@link Image} on the provider.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* the id of the image to delete
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean deleteImage(String id);
|
||||||
|
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput;
|
import org.jclouds.compute.callables.BlockUntilInitScriptStatusIsZeroThenReturnOutput;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh;
|
import org.jclouds.compute.callables.RunScriptOnNodeAsInitScriptUsingSsh;
|
||||||
|
@ -61,6 +62,7 @@ import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
import org.jclouds.ssh.SshClient;
|
import org.jclouds.ssh.SshClient;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -299,5 +301,12 @@ public abstract class BaseComputeServiceContextModule extends AbstractModule {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
protected Optional<ImageExtension> provideImageExtension(Injector i){
|
||||||
|
return Optional.absent();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.compute.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link ImageTemplate} for the purpose of cloning an existing node.
|
||||||
|
*
|
||||||
|
* @author David Alves
|
||||||
|
*/
|
||||||
|
public interface CloneImageTemplate extends ImageTemplate {
|
||||||
|
|
||||||
|
public String getSourceNodeId();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.compute.domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A template for building new {@link Image}s.
|
||||||
|
*
|
||||||
|
* @author David Alves
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ImageTemplate {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name of the new image
|
||||||
|
*/
|
||||||
|
public String getName();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.compute.domain;
|
||||||
|
|
||||||
|
import org.jclouds.compute.domain.internal.ImageTemplateImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder for {@link ImageTemplate}s. Includes sub-builders to build specific
|
||||||
|
* {@link ImageTemplate}s for different purposes, such as cloning, creating from iso, creating from
|
||||||
|
* netboot.
|
||||||
|
*
|
||||||
|
* @author David Alves
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class ImageTemplateBuilder {
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
|
private ImageTemplateBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageTemplateBuilder name(String name) {
|
||||||
|
this.name = name;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CloneImageTemplateBuilder extends ImageTemplateBuilder {
|
||||||
|
|
||||||
|
String nodeId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CloneImageTemplateBuilder name(String name) {
|
||||||
|
return CloneImageTemplateBuilder.class.cast(super.name(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public CloneImageTemplateBuilder nodeId(String nodeId) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CloneImageTemplate build() {
|
||||||
|
return new ImageTemplateImpl.CloneImageTemplateImpl(name, nodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.compute.domain.internal;
|
||||||
|
|
||||||
|
import org.jclouds.compute.domain.CloneImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplate;
|
||||||
|
|
||||||
|
public abstract class ImageTemplateImpl implements ImageTemplate {
|
||||||
|
|
||||||
|
protected final String name;
|
||||||
|
|
||||||
|
public ImageTemplateImpl(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CloneImageTemplateImpl extends ImageTemplateImpl implements CloneImageTemplate {
|
||||||
|
|
||||||
|
protected final String sourceNodeId;
|
||||||
|
|
||||||
|
public CloneImageTemplateImpl(String name, String sourceNodeId) {
|
||||||
|
super(name);
|
||||||
|
this.sourceNodeId = sourceNodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSourceNodeId() {
|
||||||
|
return this.sourceNodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -51,6 +51,7 @@ import org.jclouds.Constants;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeService;
|
import org.jclouds.compute.ComputeService;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.RunNodesException;
|
import org.jclouds.compute.RunNodesException;
|
||||||
import org.jclouds.compute.RunScriptOnNodesException;
|
import org.jclouds.compute.RunScriptOnNodesException;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
|
@ -90,6 +91,7 @@ import org.jclouds.scriptbuilder.functions.InitAdminAccess;
|
||||||
import org.jclouds.util.Maps2;
|
import org.jclouds.util.Maps2;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -134,6 +136,7 @@ public class BaseComputeService implements ComputeService {
|
||||||
private final PersistNodeCredentials persistNodeCredentials;
|
private final PersistNodeCredentials persistNodeCredentials;
|
||||||
private final RunScriptOnNode.Factory runScriptOnNodeFactory;
|
private final RunScriptOnNode.Factory runScriptOnNodeFactory;
|
||||||
private final ExecutorService executor;
|
private final ExecutorService executor;
|
||||||
|
private final Optional<ImageExtension> imageExtension;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
|
protected BaseComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
|
||||||
|
@ -148,7 +151,8 @@ public class BaseComputeService implements ComputeService {
|
||||||
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
|
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
|
||||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
|
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
|
||||||
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
|
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
|
||||||
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
|
||||||
|
Optional<ImageExtension> imageExtension) {
|
||||||
this.context = checkNotNull(context, "context");
|
this.context = checkNotNull(context, "context");
|
||||||
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
|
this.credentialStore = checkNotNull(credentialStore, "credentialStore");
|
||||||
this.images = checkNotNull(images, "images");
|
this.images = checkNotNull(images, "images");
|
||||||
|
@ -172,6 +176,7 @@ public class BaseComputeService implements ComputeService {
|
||||||
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
|
this.runScriptOnNodeFactory = checkNotNull(runScriptOnNodeFactory, "runScriptOnNodeFactory");
|
||||||
this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
|
this.persistNodeCredentials = checkNotNull(persistNodeCredentials, "persistNodeCredentials");
|
||||||
this.executor = checkNotNull(executor, "executor");
|
this.executor = checkNotNull(executor, "executor");
|
||||||
|
this.imageExtension = imageExtension;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -668,5 +673,13 @@ public class BaseComputeService implements ComputeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Optional<ImageExtension> getImageExtension() {
|
||||||
|
return imageExtension;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,134 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.compute.internal;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
import static junit.framework.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.jclouds.compute.ComputeService;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
|
import org.jclouds.compute.RunNodesException;
|
||||||
|
import org.jclouds.compute.domain.ExecResponse;
|
||||||
|
import org.jclouds.compute.domain.Image;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.compute.domain.Template;
|
||||||
|
import org.jclouds.ssh.SshClient;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base test for {@link ImageExtension} implementations.
|
||||||
|
*
|
||||||
|
* @author David Alves
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class BaseImageExtensionLiveTest extends BaseComputeServiceContextLiveTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the template for the base node, override to test different templates.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Template getNodeTemplate() {
|
||||||
|
return context.getComputeService().templateBuilder().any().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(groups = { "integration", "live" }, singleThreaded = true)
|
||||||
|
public void testCreateImage() throws RunNodesException, InterruptedException {
|
||||||
|
|
||||||
|
ComputeService computeService = context.getComputeService();
|
||||||
|
|
||||||
|
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
|
||||||
|
assertTrue("image extension was not present", imageExtension.isPresent());
|
||||||
|
|
||||||
|
Set<? extends Image> imagesBefore = computeService.listImages();
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1,
|
||||||
|
getNodeTemplate()));
|
||||||
|
|
||||||
|
ImageTemplate newImageTemplate = imageExtension.get().buildImageTemplateFromNode("test-create-image",
|
||||||
|
node.getId());
|
||||||
|
|
||||||
|
Image image = imageExtension.get().createImage(newImageTemplate);
|
||||||
|
|
||||||
|
assertEquals("test-create-image", image.getName());
|
||||||
|
|
||||||
|
computeService.destroyNode(node.getId());
|
||||||
|
|
||||||
|
Set<? extends Image> imagesAfter = computeService.listImages();
|
||||||
|
|
||||||
|
assertTrue(imagesBefore.size() == imagesAfter.size() - 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = "testCreateImage")
|
||||||
|
public void testSpawnNodeFromImage() throws RunNodesException {
|
||||||
|
|
||||||
|
ComputeService computeService = context.getComputeService();
|
||||||
|
|
||||||
|
Template template = computeService.templateBuilder().fromImage(getImage().get()).build();
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(computeService.createNodesInGroup("test-create-image", 1, template));
|
||||||
|
|
||||||
|
SshClient client = context.utils().sshForNode().apply(node);
|
||||||
|
client.connect();
|
||||||
|
|
||||||
|
ExecResponse hello = client.exec("echo hello");
|
||||||
|
|
||||||
|
assertEquals(hello.getOutput().trim(), "hello");
|
||||||
|
|
||||||
|
context.getComputeService().destroyNode(node.getId());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(groups = { "integration", "live" }, singleThreaded = true, dependsOnMethods = { "testCreateImage",
|
||||||
|
"testSpawnNodeFromImage" })
|
||||||
|
public void testDeleteImage() {
|
||||||
|
|
||||||
|
ComputeService computeService = context.getComputeService();
|
||||||
|
|
||||||
|
Optional<ImageExtension> imageExtension = computeService.getImageExtension();
|
||||||
|
assertTrue("image extension was not present", imageExtension.isPresent());
|
||||||
|
|
||||||
|
Optional<? extends Image> optImage = getImage();
|
||||||
|
|
||||||
|
assertTrue(optImage.isPresent());
|
||||||
|
|
||||||
|
Image image = optImage.get();
|
||||||
|
|
||||||
|
assertTrue(imageExtension.get().deleteImage(image.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<? extends Image> getImage() {
|
||||||
|
return Iterables.tryFind(context.getComputeService().listImages(), new Predicate<Image>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(Image input) {
|
||||||
|
return input.getId().contains("test-create-image");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -40,7 +40,7 @@
|
||||||
<test.virtualbox.build-version>4.1.8r75467</test.virtualbox.build-version>
|
<test.virtualbox.build-version>4.1.8r75467</test.virtualbox.build-version>
|
||||||
<test.virtualbox.identity>administrator</test.virtualbox.identity>
|
<test.virtualbox.identity>administrator</test.virtualbox.identity>
|
||||||
<test.virtualbox.credential>12345</test.virtualbox.credential>
|
<test.virtualbox.credential>12345</test.virtualbox.credential>
|
||||||
<test.virtualbox.image-id>default-ubuntu-11.04-i386</test.virtualbox.image-id>
|
<test.virtualbox.image-id>test-ubuntu-11.10-i386</test.virtualbox.image-id>
|
||||||
<test.virtualbox.image.login-user>toor:password</test.virtualbox.image.login-user>
|
<test.virtualbox.image.login-user>toor:password</test.virtualbox.image.login-user>
|
||||||
<test.virtualbox.image.authenticate-sudo>true</test.virtualbox.image.authenticate-sudo>
|
<test.virtualbox.image.authenticate-sudo>true</test.virtualbox.image.authenticate-sudo>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
|
@ -27,12 +27,15 @@ import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_
|
||||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
|
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_NODE_PREFIX;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
|
||||||
import org.jclouds.compute.ComputeServiceAdapter;
|
import org.jclouds.compute.ComputeServiceAdapter;
|
||||||
|
import org.jclouds.compute.domain.Hardware;
|
||||||
|
import org.jclouds.compute.domain.HardwareBuilder;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
import org.jclouds.compute.domain.Template;
|
import org.jclouds.compute.domain.Template;
|
||||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
|
@ -58,6 +61,7 @@ import com.google.common.base.Throwables;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,25 +71,28 @@ import com.google.inject.Singleton;
|
||||||
* @author Mattias Holmqvist, Andrea Turli, David Alves
|
* @author Mattias Holmqvist, Andrea Turli, David Alves
|
||||||
*/
|
*/
|
||||||
@Singleton
|
@Singleton
|
||||||
public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, IMachine, Image, Location> {
|
public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IMachine, Hardware, Image, Location> {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||||
protected Logger logger = Logger.NULL;
|
protected Logger logger = Logger.NULL;
|
||||||
|
|
||||||
private final Supplier<VirtualBoxManager> manager;
|
private final Supplier<VirtualBoxManager> manager;
|
||||||
private final Map<Image, YamlImage> images;
|
private final Map<Image, YamlImage> imagesToYamlImages;
|
||||||
private final LoadingCache<Image, Master> mastersLoader;
|
private final LoadingCache<Image, Master> mastersLoader;
|
||||||
private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
|
private final Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator;
|
||||||
|
private final Function<IMachine, Image> imachineToImage;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
|
public VirtualBoxComputeServiceAdapter(Supplier<VirtualBoxManager> manager,
|
||||||
Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader,
|
Supplier<Map<Image, YamlImage>> imagesMapper, LoadingCache<Image, Master> mastersLoader,
|
||||||
Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator) {
|
Function<NodeSpec, NodeAndInitialCredentials<IMachine>> cloneCreator,
|
||||||
|
Function<IMachine, Image> imachineToImage) {
|
||||||
this.manager = checkNotNull(manager, "manager");
|
this.manager = checkNotNull(manager, "manager");
|
||||||
this.images = imagesMapper.get();
|
this.imagesToYamlImages = imagesMapper.get();
|
||||||
this.mastersLoader = mastersLoader;
|
this.mastersLoader = mastersLoader;
|
||||||
this.cloneCreator = cloneCreator;
|
this.cloneCreator = cloneCreator;
|
||||||
|
this.imachineToImage = imachineToImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -97,7 +104,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
|
||||||
checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "node names cannot contain \""
|
checkState(!name.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "node names cannot contain \""
|
||||||
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
|
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
|
||||||
Master master = mastersLoader.get(template.getImage());
|
Master master = mastersLoader.get(template.getImage());
|
||||||
checkState(master != null, "could not find a master for image: "+template.getClass());
|
checkState(master != null, "could not find a master for image: " + template.getImage());
|
||||||
NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build();
|
NodeSpec nodeSpec = NodeSpec.builder().master(master).name(name).tag(tag).template(template).build();
|
||||||
return cloneCreator.apply(nodeSpec);
|
return cloneCreator.apply(nodeSpec);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -116,13 +123,39 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<IMachine> listHardwareProfiles() {
|
public Iterable<Hardware> listHardwareProfiles() {
|
||||||
return imageMachines();
|
Set<Hardware> hardware = Sets.newLinkedHashSet();
|
||||||
|
hardware.add(new HardwareBuilder().ids("t1.micro").hypervisor("VirtualBox").name("t1.micro").ram(512).build());
|
||||||
|
hardware.add(new HardwareBuilder().ids("m1.small").hypervisor("VirtualBox").name("m1.small").ram(1024).build());
|
||||||
|
hardware.add(new HardwareBuilder().ids("m1.medium").hypervisor("VirtualBox").name("m1.medium").ram(3840).build());
|
||||||
|
hardware.add(new HardwareBuilder().ids("m1.large").hypervisor("VirtualBox").name("m1.large").ram(7680).build());
|
||||||
|
return hardware;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterable<Image> listImages() {
|
public Iterable<Image> listImages() {
|
||||||
return images.keySet();
|
// the set of image vm names that were (or could be) built from the yaml file
|
||||||
|
final Set<String> imagesFromYamlNames = Sets.newHashSet(Iterables.transform(imagesToYamlImages.keySet(),
|
||||||
|
new Function<Image, String>() {
|
||||||
|
@Override
|
||||||
|
public String apply(Image input) {
|
||||||
|
return VIRTUALBOX_IMAGE_PREFIX + input.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
// IMachines that were not built from the yaml file transformed to Images
|
||||||
|
Set<Image> imagesFromCloning = Sets.newHashSet(Iterables.transform(
|
||||||
|
Iterables.filter(imageMachines(), new Predicate<IMachine>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(IMachine input) {
|
||||||
|
return !imagesFromYamlNames.contains(input.getName());
|
||||||
|
}
|
||||||
|
}), imachineToImage));
|
||||||
|
|
||||||
|
// final set of images are those from yaml and those from vbox that were not a transformation
|
||||||
|
// of the yaml ones
|
||||||
|
return Sets.union(imagesToYamlImages.keySet(), imagesFromCloning);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Iterable<IMachine> imageMachines() {
|
private Iterable<IMachine> imageMachines() {
|
||||||
|
@ -147,7 +180,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
|
||||||
try {
|
try {
|
||||||
return manager.get().getVBox().findMachine(vmName);
|
return manager.get().getVBox().findMachine(vmName);
|
||||||
} catch (VBoxException e) {
|
} catch (VBoxException e) {
|
||||||
if (e.getMessage().contains("Could not find a registered machine named")){
|
if (e.getMessage().contains("Could not find a registered machine named")) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
throw Throwables.propagate(e);
|
throw Throwables.propagate(e);
|
||||||
|
@ -202,7 +235,7 @@ public class VirtualBoxComputeServiceAdapter implements ComputeServiceAdapter<IM
|
||||||
|
|
||||||
private void powerDownMachine(IMachine machine) {
|
private void powerDownMachine(IMachine machine) {
|
||||||
try {
|
try {
|
||||||
if (machine.getState() == MachineState.PoweredOff){
|
if (machine.getState() == MachineState.PoweredOff) {
|
||||||
logger.debug("vm was already powered down: ", machine.getId());
|
logger.debug("vm was already powered down: ", machine.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,162 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.virtualbox.compute;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_DEFAULT_DIR;
|
||||||
|
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
|
||||||
|
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_WORKINGDIR;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.compute.ComputeServiceAdapter;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
|
import org.jclouds.compute.domain.CloneImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.Hardware;
|
||||||
|
import org.jclouds.compute.domain.Image;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplate;
|
||||||
|
import org.jclouds.compute.domain.ImageTemplateBuilder;
|
||||||
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
|
import org.jclouds.domain.Location;
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
import org.jclouds.virtualbox.functions.IMachineToVmSpec;
|
||||||
|
import org.jclouds.virtualbox.functions.TakeSnapshotIfNotAlreadyAttached;
|
||||||
|
import org.jclouds.virtualbox.functions.admin.UnregisterMachineIfExistsAndDeleteItsMedia;
|
||||||
|
import org.jclouds.virtualbox.util.MachineUtils;
|
||||||
|
import org.virtualbox_4_1.CloneMode;
|
||||||
|
import org.virtualbox_4_1.CloneOptions;
|
||||||
|
import org.virtualbox_4_1.IMachine;
|
||||||
|
import org.virtualbox_4_1.IProgress;
|
||||||
|
import org.virtualbox_4_1.ISnapshot;
|
||||||
|
import org.virtualbox_4_1.VirtualBoxManager;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class VirtualBoxImageExtension implements ImageExtension {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
||||||
|
private Logger logger = Logger.NULL;
|
||||||
|
private ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter;
|
||||||
|
private Function<IMachine, NodeMetadata> machineToNode;
|
||||||
|
private Supplier<VirtualBoxManager> manager;
|
||||||
|
private String workingDir;
|
||||||
|
private boolean isLinkedClone = true;
|
||||||
|
private Function<IMachine, Image> imachineToImage;
|
||||||
|
private MachineUtils machineUtils;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public VirtualBoxImageExtension(ComputeServiceAdapter<IMachine, Hardware, Image, Location> vboxAdapter,
|
||||||
|
Function<IMachine, NodeMetadata> machineToNode, Supplier<VirtualBoxManager> manager,
|
||||||
|
@Named(VIRTUALBOX_WORKINGDIR) String workingDir, Function<IMachine, Image> imachineToImage,
|
||||||
|
MachineUtils machineUtils) {
|
||||||
|
this.vboxAdapter = vboxAdapter;
|
||||||
|
this.machineToNode = machineToNode;
|
||||||
|
this.manager = manager;
|
||||||
|
this.workingDir = workingDir == null ? VIRTUALBOX_DEFAULT_DIR : workingDir;
|
||||||
|
this.imachineToImage = imachineToImage;
|
||||||
|
this.machineUtils = machineUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ImageTemplate buildImageTemplateFromNode(String name, final String id) {
|
||||||
|
Optional<NodeMetadata> sourceNode = getNodeById(id);
|
||||||
|
checkState(sourceNode.isPresent(), " there is no node with id " + id);
|
||||||
|
String vmName = VIRTUALBOX_IMAGE_PREFIX + name;
|
||||||
|
|
||||||
|
IMachine vm = null;
|
||||||
|
try {
|
||||||
|
vm = manager.get().getVBox().findMachine(vmName);
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
checkState(vm == null, " a machine exists with name: " + vmName);
|
||||||
|
return new ImageTemplateBuilder.CloneImageTemplateBuilder().name(vmName).nodeId(id).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Image createImage(ImageTemplate template) {
|
||||||
|
checkState(template instanceof CloneImageTemplate, " vbox image extension only supports cloning for the moment.");
|
||||||
|
CloneImageTemplate cloneTemplate = CloneImageTemplate.class.cast(template);
|
||||||
|
|
||||||
|
IMachine source = manager.get().getVBox().findMachine(cloneTemplate.getSourceNodeId());
|
||||||
|
|
||||||
|
String settingsFile = manager.get().getVBox().composeMachineFilename(template.getName(), workingDir);
|
||||||
|
IMachine clonedMachine = manager.get().getVBox()
|
||||||
|
.createMachine(settingsFile, template.getName(), source.getOSTypeId(), template.getName(), true);
|
||||||
|
|
||||||
|
List<CloneOptions> options = new ArrayList<CloneOptions>();
|
||||||
|
if (isLinkedClone)
|
||||||
|
options.add(CloneOptions.Link);
|
||||||
|
|
||||||
|
// TODO snapshot name
|
||||||
|
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "pre-image-spawn", "before spawning "
|
||||||
|
+ template.getName(), logger).apply(source);
|
||||||
|
|
||||||
|
checkNotNull(currentSnapshot);
|
||||||
|
|
||||||
|
// clone
|
||||||
|
IProgress progress = currentSnapshot.getMachine().cloneTo(clonedMachine, CloneMode.MachineState, options);
|
||||||
|
progress.waitForCompletion(-1);
|
||||||
|
|
||||||
|
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
|
||||||
|
|
||||||
|
// registering
|
||||||
|
manager.get().getVBox().registerMachine(clonedMachine);
|
||||||
|
|
||||||
|
return imachineToImage.apply(clonedMachine);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean deleteImage(String id) {
|
||||||
|
try {
|
||||||
|
IMachine machine = manager.get().getVBox().findMachine(VIRTUALBOX_IMAGE_PREFIX + id);
|
||||||
|
machineUtils.applyForMachine(machine.getId(), new UnregisterMachineIfExistsAndDeleteItsMedia(
|
||||||
|
new IMachineToVmSpec().apply(machine)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(e, "Could not delete machine with id %s ", id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<NodeMetadata> getNodeById(final String id) {
|
||||||
|
return Iterables.tryFind(Iterables.transform(vboxAdapter.listNodes(), machineToNode),
|
||||||
|
new Predicate<NodeMetadata>() {
|
||||||
|
@Override
|
||||||
|
public boolean apply(NodeMetadata input) {
|
||||||
|
return input.getId().equals(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -40,8 +40,9 @@ import org.jclouds.byon.Node;
|
||||||
import org.jclouds.byon.functions.NodeToNodeMetadata;
|
import org.jclouds.byon.functions.NodeToNodeMetadata;
|
||||||
import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty;
|
import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty;
|
||||||
import org.jclouds.compute.ComputeServiceAdapter;
|
import org.jclouds.compute.ComputeServiceAdapter;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
|
||||||
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
|
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
|
||||||
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.HardwareBuilder;
|
import org.jclouds.compute.domain.HardwareBuilder;
|
||||||
|
@ -58,6 +59,7 @@ import org.jclouds.ssh.SshClient;
|
||||||
import org.jclouds.sshj.config.SshjSshClientModule;
|
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||||
import org.jclouds.virtualbox.Host;
|
import org.jclouds.virtualbox.Host;
|
||||||
import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
|
import org.jclouds.virtualbox.compute.VirtualBoxComputeServiceAdapter;
|
||||||
|
import org.jclouds.virtualbox.compute.VirtualBoxImageExtension;
|
||||||
import org.jclouds.virtualbox.domain.CloneSpec;
|
import org.jclouds.virtualbox.domain.CloneSpec;
|
||||||
import org.jclouds.virtualbox.domain.ExecutionType;
|
import org.jclouds.virtualbox.domain.ExecutionType;
|
||||||
import org.jclouds.virtualbox.domain.IsoSpec;
|
import org.jclouds.virtualbox.domain.IsoSpec;
|
||||||
|
@ -88,6 +90,7 @@ import org.virtualbox_4_1.VirtualBoxManager;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Functions;
|
import com.google.common.base.Functions;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
|
@ -105,17 +108,19 @@ import com.google.inject.TypeLiteral;
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class VirtualBoxComputeServiceContextModule extends
|
public class VirtualBoxComputeServiceContextModule extends
|
||||||
ComputeServiceAdapterContextModule<IMachine, IMachine, Image, Location> {
|
ComputeServiceAdapterContextModule<IMachine, Hardware, Image, Location> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
super.configure();
|
super.configure();
|
||||||
bind(new TypeLiteral<ComputeServiceAdapter<IMachine, IMachine, Image, Location>>() {
|
bind(new TypeLiteral<ComputeServiceAdapter<IMachine, Hardware, Image, Location>>() {
|
||||||
}).to(VirtualBoxComputeServiceAdapter.class);
|
}).to(VirtualBoxComputeServiceAdapter.class);
|
||||||
bind(new TypeLiteral<Function<IMachine, NodeMetadata>>() {
|
bind(new TypeLiteral<Function<IMachine, NodeMetadata>>() {
|
||||||
}).to(IMachineToNodeMetadata.class);
|
}).to(IMachineToNodeMetadata.class);
|
||||||
bind(new TypeLiteral<Function<Location, Location>>() {
|
bind(new TypeLiteral<Function<Location, Location>>() {
|
||||||
}).to((Class) IdentityFunction.class);
|
}).to((Class) IdentityFunction.class);
|
||||||
|
bind(new TypeLiteral<Function<Hardware, Hardware>>() {
|
||||||
|
}).to((Class) IdentityFunction.class);
|
||||||
bind(new TypeLiteral<Function<Image, Image>>() {
|
bind(new TypeLiteral<Function<Image, Image>>() {
|
||||||
}).to((Class) IdentityFunction.class);
|
}).to((Class) IdentityFunction.class);
|
||||||
bind(new TypeLiteral<Function<IMachine, Hardware>>() {
|
bind(new TypeLiteral<Function<IMachine, Hardware>>() {
|
||||||
|
@ -139,6 +144,10 @@ public class VirtualBoxComputeServiceContextModule extends
|
||||||
bind(new TypeLiteral<LoadingCache<Image, Master>>() {
|
bind(new TypeLiteral<LoadingCache<Image, Master>>() {
|
||||||
}).to(MastersLoadingCache.class);
|
}).to(MastersLoadingCache.class);
|
||||||
|
|
||||||
|
// the vbox image extension
|
||||||
|
bind(new TypeLiteral<ImageExtension>() {
|
||||||
|
}).to(VirtualBoxImageExtension.class);
|
||||||
|
|
||||||
// the master creating function
|
// the master creating function
|
||||||
bind(new TypeLiteral<Function<MasterSpec, IMachine>>() {
|
bind(new TypeLiteral<Function<MasterSpec, IMachine>>() {
|
||||||
}).to((Class) CreateAndInstallVm.class);
|
}).to((Class) CreateAndInstallVm.class);
|
||||||
|
@ -166,10 +175,9 @@ public class VirtualBoxComputeServiceContextModule extends
|
||||||
@Host
|
@Host
|
||||||
@Singleton
|
@Singleton
|
||||||
protected ComputeServiceContext provideHostController() {
|
protected ComputeServiceContext provideHostController() {
|
||||||
return ContextBuilder.newBuilder(new BYONApiMetadata())
|
return ContextBuilder.newBuilder(new BYONApiMetadata()).credentials("", "")
|
||||||
.credentials("", "")
|
.modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()))
|
||||||
.modules(ImmutableSet.<Module> of(new SLF4JLoggingModule(), new SshjSshClientModule()))
|
.build(ComputeServiceContext.class);
|
||||||
.build(ComputeServiceContext.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -202,18 +210,6 @@ public class VirtualBoxComputeServiceContextModule extends
|
||||||
return new RetryablePredicate<SshClient>(sshResponds, timeouts.nodeRunning, 500l, TimeUnit.MILLISECONDS);
|
return new RetryablePredicate<SshClient>(sshResponds, timeouts.nodeRunning, 500l, TimeUnit.MILLISECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Supplier provideHardware(ComputeServiceAdapter<IMachine, IMachine, Image, Location> adapter,
|
|
||||||
Function<IMachine, Hardware> transformer) {
|
|
||||||
// since no vms might be available we need to list images
|
|
||||||
Iterable<Image> images = adapter.listImages();
|
|
||||||
Set<Hardware> hardware = Sets.newHashSet();
|
|
||||||
for (Image image : images) {
|
|
||||||
hardware.add(new HardwareBuilder().ids(image.getId()).hypervisor("VirtualBox").name(image.getName()).build());
|
|
||||||
}
|
|
||||||
return Suppliers.ofInstance(hardware);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
|
protected TemplateBuilder provideTemplate(Injector injector, TemplateBuilder template) {
|
||||||
return template.osFamily(VIRTUALBOX_DEFAULT_IMAGE_OS).osVersionMatches(VIRTUALBOX_DEFAULT_IMAGE_VERSION)
|
return template.osFamily(VIRTUALBOX_DEFAULT_IMAGE_OS).osVersionMatches(VIRTUALBOX_DEFAULT_IMAGE_VERSION)
|
||||||
|
@ -233,6 +229,11 @@ public class VirtualBoxComputeServiceContextModule extends
|
||||||
}), nodes);
|
}), nodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Optional<ImageExtension> provideImageExtension(Injector i) {
|
||||||
|
return Optional.of(i.getInstance(ImageExtension.class));
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public static final Map<MachineState, NodeState> machineToNodeState = ImmutableMap
|
public static final Map<MachineState, NodeState> machineToNodeState = ImmutableMap
|
||||||
.<MachineState, NodeState> builder().put(MachineState.Running, NodeState.RUNNING)
|
.<MachineState, NodeState> builder().put(MachineState.Running, NodeState.RUNNING)
|
||||||
|
|
|
@ -99,13 +99,13 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
|
||||||
.getVBox()
|
.getVBox()
|
||||||
.createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(), vmSpec.getVmId(),
|
.createMachine(settingsFile, vmSpec.getVmName(), vmSpec.getOsTypeId(), vmSpec.getVmId(),
|
||||||
vmSpec.isForceOverwrite());
|
vmSpec.isForceOverwrite());
|
||||||
|
|
||||||
List<CloneOptions> options = new ArrayList<CloneOptions>();
|
List<CloneOptions> options = new ArrayList<CloneOptions>();
|
||||||
if (isLinkedClone)
|
if (isLinkedClone)
|
||||||
options.add(CloneOptions.Link);
|
options.add(CloneOptions.Link);
|
||||||
|
|
||||||
// TODO snapshot name
|
// TODO snapshot name
|
||||||
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc")
|
ISnapshot currentSnapshot = new TakeSnapshotIfNotAlreadyAttached(manager, "snapshotName", "snapshotDesc", logger)
|
||||||
.apply(master);
|
.apply(master);
|
||||||
|
|
||||||
// clone
|
// clone
|
||||||
|
@ -114,6 +114,9 @@ public class CloneAndRegisterMachineFromIMachineIfNotAlreadyExists implements Fu
|
||||||
progress.waitForCompletion(-1);
|
progress.waitForCompletion(-1);
|
||||||
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
|
logger.debug(String.format("Machine %s is cloned correctly", clonedMachine.getName()));
|
||||||
|
|
||||||
|
// memory may not be the same as the master vm
|
||||||
|
clonedMachine.setMemorySize(cloneSpec.getVmSpec().getMemory());
|
||||||
|
|
||||||
// registering
|
// registering
|
||||||
manager.get().getVBox().registerMachine(clonedMachine);
|
manager.get().getVBox().registerMachine(clonedMachine);
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.jclouds.compute.domain.ImageBuilder;
|
||||||
import org.jclouds.compute.domain.OperatingSystem;
|
import org.jclouds.compute.domain.OperatingSystem;
|
||||||
import org.jclouds.compute.domain.OsFamily;
|
import org.jclouds.compute.domain.OsFamily;
|
||||||
import org.jclouds.javax.annotation.Nullable;
|
import org.jclouds.javax.annotation.Nullable;
|
||||||
|
import org.jclouds.virtualbox.config.VirtualBoxConstants;
|
||||||
import org.virtualbox_4_1.IGuestOSType;
|
import org.virtualbox_4_1.IGuestOSType;
|
||||||
import org.virtualbox_4_1.IMachine;
|
import org.virtualbox_4_1.IMachine;
|
||||||
import org.virtualbox_4_1.VirtualBoxManager;
|
import org.virtualbox_4_1.VirtualBoxManager;
|
||||||
|
@ -63,7 +64,9 @@ public class IMachineToImage implements Function<IMachine, Image> {
|
||||||
OperatingSystem os = OperatingSystem.builder().description(guestOSType.getDescription()).family(family)
|
OperatingSystem os = OperatingSystem.builder().description(guestOSType.getDescription()).family(family)
|
||||||
.version(version).is64Bit(guestOSType.getIs64Bit()).build();
|
.version(version).is64Bit(guestOSType.getIs64Bit()).build();
|
||||||
|
|
||||||
return new ImageBuilder().id("" + from.getId()).name(from.getName()).description(from.getDescription())
|
return new ImageBuilder()
|
||||||
|
.id(from.getName().substring(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX.length(),
|
||||||
|
from.getName().length())).name(from.getName()).description(from.getDescription())
|
||||||
.operatingSystem(os).build();
|
.operatingSystem(os).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,8 +95,6 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
|
||||||
nodeState = NodeState.UNRECOGNIZED;
|
nodeState = NodeState.UNRECOGNIZED;
|
||||||
nodeMetadataBuilder.state(nodeState);
|
nodeMetadataBuilder.state(nodeState);
|
||||||
|
|
||||||
logger.debug("Setting virtualbox node to: " + nodeState + " from machine state: " + vmState);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// nat adapter
|
// nat adapter
|
||||||
INetworkAdapter natAdapter = vm.getNetworkAdapter(0l);
|
INetworkAdapter natAdapter = vm.getNetworkAdapter(0l);
|
||||||
|
@ -139,7 +137,6 @@ public class IMachineToNodeMetadata implements Function<IMachine, NodeMetadata>
|
||||||
|
|
||||||
private NodeMetadataBuilder getIpAddresses(IMachine vm, NodeMetadataBuilder nodeMetadataBuilder) {
|
private NodeMetadataBuilder getIpAddresses(IMachine vm, NodeMetadataBuilder nodeMetadataBuilder) {
|
||||||
List<String> publicIpAddresses = Lists.newArrayList();
|
List<String> publicIpAddresses = Lists.newArrayList();
|
||||||
List<String> privateIpAddresses = Lists.newArrayList();
|
|
||||||
|
|
||||||
for(long slot = 0; slot < 4; slot ++) {
|
for(long slot = 0; slot < 4; slot ++) {
|
||||||
INetworkAdapter adapter = vm.getNetworkAdapter(slot);
|
INetworkAdapter adapter = vm.getNetworkAdapter(slot);
|
||||||
|
|
|
@ -141,14 +141,51 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
|
||||||
return masters.get(key.getId());
|
return masters.get(key.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// the yaml image
|
checkState(!key.getId().contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
|
||||||
YamlImage currentImage = imageMapping.get(key.getId());
|
|
||||||
|
|
||||||
checkNotNull(currentImage, "could not find yaml image for image: " + key);
|
|
||||||
|
|
||||||
checkState(!currentImage.id.contains(VIRTUALBOX_NODE_NAME_SEPARATOR), "master image names cannot contain \""
|
|
||||||
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
|
+ VIRTUALBOX_NODE_NAME_SEPARATOR + "\"");
|
||||||
|
|
||||||
|
String vmName = VIRTUALBOX_IMAGE_PREFIX + key.getId();
|
||||||
|
|
||||||
|
IMachine masterMachine;
|
||||||
|
|
||||||
|
Master master;
|
||||||
|
|
||||||
|
// ready the preseed file server
|
||||||
|
PreseedCfgServer server = new PreseedCfgServer();
|
||||||
|
try {
|
||||||
|
// try and find a master machine in vbox
|
||||||
|
masterMachine = manager.get().getVBox().findMachine(vmName);
|
||||||
|
master = Master.builder().machine(masterMachine).build();
|
||||||
|
|
||||||
|
} catch (VBoxException e) {
|
||||||
|
if (machineNotFoundException(e)) {
|
||||||
|
// machine was not found try to build one from a yaml file
|
||||||
|
YamlImage currentImage = imageMapping.get(key.getId());
|
||||||
|
|
||||||
|
checkNotNull(currentImage);
|
||||||
|
|
||||||
|
server.start(preconfigurationUrl, currentImage.preseed_cfg);
|
||||||
|
|
||||||
|
MasterSpec masterSpec = buildMasterSpecFromYaml(currentImage, vmName);
|
||||||
|
|
||||||
|
// create the master machine if it can't be found
|
||||||
|
masterMachine = masterCreatorAndInstaller.apply(masterSpec);
|
||||||
|
|
||||||
|
// build the master
|
||||||
|
master = Master.builder().machine(masterMachine).spec(masterSpec).build();
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
server.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
masters.put(key.getId(), master);
|
||||||
|
return master;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MasterSpec buildMasterSpecFromYaml(YamlImage currentImage, String vmName) throws ExecutionException {
|
||||||
|
|
||||||
String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version);
|
String guestAdditionsFileName = String.format("VBoxGuestAdditions_%s.iso", version);
|
||||||
String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName);
|
String guestAdditionsIso = String.format("%s/%s", isosDir, guestAdditionsFileName);
|
||||||
String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName;
|
String guestAdditionsUri = "http://download.virtualbox.org/virtualbox/" + version + "/" + guestAdditionsFileName;
|
||||||
|
@ -160,8 +197,6 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
|
||||||
// check if the iso is here, download if not
|
// check if the iso is here, download if not
|
||||||
String localIsoUrl = getFilePathOrDownload(currentImage.iso);
|
String localIsoUrl = getFilePathOrDownload(currentImage.iso);
|
||||||
|
|
||||||
String vmName = VIRTUALBOX_IMAGE_PREFIX + currentImage.id;
|
|
||||||
|
|
||||||
String adminDisk = workingDir + File.separator + vmName + ".vdi";
|
String adminDisk = workingDir + File.separator + vmName + ".vdi";
|
||||||
|
|
||||||
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1)
|
HardDisk hardDisk = HardDisk.builder().diskpath(adminDisk).autoDelete(true).controllerPort(0).deviceSlot(1)
|
||||||
|
@ -174,46 +209,19 @@ public class MastersLoadingCache extends AbstractLoadingCache<Image, Master> {
|
||||||
.controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
|
.controller(ideController).forceOverwrite(true).cleanUpMode(CleanupMode.Full).build();
|
||||||
|
|
||||||
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
|
NetworkAdapter networkAdapter = NetworkAdapter.builder().networkAttachmentType(NetworkAttachmentType.NAT)
|
||||||
.tcpRedirectRule("127.0.0.1", MASTER_PORT , "", 22).build();
|
.tcpRedirectRule("127.0.0.1", MASTER_PORT, "", 22).build();
|
||||||
|
|
||||||
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
|
NetworkInterfaceCard networkInterfaceCard = NetworkInterfaceCard.builder().addNetworkAdapter(networkAdapter)
|
||||||
.slot(0L).build();
|
.slot(0L).build();
|
||||||
|
|
||||||
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
|
NetworkSpec networkSpec = NetworkSpec.builder().addNIC(networkInterfaceCard).build();
|
||||||
|
|
||||||
MasterSpec masterSpec = MasterSpec
|
return MasterSpec
|
||||||
.builder()
|
.builder()
|
||||||
.vm(vmSpecification)
|
.vm(vmSpecification)
|
||||||
.iso(IsoSpec.builder().sourcePath(localIsoUrl)
|
.iso(IsoSpec.builder().sourcePath(localIsoUrl)
|
||||||
.installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName()))
|
.installationScript(installationKeySequence.replace("HOSTNAME", vmSpecification.getVmName()))
|
||||||
.build()).network(networkSpec).build();
|
.build()).network(networkSpec).build();
|
||||||
|
|
||||||
IMachine masterMachine;
|
|
||||||
|
|
||||||
|
|
||||||
// ready the preseed file server
|
|
||||||
PreseedCfgServer server = new PreseedCfgServer();
|
|
||||||
try {
|
|
||||||
// try and find a master machine in vbox
|
|
||||||
masterMachine = manager.get().getVBox().findMachine(vmName);
|
|
||||||
} catch (VBoxException e) {
|
|
||||||
if (machineNotFoundException(e)) {
|
|
||||||
server.start(preconfigurationUrl,currentImage.preseed_cfg);
|
|
||||||
// create the master machine if it can't be found
|
|
||||||
masterMachine = masterCreatorAndInstaller.apply(masterSpec);
|
|
||||||
} else {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
server.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Master master = Master.builder().machine(masterMachine).spec(masterSpec).build();
|
|
||||||
|
|
||||||
masters.put(key.getId(), master);
|
|
||||||
|
|
||||||
return master;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -118,12 +118,18 @@ public class NodeCreator implements Function<NodeSpec, NodeAndInitialCredentials
|
||||||
progress.waitForCompletion(-1);
|
progress.waitForCompletion(-1);
|
||||||
session.unlockMachine();
|
session.unlockMachine();
|
||||||
}
|
}
|
||||||
String masterNameWithoutPrefix = master.getSpec().getVmSpec().getVmName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
|
String masterNameWithoutPrefix = master.getMachine().getName().replace(VIRTUALBOX_IMAGE_PREFIX, "");
|
||||||
|
|
||||||
String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + VIRTUALBOX_NODE_NAME_SEPARATOR
|
String cloneName = VIRTUALBOX_NODE_PREFIX + masterNameWithoutPrefix + VIRTUALBOX_NODE_NAME_SEPARATOR
|
||||||
+ nodeSpec.getTag() + VIRTUALBOX_NODE_NAME_SEPARATOR + nodeSpec.getName();
|
+ nodeSpec.getTag() + VIRTUALBOX_NODE_NAME_SEPARATOR + nodeSpec.getName();
|
||||||
|
|
||||||
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(512).cleanUpMode(CleanupMode.Full)
|
int ram = 512;
|
||||||
|
if (nodeSpec.getTemplate() != null && nodeSpec.getTemplate().getHardware() != null
|
||||||
|
&& nodeSpec.getTemplate().getHardware().getRam() > 0) {
|
||||||
|
ram = nodeSpec.getTemplate().getHardware().getRam();
|
||||||
|
}
|
||||||
|
|
||||||
|
VmSpec cloneVmSpec = VmSpec.builder().id(cloneName).name(cloneName).memoryMB(ram).cleanUpMode(CleanupMode.Full)
|
||||||
.forceOverwrite(true).build();
|
.forceOverwrite(true).build();
|
||||||
|
|
||||||
// CASE NAT + HOST-ONLY
|
// CASE NAT + HOST-ONLY
|
||||||
|
|
|
@ -20,15 +20,13 @@
|
||||||
package org.jclouds.virtualbox.functions;
|
package org.jclouds.virtualbox.functions;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.inject.Named;
|
|
||||||
|
|
||||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
import org.virtualbox_4_1.IMachine;
|
import org.virtualbox_4_1.IMachine;
|
||||||
import org.virtualbox_4_1.IProgress;
|
import org.virtualbox_4_1.IProgress;
|
||||||
import org.virtualbox_4_1.ISession;
|
import org.virtualbox_4_1.ISession;
|
||||||
import org.virtualbox_4_1.ISnapshot;
|
import org.virtualbox_4_1.ISnapshot;
|
||||||
|
import org.virtualbox_4_1.MachineState;
|
||||||
import org.virtualbox_4_1.VirtualBoxManager;
|
import org.virtualbox_4_1.VirtualBoxManager;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
@ -40,55 +38,80 @@ import com.google.common.base.Throwables;
|
||||||
*/
|
*/
|
||||||
public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> {
|
public class TakeSnapshotIfNotAlreadyAttached implements Function<IMachine, ISnapshot> {
|
||||||
|
|
||||||
@Resource
|
|
||||||
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
|
|
||||||
protected Logger logger = Logger.NULL;
|
|
||||||
|
|
||||||
private Supplier<VirtualBoxManager> manager;
|
private Supplier<VirtualBoxManager> manager;
|
||||||
private String snapshotName;
|
private String snapshotName;
|
||||||
private String snapshotDesc;
|
private String snapshotDesc;
|
||||||
|
private Logger logger;
|
||||||
|
|
||||||
public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName, String snapshotDesc) {
|
public TakeSnapshotIfNotAlreadyAttached(Supplier<VirtualBoxManager> manager, String snapshotName,
|
||||||
|
String snapshotDesc, Logger logger) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
this.snapshotName = snapshotName;
|
this.snapshotName = snapshotName;
|
||||||
this.snapshotDesc = snapshotDesc;
|
this.snapshotDesc = snapshotDesc;
|
||||||
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ISnapshot apply(@Nullable IMachine machine) {
|
public ISnapshot apply(@Nullable IMachine machine) {
|
||||||
// Snapshot a machine
|
// Snapshot a machine
|
||||||
ISession session = null;
|
ISession session = null;
|
||||||
if (machine.getCurrentSnapshot() == null) {
|
ISnapshot snap = machine.getCurrentSnapshot();
|
||||||
int retries = 10;
|
|
||||||
while (true) {
|
if (snap == null) {
|
||||||
try {
|
try {
|
||||||
session = manager.get().openMachineSession(machine);
|
session = manager.get().openMachineSession(machine);
|
||||||
IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
|
logger.debug("No snapshot available taking new one: %s (description: %s) taken from %s", snapshotName,
|
||||||
progress.waitForCompletion(-1);
|
snapshotDesc, machine.getName());
|
||||||
logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc,
|
int retries = 10;
|
||||||
machine.getName());
|
while (true) {
|
||||||
break;
|
try {
|
||||||
} catch (Exception e) {
|
|
||||||
if (e.getMessage().contains("VirtualBox error: The object is not ready")) {
|
// running machines need to be pause before a snapshot can be taken
|
||||||
retries--;
|
// due to a vbox bug see https://www.virtualbox.org/ticket/9255
|
||||||
if (retries == 0) {
|
boolean paused = false;
|
||||||
logger.error(e,
|
if (machine.getState() == MachineState.Running) {
|
||||||
"Problem creating snapshot (too many retries) %s (descripton: %s) from machine %s",
|
session.getConsole().pause();
|
||||||
snapshotName, snapshotDesc, machine.getName());
|
paused = true;
|
||||||
throw Throwables.propagate(e);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName,
|
IProgress progress = session.getConsole().takeSnapshot(snapshotName, snapshotDesc);
|
||||||
snapshotDesc, machine.getName());
|
progress.waitForCompletion(-1);
|
||||||
throw Throwables.propagate(e);
|
|
||||||
} finally {
|
if (paused) {
|
||||||
if (session != null) {
|
session.getConsole().resume();
|
||||||
session.unlockMachine();
|
}
|
||||||
|
|
||||||
|
snap = machine.getCurrentSnapshot();
|
||||||
|
logger.debug("Snapshot %s (description: %s) taken from %s", snapshotName, snapshotDesc,
|
||||||
|
machine.getName());
|
||||||
|
break;
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (e.getMessage().contains("VirtualBox error: The object is not ready")
|
||||||
|
|| e.getMessage().contains("This machine does not have any snapshots")) {
|
||||||
|
retries--;
|
||||||
|
if (retries == 0) {
|
||||||
|
logger.error(e,
|
||||||
|
"Problem creating snapshot (too many retries) %s (descripton: %s) from machine %s",
|
||||||
|
snapshotName, snapshotDesc, machine.getName());
|
||||||
|
throw Throwables.propagate(e);
|
||||||
|
}
|
||||||
|
Thread.sleep(1000L);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
logger.error(e, "Problem creating snapshot %s (descripton: %s) from machine %s", snapshotName,
|
||||||
|
snapshotDesc, machine.getName());
|
||||||
|
throw Throwables.propagate(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Throwables.propagate(e);
|
||||||
|
} finally {
|
||||||
|
if (session != null) {
|
||||||
|
manager.get().closeMachineSession(session);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return machine.getCurrentSnapshot();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
return snap;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
|
@ -74,10 +73,10 @@ public class StartVBoxIfNotAlreadyRunning implements Supplier<VirtualBoxManager>
|
||||||
this.host = checkNotNull(host, "host");
|
this.host = checkNotNull(host, "host");
|
||||||
this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed");
|
this.providerSupplier = checkNotNull(providerSupplier, "endpoint to virtualbox websrvd is needed");
|
||||||
this.managerForNode = checkNotNull(managerForNode, "managerForNode");
|
this.managerForNode = checkNotNull(managerForNode, "managerForNode");
|
||||||
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostConstruct
|
public synchronized void start() {
|
||||||
public void start() {
|
|
||||||
URI provider = providerSupplier.get();
|
URI provider = providerSupplier.get();
|
||||||
if (!socketTester.apply(new IPSocket(provider.getHost(), provider.getPort()))) {
|
if (!socketTester.apply(new IPSocket(provider.getHost(), provider.getPort()))) {
|
||||||
logger.debug("disabling password access");
|
logger.debug("disabling password access");
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
U * Licensed to jclouds, Inc. (jclouds) under one or more
|
U * Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
* contributor license agreements. See the NOTICE file
|
* contributor license agreements. See the NOTICE file
|
||||||
* distributed with this work for additional information
|
* distributed with this work for additional information
|
||||||
* regarding copyright ownership. jclouds licenses this file
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
@ -93,8 +93,8 @@ public class UnregisterMachineIfExistsAndDeleteItsMedia implements Function<IMac
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(filter(mediaToBeDeleted,
|
List<IMedium> filteredMediaToBeDeleted = Lists.newArrayList(transform(
|
||||||
new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium()));
|
filter(mediaToBeDeleted, new AutoDeleteHardDiskPredicate(vmSpec)), new DeleteChildrenOfMedium()));
|
||||||
|
|
||||||
if (!filteredMediaToBeDeleted.isEmpty()) {
|
if (!filteredMediaToBeDeleted.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
|
@ -105,7 +105,7 @@ public class UnregisterMachineIfExistsAndDeleteItsMedia implements Function<IMac
|
||||||
Throwables.propagate(e);
|
Throwables.propagate(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,8 +105,17 @@ public class UnregisterMachineIfExistsAndForceDeleteItsMedia implements Function
|
||||||
checkNotNull(medium.getChildren());
|
checkNotNull(medium.getChildren());
|
||||||
if (medium.getDeviceType().equals(DeviceType.HardDisk)) {
|
if (medium.getDeviceType().equals(DeviceType.HardDisk)) {
|
||||||
for (IMedium child : medium.getChildren()) {
|
for (IMedium child : medium.getChildren()) {
|
||||||
IProgress deletion = child.deleteStorage();
|
try {
|
||||||
deletion.waitForCompletion(-1);
|
IProgress deletion = child.deleteStorage();
|
||||||
|
deletion.waitForCompletion(-1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// work around media that are still attached to other vm's. this can happen when a
|
||||||
|
// running node is used to create a new image and then an attempt at deleting it
|
||||||
|
// is made
|
||||||
|
if (e.getMessage().contains("is still attached to the following")) {
|
||||||
|
logger.warn("Media could not be deleted. Ignoring... [Message %s]", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return medium;
|
return medium;
|
||||||
|
|
|
@ -39,6 +39,7 @@ import org.jclouds.concurrent.MoreExecutors;
|
||||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
import org.jclouds.config.ValueOfConfigurationKeyOrNull;
|
import org.jclouds.config.ValueOfConfigurationKeyOrNull;
|
||||||
import org.jclouds.rest.annotations.BuildVersion;
|
import org.jclouds.rest.annotations.BuildVersion;
|
||||||
|
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||||
import org.jclouds.virtualbox.config.VirtualBoxConstants;
|
import org.jclouds.virtualbox.config.VirtualBoxConstants;
|
||||||
import org.jclouds.virtualbox.domain.HardDisk;
|
import org.jclouds.virtualbox.domain.HardDisk;
|
||||||
import org.jclouds.virtualbox.domain.IsoSpec;
|
import org.jclouds.virtualbox.domain.IsoSpec;
|
||||||
|
@ -217,6 +218,11 @@ public class BaseVirtualBoxClientLiveTest extends BaseComputeServiceContextLiveT
|
||||||
"/default-images.yaml")).get();
|
"/default-images.yaml")).get();
|
||||||
return images.get(Iterables.getOnlyElement(Iterables.filter(images.keySet(), new DefaultImagePredicate())));
|
return images.get(Iterables.getOnlyElement(Iterables.filter(images.keySet(), new DefaultImagePredicate())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Module getSshModule() {
|
||||||
|
return new SshjSshClientModule();
|
||||||
|
}
|
||||||
|
|
||||||
@AfterClass(groups = "live")
|
@AfterClass(groups = "live")
|
||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import javax.inject.Inject;
|
||||||
|
|
||||||
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
|
import org.jclouds.compute.ComputeServiceAdapter.NodeAndInitialCredentials;
|
||||||
import org.jclouds.compute.domain.ExecResponse;
|
import org.jclouds.compute.domain.ExecResponse;
|
||||||
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
import org.jclouds.compute.domain.Template;
|
import org.jclouds.compute.domain.Template;
|
||||||
import org.jclouds.domain.LoginCredentials;
|
import org.jclouds.domain.LoginCredentials;
|
||||||
|
@ -76,7 +77,7 @@ public class VirtualBoxComputeServiceAdapterLiveTest extends BaseVirtualBoxClien
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testListHardwareProfiles() {
|
public void testListHardwareProfiles() {
|
||||||
Iterable<IMachine> profiles = adapter.listHardwareProfiles();
|
Iterable<Hardware> profiles = adapter.listHardwareProfiles();
|
||||||
assertTrue(!Iterables.isEmpty(profiles));
|
assertTrue(!Iterables.isEmpty(profiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.virtualbox.compute;
|
||||||
|
|
||||||
|
import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
|
||||||
|
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
@Test(groups = "live", singleThreaded = true, testName = "VirtualBoxImageExtensionLiveTest")
|
||||||
|
public class VirtualBoxImageExtensionLiveTest extends BaseImageExtensionLiveTest {
|
||||||
|
|
||||||
|
public VirtualBoxImageExtensionLiveTest() {
|
||||||
|
provider = "virtualbox";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Module getSshModule() {
|
||||||
|
return new SshjSshClientModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,7 +20,7 @@
|
||||||
package org.jclouds.virtualbox.functions;
|
package org.jclouds.virtualbox.functions;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
import static junit.framework.Assert.assertEquals;
|
import static junit.framework.Assert.assertTrue;
|
||||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
|
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX;
|
||||||
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
|
import static org.jclouds.virtualbox.config.VirtualBoxConstants.VIRTUALBOX_INSTALLATION_KEY_SEQUENCE;
|
||||||
|
|
||||||
|
@ -56,9 +56,7 @@ import org.virtualbox_4_1.StorageBus;
|
||||||
import com.google.common.base.CaseFormat;
|
import com.google.common.base.CaseFormat;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Splitter;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
import com.google.inject.Injector;
|
import com.google.inject.Injector;
|
||||||
|
|
||||||
|
@ -166,15 +164,14 @@ public class CreateAndInstallVmLiveTest extends BaseVirtualBoxClientLiveTest {
|
||||||
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
|
checkState(sshResponds.apply(client), "timed out waiting for guest %s to be accessible via ssh",
|
||||||
machine.getName());
|
machine.getName());
|
||||||
|
|
||||||
String vboxVersion = Iterables.get(
|
String version = machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
|
||||||
Splitter.on('r').split(context.getProviderSpecificContext().getBuildVersion()), 0);
|
@Override
|
||||||
assertEquals(vboxVersion,
|
public String apply(ISession session) {
|
||||||
machineUtils.sharedLockMachineAndApplyToSession(machine.getName(), new Function<ISession, String>() {
|
return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
|
||||||
@Override
|
}
|
||||||
public String apply(ISession session) {
|
});
|
||||||
return session.getMachine().getGuestPropertyValue("/VirtualBox/GuestAdd/Version");
|
|
||||||
}
|
assertTrue(version != null && !version.isEmpty());
|
||||||
}));
|
|
||||||
} finally {
|
} finally {
|
||||||
for (VmSpec spec : ImmutableSet.of(machineSpec.getVmSpec())) {
|
for (VmSpec spec : ImmutableSet.of(machineSpec.getVmSpec())) {
|
||||||
machineController.ensureMachineIsShutdown(spec.getVmName());
|
machineController.ensureMachineIsShutdown(spec.getVmName());
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.jclouds.compute.domain.OsFamily;
|
||||||
import org.jclouds.compute.reference.ComputeServiceConstants;
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
import org.jclouds.json.Json;
|
import org.jclouds.json.Json;
|
||||||
import org.jclouds.json.config.GsonModule;
|
import org.jclouds.json.config.GsonModule;
|
||||||
|
import org.jclouds.virtualbox.config.VirtualBoxConstants;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
import org.virtualbox_4_1.IGuestOSType;
|
import org.virtualbox_4_1.IGuestOSType;
|
||||||
import org.virtualbox_4_1.IMachine;
|
import org.virtualbox_4_1.IMachine;
|
||||||
|
@ -48,7 +49,7 @@ public class IMachineToImageTest {
|
||||||
|
|
||||||
Map<OsFamily, Map<String, String>> map = new BaseComputeServiceContextModule() {
|
Map<OsFamily, Map<String, String>> map = new BaseComputeServiceContextModule() {
|
||||||
}.provideOsVersionMap(new ComputeServiceConstants.ReferenceData(), Guice.createInjector(new GsonModule())
|
}.provideOsVersionMap(new ComputeServiceConstants.ReferenceData(), Guice.createInjector(new GsonModule())
|
||||||
.getInstance(Json.class));
|
.getInstance(Json.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConvert() throws Exception {
|
public void testConvert() throws Exception {
|
||||||
|
@ -61,6 +62,7 @@ public class IMachineToImageTest {
|
||||||
expect(vbm.getVBox()).andReturn(vBox).anyTimes();
|
expect(vbm.getVBox()).andReturn(vBox).anyTimes();
|
||||||
|
|
||||||
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
|
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
|
||||||
|
expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
|
||||||
expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
|
expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
|
||||||
expect(vm.getDescription()).andReturn("my-ubuntu-machine").anyTimes();
|
expect(vm.getDescription()).andReturn("my-ubuntu-machine").anyTimes();
|
||||||
expect(guestOsType.getDescription()).andReturn(linuxDescription).anyTimes();
|
expect(guestOsType.getDescription()).andReturn(linuxDescription).anyTimes();
|
||||||
|
@ -77,6 +79,7 @@ public class IMachineToImageTest {
|
||||||
assertTrue(image.getOperatingSystem().is64Bit());
|
assertTrue(image.getOperatingSystem().is64Bit());
|
||||||
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
|
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
|
||||||
assertEquals(image.getOperatingSystem().getVersion(), "10.04");
|
assertEquals(image.getOperatingSystem().getVersion(), "10.04");
|
||||||
|
assertEquals(image.getId(), "my-vm-id");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +94,7 @@ public class IMachineToImageTest {
|
||||||
String vmDescription = "ubuntu-11.04-server-i386";
|
String vmDescription = "ubuntu-11.04-server-i386";
|
||||||
expect(vbm.getVBox()).andReturn(vBox).anyTimes();
|
expect(vbm.getVBox()).andReturn(vBox).anyTimes();
|
||||||
|
|
||||||
|
expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
|
||||||
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
|
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
|
||||||
expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
|
expect(vBox.getGuestOSType(eq("os-type"))).andReturn(guestOsType);
|
||||||
expect(vm.getDescription()).andReturn(vmDescription).anyTimes();
|
expect(vm.getDescription()).andReturn(vmDescription).anyTimes();
|
||||||
|
@ -108,6 +112,7 @@ public class IMachineToImageTest {
|
||||||
assertTrue(image.getOperatingSystem().is64Bit());
|
assertTrue(image.getOperatingSystem().is64Bit());
|
||||||
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
|
assertEquals(image.getOperatingSystem().getFamily(), OsFamily.UBUNTU);
|
||||||
assertEquals(image.getOperatingSystem().getVersion(), "11.04");
|
assertEquals(image.getOperatingSystem().getVersion(), "11.04");
|
||||||
|
assertEquals(image.getId(), "my-vm-id");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,6 +126,7 @@ public class IMachineToImageTest {
|
||||||
|
|
||||||
expect(vbm.getVBox()).andReturn(vBox).anyTimes();
|
expect(vbm.getVBox()).andReturn(vBox).anyTimes();
|
||||||
|
|
||||||
|
expect(vm.getName()).andReturn(VirtualBoxConstants.VIRTUALBOX_IMAGE_PREFIX + "my-vm-id").anyTimes();
|
||||||
String unknownOsDescription = "SomeOtherOs 2.04";
|
String unknownOsDescription = "SomeOtherOs 2.04";
|
||||||
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
|
expect(vm.getOSTypeId()).andReturn("os-type").anyTimes();
|
||||||
expect(vm.getDescription()).andReturn("my-unknown-machine").anyTimes();
|
expect(vm.getDescription()).andReturn("my-unknown-machine").anyTimes();
|
||||||
|
@ -136,6 +142,7 @@ public class IMachineToImageTest {
|
||||||
|
|
||||||
assertEquals(image.getOperatingSystem().getDescription(), "SomeOtherOs 2.04");
|
assertEquals(image.getOperatingSystem().getDescription(), "SomeOtherOs 2.04");
|
||||||
assertEquals(image.getOperatingSystem().getVersion(), "");
|
assertEquals(image.getOperatingSystem().getVersion(), "");
|
||||||
|
assertEquals(image.getId(), "my-vm-id");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import static org.easymock.EasyMock.expect;
|
||||||
import static org.easymock.EasyMock.replay;
|
import static org.easymock.EasyMock.replay;
|
||||||
import static org.easymock.EasyMock.verify;
|
import static org.easymock.EasyMock.verify;
|
||||||
|
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
import org.virtualbox_4_1.IConsole;
|
import org.virtualbox_4_1.IConsole;
|
||||||
import org.virtualbox_4_1.IMachine;
|
import org.virtualbox_4_1.IMachine;
|
||||||
|
@ -31,6 +32,7 @@ import org.virtualbox_4_1.IProgress;
|
||||||
import org.virtualbox_4_1.ISession;
|
import org.virtualbox_4_1.ISession;
|
||||||
import org.virtualbox_4_1.ISnapshot;
|
import org.virtualbox_4_1.ISnapshot;
|
||||||
import org.virtualbox_4_1.IVirtualBox;
|
import org.virtualbox_4_1.IVirtualBox;
|
||||||
|
import org.virtualbox_4_1.MachineState;
|
||||||
import org.virtualbox_4_1.VirtualBoxManager;
|
import org.virtualbox_4_1.VirtualBoxManager;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.google.common.base.Suppliers;
|
||||||
|
@ -55,6 +57,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
|
||||||
IProgress progress = createNiceMock(IProgress.class);
|
IProgress progress = createNiceMock(IProgress.class);
|
||||||
ISnapshot snapshot = createNiceMock(ISnapshot.class);
|
ISnapshot snapshot = createNiceMock(ISnapshot.class);
|
||||||
expect(machine.getCurrentSnapshot()).andReturn(snapshot).anyTimes();
|
expect(machine.getCurrentSnapshot()).andReturn(snapshot).anyTimes();
|
||||||
|
expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
|
||||||
|
|
||||||
expect(manager.openMachineSession(machine)).andReturn(session);
|
expect(manager.openMachineSession(machine)).andReturn(session);
|
||||||
|
|
||||||
|
@ -66,7 +69,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
|
||||||
session.unlockMachine();
|
session.unlockMachine();
|
||||||
replay(manager, machine, vBox, session, console, progress);
|
replay(manager, machine, vBox, session, console, progress);
|
||||||
|
|
||||||
new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc)
|
new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc, Logger.CONSOLE)
|
||||||
.apply(machine);
|
.apply(machine);
|
||||||
|
|
||||||
verify(machine);
|
verify(machine);
|
||||||
|
@ -87,6 +90,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
|
||||||
expect(progress.getCompleted()).andReturn(true);
|
expect(progress.getCompleted()).andReturn(true);
|
||||||
expect(machine.getCurrentSnapshot()).andReturn(null).anyTimes();
|
expect(machine.getCurrentSnapshot()).andReturn(null).anyTimes();
|
||||||
expect(manager.openMachineSession(machine)).andReturn(session);
|
expect(manager.openMachineSession(machine)).andReturn(session);
|
||||||
|
expect(machine.getState()).andReturn(MachineState.PoweredOff).anyTimes();
|
||||||
|
|
||||||
expect(machine.getName()).andReturn("machine").anyTimes();
|
expect(machine.getName()).andReturn("machine").anyTimes();
|
||||||
expect(session.getConsole()).andReturn(console);
|
expect(session.getConsole()).andReturn(console);
|
||||||
|
@ -96,7 +100,7 @@ public class TakeSnapshotIfNotAlreadyAttachedTest {
|
||||||
session.unlockMachine();
|
session.unlockMachine();
|
||||||
replay(manager, machine, vBox, session, console, progress);
|
replay(manager, machine, vBox, session, console, progress);
|
||||||
|
|
||||||
new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc)
|
new TakeSnapshotIfNotAlreadyAttached(Suppliers.ofInstance(manager), snapshotName, snapshotDesc, Logger.CONSOLE)
|
||||||
.apply(machine);
|
.apply(machine);
|
||||||
|
|
||||||
verify(machine);
|
verify(machine);
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.virtualbox.functions.admin;
|
||||||
|
|
||||||
import static org.easymock.EasyMock.createMock;
|
import static org.easymock.EasyMock.createMock;
|
||||||
import static org.easymock.EasyMock.expect;
|
import static org.easymock.EasyMock.expect;
|
||||||
|
import static org.easymock.EasyMock.expectLastCall;
|
||||||
import static org.easymock.EasyMock.replay;
|
import static org.easymock.EasyMock.replay;
|
||||||
import static org.easymock.EasyMock.verify;
|
import static org.easymock.EasyMock.verify;
|
||||||
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
|
import static org.jclouds.compute.options.RunScriptOptions.Builder.runAsRoot;
|
||||||
|
@ -58,10 +59,9 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
|
||||||
String identity = "adminstrator";
|
String identity = "adminstrator";
|
||||||
String credential = "12345";
|
String credential = "12345";
|
||||||
expect(client.seconds(3)).andReturn(client);
|
expect(client.seconds(3)).andReturn(client);
|
||||||
|
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true).anyTimes();
|
||||||
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
|
|
||||||
|
|
||||||
manager.connect(provider.toASCIIString(), "", "");
|
manager.connect(provider.toASCIIString(), "", "");
|
||||||
|
expectLastCall().anyTimes();
|
||||||
|
|
||||||
replay(manager, runScriptOnNodeFactory, client);
|
replay(manager, runScriptOnNodeFactory, client);
|
||||||
|
|
||||||
|
@ -87,17 +87,18 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
|
||||||
String credential = "12345";
|
String credential = "12345";
|
||||||
|
|
||||||
expect(client.seconds(3)).andReturn(client);
|
expect(client.seconds(3)).andReturn(client);
|
||||||
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(false);
|
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(false).once().andReturn(true).once();
|
||||||
expect(
|
expect(
|
||||||
runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
|
runScriptOnNodeFactory.create(host, Statements.exec("VBoxManage setproperty websrvauthlibrary null"),
|
||||||
runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode);
|
runAsRoot(false).wrapInInitScript(false))).andReturn(runScriptOnNode);
|
||||||
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
|
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
|
||||||
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
|
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
|
||||||
expect(client.apply(new IPSocket(provider.getHost(), provider.getPort()))).andReturn(true);
|
|
||||||
expect(
|
expect(
|
||||||
runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false)
|
runScriptOnNodeFactory.create(host, Statements.exec("vboxwebsrv -t 10000 -v -b"), runAsRoot(false)
|
||||||
.wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn(
|
.wrapInInitScript(false).blockOnComplete(false).nameTask("vboxwebsrv"))).andReturn(
|
||||||
runScriptOnNode);
|
runScriptOnNode);
|
||||||
|
|
||||||
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
|
expect(runScriptOnNode.init()).andReturn(runScriptOnNode);
|
||||||
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
|
expect(runScriptOnNode.call()).andReturn(new ExecResponse("", "", 0));
|
||||||
|
|
||||||
|
@ -105,7 +106,7 @@ public class StartVBoxIfNotAlreadyRunningLiveTest {
|
||||||
|
|
||||||
replay(manager, runScriptOnNodeFactory, runScriptOnNode, client);
|
replay(manager, runScriptOnNodeFactory, runScriptOnNode, client);
|
||||||
new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
|
new StartVBoxIfNotAlreadyRunning((Function) Functions.constant(manager), runScriptOnNodeFactory, client,
|
||||||
Suppliers.ofInstance(host), Suppliers.ofInstance(provider), identity, credential).start();
|
Suppliers.ofInstance(host), Suppliers.ofInstance(provider), identity, credential);
|
||||||
verify(manager, runScriptOnNodeFactory, runScriptOnNode, client);
|
verify(manager, runScriptOnNodeFactory, runScriptOnNode, client);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
</appender>
|
</appender>
|
||||||
|
|
||||||
<root>
|
<root>
|
||||||
<level value="debug" />
|
<level value="DEBUG" />
|
||||||
<appender-ref ref="CONSOLE" />
|
<appender-ref ref="CONSOLE" />
|
||||||
</root>
|
</root>
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
<logger name="jclouds.wire">
|
<logger name="jclouds.wire">
|
||||||
<level value="INFO" />
|
<level value="DEBUG" />
|
||||||
<appender-ref ref="WIREFILE" />
|
<appender-ref ref="WIREFILE" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ import org.jclouds.aws.ec2.domain.PlacementGroup.State;
|
||||||
import org.jclouds.aws.util.AWSUtils;
|
import org.jclouds.aws.util.AWSUtils;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.RunNodesException;
|
import org.jclouds.compute.RunNodesException;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
|
@ -72,6 +73,7 @@ import org.jclouds.util.Preconditions2;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.cache.LoadingCache;
|
import com.google.common.cache.LoadingCache;
|
||||||
|
@ -111,12 +113,13 @@ public class AWSEC2ComputeService extends EC2ComputeService {
|
||||||
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
|
@Named("SECURITY") LoadingCache<RegionAndName, String> securityGroupMap,
|
||||||
@Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
|
@Named("PLACEMENT") LoadingCache<RegionAndName, String> placementGroupMap,
|
||||||
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted,
|
@Named("DELETED") Predicate<PlacementGroup> placementGroupDeleted,
|
||||||
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient) {
|
@Named(PROPERTY_EC2_GENERATE_INSTANCE_NAMES) boolean generateInstanceNames, AWSEC2AsyncClient aclient,
|
||||||
|
Optional<ImageExtension> imageExtension) {
|
||||||
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
|
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
|
||||||
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
||||||
nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials,
|
nodeSuspended, initScriptRunnerFactory, runScriptOnNodeFactory, initAdminAccess, persistNodeCredentials,
|
||||||
timeouts, executor, ec2Client, credentialsMap, securityGroupMap);
|
timeouts, executor, ec2Client, credentialsMap, securityGroupMap, imageExtension);
|
||||||
this.ec2Client = ec2Client;
|
this.ec2Client = ec2Client;
|
||||||
this.placementGroupMap = placementGroupMap;
|
this.placementGroupMap = placementGroupMap;
|
||||||
this.placementGroupDeleted = placementGroupDeleted;
|
this.placementGroupDeleted = placementGroupDeleted;
|
||||||
|
|
|
@ -31,6 +31,7 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.Constants;
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
|
@ -53,6 +54,7 @@ import org.jclouds.domain.Location;
|
||||||
import org.jclouds.gogrid.compute.options.GoGridTemplateOptions;
|
import org.jclouds.gogrid.compute.options.GoGridTemplateOptions;
|
||||||
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
|
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
|
|
||||||
|
@ -74,12 +76,12 @@ public class GoGridComputeService extends BaseComputeService {
|
||||||
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
|
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
|
||||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
|
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
|
||||||
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
|
||||||
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor) {
|
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Optional<ImageExtension> imageExtension) {
|
||||||
super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
|
super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
|
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
|
||||||
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
||||||
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
|
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials, timeouts,
|
||||||
executor);
|
executor, imageExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.jclouds.hpcloud.compute.compute;
|
||||||
|
|
||||||
|
import org.jclouds.compute.internal.BaseImageExtensionLiveTest;
|
||||||
|
import org.jclouds.sshj.config.SshjSshClientModule;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.inject.Module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author David Alves
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Test(groups = "live", singleThreaded = true, testName = "HPCloudComputeImageExtensionLivetest")
|
||||||
|
public class HPCloudComputeImageExtensionLivetest extends BaseImageExtensionLiveTest {
|
||||||
|
|
||||||
|
public HPCloudComputeImageExtensionLivetest() {
|
||||||
|
provider = "hpcloud-compute";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Module getSshModule() {
|
||||||
|
return new SshjSshClientModule();
|
||||||
|
}
|
||||||
|
}
|
|
@ -31,6 +31,7 @@ import javax.inject.Singleton;
|
||||||
import org.jclouds.Constants;
|
import org.jclouds.Constants;
|
||||||
import org.jclouds.collect.Memoized;
|
import org.jclouds.collect.Memoized;
|
||||||
import org.jclouds.compute.ComputeServiceContext;
|
import org.jclouds.compute.ComputeServiceContext;
|
||||||
|
import org.jclouds.compute.ImageExtension;
|
||||||
import org.jclouds.compute.callables.RunScriptOnNode;
|
import org.jclouds.compute.callables.RunScriptOnNode;
|
||||||
import org.jclouds.compute.domain.Hardware;
|
import org.jclouds.compute.domain.Hardware;
|
||||||
import org.jclouds.compute.domain.Image;
|
import org.jclouds.compute.domain.Image;
|
||||||
|
@ -55,6 +56,7 @@ import org.libvirt.Connect;
|
||||||
import org.libvirt.StorageVol;
|
import org.libvirt.StorageVol;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
|
@ -85,12 +87,13 @@ public class LibvirtComputeService extends BaseComputeService {
|
||||||
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
|
@Named("NODE_SUSPENDED") Predicate<NodeMetadata> nodeSuspended,
|
||||||
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
|
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory, InitAdminAccess initAdminAccess,
|
||||||
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
|
RunScriptOnNode.Factory runScriptOnNodeFactory, PersistNodeCredentials persistNodeCredentials,
|
||||||
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Connect client) {
|
Timeouts timeouts, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, Connect client,
|
||||||
|
Optional<ImageExtension> imageExtension) {
|
||||||
super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
|
super(context, credentialStore, images, hardwareProfiles, locations, listNodesStrategy, getNodeMetadataStrategy,
|
||||||
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
|
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, resumeNodeStrategy,
|
||||||
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
suspendNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
|
||||||
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
|
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
|
||||||
timeouts, executor);
|
timeouts, executor, imageExtension);
|
||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue