JCLOUDS-1047: Fix ProfitBricks compute service live tests

This commit is contained in:
Reijhanniel Jearl Campos 2016-01-19 22:09:00 +08:00 committed by Ignasi Barrera
parent 52c6c2b7b5
commit 235b4b98d4
17 changed files with 285 additions and 284 deletions

View File

@ -16,11 +16,13 @@
*/ */
package org.jclouds.profitbricks; package org.jclouds.profitbricks;
import static org.jclouds.Constants.PROPERTY_CONNECTION_TIMEOUT;
import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT; import static org.jclouds.Constants.PROPERTY_SO_TIMEOUT;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_PERIOD; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_TERMINATED;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_INITIAL_PERIOD;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_MAX_PERIOD; import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_MAX_PERIOD;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_TIMEOUT; import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.TIMEOUT_DATACENTER_AVAILABLE;
import com.google.auto.service.AutoService; import com.google.auto.service.AutoService;
@ -52,13 +54,20 @@ public class ProfitBricksProviderMetadata extends BaseProviderMetadata {
public static Properties defaultProperties() { public static Properties defaultProperties() {
Properties properties = ProfitBricksApiMetadata.defaultProperties(); Properties properties = ProfitBricksApiMetadata.defaultProperties();
long defaultTimeout = 60l * 60l; // 1 hour properties.put(TIMEOUT_DATACENTER_AVAILABLE, 30L * 60L); // 30 minutes
properties.put(POLL_TIMEOUT, defaultTimeout); properties.put(POLL_INITIAL_PERIOD, 5L);
properties.put(POLL_PERIOD, 2l); properties.put(POLL_MAX_PERIOD, 60L);
properties.put(POLL_MAX_PERIOD, 2l * 10l);
properties.put(PROPERTY_SO_TIMEOUT, 60000 * 5); properties.put("jclouds.ssh.max-retries", "7");
properties.put(PROPERTY_CONNECTION_TIMEOUT, 60000 * 5); properties.put("jclouds.ssh.retry-auth", "true");
properties.put(PROPERTY_SO_TIMEOUT, 10 * 60 * 1000);
// Node might still not be available even after DataCenter is done provisioning
// Use 5-minute timeout by default
properties.put(TIMEOUT_NODE_RUNNING, 5 * 60 * 1000);
properties.put(TIMEOUT_NODE_SUSPENDED, 5 * 60 * 1000);
properties.put(TIMEOUT_NODE_TERMINATED, 5 * 60 * 1000);
return properties; return properties;
} }

View File

@ -16,6 +16,7 @@
*/ */
package org.jclouds.profitbricks.compute; package org.jclouds.profitbricks.compute;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Iterables.transform;
import static com.google.common.util.concurrent.Futures.allAsList; import static com.google.common.util.concurrent.Futures.allAsList;
@ -41,6 +42,8 @@ import org.jclouds.compute.domain.internal.VolumeImpl;
import org.jclouds.compute.options.TemplateOptions; import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeServiceUtils; import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.domain.Location;
import org.jclouds.domain.LocationScope;
import org.jclouds.domain.LoginCredentials; import org.jclouds.domain.LoginCredentials;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.profitbricks.ProfitBricksApi; import org.jclouds.profitbricks.ProfitBricksApi;
@ -53,6 +56,7 @@ import org.jclouds.profitbricks.features.DataCenterApi;
import org.jclouds.profitbricks.features.ServerApi; import org.jclouds.profitbricks.features.ServerApi;
import org.jclouds.profitbricks.compute.concurrent.ProvisioningJob; import org.jclouds.profitbricks.compute.concurrent.ProvisioningJob;
import org.jclouds.profitbricks.compute.concurrent.ProvisioningManager; import org.jclouds.profitbricks.compute.concurrent.ProvisioningManager;
import org.jclouds.profitbricks.compute.function.ProvisionableToImage;
import org.jclouds.profitbricks.domain.Snapshot; import org.jclouds.profitbricks.domain.Snapshot;
import org.jclouds.profitbricks.domain.Provisionable; import org.jclouds.profitbricks.domain.Provisionable;
import org.jclouds.profitbricks.util.Passwords; import org.jclouds.profitbricks.util.Passwords;
@ -99,7 +103,10 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
@Override @Override
public NodeAndInitialCredentials<Server> createNodeWithGroupEncodedIntoName(String group, String name, Template template) { public NodeAndInitialCredentials<Server> createNodeWithGroupEncodedIntoName(String group, String name, Template template) {
final String dataCenterId = template.getLocation().getId(); Location location = template.getLocation();
checkArgument(location.getScope() == LocationScope.ZONE, "Template must use a ZONE-scoped location");
final String dataCenterId = location.getId();
Hardware hardware = template.getHardware(); Hardware hardware = template.getHardware();
TemplateOptions options = template.getOptions(); TemplateOptions options = template.getOptions();
@ -116,20 +123,24 @@ public class ProfitBricksComputeServiceAdapter implements ComputeServiceAdapter<
for (final Volume volume : volumes) for (final Volume volume : volumes)
try { try {
logger.trace("<< provisioning storage '%s'", volume); logger.trace("<< provisioning storage '%s'", volume);
final Storage.Request.CreatePayload request = Storage.Request.creatingBuilder() final Storage.Request.CreatePayload.Builder storageBuilder = Storage.Request.creatingBuilder();
.dataCenterId(dataCenterId) if (i == 1) {
// put image to first storage storageBuilder.mountImageId(image.getId());
.mountImageId(i == 1 ? image.getId() : "") // we don't need to pass password to the API if we're using a snapshot
.imagePassword(password) Provisionable.Type provisionableType = Provisionable.Type.fromValue(
image.getUserMetadata().get(ProvisionableToImage.KEY_PROVISIONABLE_TYPE));
if (provisionableType == Provisionable.Type.IMAGE)
storageBuilder.imagePassword(password);
}
storageBuilder.dataCenterId(dataCenterId)
.name(format("%s-disk-%d", name, i++)) .name(format("%s-disk-%d", name, i++))
.size(volume.getSize()) .size(volume.getSize());
.build();
String storageId = (String) provisioningManager.provision(jobFactory.create(dataCenterId, new Supplier<Object>() { String storageId = (String) provisioningManager.provision(jobFactory.create(dataCenterId, new Supplier<Object>() {
@Override @Override
public Object get() { public Object get() {
return api.storageApi().createStorage(request); return api.storageApi().createStorage(storageBuilder.build());
} }
})); }));

View File

@ -0,0 +1,101 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.profitbricks.compute;
import static com.google.common.collect.Iterables.find;
import static java.lang.String.format;
import static org.jclouds.domain.LocationScope.ZONE;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.internal.TemplateBuilderImpl;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Location;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import org.jclouds.compute.domain.Image;
public class ProfitBricksTemplateBuilderImpl extends TemplateBuilderImpl {
private final Function<org.jclouds.profitbricks.domain.Location, Location> fnLocation;
@Inject
ProfitBricksTemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> hardwares,
Supplier<Location> defaultLocation, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider,
Function<org.jclouds.profitbricks.domain.Location, Location> fnLocation) {
super(locations, images, hardwares, defaultLocation, optionsProvider, defaultTemplateProvider);
this.fnLocation = fnLocation;
}
@Override
public TemplateBuilder locationId(final String locationId) {
org.jclouds.profitbricks.domain.Location nativeLocation
= org.jclouds.profitbricks.domain.Location.fromId(locationId);
Set<? extends Location> dataCenters = this.locations.get();
if (nativeLocation != org.jclouds.profitbricks.domain.Location.UNRECOGNIZED)
try {
// look for a child location instead if provided id is a Region
final Location parentLocation = fnLocation.apply(nativeLocation);
this.location = find(dataCenters, new Predicate<Location>() {
@Override
public boolean apply(Location input) {
return parentLocation.equals(input.getParent());
}
@Override
public String toString() {
return "first datacenter in locationId(" + locationId + ")";
}
});
} catch (NoSuchElementException ex) {
throw new NoSuchElementException(
format("no child location found for location id %s in: %s", locationId, locations));
}
else
super.locationId(locationId);
return this;
}
@Override
public Template build() {
Template template = super.build();
Location loc = template.getLocation();
if (loc != null && loc.getScope() != ZONE)
return fromTemplate(template).locationId(loc.getId()).build();
return template;
}
}

View File

@ -19,11 +19,11 @@ package org.jclouds.profitbricks.compute.config;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_RUNNING;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED; import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_PERIOD; import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_INITIAL_PERIOD;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_MAX_PERIOD; import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_MAX_PERIOD;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER; import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_PREDICATE_SNAPSHOT; import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_PREDICATE_SNAPSHOT;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_TIMEOUT; import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.TIMEOUT_DATACENTER_AVAILABLE;
import static org.jclouds.util.Predicates2.retry; import static org.jclouds.util.Predicates2.retry;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -36,6 +36,7 @@ import org.jclouds.compute.config.ComputeServiceAdapterContextModule;
import org.jclouds.compute.domain.Hardware; import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image; import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata; import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.Volume; import org.jclouds.compute.domain.Volume;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.functions.IdentityFunction; import org.jclouds.functions.IdentityFunction;
@ -49,6 +50,7 @@ import org.jclouds.profitbricks.compute.concurrent.ProvisioningManager;
import org.jclouds.profitbricks.domain.DataCenter; import org.jclouds.profitbricks.domain.DataCenter;
import org.jclouds.profitbricks.domain.Server; import org.jclouds.profitbricks.domain.Server;
import org.jclouds.profitbricks.domain.Storage; import org.jclouds.profitbricks.domain.Storage;
import org.jclouds.profitbricks.compute.ProfitBricksTemplateBuilderImpl;
import org.jclouds.profitbricks.compute.function.DataCenterToLocation; import org.jclouds.profitbricks.compute.function.DataCenterToLocation;
import org.jclouds.profitbricks.compute.function.LocationToLocation; import org.jclouds.profitbricks.compute.function.LocationToLocation;
import org.jclouds.profitbricks.compute.function.ProvisionableToImage; import org.jclouds.profitbricks.compute.function.ProvisionableToImage;
@ -64,6 +66,7 @@ import com.google.inject.Provides;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder; import com.google.inject.assistedinject.FactoryModuleBuilder;
public class ProfitBricksComputeServiceContextModule extends public class ProfitBricksComputeServiceContextModule extends
ComputeServiceAdapterContextModule<Server, Hardware, Provisionable, DataCenter> { ComputeServiceAdapterContextModule<Server, Hardware, Provisionable, DataCenter> {
@ -78,6 +81,8 @@ public class ProfitBricksComputeServiceContextModule extends
bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Singleton.class); bind(ImplicitLocationSupplier.class).to(OnlyLocationOrFirstZone.class).in(Singleton.class);
bind(new TypeLiteral<TemplateBuilder>(){}).to(ProfitBricksTemplateBuilderImpl.class);
bind(new TypeLiteral<ComputeServiceAdapter<Server, Hardware, Provisionable, DataCenter>>() { bind(new TypeLiteral<ComputeServiceAdapter<Server, Hardware, Provisionable, DataCenter>>() {
}).to(ProfitBricksComputeServiceAdapter.class); }).to(ProfitBricksComputeServiceAdapter.class);
@ -202,11 +207,11 @@ public class ProfitBricksComputeServiceContextModule extends
public static class ComputeConstants { public static class ComputeConstants {
@Inject @Inject
@Named(POLL_TIMEOUT) @Named(TIMEOUT_DATACENTER_AVAILABLE)
private String pollTimeout; private String pollTimeout;
@Inject @Inject
@Named(POLL_PERIOD) @Named(POLL_INITIAL_PERIOD)
private String pollPeriod; private String pollPeriod;
@Inject @Inject

View File

@ -33,10 +33,13 @@ import org.jclouds.profitbricks.domain.Provisionable;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject; import com.google.inject.Inject;
public class ProvisionableToImage implements Function<Provisionable, Image> { public class ProvisionableToImage implements Function<Provisionable, Image> {
public static final String KEY_PROVISIONABLE_TYPE = "provisionableType";
private final ImageToImage fnImageToImage; private final ImageToImage fnImageToImage;
private final SnapshotToImage fnSnapshotToImage; private final SnapshotToImage fnSnapshotToImage;
@ -76,7 +79,7 @@ public class ProvisionableToImage implements Function<Provisionable, Image> {
} }
} }
private static class ImageToImage implements Function<org.jclouds.profitbricks.domain.Image, Image> { private static class ImageToImage implements ImageFunction<org.jclouds.profitbricks.domain.Image> {
private static final Pattern HAS_NUMBERS = Pattern.compile(".*\\d+.*"); private static final Pattern HAS_NUMBERS = Pattern.compile(".*\\d+.*");
@ -98,12 +101,12 @@ public class ProvisionableToImage implements Function<Provisionable, Image> {
.is64Bit(is64Bit(desc, from.type())) .is64Bit(is64Bit(desc, from.type()))
.build(); .build();
return new ImageBuilder() return addTypeMetadata(new ImageBuilder()
.ids(from.id()) .ids(from.id())
.name(desc) .name(desc)
.location(fnRegion.apply(from.location())) .location(fnRegion.apply(from.location()))
.status(Image.Status.AVAILABLE) .status(Image.Status.AVAILABLE)
.operatingSystem(os) .operatingSystem(os))
.build(); .build();
} }
@ -147,9 +150,14 @@ public class ProvisionableToImage implements Function<Provisionable, Image> {
return true; return true;
} }
} }
@Override
public ImageBuilder addTypeMetadata(ImageBuilder builder) {
return builder.userMetadata(ImmutableMap.of(KEY_PROVISIONABLE_TYPE, Provisionable.Type.IMAGE.toString()));
}
} }
private static class SnapshotToImage implements Function<Snapshot, Image> { private static class SnapshotToImage implements ImageFunction<Snapshot> {
private final Function<org.jclouds.profitbricks.domain.Location, Location> fnRegion; private final Function<org.jclouds.profitbricks.domain.Location, Location> fnRegion;
@ -169,13 +177,13 @@ public class ProvisionableToImage implements Function<Provisionable, Image> {
.version("00.00") .version("00.00")
.build(); .build();
return new ImageBuilder() return addTypeMetadata(new ImageBuilder()
.ids(from.id()) .ids(from.id())
.name(from.name()) .name(from.name())
.description(from.description()) .description(from.description())
.location(fnRegion.apply(from.location())) .location(fnRegion.apply(from.location()))
.status(mapStatus(from.state())) .status(mapStatus(from.state()))
.operatingSystem(os) .operatingSystem(os))
.build(); .build();
} }
@ -211,5 +219,16 @@ public class ProvisionableToImage implements Function<Provisionable, Image> {
return Image.Status.UNRECOGNIZED; return Image.Status.UNRECOGNIZED;
} }
} }
@Override
public ImageBuilder addTypeMetadata(ImageBuilder builder) {
return builder.userMetadata(ImmutableMap.of(KEY_PROVISIONABLE_TYPE, Provisionable.Type.SNAPSHOT.toString()));
}
}
private interface ImageFunction<T extends Provisionable> extends Function<T, Image> {
ImageBuilder addTypeMetadata(ImageBuilder builder);
} }
} }

