openstack implicit security group integration with compute service; ensured hpcloud doesn't pickup kernel or ramdisk images

This commit is contained in:
Adrian Cole 2012-03-20 22:37:18 -07:00
parent ac2528ef6f
commit c9b5b1db87
55 changed files with 1380 additions and 360 deletions

View File

@ -205,6 +205,24 @@ public class NodePredicates {
}; };
} }
/**
* Return nodes who have a value for {@link NodeMetadata#getGroup}
*
*/
public static Predicate<NodeMetadata> hasGroup() {
return new Predicate<NodeMetadata>() {
@Override
public boolean apply(NodeMetadata nodeMetadata) {
return nodeMetadata.getGroup() != null;
}
@Override
public String toString() {
return "hasGroup()";
}
};
}
/** /**
* Return nodes with specified group that are in the NODE_RUNNING state. * Return nodes with specified group that are in the NODE_RUNNING state.
* *

View File

@ -243,5 +243,5 @@ filesystem.propertiesbuilder=org.jclouds.filesystem.FilesystemBlobStorePropertie
hpcloud-objectstorage-lvs.contextbuilder=org.jclouds.hpcloud.objectstorage.lvs.HPCloudObjectStorageLasVegasContextBuilder hpcloud-objectstorage-lvs.contextbuilder=org.jclouds.hpcloud.objectstorage.lvs.HPCloudObjectStorageLasVegasContextBuilder
hpcloud-objectstorage-lvs.propertiesbuilder=org.jclouds.hpcloud.objectstorage.lvs.HPCloudObjectStorageLasVegasPropertiesBuilder hpcloud-objectstorage-lvs.propertiesbuilder=org.jclouds.hpcloud.objectstorage.lvs.HPCloudObjectStorageLasVegasPropertiesBuilder
hpcloud-compute.contextbuilder=org.jclouds.openstack.nova.v1_1.NovaContextBuilder hpcloud-compute.contextbuilder=org.jclouds.hpcloud.compute.HPCloudComputeContextBuilder
hpcloud-compute.propertiesbuilder=org.jclouds.hpcloud.compute.HPCloudComputePropertiesBuilder hpcloud-compute.propertiesbuilder=org.jclouds.hpcloud.compute.HPCloudComputePropertiesBuilder

View File

@ -16,32 +16,28 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.domain; package org.jclouds.hpcloud.compute;
import java.util.List;
import java.util.Properties;
import org.jclouds.hpcloud.compute.config.HPCloudComputeServiceContextModule;
import org.jclouds.openstack.nova.v1_1.NovaContextBuilder;
import com.google.inject.Module;
/** /**
* In-flight images will have the status attribute set to SAVING and the
* conditional progress element (0-100% completion) will also be returned. Other
* possible values for the status attribute include: UNKNOWN, ACTIVE, SAVING,
* ERROR, and DELETED. Images with an ACTIVE status are available for install.
* The optional minDisk and minRam attributes set the minimum disk and RAM
* requirements needed to create a server with the image.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public enum ImageStatus { public class HPCloudComputeContextBuilder extends NovaContextBuilder {
UNRECOGNIZED, UNKNOWN, ACTIVE, SAVING, ERROR, DELETED; public HPCloudComputeContextBuilder(Properties props) {
super(props);
public String value() {
return name();
} }
public static ImageStatus fromValue(String v) { @Override
try { protected void addContextModule(List<Module> modules) {
return valueOf(v); modules.add(new HPCloudComputeServiceContextModule());
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
} }
} }
}

View File

@ -20,11 +20,12 @@ package org.jclouds.hpcloud.compute;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_ISO3166_CODES; import static org.jclouds.Constants.PROPERTY_ISO3166_CODES;
import static org.jclouds.compute.reference.ComputeServiceConstants.PROPERTY_TIMEOUT_NODE_TERMINATED;
import static org.jclouds.openstack.nova.v1_1.reference.NovaConstants.PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS;
import java.util.Properties; import java.util.Properties;
import org.jclouds.openstack.nova.v1_1.NovaPropertiesBuilder; import org.jclouds.openstack.nova.v1_1.NovaPropertiesBuilder;
import org.jclouds.openstack.nova.v1_1.reference.NovaConstants;
/** /**
* *
@ -37,7 +38,9 @@ public class HPCloudComputePropertiesBuilder extends NovaPropertiesBuilder {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ISO3166_CODES, "US-NV"); properties.setProperty(PROPERTY_ISO3166_CODES, "US-NV");
properties.setProperty(PROPERTY_ENDPOINT, "https://region-a.geo-1.identity.hpcloudsvc.com:35357"); properties.setProperty(PROPERTY_ENDPOINT, "https://region-a.geo-1.identity.hpcloudsvc.com:35357");
properties.setProperty(NovaConstants.PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS, "true"); properties.setProperty(PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS, "true");
// deallocating ip addresses can take a while
properties.setProperty(PROPERTY_TIMEOUT_NODE_TERMINATED, 60 * 1000 + "");
return properties; return properties;
} }

View File

@ -0,0 +1,45 @@
package org.jclouds.hpcloud.compute;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.location.Zone;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
import org.jclouds.openstack.nova.v1_1.compute.functions.RemoveFloatingIpFromNodeAndDeallocate;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
public class HPCloudComputeServiceAdapter extends NovaComputeServiceAdapter {
@Inject
public HPCloudComputeServiceAdapter(NovaClient novaClient, @Zone Supplier<Set<String>> zoneIds,
RemoveFloatingIpFromNodeAndDeallocate removeFloatingIpFromNodeAndDeallocate) {
super(novaClient, zoneIds, removeFloatingIpFromNodeAndDeallocate);
}
@Override
public Iterable<ImageInZone> listImages() {
return Iterables.filter(super.listImages(), new Predicate<ImageInZone>() {
@Override
public boolean apply(ImageInZone arg0) {
String imageName = arg0.getImage().getName();
return imageName.indexOf("Kernel") == -1 && imageName.indexOf("Ramdisk") == -1;
}
@Override
public String toString() {
return "notKernelOrRamdisk";
}
});
}
}

View File

@ -0,0 +1,37 @@
/**
* 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.config;
import org.jclouds.hpcloud.compute.HPCloudComputeServiceAdapter;
import org.jclouds.openstack.nova.v1_1.compute.NovaComputeServiceAdapter;
import org.jclouds.openstack.nova.v1_1.compute.config.NovaComputeServiceContextModule;
/**
*
* @author Adrian Cole
*/
public class HPCloudComputeServiceContextModule extends NovaComputeServiceContextModule {
@Override
protected void configure() {
super.configure();
bind(NovaComputeServiceAdapter.class).to(HPCloudComputeServiceAdapter.class);
}
}

View File

@ -73,6 +73,7 @@ public class HPCloudComputeTemplateBuilderLiveTest extends BaseTemplateBuilderLi
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "11.10"); assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "11.10");
assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU); assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(defaultTemplate.getImage().getName(), "Ubuntu Oneiric 11.10 Server 64-bit 20111212");
assertEquals(defaultTemplate.getLocation().getId(), "az-1.region-a.geo-1"); assertEquals(defaultTemplate.getLocation().getId(), "az-1.region-a.geo-1");
assertEquals(defaultTemplate.getOptions().as(NovaTemplateOptions.class).shouldAutoAssignFloatingIp(), true); assertEquals(defaultTemplate.getOptions().as(NovaTemplateOptions.class).shouldAutoAssignFloatingIp(), true);
assertEquals(getCores(defaultTemplate.getHardware()), 1.0d); assertEquals(getCores(defaultTemplate.getHardware()), 1.0d);

View File

@ -45,7 +45,6 @@ public class NovaPropertiesBuilder extends PropertiesBuilder {
properties.setProperty(PROPERTY_API_VERSION, "1.1"); properties.setProperty(PROPERTY_API_VERSION, "1.1");
properties.setProperty(PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS, "false"); properties.setProperty(PROPERTY_NOVA_AUTO_ALLOCATE_FLOATING_IPS, "false");
properties.setProperty(PROPERTY_NOVA_TIMEOUT_SECURITYGROUP_PRESENT, "500"); properties.setProperty(PROPERTY_NOVA_TIMEOUT_SECURITYGROUP_PRESENT, "500");
return properties; return properties;
} }

View File

@ -0,0 +1,147 @@
/**
* 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 java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.callables.RunScriptOnNode;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.internal.BaseComputeService;
import org.jclouds.compute.internal.PersistNodeCredentials;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants.Timeouts;
import org.jclouds.compute.strategy.CreateNodesInGroupThenAddToSet;
import org.jclouds.compute.strategy.DestroyNodeStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.strategy.InitializeRunScriptOnNodeOrPlaceInBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy;
import org.jclouds.compute.strategy.ResumeNodeStrategy;
import org.jclouds.compute.strategy.SuspendNodeStrategy;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.Location;
import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
import org.jclouds.openstack.nova.v1_1.predicates.SecurityGroupPredicates;
import org.jclouds.scriptbuilder.functions.InitAdminAccess;
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.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/**
* @author Adrian Cole
*/
@Singleton
public class NovaComputeService extends BaseComputeService {
private final NovaClient novaClient;
private final LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap;
private final Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId;
@Inject
protected NovaComputeService(ComputeServiceContext context, Map<String, Credentials> credentialStore,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> sizes,
@Memoized Supplier<Set<? extends Location>> locations, ListNodesStrategy listNodesStrategy,
GetNodeMetadataStrategy getNodeMetadataStrategy,
CreateNodesInGroupThenAddToSet runNodesAndAddToSetStrategy, RebootNodeStrategy rebootNodeStrategy,
DestroyNodeStrategy destroyNodeStrategy, ResumeNodeStrategy startNodeStrategy,
SuspendNodeStrategy stopNodeStrategy, Provider<TemplateBuilder> templateBuilderProvider,
Provider<TemplateOptions> templateOptionsProvider,
@Named("NODE_RUNNING") Predicate<AtomicReference<NodeMetadata>> nodeRunning,
@Named("NODE_TERMINATED") Predicate<AtomicReference<NodeMetadata>> nodeTerminated,
@Named("NODE_SUSPENDED") Predicate<AtomicReference<NodeMetadata>> nodeSuspended,
InitializeRunScriptOnNodeOrPlaceInBadMap.Factory initScriptRunnerFactory,
RunScriptOnNode.Factory runScriptOnNodeFactory, InitAdminAccess initAdminAccess,
PersistNodeCredentials persistNodeCredentials, Timeouts timeouts,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, NovaClient novaClient,
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap,
Function<Set<? extends NodeMetadata>, Multimap<String, String>> orphanedGroupsByZoneId) {
super(context, credentialStore, images, sizes, locations, listNodesStrategy, getNodeMetadataStrategy,
runNodesAndAddToSetStrategy, rebootNodeStrategy, destroyNodeStrategy, startNodeStrategy,
stopNodeStrategy, templateBuilderProvider, templateOptionsProvider, nodeRunning, nodeTerminated,
nodeSuspended, initScriptRunnerFactory, initAdminAccess, runScriptOnNodeFactory, persistNodeCredentials,
timeouts, executor);
this.novaClient = checkNotNull(novaClient, "novaClient");
this.securityGroupMap = checkNotNull(securityGroupMap, "securityGroupMap");
this.orphanedGroupsByZoneId = checkNotNull(orphanedGroupsByZoneId, "orphanedGroupsByZoneId");
}
@Override
protected void cleanUpIncidentalResourcesOfDeadNodes(Set<? extends NodeMetadata> deadNodes) {
Multimap<String, String> zoneToZoneAndGroupNames = orphanedGroupsByZoneId.apply(deadNodes);
for (String zoneId : zoneToZoneAndGroupNames.keySet()) {
cleanOrphanedGroupsInZone(ImmutableSet.copyOf(zoneToZoneAndGroupNames.get(zoneId)), zoneId);
}
}
protected void cleanOrphanedGroupsInZone(Set<String> groups, String zoneId) {
cleanupOrphanedSecurityGroupsInZone(groups, zoneId);
}
private void cleanupOrphanedSecurityGroupsInZone(Set<String> groups, String zoneId) {
Optional<SecurityGroupClient> securityGroupClient = novaClient.getSecurityGroupExtensionForZone(zoneId);
if (securityGroupClient.isPresent()) {
for (String group : groups) {
for (SecurityGroup securityGroup : Iterables.filter(securityGroupClient.get().listSecurityGroups(),
SecurityGroupPredicates.nameEquals("jclouds#" + group))) {
ZoneAndName zoneAndName = ZoneAndName.fromZoneAndName(zoneId, securityGroup.getName());
logger.debug(">> deleting securityGroup(%s)", zoneAndName);
securityGroupClient.get().deleteSecurityGroup(securityGroup.getId());
// TODO: test this clear happens
securityGroupMap.invalidate(zoneAndName);
logger.debug("<< deleted securityGroup(%s)", zoneAndName);
}
}
}
}
/**
* returns template options, except of type {@link NovaTemplateOptions}.
*/
@Override
public NovaTemplateOptions templateOptions() {
return NovaTemplateOptions.class.cast(super.templateOptions());
}
}

