diff --git a/common/openstack/src/main/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionSupplier.java b/common/openstack/src/main/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionSupplier.java index 24c0975d3e..08c041a2e4 100644 --- a/common/openstack/src/main/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionSupplier.java +++ b/common/openstack/src/main/java/org/jclouds/openstack/keystone/v2_0/suppliers/RegionIdToURIFromAccessForTypeAndVersionSupplier.java @@ -79,6 +79,9 @@ public class RegionIdToURIFromAccessForTypeAndVersionSupplier implements RegionI @Override public boolean apply(Endpoint input) { + if (input.getVersionId() == null) { + return true; + } return input.getVersionId().equals(apiVersion); } diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java index 70d4338409..1537554022 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaAsyncClient.java @@ -23,7 +23,12 @@ import java.util.Set; import org.jclouds.javax.annotation.Nullable; import org.jclouds.location.Region; import org.jclouds.location.functions.RegionToEndpointOrProviderIfNull; -import org.jclouds.openstack.nova.v1_1.features.*; +import org.jclouds.openstack.nova.v1_1.features.FlavorAsyncClient; +import org.jclouds.openstack.nova.v1_1.features.FloatingIPAsyncClient; +import org.jclouds.openstack.nova.v1_1.features.KeyPairAsyncClient; +import org.jclouds.openstack.nova.v1_1.features.SecurityGroupAsyncClient; +import org.jclouds.openstack.nova.v1_1.features.ImageAsyncClient; +import org.jclouds.openstack.nova.v1_1.features.ServerAsyncClient; import org.jclouds.rest.annotations.Delegate; import org.jclouds.rest.annotations.EndpointParam; @@ -88,5 +93,4 @@ public interface NovaAsyncClient { @Delegate KeyPairAsyncClient getKeyPairClientForRegion( @EndpointParam(parser = RegionToEndpointOrProviderIfNull.class) @Nullable String region); - } diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaContextBuilder.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaContextBuilder.java index 867d84fef9..3e6fec7be3 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaContextBuilder.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/NovaContextBuilder.java @@ -21,16 +21,20 @@ package org.jclouds.openstack.nova.v1_1; import java.util.List; import java.util.Properties; +import org.jclouds.compute.ComputeServiceContextBuilder; +import org.jclouds.openstack.nova.v1_1.compute.config.NovaComputeServiceContextModule; import org.jclouds.openstack.nova.v1_1.config.NovaRestClientModule; import org.jclouds.rest.RestContextBuilder; import com.google.inject.Module; /** - * + * A context builder for getting nova clients. + * * @author Adrian Cole */ -public class NovaContextBuilder extends RestContextBuilder { +public class NovaContextBuilder extends ComputeServiceContextBuilder +{ public NovaContextBuilder(Properties props) { super(NovaClient.class, NovaAsyncClient.class, props); @@ -41,4 +45,8 @@ public class NovaContextBuilder extends RestContextBuilder modules) { + modules.add(new NovaComputeServiceContextModule()); + } } diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java new file mode 100644 index 0000000000..7e589a7eef --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/config/NovaComputeServiceContextModule.java @@ -0,0 +1,71 @@ +/** + * 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.config; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.config.ComputeServiceAdapterContextModule; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.domain.Location; +import org.jclouds.functions.IdentityFunction; +import org.jclouds.openstack.nova.v1_1.NovaAsyncClient; +import org.jclouds.openstack.nova.v1_1.NovaClient; +import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorToHardware; +import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToImage; +import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToOperatingSystem; +import org.jclouds.openstack.nova.v1_1.compute.functions.ServerToNodeMetadata; +import org.jclouds.openstack.nova.v1_1.compute.strategy.NovaComputeServiceAdapter; +import org.jclouds.openstack.nova.v1_1.domain.Flavor; +import org.jclouds.openstack.nova.v1_1.domain.Server; + +/** + * Module for building a compute service context for Nova + * + * @author Matt Stephenson + */ +public class NovaComputeServiceContextModule extends + ComputeServiceAdapterContextModule +{ + public NovaComputeServiceContextModule() + { + super(NovaClient.class, NovaAsyncClient.class); + } + + @SuppressWarnings("unchecked") + @Override + protected void configure() + { + super.configure(); + bind(new TypeLiteral>(){}).to(NovaComputeServiceAdapter.class); + + bind(new TypeLiteral>(){}).to(ServerToNodeMetadata.class); + + bind(new TypeLiteral>(){}).to(NovaImageToImage.class); + bind(new TypeLiteral>(){}).to(NovaImageToOperatingSystem.class); + + bind(new TypeLiteral>(){}).to(FlavorToHardware.class); + + // we aren't converting location from a provider-specific type + bind(new TypeLiteral>(){}).to((Class)IdentityFunction.class); + } +} \ No newline at end of file diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/FlavorToHardware.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/FlavorToHardware.java new file mode 100644 index 0000000000..612162c957 --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/FlavorToHardware.java @@ -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.compute.functions; + +import com.google.common.base.Function; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.HardwareBuilder; +import org.jclouds.compute.domain.Processor; +import org.jclouds.compute.domain.internal.VolumeImpl; +import org.jclouds.openstack.nova.v1_1.domain.Flavor; + +/** + * A function for transforming the nova specific Flavor object to the generic Hardware object. + * + * @author Matt Stephenson + */ +public class FlavorToHardware implements Function +{ + @Override + public Hardware apply(Flavor flavor) + { + return new HardwareBuilder() + .id(flavor.getId()) + .name(flavor.getName()) + .ram(flavor.getRam()) + .processor(new Processor(flavor.getVcpus(), 1.0)) + .volume(new VolumeImpl(Float.valueOf(flavor.getDisk()), true, true)) + .build(); + } +} diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/NovaImageToImage.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/NovaImageToImage.java new file mode 100644 index 0000000000..4ee628e9be --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/NovaImageToImage.java @@ -0,0 +1,52 @@ +/** + * 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 com.google.common.base.Function; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.domain.OperatingSystem; +import javax.inject.Inject; + +/** + * A function for transforming a nova-specific Image into a generic Image object. + * + * @author Matt Stephenson + */ +public class NovaImageToImage implements Function +{ + private final Function imageToOs; + + @Inject + public NovaImageToImage(Function imageToOs) + { + this.imageToOs = imageToOs; + } + + @Override + public Image apply(org.jclouds.openstack.nova.v1_1.domain.Image image) + { + return new ImageBuilder() + .id(image.getId()) + .name(image.getName()) + .operatingSystem(imageToOs.apply(image)) + .description(image.getName()) + .build(); + } +} diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/NovaImageToOperatingSystem.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/NovaImageToOperatingSystem.java new file mode 100644 index 0000000000..299171ad5d --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/NovaImageToOperatingSystem.java @@ -0,0 +1,115 @@ +/** + * 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 com.google.common.base.CharMatcher; +import com.google.common.base.Function; +import com.google.common.base.Objects; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.base.Splitter; +import com.google.common.collect.Iterables; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.compute.util.ComputeServiceUtils; +import org.jclouds.logging.Logger; +import org.jclouds.openstack.nova.v1_1.domain.Image; +import java.util.Arrays; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Named; + +/** + * A function for transforming a nova specific Image into a generic OperatingSystem object. + * + * @author Matt Stephenson + */ +public class NovaImageToOperatingSystem implements Function +{ + public static final Pattern DEFAULT_PATTERN = Pattern.compile("(([^ ]*) ([0-9.]+) ?.*)"); + // Windows Server 2008 R2 x64 + public static final Pattern WINDOWS_PATTERN = Pattern.compile("Windows (.*) (x[86][64])"); + + @javax.annotation.Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + private final Map> osVersionMap; + + @Inject + public NovaImageToOperatingSystem(Map> osVersionMap) + { + this.osVersionMap = osVersionMap; + } + + public OperatingSystem apply(final Image from) + { + OsFamily osFamily = null; + String osVersion = null; + + String imageName = Objects.firstNonNull(from.getName(), "unspecified"); + + boolean is64Bit = true; + + if (imageName.indexOf("Windows") != -1) + { + osFamily = OsFamily.WINDOWS; + Matcher matcher = WINDOWS_PATTERN.matcher(from.getName()); + if (matcher.find()) + { + osVersion = ComputeServiceUtils.parseVersionOrReturnEmptyString(osFamily, matcher.group(1), osVersionMap); + is64Bit = matcher.group(2).equals("x64"); + } + } + else + { + if (imageName.contains("Red Hat EL")) + { + osFamily = OsFamily.RHEL; + } + else if (imageName.contains("Oracle EL")) + { + osFamily = OsFamily.OEL; + } + else + { + final Iterable imageNameParts = Splitter.on(CharMatcher.WHITESPACE).trimResults().split(imageName.toLowerCase()); + + osFamily = Iterables.find(Arrays.asList(OsFamily.values()), new Predicate() + { + @Override + public boolean apply(@Nullable OsFamily osFamily) + { + return Iterables.any(imageNameParts, Predicates.equalTo(osFamily.name().toLowerCase())); + } + }); + } + Matcher matcher = DEFAULT_PATTERN.matcher(imageName); + if (matcher.find() && matcher.groupCount() >= 3) + { + osVersion = ComputeServiceUtils.parseVersionOrReturnEmptyString(osFamily, matcher.group(3), osVersionMap); + } + } + return new OperatingSystem(osFamily, imageName, osVersion, null, imageName, is64Bit); + } +} diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerToNodeMetadata.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerToNodeMetadata.java new file mode 100644 index 0000000000..d564c093c6 --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/functions/ServerToNodeMetadata.java @@ -0,0 +1,76 @@ +/** + * 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 com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.NodeMetadataBuilder; +import org.jclouds.compute.domain.NodeState; +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.ServerStatus; +import java.util.Map; + +/** + * A function for transforming a nova-specific Server into a generic NodeMetadata object. + * + * @author Matt Stephenson + */ +public class ServerToNodeMetadata implements Function +{ + + @VisibleForTesting + public static final Map serverToNodeState = ImmutableMap.builder() + .put(ServerStatus.ACTIVE, NodeState.RUNNING) + .put(ServerStatus.SUSPENDED, NodeState.SUSPENDED) + .put(ServerStatus.DELETED, NodeState.TERMINATED) + .put(ServerStatus.RESIZE, NodeState.PENDING) + .put(ServerStatus.VERIFY_RESIZE, NodeState.PENDING) + .put(ServerStatus.BUILD, NodeState.PENDING) + .put(ServerStatus.PASSWORD, NodeState.PENDING) + .put(ServerStatus.REBUILD, NodeState.PENDING) + .put(ServerStatus.REBOOT, NodeState.PENDING) + .put(ServerStatus.HARD_REBOOT, NodeState.PENDING) + .put(ServerStatus.UNKNOWN, NodeState.UNRECOGNIZED) + .put(ServerStatus.UNRECOGNIZED, NodeState.UNRECOGNIZED).build(); + + @Override + public NodeMetadata apply(Server server) + { + return new NodeMetadataBuilder() + .id(server.getId()) + .name(server.getName()) + .publicAddresses(Iterables.transform(server.getPublicAddresses(), new AddressToStringTransformationFunction())) + .privateAddresses(Iterables.transform(server.getPrivateAddresses(), new AddressToStringTransformationFunction())) + .state(server.getStatus().getNodeState()) + .build(); + } + + private class AddressToStringTransformationFunction implements Function + { + @Override + public String apply(Address address) + { + return address.getAddr(); + } + } +} diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/strategy/NovaComputeServiceAdapter.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/strategy/NovaComputeServiceAdapter.java new file mode 100644 index 0000000000..557f411cc0 --- /dev/null +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/compute/strategy/NovaComputeServiceAdapter.java @@ -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.strategy; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.domain.Template; +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.openstack.nova.v1_1.NovaClient; +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.RebootType; +import org.jclouds.openstack.nova.v1_1.domain.Server; +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.ServerClient; +import java.util.Set; +import javax.annotation.Nullable; +import javax.inject.Inject; + +/** + * The adapter used by the NovaComputeServiceContextModule to interface the nova-specific domain model to the computeService generic domain model. + * + * @author Matt Stephenson + */ +public class NovaComputeServiceAdapter implements ComputeServiceAdapter +{ + + private final NovaClient novaClient; + private final ServerClient defaultLocationServerClient; + private final FlavorClient defaultFlavorClient; + private final ImageClient defaultImageClient; + private final Set regions; + + + @Inject + public NovaComputeServiceAdapter(NovaClient novaClient) + { + this.novaClient = novaClient; + regions = novaClient.getConfiguredRegions(); + if (regions.isEmpty()) + { + throw new IllegalStateException("No regions exist for this compute service. The Nova compute service requires at least 1 region."); + } + String region = regions.iterator().next(); + this.defaultLocationServerClient = novaClient.getServerClientForRegion(region); + this.defaultFlavorClient = novaClient.getFlavorClientForRegion(region); + this.defaultImageClient = novaClient.getImageClientForRegion(region); + } + + @Override + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String tag, String name, Template template) + { + ServerClient serverClient = template.getLocation() != null ? novaClient.getServerClientForRegion(template.getLocation().getId()) : defaultLocationServerClient; + Server server = serverClient.createServer(name, template.getImage().getId(), template.getHardware().getId()); + return new NodeAndInitialCredentials(server, server.getId() + "", LoginCredentials.builder().password(server.getAdminPass()).build()); + } + + @Override + public Iterable listHardwareProfiles() + { + return defaultFlavorClient.listFlavorsInDetail(); + } + + @Override + public Iterable listImages() + { + return defaultImageClient.listImagesInDetail(); + } + + @Override + public Iterable listLocations() + { + return Iterables.transform(novaClient.getConfiguredRegions(), new Function() + { + + @Override + public Location apply(@Nullable String region) + { + return new LocationBuilder().id(region).description(region).build(); + } + }); + } + + @Override + public Server getNode(String id) + { + return defaultLocationServerClient.getServer(id); + } + + @Override + public void destroyNode(String id) + { + defaultLocationServerClient.deleteServer(id); + } + + @Override + public void rebootNode(String id) + { + defaultLocationServerClient.rebootServer(id, RebootType.SOFT); + } + + @Override + public void resumeNode(String id) + { + throw new UnsupportedOperationException("suspend not supported"); + } + + @Override + public void suspendNode(String id) + { + throw new UnsupportedOperationException("suspend not supported"); + } + + @Override + public Iterable listNodes() + { + ImmutableSet.Builder servers = new ImmutableSet.Builder(); + + for (String region : regions) + { + servers.addAll(novaClient.getServerClientForRegion(region).listServersInDetail()); + } + + return servers.build(); + } +} diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java index 4ec522c217..4328bf5b89 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/Server.java @@ -18,11 +18,9 @@ */ package org.jclouds.openstack.nova.v1_1.domain; -import static com.google.common.base.Objects.toStringHelper; -import static com.google.common.base.Preconditions.checkNotNull; - import java.util.Collection; import java.util.Date; +import java.util.Collections; import java.util.Map; import java.util.Set; @@ -37,6 +35,8 @@ import org.jclouds.util.Multimaps2; import com.google.gson.annotations.SerializedName; +import static com.google.common.base.Objects.toStringHelper; +import static com.google.common.base.Preconditions.checkNotNull; /** * A server is a virtual machine instance in the compute system. Flavor and * image are requisite elements when creating a server. @@ -69,8 +69,8 @@ public class Server extends Resource { private Resource flavor; private Map metadata = Maps.newHashMap(); // TODO: get gson multimap ad - private Multimap addresses = LinkedHashMultimap - .create(); + private Multimap addresses = LinkedHashMultimap.create(); + private String adminPass; /** * @see Server#getTenantId() @@ -211,11 +211,19 @@ public class Server extends Resource { return this; } + /** + * @see Server#getAdminPass() + */ + public Builder adminPass(String adminPass) { + this.adminPass = adminPass; + return this; + } + public Server build() { // return new Server(id, name, links, addresses); return new Server(id, name, links, tenantId, userId, updated, created, hostId, accessIPv4, accessIPv6, status, progress, - image, flavor, addresses, metadata); + image, flavor, adminPass, addresses, metadata); } public Builder fromServer(Server in) { @@ -268,15 +276,15 @@ public class Server extends Resource { protected int progress; protected Resource image; protected Resource flavor; + protected final String adminPass; // TODO: get gson multimap adapter! protected final Map> addresses; protected Map metadata; - protected String adminPass; protected Server(String id, String name, Set links, String tenantId, String userId, Date updated, Date created, String hostId, String accessIPv4, String accessIPv6, ServerStatus status, - int progress, Resource image, Resource flavor, + int progress, Resource image, Resource flavor, String adminPass, Multimap addresses, Map metadata) { super(id, name, links); this.tenantId = tenantId; @@ -293,7 +301,7 @@ public class Server extends Resource { this.metadata = Maps.newHashMap(metadata); this.addresses = Multimaps2.toOldSchool(ImmutableMultimap .copyOf(checkNotNull(addresses, "addresses"))); - + this.adminPass = adminPass; } public String getTenantId() { @@ -343,11 +351,6 @@ public class Server extends Resource { public Map getMetadata() { return this.metadata; } - - - public String getAdminPass() { - return this.adminPass; - } /** * @return the private ip addresses assigned to the server @@ -402,6 +405,13 @@ public class Server extends Resource { } } + /** + * @return the administrative password for this server. + */ + public String getAdminPass() { + return adminPass; + } + @Override public String toString() { return toStringHelper("").add("id", id).add("name", name) @@ -411,7 +421,7 @@ public class Server extends Resource { .add("status", status).add("progress", progress) .add("image", image).add("flavor", flavor) .add("metadata", metadata) - .add("links", links).add("addresses", addresses).toString(); + .add("links", links).add("addresses", addresses) + .add("adminPass",adminPass).toString(); } - } diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/ServerStatus.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/ServerStatus.java index 77c9531a04..799b614f41 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/ServerStatus.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/domain/ServerStatus.java @@ -18,6 +18,8 @@ */ 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. @@ -29,7 +31,27 @@ package org.jclouds.openstack.nova.v1_1.domain; * @author Adrian Cole */ public enum ServerStatus { - ACTIVE, BUILD, REBUILD, SUSPENDED, RESIZE, VERIFY_RESIZE, REVERT_RESIZE, PASSWORD, REBOOT, HARD_REBOOT, DELETED, UNKNOWN, ERROR, UNRECOGNIZED; + + 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(); @@ -43,4 +65,8 @@ public enum ServerStatus { } } + public NodeState getNodeState() + { + return nodeState; + } } diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClient.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClient.java index 4ea13135bc..f408b5206a 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClient.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerAsyncClient.java @@ -94,9 +94,8 @@ public interface ServerAsyncClient { @ExceptionParser(ReturnNullOnNotFoundOr404.class) ListenableFuture getServer(@PathParam("id") String id); - /** - * @see NovaClient#deleteServer + * @see ServerClient#deleteServer */ @DELETE @Consumes @@ -105,7 +104,7 @@ public interface ServerAsyncClient { ListenableFuture deleteServer(@PathParam("id") String id); /** - * @see NovaClient#rebootServer + * @see ServerClient#rebootServer */ @POST @Path("/servers/{id}/action") @@ -115,7 +114,7 @@ public interface ServerAsyncClient { ListenableFuture rebootServer(@PathParam("id") String id, @PayloadParam("type") RebootType rebootType); /** - * @see NovaClient#resizeServer + * @see ServerClient#resizeServer */ @POST @Path("/servers/{id}/action") @@ -125,7 +124,7 @@ public interface ServerAsyncClient { ListenableFuture resizeServer(@PathParam("id") String id, @PayloadParam("flavorId") String flavorId); /** - * @see NovaClient#confirmResizeServer + * @see ServerClient#confirmResizeServer */ @POST @Path("/servers/{id}/action") @@ -135,7 +134,7 @@ public interface ServerAsyncClient { ListenableFuture confirmResizeServer(@PathParam("id") String id); /** - * @see NovaClient#revertResizeServer + * @see ServerClient#revertResizeServer */ @POST @Path("/servers/{id}/action") @@ -145,7 +144,7 @@ public interface ServerAsyncClient { ListenableFuture revertResizeServer(@PathParam("id") String id); /** - * @see NovaClient#createServer + * @see ServerClient#createServer */ @POST @Unwrap @@ -156,7 +155,7 @@ public interface ServerAsyncClient { @PayloadParam("flavorRef") String flavorRef, CreateServerOptions... options); /** - * @see NovaClient#rebuildServer + * @see ServerClient#rebuildServer */ @POST @Path("/servers/{id}/action") @@ -166,7 +165,7 @@ public interface ServerAsyncClient { /** - * @see NovaClient#changeAdminPass + * @see ServerClient#changeAdminPass */ @POST @Path("/servers/{id}/action") @@ -176,7 +175,7 @@ public interface ServerAsyncClient { ListenableFuture changeAdminPass(@PathParam("id") String id, @PayloadParam("adminPass") String adminPass); /** - * @see NovaClient#renameServer + * @see ServerClient#renameServer */ @PUT @Path("/servers/{id}") diff --git a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerClient.java b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerClient.java index a281ad941f..130db0720f 100644 --- a/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerClient.java +++ b/labs/openstack-nova/src/main/java/org/jclouds/openstack/nova/v1_1/features/ServerClient.java @@ -18,33 +18,14 @@ */ package org.jclouds.openstack.nova.v1_1.features; -import java.util.Set; -import java.util.concurrent.TimeUnit; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - import org.jclouds.concurrent.Timeout; import org.jclouds.openstack.domain.Resource; -import org.jclouds.openstack.nova.v1_1.NovaClient; 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.options.CreateServerOptions; import org.jclouds.openstack.nova.v1_1.options.RebuildServerOptions; -import org.jclouds.rest.annotations.ExceptionParser; -import org.jclouds.rest.annotations.MapBinder; -import org.jclouds.rest.annotations.Payload; -import org.jclouds.rest.annotations.PayloadParam; -import org.jclouds.rest.annotations.Unwrap; -import org.jclouds.rest.functions.ReturnFalseOnNotFoundOr404; - -import com.google.common.util.concurrent.ListenableFuture; +import java.util.Set; +import java.util.concurrent.TimeUnit; /** * Provides synchronous access to Server. @@ -82,49 +63,92 @@ public interface ServerClient { Server getServer(String id); /** - * @see NovaClient#createServer + * Create a new server + * + * @param name + * name of the server to create + * @param imageRef + * reference to the image for the server to use + * @param flavorRef + * reference to the flavor to use when creating the server + * @param options + * optional parameters to be passed into the server creation request + * @return the newly created server */ - Server createServer(String name, String imageRef, - String flavorRef, CreateServerOptions... options); + Server createServer(String name, String imageRef, String flavorRef, CreateServerOptions... options); /** - * @see NovaClient#deleteServer + * Terminate and delete a server. + * + * @param id + * id of the server + * @return True if successful, False otherwise */ Boolean deleteServer(String id); - /** - * @see NovaClient#rebootServer - */ + /** + * Reboot a server. + * + * @param id + * id of the server + * @param rebootType + * The type of reboot to perform (Hard/Soft) + */ void rebootServer(String id, RebootType rebootType); - /** - * @see NovaClient#resizeServer - */ + /** + * Resize a server to a new flavor size. + * + * @param id + * id of the server + * @param flavorId + * id of the new flavor to use + */ void resizeServer(String id, String flavorId); - /** - * @see NovaClient#confirmResizeServer + /** + * Confirm a resize operation. + * + * @param id + * id of the server */ void confirmResizeServer(String id); - /** - * @see NovaClient#revertResizeServer - */ + /** + * Revert a resize operation. + * + * @param id + * id of the server + */ void revertResizeServer(String id); - /** - * @see NovaClient#rebuildServer + /** + * Rebuild a server. + * + * @param id + * id of the server + * @param options + * Optional paramaters to the rebuilding operation. */ void rebuildServer(String id, RebuildServerOptions... options); - /** - * @see NovaClient#changeAdminPass + /** + * Change the administrative password to a server. + * + * @param id + * id of the server + * @param adminPass + * The new administrative password to use */ void changeAdminPass(String id, String adminPass); - /** - * @see NovaClient#renameServer + /** + * Rename a server. + * + * @param id + * id of the server + * @param newName + * The new name for the server */ void renameServer(String id, String newName); - } diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientExpectTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientExpectTest.java index bcd103da73..134082d018 100644 --- a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientExpectTest.java +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FlavorClientExpectTest.java @@ -1,3 +1,21 @@ +/** + * 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.features; import static org.testng.Assert.assertEquals; diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FloatingIPClientExpectTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FloatingIPClientExpectTest.java index e1d95586ad..8f1a3ec534 100644 --- a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FloatingIPClientExpectTest.java +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/FloatingIPClientExpectTest.java @@ -1,3 +1,21 @@ +/** + * 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.features; import com.google.common.collect.ImmutableMultimap; diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/NovaComputeServiceExpectTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/NovaComputeServiceExpectTest.java new file mode 100644 index 0000000000..8ddab690cc --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/features/NovaComputeServiceExpectTest.java @@ -0,0 +1,82 @@ +/** + * 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.features; + +import com.google.common.collect.ImmutableMultimap; +import org.jclouds.compute.ComputeService; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.openstack.domain.Resource; +import org.jclouds.openstack.nova.v1_1.domain.Server; +import org.jclouds.openstack.nova.v1_1.internal.BaseNovaComputeServiceExpectTest; +import org.jclouds.openstack.nova.v1_1.parse.ParseServerListTest; +import org.testng.annotations.Test; +import java.net.URI; +import java.util.Set; + +import static org.testng.Assert.*; + +/** + * Tests the compute service abstraction of the nova client. + * + * @author Matt Stephenson + */ +@Test(groups = "unit", testName = "NovaComputeServiceExpectTest") +public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTest +{ + + public void testListServersWhenResponseIs2xx() throws Exception + { + HttpRequest listServers = HttpRequest.builder().method("GET").endpoint( + URI.create("https://compute.north.host/v1.1/3456/servers/detail")).headers( + ImmutableMultimap.builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listServersResponse = HttpResponse.builder().statusCode(200).payload( + payloadFromResource("/server_list_details.json")).build(); + + ComputeService clientWhenServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey, + responseWithKeystoneAccess, listServers, listServersResponse); + + + assertNotNull(clientWhenServersExist.listAssignableLocations()); + assertEquals(clientWhenServersExist.listAssignableLocations().size(), 1); + assertEquals(clientWhenServersExist.listAssignableLocations().iterator().next().getId(), "North"); + + assertNotNull(clientWhenServersExist.listNodes()); + assertEquals(clientWhenServersExist.listNodes().size(), 1); + assertEquals(clientWhenServersExist.listNodes().iterator().next().getId(), "52415800-8b69-11e0-9b19-734f000004d2"); + assertEquals(clientWhenServersExist.listNodes().iterator().next().getName(), "sample-server"); + } + + public void testListServersWhenReponseIs404IsEmpty() throws Exception + { + HttpRequest listServers = HttpRequest.builder().method("GET").endpoint( + URI.create("https://compute.north.host/v1.1/3456/servers/detail")).headers( + ImmutableMultimap.builder().put("Accept", "application/json").put("X-Auth-Token", + authToken).build()).build(); + + HttpResponse listServersResponse = HttpResponse.builder().statusCode(404).build(); + + ComputeService clientWhenNoServersExist = requestsSendResponses(keystoneAuthWithAccessKeyAndSecretKey, + responseWithKeystoneAccess, listServers, listServersResponse); + + assertTrue(clientWhenNoServersExist.listNodes().isEmpty()); + } +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/FlavorToHardwareTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/FlavorToHardwareTest.java new file mode 100644 index 0000000000..e86e37bd73 --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/FlavorToHardwareTest.java @@ -0,0 +1,62 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.openstack.nova.v1_1.functions; + +import org.jclouds.compute.domain.Hardware; +import org.jclouds.openstack.nova.v1_1.compute.functions.FlavorToHardware; +import org.jclouds.openstack.nova.v1_1.domain.Flavor; +import org.testng.annotations.Test; +import java.util.UUID; + +import static org.testng.Assert.*; + +/** + * Tests the function used to transform Flavor objects into Hardware objects + * + * @author Matt Stephenson + */ +public class FlavorToHardwareTest +{ + @Test + public void testConversion() + { + UUID id = UUID.randomUUID(); + Flavor flavorToConvert = Flavor.builder() + .id(id.toString()) + .name("Test Flavor " + id) + .ram(262144) + .disk(10000) + .vcpus(16) + .build(); + + Hardware converted = new FlavorToHardware().apply(flavorToConvert); + + assertEquals(converted.getName(), flavorToConvert.getName()); + assertEquals(converted.getId(), flavorToConvert.getId()); + assertEquals(converted.getRam(), flavorToConvert.getRam()); + + assertNotNull(converted.getProcessors()); + assertFalse(converted.getProcessors().isEmpty()); + assertEquals(converted.getProcessors().iterator().next().getCores(), (double)flavorToConvert.getVcpus()); + + assertNotNull(converted.getVolumes()); + assertFalse(converted.getVolumes().isEmpty()); + assertEquals(converted.getVolumes().iterator().next().getSize(), Float.valueOf(flavorToConvert.getDisk())); + } +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/NovaImageToImageTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/NovaImageToImageTest.java new file mode 100644 index 0000000000..91e534e56c --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/NovaImageToImageTest.java @@ -0,0 +1,75 @@ +/** + * 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.functions; + +import com.google.common.base.Function; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToImage; +import org.jclouds.openstack.nova.v1_1.domain.Image; +import org.testng.annotations.Test; +import java.util.UUID; +import javax.annotation.Nullable; + +import static org.testng.Assert.assertEquals; + +/** + * Tests the function that transforms nova-specific images to generic images. + * + * @author Matt Stephenson + */ +public class NovaImageToImageTest +{ + @Test + public void testConversion() + { + UUID id = UUID.randomUUID(); + Image novaImageToConvert = Image.builder().id(id.toString()).name("Test Image " + id).build(); + OperatingSystem operatingSystem = new OperatingSystem(OsFamily.UBUNTU, "My Test OS", "My Test Version", "x86", "My Test OS", true); + NovaImageToImage converter = new NovaImageToImage(new MockImageToOsConverter(operatingSystem)); + org.jclouds.compute.domain.Image convertedImage = converter.apply(novaImageToConvert); + + assertEquals(convertedImage.getId(), novaImageToConvert.getId()); + assertEquals(convertedImage.getName(), novaImageToConvert.getName()); + assertEquals(convertedImage.getOperatingSystem(), operatingSystem); + } + + private class MockImageToOsConverter implements Function + { + + private final OperatingSystem operatingSystem; + + public MockImageToOsConverter(OperatingSystem operatingSystem) + { + this.operatingSystem = operatingSystem; + } + + @Override + public OperatingSystem apply(@Nullable Image image) + { + return operatingSystem; + } + + @Override + public boolean equals(@Nullable Object o) + { + return false; + } + } +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/NovaImageToOperatingSystemTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/NovaImageToOperatingSystemTest.java new file mode 100644 index 0000000000..1873120c24 --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/NovaImageToOperatingSystemTest.java @@ -0,0 +1,157 @@ +/** + * 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.functions; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.openstack.nova.v1_1.compute.functions.NovaImageToOperatingSystem; +import org.jclouds.openstack.nova.v1_1.domain.Image; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Nullable; + +import static org.testng.Assert.*; + +/** + * Tests for the function for transforming a nova specific Image into a generic OperatingSystem object. + * + * @author Matt Stephenson + */ +public class NovaImageToOperatingSystemTest +{ + + @Test(dataProvider = "getOsFamilyValues") + public void testOsFamilyValues(OsFamily family) + { + + Image imageToConvert = Image.builder().id("id-" + family.name()).name(family.name()).build(); + + NovaImageToOperatingSystem converter = new NovaImageToOperatingSystem(new HashMap>()); + + OperatingSystem convertedOs = converter.apply(imageToConvert); + + assertEquals(convertedOs.getName(), imageToConvert.getName()); + assertEquals(convertedOs.getFamily(), family); + assertEquals(convertedOs.getDescription(), imageToConvert.getName()); + assertEquals(convertedOs.getVersion(), null); + assertEquals(convertedOs.getArch(), null); + assertTrue(convertedOs.is64Bit()); + } + + @DataProvider + public Object[][] getOsFamilyValues() + { + return Iterables.toArray(Iterables.transform(Arrays.asList(OsFamily.values()), new Function() + { + @Override + public Object[] apply(@Nullable OsFamily osFamily) + { + return new Object[]{osFamily}; + } + }), Object[].class); + } + + @Test + public void testWindowsServer2008R2x64() + { + String name = "Windows Server 2008 R2 x64"; + + Image imageToConvert = Image.builder().id("id-" + name).name(name).build(); + + Map> osFamilyMap = new HashMap>(); + osFamilyMap.put(OsFamily.WINDOWS, ImmutableMap.of("Server 2008 R2", "Server-2008-R2")); + + NovaImageToOperatingSystem converter = new NovaImageToOperatingSystem(osFamilyMap); + + OperatingSystem convertedOs = converter.apply(imageToConvert); + + assertEquals(convertedOs.getName(), imageToConvert.getName()); + assertEquals(convertedOs.getFamily(), OsFamily.WINDOWS); + assertEquals(convertedOs.getDescription(), imageToConvert.getName()); + assertEquals(convertedOs.getVersion(), "Server-2008-R2"); + assertEquals(convertedOs.getArch(), null); + assertTrue(convertedOs.is64Bit()); + } + + @Test + public void testWindows98x86() + { + String name = "Windows 98 x86"; + + Image imageToConvert = Image.builder().id("id-" + name).name(name).build(); + + Map> osFamilyMap = new HashMap>(); + osFamilyMap.put(OsFamily.WINDOWS, ImmutableMap.of("98", "98")); + + NovaImageToOperatingSystem converter = new NovaImageToOperatingSystem(osFamilyMap); + + OperatingSystem convertedOs = converter.apply(imageToConvert); + + assertEquals(convertedOs.getName(), imageToConvert.getName()); + assertEquals(convertedOs.getFamily(), OsFamily.WINDOWS); + assertEquals(convertedOs.getDescription(), imageToConvert.getName()); + assertEquals(convertedOs.getVersion(), "98"); + assertEquals(convertedOs.getArch(), null); + assertFalse(convertedOs.is64Bit()); + } + + @Test + public void testRHEL() + { + String name = "Red Hat EL"; + + Image imageToConvert = Image.builder().id("id-" + name).name(name).build(); + + NovaImageToOperatingSystem converter = new NovaImageToOperatingSystem(new HashMap>()); + + OperatingSystem convertedOs = converter.apply(imageToConvert); + + assertEquals(convertedOs.getName(), imageToConvert.getName()); + assertEquals(convertedOs.getFamily(), OsFamily.RHEL); + assertEquals(convertedOs.getDescription(), imageToConvert.getName()); + assertEquals(convertedOs.getVersion(), null); + assertEquals(convertedOs.getArch(), null); + assertTrue(convertedOs.is64Bit()); + } + + @Test + public void testOEL() + { + String name = "Oracle EL"; + + Image imageToConvert = Image.builder().id("id-" + name).name(name).build(); + + NovaImageToOperatingSystem converter = new NovaImageToOperatingSystem(new HashMap>()); + + OperatingSystem convertedOs = converter.apply(imageToConvert); + + assertEquals(convertedOs.getName(), imageToConvert.getName()); + assertEquals(convertedOs.getFamily(), OsFamily.OEL); + assertEquals(convertedOs.getDescription(), imageToConvert.getName()); + assertEquals(convertedOs.getVersion(), null); + assertEquals(convertedOs.getArch(), null); + assertTrue(convertedOs.is64Bit()); + } +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/ServerToNodeMetadataTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/ServerToNodeMetadataTest.java new file mode 100644 index 0000000000..c587517b57 --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/functions/ServerToNodeMetadataTest.java @@ -0,0 +1,67 @@ +/** + * 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.functions; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.openstack.nova.v1_1.compute.functions.ServerToNodeMetadata; +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.ServerStatus; +import org.testng.annotations.Test; +import java.util.UUID; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +/** + * Tests for the function for transforming a nova specific Server into a generic NodeMetadata object. + * + * @author Matt Stephenson + */ +public class ServerToNodeMetadataTest +{ + @Test + public void testConversion() + { + UUID id = UUID.randomUUID(); + Server serverToConvert = Server.builder() + .id(id.toString()) + .name("Test Server " + id) + .privateAddresses(Address.createV4("10.0.0.1")) + .publicAddresses(Address.createV4("10.0.1.1")) + .status(ServerStatus.ACTIVE) + .build(); + + ServerToNodeMetadata converter = new ServerToNodeMetadata(); + + NodeMetadata convertedNodeMetadata = converter.apply(serverToConvert); + + assertEquals(serverToConvert.getId(), convertedNodeMetadata.getId()); + assertEquals(serverToConvert.getName(), convertedNodeMetadata.getName()); + assertEquals(serverToConvert.getStatus().getNodeState(), convertedNodeMetadata.getState()); + + assertNotNull(convertedNodeMetadata.getPrivateAddresses()); + assertEquals(convertedNodeMetadata.getPrivateAddresses().size(), 1); + assertEquals(convertedNodeMetadata.getPrivateAddresses().iterator().next(), "10.0.0.1"); + + assertNotNull(convertedNodeMetadata.getPublicAddresses()); + assertEquals(convertedNodeMetadata.getPublicAddresses().size(), 1); + assertEquals(convertedNodeMetadata.getPublicAddresses().iterator().next(), "10.0.1.1"); + } +} diff --git a/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceExpectTest.java b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceExpectTest.java new file mode 100644 index 0000000000..db515f307e --- /dev/null +++ b/labs/openstack-nova/src/test/java/org/jclouds/openstack/nova/v1_1/internal/BaseNovaComputeServiceExpectTest.java @@ -0,0 +1,65 @@ +/** + * 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.internal; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceContextFactory; +import org.jclouds.http.HttpRequest; +import org.jclouds.http.HttpResponse; +import org.jclouds.logging.config.NullLoggingModule; +import org.jclouds.openstack.keystone.v2_0.internal.KeystoneFixture; +import org.jclouds.rest.BaseRestClientExpectTest; +import java.util.Properties; + +/** + * Base class for writing KeyStone Expect tests with the ComputeService abstraction + * + * @author Matt Stephenson + */ +public class BaseNovaComputeServiceExpectTest extends BaseRestClientExpectTest +{ + protected HttpRequest keystoneAuthWithUsernameAndPassword; + protected HttpRequest keystoneAuthWithAccessKeyAndSecretKey; + protected String authToken; + protected HttpResponse responseWithKeystoneAccess; + + public BaseNovaComputeServiceExpectTest() + { + provider = "openstack-nova"; + keystoneAuthWithUsernameAndPassword = KeystoneFixture.INSTANCE.initialAuthWithUsernameAndPassword(identity, + credential); + keystoneAuthWithAccessKeyAndSecretKey = KeystoneFixture.INSTANCE.initialAuthWithAccessKeyAndSecretKey(identity, + credential); + authToken = KeystoneFixture.INSTANCE.getAuthToken(); + responseWithKeystoneAccess = KeystoneFixture.INSTANCE.responseWithAccess(); + // now, createContext arg will need tenant prefix + identity = KeystoneFixture.INSTANCE.getTenantName() + ":" + identity; + } + + + @Override + public ComputeService createClient(Function fn, Module module, Properties props) + { + return new ComputeServiceContextFactory(setupRestProperties()).createContext(provider, identity, credential, + ImmutableSet.of(new ExpectModule(fn), new NullLoggingModule(), module), props).getComputeService(); + } +} diff --git a/labs/openstack-nova/src/test/resources/server_list_details.json b/labs/openstack-nova/src/test/resources/server_list_details.json new file mode 100644 index 0000000000..7ad6a75554 --- /dev/null +++ b/labs/openstack-nova/src/test/resources/server_list_details.json @@ -0,0 +1,79 @@ +{ + "servers": [ + { + "id": "52415800-8b69-11e0-9b19-734f000004d2", + "tenant_id": "1234", + "user_id": "5678", + "name": "sample-server", + "updated": "2010-10-10T12:00:00Z", + "created": "2010-08-10T12:00:00Z", + "hostId": "e4d909c290d0fb1ca068ffaddf22cbd0", + "accessIPv4" : "67.23.10.132", + "accessIPv6" : "::babe:67.23.10.132", + "status": "BUILD", + "progress": 60, + "image" : { + "id": "52415800-8b69-11e0-9b19-734f6f006e54", + "links": [ + { + "rel": "self", + "href": "http://servers.api.openstack.org/v1.1/1234/images/52415800-8b69-11e0-9b19-734f6f006e54" + }, + { + "rel": "bookmark", + "href": "http://servers.api.openstack.org/1234/images/52415800-8b69-11e0-9b19-734f6f006e54" + } + ] + }, + "flavor" : { + "id": "52415800-8b69-11e0-9b19-734f216543fd", + "links": [ + { + "rel": "self", + "href": "http://servers.api.openstack.org/v1.1/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd" + }, + { + "rel": "bookmark", + "href": "http://servers.api.openstack.org/1234/flavors/52415800-8b69-11e0-9b19-734f216543fd" + } + ] + }, + "addresses": { + "public" : [ + { + "version": 4, + "addr": "67.23.10.132" + }, + { + "version": 6, + "addr": "::babe:67.23.10.132" + }, + { + "version": 4, + "addr": "67.23.10.131" + }, + { + "version": 6, + "addr": "::babe:4317:0A83" + } + ], + "private" : [ + { + "version": 4, + "addr": "10.176.42.16" + }, + { + "version": 6, + "addr": "::babe:10.176.42.16" + } + ] + }, + "metadata": { + "Server Label": "Web Head 1", + "Image Version": "2.1" + }, + "links": [ + ] + } + ] +} \ No newline at end of file