View File

@ -18,12 +18,12 @@ package org.jclouds.profitbricks.config;
public class ProfitBricksComputeProperties { public class ProfitBricksComputeProperties {
public static final String POLL_PREDICATE_DATACENTER = "jclouds.profitbricks.predicate.datacenter"; public static final String POLL_PREDICATE_DATACENTER = "jclouds.profitbricks.predicate.datacenter";
public static final String POLL_PREDICATE_SNAPSHOT = "jclouds.profitbricks.predicate.snapshot"; public static final String POLL_PREDICATE_SNAPSHOT = "jclouds.profitbricks.predicate.snapshot";
public static final String POLL_TIMEOUT = "jclouds.profitbricks.poll.timeout"; public static final String TIMEOUT_DATACENTER_AVAILABLE = "jclouds.profitbricks.timeout.datacenter-available";
public static final String POLL_PERIOD = "jclouds.profitbricks.operation.poll.initial-period"; public static final String POLL_INITIAL_PERIOD = "jclouds.profitbricks.poll-status.initial-period";
public static final String POLL_MAX_PERIOD = "jclouds.profitbricks.operation.poll.max-period"; public static final String POLL_MAX_PERIOD = "jclouds.profitbricks.poll-status.poll.max-period";
private ProfitBricksComputeProperties() { private ProfitBricksComputeProperties() {
throw new AssertionError("Intentionally unimplemented"); throw new AssertionError("Intentionally unimplemented");

View File

@ -16,10 +16,20 @@
*/ */
package org.jclouds.profitbricks.domain; package org.jclouds.profitbricks.domain;
import com.google.common.base.Enums;
/** /**
* Marker interface for {@link org.jclouds.profitbricks.domain.Image} and * Marker interface for {@link org.jclouds.profitbricks.domain.Image} and
* {@link org.jclouds.profitbricks.domain.Snapshot} * {@link org.jclouds.profitbricks.domain.Snapshot}
*/ */
public interface Provisionable { public interface Provisionable {
public enum Type {
IMAGE, SNAPSHOT;
public static Type fromValue(String v) {
return Enums.getIfPresent(Type.class, v).or(IMAGE);
}
}
} }

View File

@ -1,44 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.profitbricks.domain.internal;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.profitbricks.domain.Firewall;
public interface FirewallRuleCommonProperties {
@Nullable
String name();
@Nullable
Integer portRangeEnd();
@Nullable
Integer portRangeStart();
@Nullable
Firewall.Protocol protocol();
@Nullable
String sourceIp();
@Nullable
String sourceMac();
@Nullable
String targetIp();
}

View File

@ -1,102 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.profitbricks.domain.internal;
import org.jclouds.javax.annotation.Nullable;
public interface HotPluggable {
@Nullable
Boolean isCpuHotPlug();
@Nullable
Boolean isCpuHotUnPlug();
@Nullable
Boolean isRamHotPlug();
@Nullable
Boolean isRamHotUnPlug();
@Nullable
Boolean isNicHotPlug();
@Nullable
Boolean isNicHotUnPlug();
@Nullable
Boolean isDiscVirtioHotPlug();
@Nullable
Boolean isDiscVirtioHotUnPlug();
public abstract static class Builder<B extends Builder, D extends HotPluggable> {
protected Boolean cpuHotPlug;
protected Boolean cpuHotUnPlug;
protected Boolean ramHotPlug;
protected Boolean ramHotUnPlug;
protected Boolean nicHotPlug;
protected Boolean nicHotUnPlug;
protected Boolean discVirtioHotPlug;
protected Boolean discVirtioHotUnPlug;
public B isCpuHotPlug(Boolean cpuHotPlug) {
this.cpuHotPlug = cpuHotPlug;
return self();
}
public B isCpuHotUnPlug(Boolean cpuHotUnplug) {
this.cpuHotUnPlug = cpuHotUnplug;
return self();
}
public B isRamHotPlug(Boolean ramHotPlug) {
this.ramHotPlug = ramHotPlug;
return self();
}
public B isRamHotUnPlug(Boolean ramHotUnplug) {
this.ramHotUnPlug = ramHotUnplug;
return self();
}
public B isNicHotPlug(Boolean nicHotPlug) {
this.nicHotPlug = nicHotPlug;
return self();
}
public B isNicHotUnPlug(Boolean nicHotUnPlug) {
this.nicHotUnPlug = nicHotUnPlug;
return self();
}
public B isDiscVirtioHotPlug(Boolean discVirtioHotPlug) {
this.discVirtioHotPlug = discVirtioHotPlug;
return self();
}
public B isDiscVirtioHotUnPlug(Boolean discVirtioHotUnPlug) {
this.discVirtioHotUnPlug = discVirtioHotUnPlug;
return self();
}
public abstract B self();
public abstract D build();
}
}

View File

@ -1,67 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.profitbricks.domain.internal;
import org.jclouds.profitbricks.domain.Location;
import org.jclouds.profitbricks.domain.OsType;
public interface Provisionable extends HotPluggable {
String id();
String name();
float size(); // MB
Location location();
OsType osType();
public abstract static class Builder<B extends Builder, D extends Provisionable> extends HotPluggable.Builder<B, D> {
protected String id;
protected String name;
protected float size;
protected Location location;
protected OsType osType;
public B id(String id) {
this.id = id;
return self();
}
public B name(String name) {
this.name = name;
return self();
}
public B size(float size) {
this.size = size;
return self();
}
public B location(Location location) {
this.location = location;
return self();
}
public B osType(OsType osType) {
this.osType = osType;
return self();
}
}
}

View File

@ -1,29 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.profitbricks.domain.internal;
/**
* An interface used as common data type for {@link org.jclouds.profitbricks.domain.Server.Builder}
*/
public interface ServerCommonProperties extends HotPluggable {
String name();
int cores();
int ram(); // in MB
}

View File

@ -51,7 +51,7 @@ public class ProfitBricksSoapMessageEnvelope implements HttpRequestFilter {
String body = SOAP_PREFIX.concat(oldPayload.getRawContent().toString()).concat(SOAP_SUFFIX); String body = SOAP_PREFIX.concat(oldPayload.getRawContent().toString()).concat(SOAP_SUFFIX);
Payload newPayload = Payloads.newStringPayload(body); Payload newPayload = Payloads.newStringPayload(body);
HttpUtils.copy(oldMetadata, newPayload.getContentMetadata()); HttpUtils.copy(oldMetadata, newPayload.getContentMetadata());
newPayload.getContentMetadata().setContentLength(Long.valueOf(body.length())); // resize, add prefix/suffix length newPayload.getContentMetadata().setContentLength(Long.valueOf(body.getBytes().length)); // resize, add prefix/suffix length
return request.toBuilder().payload(newPayload).build(); return request.toBuilder().payload(newPayload).build();
} }

View File

@ -45,12 +45,12 @@ import org.jclouds.profitbricks.ProfitBricksApi;
import org.jclouds.profitbricks.domain.DataCenter; import org.jclouds.profitbricks.domain.DataCenter;
import org.jclouds.profitbricks.features.DataCenterApi; import org.jclouds.profitbricks.features.DataCenterApi;
import org.testng.annotations.AfterClass; import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeGroups; import org.testng.annotations.BeforeClass;
@Test(groups = "live", singleThreaded = true, testName = "ProfitBricksComputeServiceLiveTest") @Test(groups = "live", singleThreaded = true, testName = "ProfitBricksComputeServiceLiveTest")
public class ProfitBricksComputeServiceLiveTest extends BaseComputeServiceLiveTest { public class ProfitBricksComputeServiceLiveTest extends BaseComputeServiceLiveTest {
private static final String TEST_DC_NAME = "computeServiceLiveTest" + System.currentTimeMillis(); private static final String TEST_DC_NAME = "computeServiceLiveTest-" + System.currentTimeMillis();
private DataCenter dataCenter; private DataCenter dataCenter;
@ -58,7 +58,7 @@ public class ProfitBricksComputeServiceLiveTest extends BaseComputeServiceLiveTe
provider = "profitbricks"; provider = "profitbricks";
} }
@BeforeGroups(groups = {"integration", "live"}) @BeforeClass
@Override @Override
public void setupContext() { public void setupContext() {
super.setupContext(); super.setupContext();

View File

@ -16,19 +16,85 @@
*/ */
package org.jclouds.profitbricks.compute; package org.jclouds.profitbricks.compute;
import static org.jclouds.profitbricks.BaseProfitBricksLiveTest.testLocation;
import static org.jclouds.profitbricks.config.ProfitBricksComputeProperties.POLL_PREDICATE_DATACENTER;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest; import org.jclouds.compute.internal.BaseTemplateBuilderLiveTest;
import org.jclouds.profitbricks.ProfitBricksApi;
import org.jclouds.profitbricks.domain.DataCenter;
import org.jclouds.profitbricks.features.DataCenterApi;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@Test(groups = "live", testName = "ProfitBricksTemplateBuilderLiveTest") @Test(groups = "live", testName = "ProfitBricksTemplateBuilderLiveTest", singleThreaded = true)
public class ProfitBricksTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest { public class ProfitBricksTemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
private static final String TEST_DC_NAME = "templateBuilderLiveTest-" + System.currentTimeMillis();
private DataCenter dataCenter;
public ProfitBricksTemplateBuilderLiveTest() { public ProfitBricksTemplateBuilderLiveTest() {
this.provider = "profitbricks"; this.provider = "profitbricks";
} }
@BeforeClass
@Override
public void setupContext() {
super.setupContext();
final DataCenterApi api = getDataCenterApi();
final Predicate<String> predicate = getDataCenterPredicate();
dataCenter = FluentIterable.from(api.getAllDataCenters()).firstMatch(new Predicate<DataCenter>() {
@Override
public boolean apply(DataCenter input) {
boolean match = Objects.equals(input.name(), TEST_DC_NAME);
if (match && input.location() == testLocation)
return predicate.apply(input.id());
return match;
}
}).or(new Supplier<DataCenter>() {
@Override
public DataCenter get() {
DataCenter dataCenter = api.createDataCenter(
DataCenter.Request.creatingPayload(TEST_DC_NAME, testLocation));
predicate.apply(dataCenter.id());
return api.getDataCenter(dataCenter.id());
}
});
}
private Predicate<String> getDataCenterPredicate() {
return view.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<String>>() {
}, Names.named(POLL_PREDICATE_DATACENTER)));
}
private DataCenterApi getDataCenterApi() {
return view.unwrapApi(ProfitBricksApi.class).dataCenterApi();
}
@AfterClass(groups = {"integration", "live"}, alwaysRun = true)
@Override
protected void tearDownContext() {
super.tearDownContext();
if (dataCenter != null)
getDataCenterApi().deleteDataCenter(dataCenter.id());
}
@Override @Override
protected Set<String> getIso3166Codes() { protected Set<String> getIso3166Codes() {
return ImmutableSet.of(); return ImmutableSet.of();

View File

@ -35,6 +35,7 @@ import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Suppliers; import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@Test(groups = "unit", testName = "ProvisionableToImageTest") @Test(groups = "unit", testName = "ProvisionableToImageTest")
@ -88,6 +89,7 @@ public class ProvisionableToImageTest {
.version("14.04") .version("14.04")
.is64Bit(false) .is64Bit(false)
.build()) .build())
.userMetadata(ImmutableMap.of("provisionableType", "image"))
.build(); .build();
assertEquals(actual, expected); assertEquals(actual, expected);
@ -118,6 +120,7 @@ public class ProvisionableToImageTest {
.version("7") .version("7")
.is64Bit(true) .is64Bit(true)
.build()) .build())
.userMetadata(ImmutableMap.of("provisionableType", "image"))
.build(); .build();
assertEquals(actual1, expected1); assertEquals(actual1, expected1);
@ -145,6 +148,7 @@ public class ProvisionableToImageTest {
.version("6.5.0") .version("6.5.0")
.is64Bit(true) .is64Bit(true)
.build()) .build())
.userMetadata(ImmutableMap.of("provisionableType", "image"))
.build(); .build();
assertEquals(actual2, expected2); assertEquals(actual2, expected2);
@ -172,6 +176,7 @@ public class ProvisionableToImageTest {
.version("2008") .version("2008")
.is64Bit(false) .is64Bit(false)
.build()) .build())
.userMetadata(ImmutableMap.of("provisionableType", "image"))
.build(); .build();
assertEquals(actual3, expected3); assertEquals(actual3, expected3);
@ -213,6 +218,7 @@ public class ProvisionableToImageTest {
.family(OsFamily.LINUX) .family(OsFamily.LINUX)
.is64Bit(true) .is64Bit(true)
.build()) .build())
.userMetadata(ImmutableMap.of("provisionableType", "snapshot"))
.build(); .build();
assertEquals(actual1, expected1); assertEquals(actual1, expected1);
@ -251,6 +257,7 @@ public class ProvisionableToImageTest {
.is64Bit(true) .is64Bit(true)
.version("00.00") .version("00.00")
.build()) .build())
.userMetadata(ImmutableMap.of("provisionableType", "snapshot"))
.build(); .build();
assertEquals(actual2, expected2); assertEquals(actual2, expected2);