View File

@ -34,10 +34,6 @@ import org.jclouds.domain.LoginCredentials;
import org.jclouds.location.Zone; import org.jclouds.location.Zone;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.FlavorInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ImageInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ServerInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.compute.functions.RemoveFloatingIpFromNodeAndDeallocate; import org.jclouds.openstack.nova.v1_1.compute.functions.RemoveFloatingIpFromNodeAndDeallocate;
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions; import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
@ -45,12 +41,17 @@ import org.jclouds.openstack.nova.v1_1.domain.Flavor;
import org.jclouds.openstack.nova.v1_1.domain.Image; import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.openstack.nova.v1_1.domain.RebootType; import org.jclouds.openstack.nova.v1_1.domain.RebootType;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.FlavorInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.options.CreateServerOptions; import org.jclouds.openstack.nova.v1_1.options.CreateServerOptions;
import org.jclouds.openstack.nova.v1_1.predicates.ImagePredicates;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables; import static com.google.common.collect.Iterables.*;
import com.google.common.collect.ImmutableSet.Builder; import com.google.common.collect.ImmutableSet.Builder;
/** /**
@ -103,7 +104,7 @@ public class NovaComputeServiceAdapter implements
public Iterable<FlavorInZone> listHardwareProfiles() { public Iterable<FlavorInZone> listHardwareProfiles() {
Builder<FlavorInZone> builder = ImmutableSet.<FlavorInZone> builder(); Builder<FlavorInZone> builder = ImmutableSet.<FlavorInZone> builder();
for (final String zoneId : zoneIds.get()) { for (final String zoneId : zoneIds.get()) {
builder.addAll(Iterables.transform(novaClient.getFlavorClientForZone(zoneId).listFlavorsInDetail(), builder.addAll(transform(novaClient.getFlavorClientForZone(zoneId).listFlavorsInDetail(),
new Function<Flavor, FlavorInZone>() { new Function<Flavor, FlavorInZone>() {
@Override @Override
@ -120,8 +121,8 @@ public class NovaComputeServiceAdapter implements
public Iterable<ImageInZone> listImages() { public Iterable<ImageInZone> listImages() {
Builder<ImageInZone> builder = ImmutableSet.<ImageInZone> builder(); Builder<ImageInZone> builder = ImmutableSet.<ImageInZone> builder();
for (final String zoneId : zoneIds.get()) { for (final String zoneId : zoneIds.get()) {
builder.addAll(Iterables.transform(novaClient.getImageClientForZone(zoneId).listImagesInDetail(), builder.addAll(transform(filter(novaClient.getImageClientForZone(zoneId).listImagesInDetail(), ImagePredicates
new Function<Image, ImageInZone>() { .statusEquals(Image.Status.ACTIVE)), new Function<Image, ImageInZone>() {
@Override @Override
public ImageInZone apply(Image arg0) { public ImageInZone apply(Image arg0) {
@ -137,7 +138,7 @@ public class NovaComputeServiceAdapter implements
public Iterable<ServerInZone> listNodes() { public Iterable<ServerInZone> listNodes() {
Builder<ServerInZone> builder = ImmutableSet.<ServerInZone> builder(); Builder<ServerInZone> builder = ImmutableSet.<ServerInZone> builder();
for (final String zoneId : zoneIds.get()) { for (final String zoneId : zoneIds.get()) {
builder.addAll(Iterables.transform(novaClient.getServerClientForZone(zoneId).listServersInDetail(), builder.addAll(transform(novaClient.getServerClientForZone(zoneId).listServersInDetail(),
new Function<Server, ServerInZone>() { new Function<Server, ServerInZone>() {
@Override @Override

View File

@ -27,6 +27,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.ComputeService;
import org.jclouds.compute.ComputeServiceAdapter; import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.config.ComputeServiceAdapterContextModule; import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
@ -39,23 +40,25 @@ import org.jclouds.domain.Location;
import org.jclouds.functions.IdentityFunction; import org.jclouds.functions.IdentityFunction;
import org.jclouds.openstack.nova.v1_1.NovaAsyncClient; import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
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.domain.FlavorInZone; import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.openstack.nova.v1_1.compute.domain.ImageInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ServerInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupInZone;
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;
import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToOperatingSystem; import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToOperatingSystem;
import org.jclouds.openstack.nova.v1_1.compute.functions.OrphanedGroupsByZoneId;
import org.jclouds.openstack.nova.v1_1.compute.functions.ServerInZoneToNodeMetadata; import org.jclouds.openstack.nova.v1_1.compute.functions.ServerInZoneToNodeMetadata;
import org.jclouds.openstack.nova.v1_1.compute.loaders.CreateOrUpdateSecurityGroupAsNeeded; import org.jclouds.openstack.nova.v1_1.compute.loaders.FindSecurityGroupOrCreate;
import org.jclouds.openstack.nova.v1_1.compute.loaders.LoadFloatingIpsForInstance; import org.jclouds.openstack.nova.v1_1.compute.loaders.LoadFloatingIpsForInstance;
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions; import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet; import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.FlavorInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndReturnTrue; import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndReturnTrue;
import org.jclouds.openstack.nova.v1_1.reference.NovaConstants; import org.jclouds.openstack.nova.v1_1.reference.NovaConstants;
import org.jclouds.predicates.RetryablePredicate; import org.jclouds.predicates.RetryablePredicate;
@ -68,6 +71,7 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader; import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.inject.Injector; import com.google.inject.Injector;
import com.google.inject.Key; import com.google.inject.Key;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -93,9 +97,14 @@ public class NovaComputeServiceContextModule
bind(new TypeLiteral<ComputeServiceAdapter<ServerInZone, FlavorInZone, ImageInZone, Location>>() { bind(new TypeLiteral<ComputeServiceAdapter<ServerInZone, FlavorInZone, ImageInZone, Location>>() {
}).to(NovaComputeServiceAdapter.class); }).to(NovaComputeServiceAdapter.class);
bind(ComputeService.class).to(NovaComputeService.class);
bind(new TypeLiteral<Function<ServerInZone, NodeMetadata>>() { bind(new TypeLiteral<Function<ServerInZone, NodeMetadata>>() {
}).to(ServerInZoneToNodeMetadata.class); }).to(ServerInZoneToNodeMetadata.class);
bind(new TypeLiteral<Function<Set<? extends NodeMetadata>, Multimap<String, String>>>() {
}).to(OrphanedGroupsByZoneId.class);
bind(new TypeLiteral<Function<ImageInZone, Image>>() { bind(new TypeLiteral<Function<ImageInZone, Image>>() {
}).to(ImageInZoneToImage.class); }).to(ImageInZoneToImage.class);
bind(new TypeLiteral<Function<org.jclouds.openstack.nova.v1_1.domain.Image, OperatingSystem>>() { bind(new TypeLiteral<Function<org.jclouds.openstack.nova.v1_1.domain.Image, OperatingSystem>>() {
@ -114,10 +123,10 @@ public class NovaComputeServiceContextModule
}).annotatedWith(Names.named("FLOATINGIP")).to(LoadFloatingIpsForInstance.class); }).annotatedWith(Names.named("FLOATINGIP")).to(LoadFloatingIpsForInstance.class);
bind(new TypeLiteral<Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>>() { bind(new TypeLiteral<Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>>() {
}).to(CreateSecurityGroupInZone.class); }).to(CreateSecurityGroupIfNeeded.class);
bind(new TypeLiteral<CacheLoader<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>>() { bind(new TypeLiteral<CacheLoader<ZoneAndName, SecurityGroupInZone>>() {
}).to(CreateOrUpdateSecurityGroupAsNeeded.class); }).to(FindSecurityGroupOrCreate.class);
bind(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to( bind(CreateNodesWithGroupEncodedIntoNameThenAddToSet.class).to(
ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.class); ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet.class);
@ -141,8 +150,8 @@ public class NovaComputeServiceContextModule
@Provides @Provides
@Singleton @Singleton
protected LoadingCache<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> securityGroupMap( protected LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupMap(
CacheLoader<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> in) { CacheLoader<ZoneAndName, SecurityGroupInZone> in) {
return CacheBuilder.newBuilder().build(in); return CacheBuilder.newBuilder().build(in);
} }

View File

@ -34,8 +34,8 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP; import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient; import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient;
import org.jclouds.rest.InsufficientResourcesException; import org.jclouds.rest.InsufficientResourcesException;

View File

@ -20,6 +20,8 @@ package org.jclouds.openstack.nova.v1_1.compute.functions;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.find;
import static org.jclouds.openstack.nova.v1_1.predicates.SecurityGroupPredicates.nameEquals;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
@ -29,11 +31,11 @@ import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.domain.Ingress; import org.jclouds.openstack.nova.v1_1.domain.Ingress;
import org.jclouds.openstack.nova.v1_1.domain.IpProtocol; import org.jclouds.openstack.nova.v1_1.domain.IpProtocol;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup; import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient; import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -44,14 +46,14 @@ import com.google.common.base.Optional;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class CreateSecurityGroupInZone implements Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> { public class CreateSecurityGroupIfNeeded implements Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> {
@Resource @Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER) @Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
protected final NovaClient novaClient; protected final NovaClient novaClient;
@Inject @Inject
public CreateSecurityGroupInZone(NovaClient novaClient) { public CreateSecurityGroupIfNeeded(NovaClient novaClient) {
this.novaClient = checkNotNull(novaClient, "novaClient"); this.novaClient = checkNotNull(novaClient, "novaClient");
} }
@ -62,8 +64,9 @@ public class CreateSecurityGroupInZone implements Function<ZoneSecurityGroupName
String zoneId = zoneSecurityGroupNameAndPorts.getZone(); String zoneId = zoneSecurityGroupNameAndPorts.getZone();
Optional<SecurityGroupClient> client = novaClient.getSecurityGroupExtensionForZone(zoneId); Optional<SecurityGroupClient> client = novaClient.getSecurityGroupExtensionForZone(zoneId);
checkArgument(client.isPresent(), "Security groups are required, but the extension is not available!"); checkArgument(client.isPresent(), "Security groups are required, but the extension is not available!");
logger.debug(">> creating securityGroup %s", zoneSecurityGroupNameAndPorts); logger.debug(">> creating securityGroup %s", zoneSecurityGroupNameAndPorts);
try {
SecurityGroup securityGroup = client.get().createSecurityGroupWithNameAndDescription( SecurityGroup securityGroup = client.get().createSecurityGroupWithNameAndDescription(
zoneSecurityGroupNameAndPorts.getName(), zoneSecurityGroupNameAndPorts.getName()); zoneSecurityGroupNameAndPorts.getName(), zoneSecurityGroupNameAndPorts.getName());
@ -72,6 +75,13 @@ public class CreateSecurityGroupInZone implements Function<ZoneSecurityGroupName
authorizeGroupToItselfAndAllIPsToTCPPort(client.get(), securityGroup, port); authorizeGroupToItselfAndAllIPsToTCPPort(client.get(), securityGroup, port);
} }
return new SecurityGroupInZone(client.get().getSecurityGroup(securityGroup.getId()), zoneId); return new SecurityGroupInZone(client.get().getSecurityGroup(securityGroup.getId()), zoneId);
} catch (IllegalStateException e) {
logger.trace("<< trying to find securityGroup(%s): %s", zoneSecurityGroupNameAndPorts, e.getMessage());
SecurityGroup group = find(client.get().listSecurityGroups(), nameEquals(zoneSecurityGroupNameAndPorts
.getName()));
logger.debug("<< reused securityGroup(%s)", group.getId());
return new SecurityGroupInZone(group, zoneId);
}
} }
private void authorizeGroupToItselfAndAllIPsToTCPPort(SecurityGroupClient securityGroupClient, private void authorizeGroupToItselfAndAllIPsToTCPPort(SecurityGroupClient securityGroupClient,

View File

@ -30,8 +30,8 @@ import org.jclouds.compute.domain.HardwareBuilder;
import org.jclouds.compute.domain.Processor; import org.jclouds.compute.domain.Processor;
import org.jclouds.compute.domain.internal.VolumeImpl; import org.jclouds.compute.domain.internal.VolumeImpl;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.openstack.nova.v1_1.compute.domain.FlavorInZone;
import org.jclouds.openstack.nova.v1_1.domain.Flavor; import org.jclouds.openstack.nova.v1_1.domain.Flavor;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.FlavorInZone;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;

View File

@ -29,7 +29,7 @@ import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.ImageBuilder; import org.jclouds.compute.domain.ImageBuilder;
import org.jclouds.compute.domain.OperatingSystem; import org.jclouds.compute.domain.OperatingSystem;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.openstack.nova.v1_1.compute.domain.ImageInZone; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
@ -55,8 +55,8 @@ public class ImageInZoneToImage implements Function<ImageInZone, Image> {
Location location = locationIndex.get().get(imageInZone.getZone()); Location location = locationIndex.get().get(imageInZone.getZone());
checkState(location != null, "location %s not in locationIndex: %s", imageInZone.getZone(), locationIndex.get()); checkState(location != null, "location %s not in locationIndex: %s", imageInZone.getZone(), locationIndex.get());
org.jclouds.openstack.nova.v1_1.domain.Image image = imageInZone.getImage(); org.jclouds.openstack.nova.v1_1.domain.Image image = imageInZone.getImage();
return new ImageBuilder() return new ImageBuilder().id(imageInZone.slashEncode()).providerId(image.getId()).name(image.getName())
.id(imageInZone.slashEncode()).providerId(image.getId()).name(image.getName()).operatingSystem( .userMetadata(image.getMetadata()).operatingSystem(imageToOs.apply(image)).description(image.getName())
imageToOs.apply(image)).description(image.getName()).location(location).build(); .location(location).build();
} }
} }

View File

@ -0,0 +1,79 @@
/**
* 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.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Sets.filter;
import java.util.Set;
import javax.inject.Inject;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.domain.LocationScope;
import org.jclouds.openstack.nova.v1_1.compute.predicates.AllNodesInGroupTerminated;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
/**
*
* @author Adrian Cole
*/
public class OrphanedGroupsByZoneId implements Function<Set<? extends NodeMetadata>, Multimap<String, String>> {
private final Predicate<ZoneAndName> allNodesInGroupTerminated;
@Inject
protected OrphanedGroupsByZoneId(ComputeService computeService) {
this(new AllNodesInGroupTerminated(checkNotNull(computeService, "computeService")));
}
@VisibleForTesting
OrphanedGroupsByZoneId(Predicate<ZoneAndName> allNodesInGroupTerminated) {
this.allNodesInGroupTerminated = checkNotNull(allNodesInGroupTerminated, "allNodesInGroupTerminated");
}
public Multimap<String, String> apply(Set<? extends NodeMetadata> deadNodes) {
Iterable<? extends NodeMetadata> nodesWithGroup = filter(deadNodes, NodePredicates.hasGroup());
Set<ZoneAndName> zoneAndGroupNames = ImmutableSet.copyOf(filter(transform(nodesWithGroup,
new Function<NodeMetadata, ZoneAndName>() {
@Override
public ZoneAndName apply(NodeMetadata input) {
String zoneId = input.getLocation().getScope() == LocationScope.HOST ? input.getLocation()
.getParent().getId() : input.getLocation().getId();
return ZoneAndName.fromZoneAndName(zoneId, input.getGroup());
}
}), allNodesInGroupTerminated));
Multimap<String, String> zoneToZoneAndGroupNames = Multimaps.transformValues(Multimaps.index(zoneAndGroupNames,
ZoneAndName.ZONE_FUNCTION), ZoneAndName.NAME_FUNCTION);
return zoneToZoneAndGroupNames;
}
}

View File

@ -27,7 +27,7 @@ import javax.inject.Named;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient; import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient;
import com.google.common.base.Function; import com.google.common.base.Function;

View File

@ -20,8 +20,13 @@ package org.jclouds.openstack.nova.v1_1.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.transform;
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName; import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
import java.net.Inet4Address;
import java.util.Map; import java.util.Map;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Set; import java.util.Set;
@ -42,16 +47,16 @@ import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.compute.domain.ServerInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.domain.Address; import org.jclouds.openstack.nova.v1_1.domain.Address;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
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.Supplier; import com.google.common.base.Supplier;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.Iterables; import com.google.common.net.InetAddresses;
/** /**
* A function for transforming a nova-specific Server into a generic NodeMetadata object. * A function for transforming a nova-specific Server into a generic NodeMetadata object.
@ -97,15 +102,29 @@ public class ServerInZoneToNodeMetadata implements Function<ServerInZone, NodeMe
builder.operatingSystem(findOperatingSystemForServerOrNull(serverInZone)); builder.operatingSystem(findOperatingSystemForServerOrNull(serverInZone));
builder.hardware(findHardwareForServerOrNull(serverInZone)); builder.hardware(findHardwareForServerOrNull(serverInZone));
builder.state(from.getStatus().getNodeState()); builder.state(from.getStatus().getNodeState());
builder.publicAddresses(getPublicAddresses(serverInZone)); builder.publicAddresses(filter(getPublicAddresses(serverInZone), isInet4Address));
builder.privateAddresses(Iterables.transform(from.getPrivateAddresses(), builder.privateAddresses(filter(transform(from.getPrivateAddresses(),
AddressToStringTransformationFunction.INSTANCE)); AddressToStringTransformationFunction.INSTANCE), isInet4Address));
return builder.build(); return builder.build();
} }
public static final Predicate<String> isInet4Address = new Predicate<String>() {
@Override
public boolean apply(String input) {
try {
// Note we can do this, as InetAddress is now on the white list
return (InetAddresses.forString(input) instanceof Inet4Address);
} catch (IllegalArgumentException e) {
// could be a hostname
return true;
}
}
};
protected Iterable<String> getPublicAddresses(ServerInZone serverInZone) { protected Iterable<String> getPublicAddresses(ServerInZone serverInZone) {
return Iterables.concat(Iterables.transform(serverInZone.getServer().getPublicAddresses(), return concat(transform(serverInZone.getServer().getPublicAddresses(),
AddressToStringTransformationFunction.INSTANCE), floatingIpCache.getUnchecked(serverInZone)); AddressToStringTransformationFunction.INSTANCE), floatingIpCache.getUnchecked(serverInZone));
} }
@ -131,7 +150,7 @@ public class ServerInZoneToNodeMetadata implements Function<ServerInZone, NodeMe
public <T extends ComputeMetadata> T findObjectOfTypeForServerOrNull(Set<? extends T> supply, String type, public <T extends ComputeMetadata> T findObjectOfTypeForServerOrNull(Set<? extends T> supply, String type,
final String objectId, final ZoneAndId serverInZone) { final String objectId, final ZoneAndId serverInZone) {
try { try {
return Iterables.find(supply, new Predicate<T>() { return find(supply, new Predicate<T>() {
@Override @Override
public boolean apply(T input) { public boolean apply(T input) {
return input.getId().equals(ZoneAndId.fromZoneAndId(serverInZone.getZone(), objectId).slashEncode()); return input.getId().equals(ZoneAndId.fromZoneAndId(serverInZone.getZone(), objectId).slashEncode());

View File

@ -1,83 +0,0 @@
/**
* 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.loaders;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.atomic.AtomicReference;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.CacheLoader;
/**
*
* @author Adrian Cole
*/
@Singleton
public class CreateOrUpdateSecurityGroupAsNeeded extends
CacheLoader<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> {
@Resource
@Named(ComputeServiceConstants.COMPUTE_LOGGER)
protected Logger logger = Logger.NULL;
protected final Predicate<AtomicReference<ZoneAndName>> securityGroupEventualConsistencyDelay;
protected final Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator;
@Inject
public CreateOrUpdateSecurityGroupAsNeeded(
@Named("SECURITY") Predicate<AtomicReference<ZoneAndName>> securityGroupEventualConsistencyDelay,
Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator) {
this.securityGroupEventualConsistencyDelay = checkNotNull(securityGroupEventualConsistencyDelay,
"securityGroupEventualConsistencyDelay");
this.groupCreator = checkNotNull(groupCreator, "groupCreator");
}
@Override
public SecurityGroupInZone load(ZoneSecurityGroupNameAndPorts zoneSecurityGroupNameAndPorts) {
checkNotNull(zoneSecurityGroupNameAndPorts, "zoneSecurityGroupNameAndPorts");
AtomicReference<ZoneAndName> securityGroupInZoneRef = new AtomicReference<ZoneAndName>(
zoneSecurityGroupNameAndPorts);
if (securityGroupEventualConsistencyDelay.apply(securityGroupInZoneRef)) {
ZoneAndName securityGroupInZone = securityGroupInZoneRef.get();
checkState(
securityGroupInZone instanceof SecurityGroupInZone,
"programming error: predicate %s should update the atomic reference to the actual security group found",
securityGroupEventualConsistencyDelay);
// TODO: check ports are actually present!
return SecurityGroupInZone.class.cast(securityGroupInZone);
} else {
return groupCreator.apply(zoneSecurityGroupNameAndPorts);
}
}
}