View File

@ -21,6 +21,7 @@ import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue; import static org.testng.Assert.assertTrue;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import org.jclouds.profitbricks.BaseProfitBricksLiveTest; import org.jclouds.profitbricks.BaseProfitBricksLiveTest;
import org.jclouds.profitbricks.domain.OsType; import org.jclouds.profitbricks.domain.OsType;
@ -36,6 +37,8 @@ import com.google.common.base.Predicate;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.FluentIterable; import com.google.common.collect.FluentIterable;
import org.jclouds.util.Predicates2;
@Test(groups = "live", testName = "SnapshotApiLiveTest") @Test(groups = "live", testName = "SnapshotApiLiveTest")
public class SnapshotApiLiveTest extends BaseProfitBricksLiveTest { public class SnapshotApiLiveTest extends BaseProfitBricksLiveTest {
@ -142,8 +145,20 @@ public class SnapshotApiLiveTest extends BaseProfitBricksLiveTest {
@Test(dependsOnMethods = "testRollbackSnapshot", alwaysRun = true) @Test(dependsOnMethods = "testRollbackSnapshot", alwaysRun = true)
public void testDeleteSnapshot() { public void testDeleteSnapshot() {
assertSnapshotAvailable(createdSnapshotId); assertSnapshotAvailable(createdSnapshotId);
boolean result = api.snapshotApi().deleteSnapshot(createdSnapshotId); // Newly created snapshots doesn't seem to reflect in the API right away,
assertTrue(result, "Created snapshot wasn't deleted"); // so we need to persistently try to delete (to clean up resources as well)
Predicate<String> persistentDelete = Predicates2.retry(new Predicate<String>() {
@Override
public boolean apply(String input) {
try {
return api.snapshotApi().deleteSnapshot(input);
} catch (Exception ex) {
return false;
}
}
}, 120L, 5L, 10L, TimeUnit.SECONDS);
assertTrue(persistentDelete.apply(createdSnapshotId), "Created snapshot wasn't deleted");
} }
@AfterClass(alwaysRun = true) @AfterClass(alwaysRun = true)

View File

@ -45,7 +45,7 @@ public class ProfitBricksSoapMessageEnvelopeTest {
HttpRequest filtered = soapEnvelope.filter(request); HttpRequest filtered = soapEnvelope.filter(request);
assertEquals(filtered.getPayload().getRawContent(), expectedPayload); assertEquals(filtered.getPayload().getRawContent(), expectedPayload);
assertEquals(filtered.getPayload().getContentMetadata().getContentLength(), Long.valueOf(expectedPayload.length())); assertEquals(filtered.getPayload().getContentMetadata().getContentLength(), Long.valueOf(expectedPayload.getBytes().length));
} }
@Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*must contain payload message.*") @Test(expectedExceptions = NullPointerException.class, expectedExceptionsMessageRegExp = ".*must contain payload message.*")