View File

@ -0,0 +1,88 @@
/**
* 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.loaders;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.cache.CacheLoader;
/**
*
* @author Adrian Cole
*/
public class FindSecurityGroupOrCreate extends CacheLoader<ZoneAndName, SecurityGroupInZone> {
protected final Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone;
protected final Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator;
@Inject
public FindSecurityGroupOrCreate(
@Named("SECURITY") Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone,
Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator) {
this.returnSecurityGroupExistsInZone = checkNotNull(returnSecurityGroupExistsInZone,
"returnSecurityGroupExistsInZone");
this.groupCreator = checkNotNull(groupCreator, "groupCreator");
}
@Override
public SecurityGroupInZone load(ZoneAndName in) {
AtomicReference<ZoneAndName> securityGroupInZoneRef = new AtomicReference<ZoneAndName>(checkNotNull(in,
"zoneSecurityGroupNameAndPorts"));
if (returnSecurityGroupExistsInZone.apply(securityGroupInZoneRef)) {
return returnExistingSecurityGroup(securityGroupInZoneRef);
} else {
return createNewSecurityGroup(in);
}
}
private SecurityGroupInZone returnExistingSecurityGroup(AtomicReference<ZoneAndName> securityGroupInZoneRef) {
ZoneAndName securityGroupInZone = securityGroupInZoneRef.get();
checkState(securityGroupInZone instanceof SecurityGroupInZone,
"programming error: predicate %s should update the atomic reference to the actual security group found",
returnSecurityGroupExistsInZone);
return SecurityGroupInZone.class.cast(securityGroupInZone);
}
private SecurityGroupInZone createNewSecurityGroup(ZoneAndName in) {
checkState(
checkNotNull(in, "zoneSecurityGroupNameAndPorts") instanceof ZoneSecurityGroupNameAndPorts,
"programming error: when issuing get to this cacheloader, you need to pass an instance of ZoneSecurityGroupNameAndPorts, not %s",
in);
ZoneSecurityGroupNameAndPorts zoneSecurityGroupNameAndPorts = ZoneSecurityGroupNameAndPorts.class.cast(in);
return groupCreator.apply(zoneSecurityGroupNameAndPorts);
}
@Override
public String toString() {
return "returnExistingSecurityGroupInZoneOrCreateAsNeeded()";
}
}

View File

@ -22,8 +22,8 @@ import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP; import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient; import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient;
import com.google.common.base.Function; import com.google.common.base.Function;

View File

@ -0,0 +1,58 @@
/**
* 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.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.and;
import static com.google.common.collect.Iterables.all;
import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
import static org.jclouds.compute.predicates.NodePredicates.inGroup;
import static org.jclouds.compute.predicates.NodePredicates.locationId;
import static org.jclouds.compute.predicates.NodePredicates.parentLocationId;
import javax.inject.Inject;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
/**
* @author Adrian Cole
*/
public class AllNodesInGroupTerminated implements Predicate<ZoneAndName> {
private final ComputeService computeService;
//TODO: TESTME
@Inject
public AllNodesInGroupTerminated(ComputeService computeService) {
this.computeService = checkNotNull(computeService, "computeService");
}
@Override
public boolean apply(ZoneAndName input) {
// new nodes can have the zone as their location, existing nodes, the parent is the
// location
return all(computeService.listNodesDetailsMatching(Predicates.<ComputeMetadata> or(locationId(input.getZone()),
parentLocationId(input.getZone()))), and(inGroup(input.getName()), TERMINATED));
}
}

View File

@ -21,20 +21,24 @@ package org.jclouds.openstack.nova.v1_1.compute.strategy;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.compute.config.CustomizationResponse; import org.jclouds.compute.config.CustomizationResponse;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template; import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName; import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap; import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
import org.jclouds.compute.strategy.ListNodesStrategy; import org.jclouds.compute.strategy.ListNodesStrategy;
@ -43,8 +47,14 @@ import org.jclouds.concurrent.Futures;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.functions.AllocateAndAddFloatingIpToNode; import org.jclouds.openstack.nova.v1_1.compute.functions.AllocateAndAddFloatingIpToNode;
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions; import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
import com.google.common.base.Throwables;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.primitives.Ints;
/** /**
* *
@ -55,7 +65,9 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
CreateNodesWithGroupEncodedIntoNameThenAddToSet { CreateNodesWithGroupEncodedIntoNameThenAddToSet {
private final AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode; private final AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode;
private final LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache;
private final NovaClient novaClient; private final NovaClient novaClient;
private final Provider<TemplateBuilder> templateBuilderProvider;
@Inject @Inject
protected ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet( protected ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddToSet(
@ -64,9 +76,13 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
@Named("NAMING_CONVENTION") String nodeNamingConvention, @Named("NAMING_CONVENTION") String nodeNamingConvention,
CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory, CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap.Factory customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor, @Named(Constants.PROPERTY_USER_THREADS) ExecutorService executor,
AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode, NovaClient novaClient) { Provider<TemplateBuilder> templateBuilderProvider,
AllocateAndAddFloatingIpToNode allocateAndAddFloatingIpToNode,
LoadingCache<ZoneAndName, SecurityGroupInZone> securityGroupCache, NovaClient novaClient) {
super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, executor, super(addNodeWithTagStrategy, listNodesStrategy, nodeNamingConvention, executor,
customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory); customizeNodeAndAddToGoodMapOrPutExceptionIntoBadMapFactory);
this.templateBuilderProvider = checkNotNull(templateBuilderProvider, "templateBuilderProvider");
this.securityGroupCache = checkNotNull(securityGroupCache, "securityGroupCache");
this.allocateAndAddFloatingIpToNode = checkNotNull(allocateAndAddFloatingIpToNode, this.allocateAndAddFloatingIpToNode = checkNotNull(allocateAndAddFloatingIpToNode,
"allocateAndAddFloatingIpToNode"); "allocateAndAddFloatingIpToNode");
this.novaClient = checkNotNull(novaClient, "novaClient"); this.novaClient = checkNotNull(novaClient, "novaClient");
@ -75,23 +91,38 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
@Override @Override
public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes, public Map<?, Future<Void>> execute(String group, int count, Template template, Set<NodeMetadata> goodNodes,
Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) { Map<NodeMetadata, Exception> badNodes, Multimap<NodeMetadata, CustomizationResponse> customizationResponses) {
// ensure we don't mutate the input template
Template mutableTemplate = templateBuilderProvider.get().fromTemplate(template).build();
// TODO: make NovaTemplateOptions with the following: // TODO: make NovaTemplateOptions with the following:
// security group, key pair // security group, key pair
NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(template.getOptions()); NovaTemplateOptions templateOptions = NovaTemplateOptions.class.cast(mutableTemplate.getOptions());
String zone = template.getLocation().getId(); String zone = mutableTemplate.getLocation().getId();
if (templateOptions.shouldAutoAssignFloatingIp()) { if (templateOptions.shouldAutoAssignFloatingIp()) {
checkArgument(novaClient.getFloatingIPExtensionForZone(zone).isPresent(), checkArgument(novaClient.getFloatingIPExtensionForZone(zone).isPresent(),
"Floating IPs are required by options, but the extension is not available! options: %s", templateOptions); "Floating IPs are required by options, but the extension is not available! options: %s",
templateOptions);
} }
boolean securityGroupExensionPresent = novaClient.getSecurityGroupExtensionForZone(zone).isPresent();
List<Integer> inboundPorts = Ints.asList(templateOptions.getInboundPorts());
if (templateOptions.getSecurityGroupNames().size() > 0) { if (templateOptions.getSecurityGroupNames().size() > 0) {
checkArgument(novaClient.getSecurityGroupExtensionForZone(zone).isPresent(), checkArgument(novaClient.getSecurityGroupExtensionForZone(zone).isPresent(),
"Security groups are required by options, but the extension is not available! options: %s", templateOptions); "Security groups are required by options, but the extension is not available! options: %s",
templateOptions);
} else if (securityGroupExensionPresent && inboundPorts.size() > 0) {
String securityGroupName = "jclouds#" + group;
try {
securityGroupCache.get(new ZoneSecurityGroupNameAndPorts(zone, securityGroupName, inboundPorts));
} catch (ExecutionException e) {
throw Throwables.propagate(e.getCause());
}
templateOptions.securityGroupNames(securityGroupName);
} }
return super.execute(group, count, template, goodNodes, badNodes, customizationResponses); return super.execute(group, count, mutableTemplate, goodNodes, badNodes, customizationResponses);
} }
@Override @Override

View File

@ -27,20 +27,47 @@ import java.util.Set;
import org.jclouds.openstack.domain.Link; import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource; import org.jclouds.openstack.domain.Resource;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
/** /**
* An image is a collection of files you use to create or rebuild a server. * An image is a collection of files you use to create or rebuild a server. Operators provide
* Operators provide pre-built OS images by default. You may also create custom * pre-built OS images by default. You may also create custom images.
* images.
* *
* @author Jeremy Daggett * @author Jeremy Daggett
* @see <a href= * @see <a href= "http://docs.openstack.org/api/openstack-compute/1.1/content/Images-d1e4427.html"
* "http://docs.openstack.org/api/openstack-compute/1.1/content/Images-d1e4427.html"
* /> * />
*/ */
public class Image extends Resource { public class Image extends Resource {
/**
* In-flight images will have the status attribute set to SAVING and the conditional progress
* element (0-100% completion) will also be returned. Other possible values for the status
* attribute include: UNKNOWN, ACTIVE, SAVING, ERROR, and DELETED. Images with an ACTIVE status
* are available for install. The optional minDisk and minRam attributes set the minimum disk and
* RAM requirements needed to create a server with the image.
*
* @author Adrian Cole
*/
public static enum Status {
UNRECOGNIZED, UNKNOWN, ACTIVE, SAVING, ERROR, DELETED;
public String value() {
return name();
}
public static Status fromValue(String v) {
try {
return valueOf(v);
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
}
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
} }
@ -55,12 +82,12 @@ public class Image extends Resource {
private Date created; private Date created;
private String tenantId; private String tenantId;
private String userId; private String userId;
private ImageStatus status; private Status status;
private int progress; private int progress;
private int minDisk; private int minDisk;
private int minRam; private int minRam;
private Resource server; private Resource server;
private Map<String, String> metadata = Maps.newHashMap(); private Map<String, String> metadata = Maps.newLinkedHashMap();
public Builder updated(Date updated) { public Builder updated(Date updated) {
this.updated = updated; this.updated = updated;
@ -82,7 +109,7 @@ public class Image extends Resource {
return this; return this;
} }
public Builder status(ImageStatus status) { public Builder status(Status status) {
this.status = status; this.status = status;
return this; return this;
} }
@ -118,8 +145,8 @@ public class Image extends Resource {
} }
public Builder fromImage(Image in) { public Builder fromImage(Image in) {
return fromResource(in).status(in.getStatus()).updated(in.getUpdated()).created(in.getCreated()) return fromResource(in).status(in.getStatus()).updated(in.getUpdated()).created(in.getCreated()).progress(
.progress(in.getProgress()).server(in.getServer()).metadata(in.getMetadata()); in.getProgress()).server(in.getServer()).metadata(in.getMetadata());
} }
/** /**
@ -155,21 +182,21 @@ public class Image extends Resource {
} }
} }
private Date updated; private final Date updated;
private Date created; private final Date created;
@SerializedName("tenant_id") @SerializedName("tenant_id")
private String tenantId; private final String tenantId;
@SerializedName("user_id") @SerializedName("user_id")
private String userId; private final String userId;
private ImageStatus status; private final Status status;
private int progress; private final int progress;
private int minDisk; private final int minDisk;
private int minRam; private final int minRam;
private Resource server; private final Resource server;
private Map<String, String> metadata = Maps.newHashMap(); private final Map<String, String> metadata;
protected Image(String id, String name, Set<Link> links, Date updated, Date created, String tenantId, String userId, protected Image(String id, String name, Set<Link> links, Date updated, Date created, String tenantId, String userId,
ImageStatus status, int progress, int minDisk, int minRam, Resource server, Map<String, String> metadata) { Status status, int progress, int minDisk, int minRam, Resource server, Map<String, String> metadata) {
super(id, name, links); super(id, name, links);
this.updated = updated; this.updated = updated;
this.created = created; this.created = created;
@ -180,7 +207,7 @@ public class Image extends Resource {
this.minDisk = minDisk; this.minDisk = minDisk;
this.minRam = minRam; this.minRam = minRam;
this.server = server; this.server = server;
this.metadata = metadata; this.metadata = ImmutableMap.<String, String> copyOf(metadata);
} }
public Date getUpdated() { public Date getUpdated() {
@ -199,7 +226,7 @@ public class Image extends Resource {
return this.userId; return this.userId;
} }
public ImageStatus getStatus() { public Status getStatus() {
return this.status; return this.status;
} }
@ -220,15 +247,16 @@ public class Image extends Resource {
} }
public Map<String, String> getMetadata() { public Map<String, String> getMetadata() {
return this.metadata; // in case this was assigned in gson
return ImmutableMap.copyOf(Maps.filterValues(this.metadata, Predicates.notNull()));
} }
@Override @Override
public String toString() { public String toString() {
return toStringHelper("").add("id", id).add("name", name).add("links", links).add("updated", updated) return toStringHelper("").add("id", id).add("name", name).add("links", links).add("updated", updated).add(
.add("created", created).add("tenantId", tenantId).add("userId", userId).add("status", status) "created", created).add("tenantId", tenantId).add("userId", userId).add("status", status).add(
.add("progress", progress).add("minDisk", minDisk).add("minRam", minRam).add("server", server) "progress", progress).add("minDisk", minDisk).add("minRam", minRam).add("server", server).add(
.add("metadata", metadata).toString(); "metadata", metadata).toString();
} }
} }

View File

@ -26,22 +26,19 @@ import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.jclouds.compute.domain.NodeState;
import org.jclouds.javax.annotation.Nullable; import org.jclouds.javax.annotation.Nullable;
import org.jclouds.openstack.domain.Link; import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Resource; import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.nova.v1_1.domain.Address.Type; import org.jclouds.openstack.nova.v1_1.domain.Address.Type;
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient; import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
import org.jclouds.util.InetAddresses2;
import org.jclouds.util.Multimaps2; import org.jclouds.util.Multimaps2;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates; import com.google.common.base.Predicates;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
@ -57,6 +54,47 @@ import com.google.gson.annotations.SerializedName;
* /> * />
*/ */
public class Server extends Resource { public class Server extends Resource {
/**
* Servers contain a status attribute that can be used as an indication of the current server
* state. Servers with an ACTIVE status are available for use.
*
* Other possible values for the status attribute include: BUILD, REBUILD, SUSPENDED, RESIZE,
* VERIFY_RESIZE, REVERT_RESIZE, PASSWORD, REBOOT, HARD_REBOOT, DELETED, UNKNOWN, and ERROR.
*
* @author Adrian Cole
*/
public static enum Status {
ACTIVE(NodeState.RUNNING), BUILD(NodeState.PENDING), REBUILD(NodeState.PENDING), SUSPENDED(NodeState.SUSPENDED), RESIZE(
NodeState.PENDING), VERIFY_RESIZE(NodeState.PENDING), REVERT_RESIZE(NodeState.PENDING), PASSWORD(
NodeState.PENDING), REBOOT(NodeState.PENDING), HARD_REBOOT(NodeState.PENDING), DELETED(
NodeState.TERMINATED), UNKNOWN(NodeState.UNRECOGNIZED), ERROR(NodeState.ERROR), UNRECOGNIZED(
NodeState.UNRECOGNIZED);
private final NodeState nodeState;
Status(NodeState nodeState) {
this.nodeState = nodeState;
}
public String value() {
return name();
}
public static Status fromValue(String v) {
try {
return valueOf(v.replaceAll("\\(.*", ""));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
public NodeState getNodeState() {
return nodeState;
}
}
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
} }
@ -74,7 +112,7 @@ public class Server extends Resource {
private String hostId; private String hostId;
private String accessIPv4; private String accessIPv4;
private String accessIPv6; private String accessIPv6;
private ServerStatus status; private Status status;
private String configDrive; private String configDrive;
private Resource image; private Resource image;
private Resource flavor; private Resource flavor;
@ -151,7 +189,7 @@ public class Server extends Resource {
/** /**
* @see Server#getStatus() * @see Server#getStatus()
*/ */
public Builder status(ServerStatus status) { public Builder status(Status status) {
this.status = status; this.status = status;
return this; return this;
} }
@ -309,7 +347,7 @@ public class Server extends Resource {
protected final String hostId; protected final String hostId;
protected final String accessIPv4; protected final String accessIPv4;
protected final String accessIPv6; protected final String accessIPv6;
protected final ServerStatus status; protected final Status status;
protected final Resource image; protected final Resource image;
protected final Resource flavor; protected final Resource flavor;
protected final String adminPass; protected final String adminPass;
@ -323,8 +361,8 @@ public class Server extends Resource {
protected Server(String id, String name, Set<Link> links, @Nullable String uuid, String tenantId, String userId, protected Server(String id, String name, Set<Link> links, @Nullable String uuid, String tenantId, String userId,
Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4, Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4,
@Nullable String accessIPv6, ServerStatus status, @Nullable String configDrive, Resource image, @Nullable String accessIPv6, Status status, @Nullable String configDrive, Resource image, Resource flavor,
Resource flavor, String adminPass, @Nullable String keyName, Multimap<Address.Type, Address> addresses, String adminPass, @Nullable String keyName, Multimap<Address.Type, Address> addresses,
Map<String, String> metadata) { Map<String, String> metadata) {
super(id, name, links); super(id, name, links);
this.uuid = uuid; // TODO: see what version this came up in this.uuid = uuid; // TODO: see what version this came up in
@ -390,7 +428,7 @@ public class Server extends Resource {
return Strings.emptyToNull(this.accessIPv6); return Strings.emptyToNull(this.accessIPv6);
} }
public ServerStatus getStatus() { public Status getStatus() {
return this.status; return this.status;
} }
@ -408,7 +446,8 @@ public class Server extends Resource {
} }
public Map<String, String> getMetadata() { public Map<String, String> getMetadata() {
return this.metadata; // in case this was assigned in gson
return ImmutableMap.copyOf(Maps.filterValues(this.metadata, Predicates.notNull()));
} }
/** /**
@ -439,29 +478,7 @@ public class Server extends Resource {
* @return the ip addresses assigned to the server * @return the ip addresses assigned to the server
*/ */
public Multimap<Type, Address> getAddresses() { public Multimap<Type, Address> getAddresses() {
ImmutableSetMultimap.Builder<Type, Address> returnMapBuilder = new ImmutableSetMultimap.Builder<Type, Address>(); return Multimaps2.fromOldSchool(addresses);
Set<Address> publicAddresses = addresses.get(Address.Type.PUBLIC);
Set<Address> privateAddresses = addresses.get(Address.Type.PRIVATE);
if (publicAddresses != null) {
returnMapBuilder.putAll(Address.Type.PUBLIC, Iterables.filter(publicAddresses, Predicates
.not(IsPrivateAddress.INSTANCE)));
}
if (privateAddresses != null) {
returnMapBuilder.putAll(Address.Type.PRIVATE, Iterables.filter(privateAddresses, IsPrivateAddress.INSTANCE));
returnMapBuilder.putAll(Address.Type.PUBLIC, Iterables.filter(privateAddresses, Predicates
.not(IsPrivateAddress.INSTANCE)));
}
ImmutableSetMultimap<Type, Address> returnMap = returnMapBuilder.build();
return returnMap.size() > 0 ? returnMap : Multimaps2.fromOldSchool(addresses);
}
private static enum IsPrivateAddress implements Predicate<Address> {
INSTANCE;
public boolean apply(Address in) {
return InetAddresses2.IsPrivateIPAddress.INSTANCE.apply(in.getAddr());
}
} }
/** /**

View File

@ -1,61 +0,0 @@
/**
* 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.domain;
import org.jclouds.compute.domain.NodeState;
/**
* Servers contain a status attribute that can be used as an indication of the
* current server state. Servers with an ACTIVE status are available for use.
*
* Other possible values for the status attribute include: BUILD, REBUILD,
* SUSPENDED, RESIZE, VERIFY_RESIZE, REVERT_RESIZE, PASSWORD, REBOOT,
* HARD_REBOOT, DELETED, UNKNOWN, and ERROR.
*
* @author Adrian Cole
*/
public enum ServerStatus {
ACTIVE(NodeState.RUNNING), BUILD(NodeState.PENDING), REBUILD(NodeState.PENDING), SUSPENDED(NodeState.SUSPENDED), RESIZE(
NodeState.PENDING), VERIFY_RESIZE(NodeState.PENDING), REVERT_RESIZE(NodeState.PENDING), PASSWORD(
NodeState.PENDING), REBOOT(NodeState.PENDING), HARD_REBOOT(NodeState.PENDING), DELETED(NodeState.TERMINATED), UNKNOWN(
NodeState.UNRECOGNIZED), ERROR(NodeState.ERROR), UNRECOGNIZED(NodeState.UNRECOGNIZED);
private final NodeState nodeState;
ServerStatus(NodeState nodeState) {
this.nodeState = nodeState;
}
public String value() {
return name();
}
public static ServerStatus fromValue(String v) {
try {
return valueOf(v.replaceAll("\\(.*",""));
} catch (IllegalArgumentException e) {
return UNRECOGNIZED;
}
}
public NodeState getNodeState() {
return nodeState;
}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.compute.domain; package org.jclouds.openstack.nova.v1_1.domain.zonescoped;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.compute.domain; package org.jclouds.openstack.nova.v1_1.domain.zonescoped;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
@ -26,15 +26,15 @@ import org.jclouds.openstack.nova.v1_1.domain.Image;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ImageInZone extends ZoneAndId { public class ImageInZone extends ZoneAndId {
protected final Image server; protected final Image image;
public ImageInZone(Image server, String zoneId) { public ImageInZone(Image image, String zoneId) {
super(zoneId, checkNotNull(server, "server").getId()); super(zoneId, checkNotNull(image, "image").getId());
this.server = server; this.image = image;
} }
public Image getImage() { public Image getImage() {
return server; return image;
} }
// superclass hashCode/equals are good enough, and help us use ZoneAndId and ImageInZone // superclass hashCode/equals are good enough, and help us use ZoneAndId and ImageInZone
@ -42,7 +42,7 @@ public class ImageInZone extends ZoneAndId {
@Override @Override
public String toString() { public String toString() {
return "[server=" + server + ", zoneId=" + zoneId + "]"; return "[image=" + image + ", zoneId=" + zoneId + "]";
} }
} }

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.compute.domain; package org.jclouds.openstack.nova.v1_1.domain.zonescoped;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.compute.domain; package org.jclouds.openstack.nova.v1_1.domain.zonescoped;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.compute.domain; package org.jclouds.openstack.nova.v1_1.domain.zonescoped;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;

View File

@ -16,12 +16,13 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.compute.domain; package org.jclouds.openstack.nova.v1_1.domain.zonescoped;
import static com.google.common.base.Objects.equal; import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Function;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Splitter; import com.google.common.base.Splitter;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
@ -33,6 +34,25 @@ import com.google.common.collect.Iterables;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ZoneAndName { public class ZoneAndName {
public final static Function<ZoneAndName, String> NAME_FUNCTION = new Function<ZoneAndName, String>(){
@Override
public String apply(ZoneAndName input) {
return input.getName();
}
};
public final static Function<ZoneAndName, String> ZONE_FUNCTION = new Function<ZoneAndName, String>(){
@Override
public String apply(ZoneAndName input) {
return input.getZone();
}
};
public static ZoneAndName fromSlashEncoded(String name) { public static ZoneAndName fromSlashEncoded(String name) {
Iterable<String> parts = Splitter.on('/').split(checkNotNull(name, "name")); Iterable<String> parts = Splitter.on('/').split(checkNotNull(name, "name"));
checkArgument(Iterables.size(parts) == 2, "name must be in format zoneId/name"); checkArgument(Iterables.size(parts) == 2, "name must be in format zoneId/name");

View File

@ -16,29 +16,29 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
package org.jclouds.openstack.nova.v1_1.compute.domain; package org.jclouds.openstack.nova.v1_1.domain.zonescoped;
import static com.google.common.base.Objects.equal; import static com.google.common.base.Objects.equal;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List; import java.util.Set;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper; import com.google.common.base.Objects.ToStringHelper;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet;
/** /**
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ZoneSecurityGroupNameAndPorts extends ZoneAndName { public class ZoneSecurityGroupNameAndPorts extends ZoneAndName {
protected final List<Integer> ports; protected final Set<Integer> ports;
public ZoneSecurityGroupNameAndPorts(String zoneId, String name, List<Integer> ports) { public ZoneSecurityGroupNameAndPorts(String zoneId, String name, Iterable<Integer> ports) {
super(zoneId, name); super(zoneId, name);
this.ports = ImmutableList.<Integer> copyOf(checkNotNull(ports, "ports")); this.ports = ImmutableSet.<Integer> copyOf(checkNotNull(ports, "ports"));
} }
public List<Integer> getPorts() { public Set<Integer> getPorts() {
return ports; return ports;
} }

View File

@ -55,6 +55,8 @@ public class NovaErrorHandler implements HttpErrorHandler {
exception = new InsufficientResourcesException(message, exception); exception = new InsufficientResourcesException(message, exception);
else if (message.indexOf("has no fixed_ips") != -1) else if (message.indexOf("has no fixed_ips") != -1)
exception = new IllegalStateException(message, exception); exception = new IllegalStateException(message, exception);
else if (message.indexOf("already exists") != -1)
exception = new IllegalStateException(message, exception);
break; break;
case 401: case 401:
case 403: case 403:

View File

@ -29,9 +29,9 @@ import javax.inject.Singleton;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup; import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient; import org.jclouds.openstack.nova.v1_1.extensions.SecurityGroupClient;
import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.rest.ResourceNotFoundException;

View File

@ -0,0 +1,57 @@
/*
* 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.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.openstack.nova.v1_1.domain.Image.Status;
import com.google.common.base.Predicate;
/**
* Predicates handy when working with Images
*
* @author Adrian Cole
*/
public class ImagePredicates {
/**
* matches status of the given image
*
* @param status
* @return predicate that matches status
*/
public static Predicate<Image> statusEquals(final Status status) {
checkNotNull(status, "status must be defined");
return new Predicate<Image>() {
@Override
public boolean apply(Image image) {
return status.equals(image.getStatus());
}
@Override
public String toString() {
return "statusEquals(" + status + ")";
}
};
}
}

View File

@ -0,0 +1,56 @@
/*
* 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.predicates;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import com.google.common.base.Predicate;
/**
* Predicates handy when working with SecurityGroups
*
* @author Adrian Cole
*/
public class SecurityGroupPredicates {
/**
* matches name of the given extension
*
* @param name
* @return predicate that matches name
*/
public static Predicate<SecurityGroup> nameEquals(final String name) {
checkNotNull(name, "name must be defined");
return new Predicate<SecurityGroup>() {
@Override
public boolean apply(SecurityGroup ext) {
return name.equals(ext.getName());
}
@Override
public String toString() {
return "nameEquals(" + name + ")";
}
};
}
}

View File

@ -65,6 +65,17 @@ public class NovaErrorHandlerTest {
IllegalStateException.class); IllegalStateException.class);
} }
@Test
public void test400MakesIllegalStateExceptionOnAlreadyExists() {
assertCodeMakes(
"POST",
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers"),
400,
"HTTP/1.1 400 Bad Request",
"{\"badRequest\": {\"message\": \"Server with the name 'test' already exists\", \"code\": 400}}",
IllegalStateException.class);
}
@Test @Test
public void test400MakesInsufficientResourcesExceptionOnQuotaExceeded() { public void test400MakesInsufficientResourcesExceptionOnQuotaExceeded() {

View File

@ -29,8 +29,8 @@ import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v1_1.compute.domain.ServerInZone;
import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions; import org.jclouds.openstack.nova.v1_1.compute.options.NovaTemplateOptions;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaComputeServiceContextExpectTest; import org.jclouds.openstack.nova.v1_1.internal.BaseNovaComputeServiceContextExpectTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;

View File

@ -46,7 +46,7 @@ import com.google.common.collect.ImmutableSet;
* @author Matt Stephenson * @author Matt Stephenson
*/ */
@Test(groups = "unit", testName = "AllocateAndAddFloatingIpToNodeTest") @Test(groups = "unit", testName = "AllocateAndAddFloatingIpToNodeTest")
public class AllocateAndAddFloatingIpToNodeTest extends BaseNovaComputeServiceExpectTest { public class AllocateAndAddFloatingIpToNodeExpectTest extends BaseNovaComputeServiceExpectTest {
final Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description( final Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
"openstack-nova").build(); "openstack-nova").build();
final Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope( final Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(

View File

@ -29,8 +29,8 @@ import org.jclouds.compute.domain.Hardware;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.openstack.nova.v1_1.compute.domain.FlavorInZone;
import org.jclouds.openstack.nova.v1_1.domain.Flavor; import org.jclouds.openstack.nova.v1_1.domain.Flavor;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.FlavorInZone;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;

View File

@ -30,8 +30,8 @@ import org.jclouds.compute.domain.OsFamily;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.openstack.nova.v1_1.compute.domain.ImageInZone;
import org.jclouds.openstack.nova.v1_1.domain.Image; import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ImageInZone;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Function; import com.google.common.base.Function;

View File

@ -0,0 +1,108 @@
/**
* 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.functions;
import static org.testng.Assert.assertEquals;
import java.util.Map;
import java.util.Set;
import org.easymock.classextension.EasyMock;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.parse.ParseCreatedServerTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerTest;
import org.testng.annotations.Test;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
/**
*
*
* @author Adrian Cole
*/
@Test(testName = "OrphanedGroupsByZoneIdTest")
public class OrphanedGroupsByZoneIdTest {
Location provider = new LocationBuilder().scope(LocationScope.PROVIDER).id("openstack-nova").description(
"openstack-nova").build();
Location zone = new LocationBuilder().id("az-1.region-a.geo-1").description("az-1.region-a.geo-1").scope(
LocationScope.ZONE).parent(provider).build();
Supplier<Map<String, Location>> locationIndex = Suppliers.<Map<String, Location>> ofInstance(ImmutableMap
.<String, Location> of("az-1.region-a.geo-1", zone));
@Test
public void testWhenComputeServiceSaysAllNodesAreDeadBothGroupsAreReturned() {
ServerInZone withoutHost = new ServerInZone(new ParseCreatedServerTest().expected(), "az-1.region-a.geo-1");
ServerInZone withHost = new ServerInZone(new ParseServerTest().expected(), "az-1.region-a.geo-1");
LoadingCache<ZoneAndId, Iterable<String>> mockLoadingCache = EasyMock.createMock(LoadingCache.class);
EasyMock.expect(mockLoadingCache.getUnchecked(withoutHost)).andReturn(ImmutableSet.<String> of());
EasyMock.expect(mockLoadingCache.getUnchecked(withHost)).andReturn(ImmutableSet.<String> of());
EasyMock.replay(mockLoadingCache);
ServerInZoneToNodeMetadata converter = new ServerInZoneToNodeMetadata(locationIndex, Suppliers
.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of()), Suppliers
.<Set<? extends Hardware>> ofInstance(ImmutableSet.<Hardware> of()), mockLoadingCache);
Set<? extends NodeMetadata> set = ImmutableSet.of(converter.apply(withHost), converter.apply(withoutHost));
assertEquals(new OrphanedGroupsByZoneId(Predicates.<ZoneAndName> alwaysTrue()).apply(set), ImmutableMultimap
.<String, String> builder().putAll("az-1.region-a.geo-1", "sample", "test").build());
EasyMock.verify(mockLoadingCache);
}
@Test
public void testWhenComputeServiceSaysAllNodesAreDeadNoGroupsAreReturned() {
ServerInZone withoutHost = new ServerInZone(new ParseCreatedServerTest().expected(), "az-1.region-a.geo-1");
ServerInZone withHost = new ServerInZone(new ParseServerTest().expected(), "az-1.region-a.geo-1");
LoadingCache<ZoneAndId, Iterable<String>> mockLoadingCache = EasyMock.createMock(LoadingCache.class);
EasyMock.expect(mockLoadingCache.getUnchecked(withoutHost)).andReturn(ImmutableSet.<String> of());
EasyMock.expect(mockLoadingCache.getUnchecked(withHost)).andReturn(ImmutableSet.<String> of());
EasyMock.replay(mockLoadingCache);
ServerInZoneToNodeMetadata converter = new ServerInZoneToNodeMetadata(locationIndex, Suppliers
.<Set<? extends Image>> ofInstance(ImmutableSet.<Image> of()), Suppliers
.<Set<? extends Hardware>> ofInstance(ImmutableSet.<Hardware> of()), mockLoadingCache);
Set<? extends NodeMetadata> set = ImmutableSet.of(converter.apply(withHost), converter.apply(withoutHost));
assertEquals(new OrphanedGroupsByZoneId(Predicates.<ZoneAndName> alwaysFalse()).apply(set), ImmutableMultimap
.<String, String> of());
EasyMock.verify(mockLoadingCache);
}
}

View File

@ -35,9 +35,9 @@ import org.jclouds.compute.domain.OsFamily;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.LocationBuilder; import org.jclouds.domain.LocationBuilder;
import org.jclouds.domain.LocationScope; import org.jclouds.domain.LocationScope;
import org.jclouds.openstack.nova.v1_1.compute.domain.ServerInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.parse.ParseCreatedServerTest; import org.jclouds.openstack.nova.v1_1.parse.ParseCreatedServerTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseServerTest; import org.jclouds.openstack.nova.v1_1.parse.ParseServerTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -134,8 +134,8 @@ public class ServerInZoneToNodeMetadataTest {
assertEquals(convertedNodeMetadata.getPrivateAddresses(), ImmutableSet.of("10.176.42.16")); assertEquals(convertedNodeMetadata.getPrivateAddresses(), ImmutableSet.of("10.176.42.16"));
assertNotNull(convertedNodeMetadata.getPublicAddresses()); assertNotNull(convertedNodeMetadata.getPublicAddresses());
assertEquals(convertedNodeMetadata.getPublicAddresses(), ImmutableSet.of("67.23.10.132", "::babe:67.23.10.132", // note jclouds doesn't yet support ipv6 b/c not tested yet
"67.23.10.131", "::babe:4317:0A83", "::babe:10.176.42.16")); assertEquals(convertedNodeMetadata.getPublicAddresses(), ImmutableSet.of("67.23.10.132", "67.23.10.131"));
assertNotNull(convertedNodeMetadata.getUserMetadata()); assertNotNull(convertedNodeMetadata.getUserMetadata());
assertEquals(convertedNodeMetadata.getUserMetadata(), ImmutableMap.<String, String> of("Server Label", assertEquals(convertedNodeMetadata.getUserMetadata(), ImmutableMap.<String, String> of("Server Label",

View File

@ -0,0 +1,145 @@
/**
* 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.loaders;
import static org.easymock.EasyMock.createMock;
import static org.testng.Assert.assertEquals;
import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
import org.testng.annotations.Test;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", singleThreaded = true, testName = "FindSecurityGroupOrCreateTest")
public class FindSecurityGroupOrCreateTest {
@Test
public void testWhenNotFoundCreatesANewSecurityGroup() throws Exception {
Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone = Predicates.alwaysFalse();
SecurityGroupInZone securityGroupInZone = createMock(SecurityGroupInZone.class);
ZoneSecurityGroupNameAndPorts input = new ZoneSecurityGroupNameAndPorts("zone", "groupName", ImmutableSet
.<Integer> of(22, 8080));
Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator = Functions.forMap(ImmutableMap
.<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> of(input, securityGroupInZone));
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInZone, groupCreator);
assertEquals(parser.load(input), securityGroupInZone);
}
@Test
public void testWhenFoundReturnsSecurityGroupFromAtomicReferenceValueUpdatedDuringPredicateCheck() throws Exception {
final SecurityGroupInZone securityGroupInZone = createMock(SecurityGroupInZone.class);
Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone = new Predicate<AtomicReference<ZoneAndName>>(){
@Override
public boolean apply(AtomicReference<ZoneAndName> input) {
input.set(securityGroupInZone);
return true;
}
};
ZoneAndName input = ZoneAndName.fromZoneAndName("zone", "groupName");
Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator = new Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>() {
@Override
public SecurityGroupInZone apply(ZoneSecurityGroupNameAndPorts input) {
assert false;
return null;
}
};
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInZone, groupCreator);
assertEquals(parser.load(input), securityGroupInZone);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testWhenFoundPredicateMustUpdateAtomicReference() throws Exception {
Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone = Predicates.alwaysTrue();
ZoneAndName input = ZoneAndName.fromZoneAndName("zone", "groupName");
Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator = new Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>() {
@Override
public SecurityGroupInZone apply(ZoneSecurityGroupNameAndPorts input) {
assert false;
return null;
}
};
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInZone, groupCreator);
parser.load(input);
}
@Test(expectedExceptions = IllegalStateException.class)
public void testWhenNotFoundInputMustBeZoneSecurityGroupNameAndPorts() throws Exception {
Predicate<AtomicReference<ZoneAndName>> returnSecurityGroupExistsInZone = Predicates.alwaysFalse();
ZoneAndName input = ZoneAndName.fromZoneAndName("zone", "groupName");
Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone> groupCreator = new Function<ZoneSecurityGroupNameAndPorts, SecurityGroupInZone>() {
@Override
public SecurityGroupInZone apply(ZoneSecurityGroupNameAndPorts input) {
assert false;
return null;
}
};
FindSecurityGroupOrCreate parser = new FindSecurityGroupOrCreate(
returnSecurityGroupExistsInZone, groupCreator);
parser.load(input);
}
}

View File

@ -26,8 +26,8 @@ import static org.testng.Assert.assertEquals;
import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertFalse;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP; import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndId;
import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient; import org.jclouds.openstack.nova.v1_1.extensions.FloatingIPClient;
import org.testng.annotations.Test; import org.testng.annotations.Test;

View File

@ -28,7 +28,7 @@ import java.util.Set;
import org.jclouds.openstack.nova.v1_1.domain.Address; import org.jclouds.openstack.nova.v1_1.domain.Address;
import org.jclouds.openstack.nova.v1_1.domain.FloatingIP; import org.jclouds.openstack.nova.v1_1.domain.FloatingIP;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.ServerStatus; import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
import org.jclouds.openstack.nova.v1_1.features.FlavorClient; import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
import org.jclouds.openstack.nova.v1_1.features.ImageClient; import org.jclouds.openstack.nova.v1_1.features.ImageClient;
import org.jclouds.openstack.nova.v1_1.features.ServerClient; import org.jclouds.openstack.nova.v1_1.features.ServerClient;
@ -136,7 +136,7 @@ public class FloatingIPClientLiveTest extends BaseNovaClientLiveTest {
private void blockUntilServerActive(String serverId, ServerClient client) throws InterruptedException { private void blockUntilServerActive(String serverId, ServerClient client) throws InterruptedException {
Server currentDetails = null; Server currentDetails = null;
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != ServerStatus.ACTIVE; currentDetails = client for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != Status.ACTIVE; currentDetails = client
.getServer(serverId)) { .getServer(serverId)) {
System.out.printf("blocking on status active%n%s%n", currentDetails); System.out.printf("blocking on status active%n%s%n", currentDetails);
Thread.sleep(5 * 1000); Thread.sleep(5 * 1000);

View File

@ -25,9 +25,9 @@ import java.net.URI;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone; import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupIfNeeded;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneSecurityGroupNameAndPorts; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.functions.CreateSecurityGroupInZone; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneSecurityGroupNameAndPorts;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest; import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseComputeServiceTypicalSecurityGroupTest; import org.jclouds.openstack.nova.v1_1.parse.ParseComputeServiceTypicalSecurityGroupTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -35,22 +35,15 @@ import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableMap.Builder; import com.google.common.collect.ImmutableMap.Builder;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "CreateSecurityGroupInZoneExpectTest") @Test(groups = "unit", testName = "CreateSecurityGroupIfNeededTest")
public class CreateSecurityGroupInZoneExpectTest extends BaseNovaClientExpectTest { public class CreateSecurityGroupIfNeededTest extends BaseNovaClientExpectTest {
public void testUpdateReferenceWhenSecurityGroupListContainsGroupName() throws Exception {
Builder<HttpRequest, HttpResponse> builder = ImmutableMap.<HttpRequest, HttpResponse>builder();
builder.put(keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess);
builder.put(extensionsOfNovaRequest, extensionsOfNovaResponse);
HttpRequest createSecurityGroup = HttpRequest.builder().method("POST").endpoint( HttpRequest createSecurityGroup = HttpRequest.builder().method("POST").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-groups")).headers( URI.create("https://compute.north.host/v1.1/3456/os-security-groups")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token", ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
@ -59,6 +52,13 @@ public class CreateSecurityGroupInZoneExpectTest extends BaseNovaClientExpectTes
payloadFromStringWithContentType( payloadFromStringWithContentType(
"{\"security_group\":{\"name\":\"jclouds#mygroup\",\"description\":\"jclouds#mygroup\"}}", "{\"security_group\":{\"name\":\"jclouds#mygroup\",\"description\":\"jclouds#mygroup\"}}",
"application/json")).build(); "application/json")).build();
public void testCreateNewGroup() throws Exception {
Builder<HttpRequest, HttpResponse> builder = ImmutableMap.<HttpRequest, HttpResponse>builder();
builder.put(keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess);
builder.put(extensionsOfNovaRequest, extensionsOfNovaResponse);
int groupId = 2769; int groupId = 2769;
HttpResponse createSecurityGroupResponse = HttpResponse.builder().statusCode(200) HttpResponse createSecurityGroupResponse = HttpResponse.builder().statusCode(200)
@ -119,16 +119,52 @@ public class CreateSecurityGroupInZoneExpectTest extends BaseNovaClientExpectTes
builder.put(getSecurityGroup, getSecurityGroupResponse); builder.put(getSecurityGroup, getSecurityGroupResponse);
NovaClient clientWhenSecurityGroupsExist = requestsSendResponses(builder.build()); NovaClient clientCanCreateSecurityGroup = requestsSendResponses(builder.build());
CreateSecurityGroupInZone fn = new CreateSecurityGroupInZone(clientWhenSecurityGroupsExist); CreateSecurityGroupIfNeeded fn = new CreateSecurityGroupIfNeeded(clientCanCreateSecurityGroup);
// we can find it // we can find it
assertEquals(fn.apply( assertEquals(fn.apply(
new ZoneSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds#mygroup", ImmutableList.of(22, 8080))) new ZoneSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds#mygroup", ImmutableSet.of(22, 8080)))
.toString(), new SecurityGroupInZone(new ParseComputeServiceTypicalSecurityGroupTest().expected(), .toString(), new SecurityGroupInZone(new ParseComputeServiceTypicalSecurityGroupTest().expected(),
"az-1.region-a.geo-1").toString()); "az-1.region-a.geo-1").toString());
} }
public void testReturnExistingGroupOnAlreadyExists() throws Exception {
Builder<HttpRequest, HttpResponse> builder = ImmutableMap.<HttpRequest, HttpResponse>builder();
builder.put(keystoneAuthWithAccessKeyAndSecretKey, responseWithKeystoneAccess);
builder.put(extensionsOfNovaRequest, extensionsOfNovaResponse);
HttpResponse createSecurityGroupResponse = HttpResponse.builder().statusCode(400)
.payload(
payloadFromStringWithContentType(
"{\"badRequest\": {\"message\": \"Security group test already exists\", \"code\": 400}}",
"application/json; charset=UTF-8")).build();
builder.put(createSecurityGroup, createSecurityGroupResponse);
HttpRequest listSecurityGroups = HttpRequest.builder().method("GET").endpoint(
URI.create("https://compute.north.host/v1.1/3456/os-security-groups")).headers(
ImmutableMultimap.<String, String> builder().put("Accept", "application/json").put("X-Auth-Token",
authToken).build()).build();
HttpResponse listSecurityGroupsResponse = HttpResponse.builder().statusCode(200).payload(
payloadFromResource("/securitygroup_list_details_computeservice_typical.json")).build();
builder.put(listSecurityGroups, listSecurityGroupsResponse);
NovaClient clientWhenSecurityGroupsExist = requestsSendResponses(builder.build());
CreateSecurityGroupIfNeeded fn = new CreateSecurityGroupIfNeeded(clientWhenSecurityGroupsExist);
// we can find it
assertEquals(fn.apply(
new ZoneSecurityGroupNameAndPorts("az-1.region-a.geo-1", "jclouds#mygroup", ImmutableSet.of(22, 8080)))
.toString(), new SecurityGroupInZone(new ParseComputeServiceTypicalSecurityGroupTest().expected(),
"az-1.region-a.geo-1").toString());
}
} }

View File

@ -28,8 +28,8 @@ import java.util.concurrent.atomic.AtomicReference;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.openstack.nova.v1_1.NovaClient; import org.jclouds.openstack.nova.v1_1.NovaClient;
import org.jclouds.openstack.nova.v1_1.compute.domain.SecurityGroupInZone; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.SecurityGroupInZone;
import org.jclouds.openstack.nova.v1_1.compute.domain.ZoneAndName; import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ZoneAndName;
import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest; import org.jclouds.openstack.nova.v1_1.internal.BaseNovaClientExpectTest;
import org.jclouds.openstack.nova.v1_1.parse.ParseSecurityGroupListTest; import org.jclouds.openstack.nova.v1_1.parse.ParseSecurityGroupListTest;
import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndReturnTrue; import org.jclouds.openstack.nova.v1_1.predicates.FindSecurityGroupWithNameAndReturnTrue;

View File

@ -31,7 +31,7 @@ import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.domain.Link.Relation; import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule; import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.ServerStatus; import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -62,7 +62,7 @@ public class ParseCreatedServerTest extends BaseItemParserTest<Server> {
.name("test-e92") .name("test-e92")
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z")) .updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z")) .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
.status(ServerStatus.BUILD) .status(Status.BUILD)
.adminPass("ZWuHcmTMQ7eXoHeM") .adminPass("ZWuHcmTMQ7eXoHeM")
.image( .image(
Resource Resource

View File

@ -27,11 +27,11 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseItemParserTest; import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.domain.Link; import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.domain.Resource; import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule; import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.Image; import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.openstack.nova.v1_1.domain.ImageStatus; import org.jclouds.openstack.nova.v1_1.domain.Image.Status;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -63,7 +63,7 @@ public class ParseImageTest extends BaseItemParserTest<Image> {
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2010-08-10T12:00:00Z")) .created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2010-08-10T12:00:00Z"))
.tenantId("12345") .tenantId("12345")
.userId("joe") .userId("joe")
.status(ImageStatus.SAVING) .status(Status.SAVING)
.progress(80) .progress(80)
.minDisk(5) .minDisk(5)
.minRam(256) .minRam(256)

View File

@ -27,12 +27,12 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.json.BaseItemParserTest; import org.jclouds.json.BaseItemParserTest;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.openstack.domain.Link; import org.jclouds.openstack.domain.Link;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.domain.Resource; import org.jclouds.openstack.domain.Resource;
import org.jclouds.openstack.domain.Link.Relation;
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule; import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
import org.jclouds.openstack.nova.v1_1.domain.Address; import org.jclouds.openstack.nova.v1_1.domain.Address;
import org.jclouds.openstack.nova.v1_1.domain.Server; import org.jclouds.openstack.nova.v1_1.domain.Server;
import org.jclouds.openstack.nova.v1_1.domain.ServerStatus; import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
import org.jclouds.rest.annotations.SelectJson; import org.jclouds.rest.annotations.SelectJson;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -66,7 +66,7 @@ public class ParseServerTest extends BaseItemParserTest<Server> {
.hostId("e4d909c290d0fb1ca068ffaddf22cbd0") .hostId("e4d909c290d0fb1ca068ffaddf22cbd0")
.accessIPv4("67.23.10.132") .accessIPv4("67.23.10.132")
.accessIPv6("::babe:67.23.10.132") .accessIPv6("::babe:67.23.10.132")
.status(ServerStatus.BUILD) .status(Status.BUILD)
.image( .image(
Resource Resource
.builder() .builder()

View File

@ -0,0 +1,46 @@
/**
* 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.predicates;
import static org.jclouds.openstack.nova.v1_1.predicates.ImagePredicates.statusEquals;
import org.jclouds.openstack.nova.v1_1.domain.Image;
import org.jclouds.openstack.nova.v1_1.domain.Image.Status;
import org.jclouds.openstack.nova.v1_1.parse.ParseImageTest;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "ImagePredicatesTest")
public class ImagePredicatesTest {
Image ref = new ParseImageTest().expected();
@Test
public void teststatusEqualsWhenEqual() {
assert statusEquals(Status.SAVING).apply(ref);
}
@Test
public void teststatusEqualsWhenNotEqual() {
assert !statusEquals(Status.DELETED).apply(ref);
}
}

View File

@ -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.openstack.nova.v1_1.predicates;
import static org.jclouds.openstack.nova.v1_1.predicates.SecurityGroupPredicates.nameEquals;
import org.jclouds.openstack.nova.v1_1.domain.SecurityGroup;
import org.testng.annotations.Test;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "SecurityGroupPredicatesTest")
public class SecurityGroupPredicatesTest {
SecurityGroup ref = SecurityGroup.builder().name("jclouds").description("description").build();
@Test
public void testnameEqualsWhenEqual() {
assert nameEquals("jclouds").apply(ref);
}
@Test
public void testnameEqualsWhenNotEqual() {
assert !nameEquals("foo").apply(ref);
}
}

View File

@ -0,0 +1,53 @@
{
"security_groups":[
{
"rules": [{
"from_port": 22,
"group": {},
"ip_protocol": "tcp",
"to_port": 22,
"parent_group_id": 2769,
"ip_range": {
"cidr": "0.0.0.0/0"
},
"id": 10331
}, {
"from_port": 22,
"group": {
"tenant_id": "37936628937291",
"name": "jclouds#mygroup"
},
"ip_protocol": "tcp",
"to_port": 22,
"parent_group_id": 2769,
"ip_range": {},
"id": 10332
}, {
"from_port": 8080,
"group": {},
"ip_protocol": "tcp",
"to_port": 8080,
"parent_group_id": 2769,
"ip_range": {
"cidr": "0.0.0.0/0"
},
"id": 10333
}, {
"from_port": 8080,
"group": {
"tenant_id": "37936628937291",
"name": "jclouds#mygroup"
},
"ip_protocol": "tcp",
"to_port": 8080,
"parent_group_id": 2769,
"ip_range": {},
"id": 10334
}],
"tenant_id": "37936628937291",
"id": 2769,
"name": "jclouds#mygroup",
"description": "jclouds#mygroup"
}
]
}