Merge pull request #316 from andreisavu/cloudsigma-ssd-option

Add TemplateOptions to create SSD Drives on CloudSigma providers
This commit is contained in:
Adrian Cole 2012-01-15 12:11:39 -08:00
commit 4a1499b028
6 changed files with 468 additions and 7 deletions

View File

@ -32,6 +32,8 @@ import javax.inject.Singleton;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.cloudsigma.CloudSigmaClient; import org.jclouds.cloudsigma.CloudSigmaClient;
import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions;
import org.jclouds.cloudsigma.domain.AffinityType;
import org.jclouds.cloudsigma.domain.Device; import org.jclouds.cloudsigma.domain.Device;
import org.jclouds.cloudsigma.domain.DriveInfo; import org.jclouds.cloudsigma.domain.DriveInfo;
import org.jclouds.cloudsigma.domain.DriveType; import org.jclouds.cloudsigma.domain.DriveType;
@ -109,9 +111,15 @@ public class CloudSigmaComputeServiceAdapter implements
@Override @Override
public NodeAndInitialCredentials<ServerInfo> createNodeWithGroupEncodedIntoName(String tag, String name, Template template) { public NodeAndInitialCredentials<ServerInfo> createNodeWithGroupEncodedIntoName(String tag, String name, Template template) {
long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l); long bootSize = (long) (template.getHardware().getVolumes().get(0).getSize() * 1024 * 1024 * 1024l);
logger.debug(">> imaging boot drive source(%s) bytes(%d)", template.getImage().getId(), bootSize); AffinityType affinityType = AffinityType.HDD;
if (template.getOptions() instanceof CloudSigmaTemplateOptions) {
CloudSigmaTemplateOptions options = CloudSigmaTemplateOptions.class.cast(template.getOptions());
affinityType = options.getDiskDriveAffinity();
}
logger.debug(">> imaging boot drive source(%s) bytes(%d) affinityType(%s)",
template.getImage().getId(), bootSize, affinityType);
DriveInfo drive = client.cloneDrive(template.getImage().getId(), template.getImage().getId(), DriveInfo drive = client.cloneDrive(template.getImage().getId(), template.getImage().getId(),
new CloneDriveOptions().size(bootSize)); new CloneDriveOptions().size(bootSize).affinity(affinityType));
boolean success = driveNotClaimed.apply(drive); boolean success = driveNotClaimed.apply(drive);
logger.debug("<< image(%s) complete(%s)", drive.getUuid(), success); logger.debug("<< image(%s) complete(%s)", drive.getUuid(), success);
if (!success) { if (!success) {
@ -152,7 +160,7 @@ public class CloudSigmaComputeServiceAdapter implements
} }
}).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu))) }).ids(id).ram(ram).processors(ImmutableList.of(new Processor(1, cpu)))
.volumes(ImmutableList.<Volume> of(new VolumeImpl(size, true, true))).build()); .volumes(ImmutableList.<Volume>of(new VolumeImpl(size, true, true))).build());
} }
return hardware.build(); return hardware.build();
} }

View File

@ -0,0 +1,46 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.jclouds.cloudsigma.compute;
import com.google.common.base.Supplier;
import org.jclouds.collect.Memoized;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
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 javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import java.util.Set;
/**
* @author Andrei Savu
*/
public class CloudSigmaTemplateBuilderImpl extends TemplateBuilderImpl {
@Inject
public CloudSigmaTemplateBuilderImpl(@Memoized Supplier<Set<? extends Location>> locations,
@Memoized Supplier<Set<? extends Image>> images, @Memoized Supplier<Set<? extends Hardware>> hardwares,
Supplier<Location> defaultLocation2, @Named("DEFAULT") Provider<TemplateOptions> optionsProvider,
@Named("DEFAULT") Provider<TemplateBuilder> defaultTemplateProvider) {
super(locations, images, hardwares, defaultLocation2, optionsProvider, defaultTemplateProvider);
}
}

View File

@ -26,12 +26,14 @@ import javax.inject.Singleton;
import org.jclouds.cloudsigma.CloudSigmaAsyncClient; import org.jclouds.cloudsigma.CloudSigmaAsyncClient;
import org.jclouds.cloudsigma.CloudSigmaClient; import org.jclouds.cloudsigma.CloudSigmaClient;
import org.jclouds.cloudsigma.compute.CloudSigmaComputeServiceAdapter; import org.jclouds.cloudsigma.compute.CloudSigmaComputeServiceAdapter;
import org.jclouds.cloudsigma.compute.CloudSigmaTemplateBuilderImpl;
import org.jclouds.cloudsigma.compute.functions.ParseOsFamilyVersion64BitFromImageName; import org.jclouds.cloudsigma.compute.functions.ParseOsFamilyVersion64BitFromImageName;
import org.jclouds.cloudsigma.compute.functions.PreinstalledDiskToImage; import org.jclouds.cloudsigma.compute.functions.PreinstalledDiskToImage;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.DeviceToVolume; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.DeviceToVolume;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.FindImageForId; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.FindImageForId;
import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.GetImageIdFromServer; import org.jclouds.cloudsigma.compute.functions.ServerInfoToNodeMetadata.GetImageIdFromServer;
import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions;
import org.jclouds.cloudsigma.domain.Device; import org.jclouds.cloudsigma.domain.Device;
import org.jclouds.cloudsigma.domain.DriveInfo; import org.jclouds.cloudsigma.domain.DriveInfo;
import org.jclouds.cloudsigma.domain.Server; import org.jclouds.cloudsigma.domain.Server;
@ -46,6 +48,7 @@ import org.jclouds.compute.domain.OsFamily;
import org.jclouds.compute.domain.OsFamilyVersion64Bit; import org.jclouds.compute.domain.OsFamilyVersion64Bit;
import org.jclouds.compute.domain.TemplateBuilder; import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.Volume; import org.jclouds.compute.domain.Volume;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.compute.reference.ComputeServiceConstants; import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.functions.IdentityFunction; import org.jclouds.functions.IdentityFunction;
@ -104,6 +107,8 @@ public class CloudSigmaComputeServiceContextModule
}).to(ParseOsFamilyVersion64BitFromImageName.class); }).to(ParseOsFamilyVersion64BitFromImageName.class);
bind(new TypeLiteral<Supplier<Location>>() { bind(new TypeLiteral<Supplier<Location>>() {
}).to(OnlyLocationOrFirstZone.class); }).to(OnlyLocationOrFirstZone.class);
bind(TemplateBuilder.class)
.to(CloudSigmaTemplateBuilderImpl.class);
} }
@Provides @Provides
@ -134,4 +139,10 @@ public class CloudSigmaComputeServiceContextModule
return new RetryablePredicate<DriveInfo>(Predicates.not(driveClaimed), timeouts.nodeRunning, 1000, return new RetryablePredicate<DriveInfo>(Predicates.not(driveClaimed), timeouts.nodeRunning, 1000,
TimeUnit.MILLISECONDS); TimeUnit.MILLISECONDS);
} }
@Provides
@Singleton
protected TemplateOptions templateOptions() {
return new CloudSigmaTemplateOptions();
}
} }

View File

@ -21,7 +21,6 @@ package org.jclouds.cloudsigma.compute.functions;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName; import static org.jclouds.compute.util.ComputeServiceUtils.parseGroupFromName;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -102,7 +101,7 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
} }
builder.hardware(new HardwareBuilder().ids(from.getUuid()) builder.hardware(new HardwareBuilder().ids(from.getUuid())
.processors(ImmutableList.of(new Processor(1, from.getCpu()))).ram(from.getMem()) .processors(ImmutableList.of(new Processor(1, from.getCpu()))).ram(from.getMem())
.volumes((List) ImmutableList.of(Iterables.transform(from.getDevices().values(), deviceToVolume))).build()); .volumes(Iterables.transform(from.getDevices().values(), deviceToVolume)).build());
builder.state(serverStatusToNodeState.get(from.getStatus())); builder.state(serverStatusToNodeState.get(from.getStatus()));
builder.publicAddresses(ImmutableSet.<String> of(from.getVnc().getIp())); builder.publicAddresses(ImmutableSet.<String> of(from.getVnc().getIp()));
builder.privateAddresses(ImmutableSet.<String> of()); builder.privateAddresses(ImmutableSet.<String> of());
@ -133,7 +132,7 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
} catch (UncheckedExecutionException e) { } catch (UncheckedExecutionException e) {
logger.warn(e, "error finding drive %s: %s", input.getDriveUuid(), e.getMessage()); logger.warn(e, "error finding drive %s: %s", input.getDriveUuid(), e.getMessage());
} }
return new VolumeBuilder().durable(true).type(Volume.Type.NAS).build(); return builder.durable(true).type(Volume.Type.NAS).build();
} }
} }

View File

@ -0,0 +1,349 @@
/**
* 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.cloudsigma.compute.options;
import org.jclouds.cloudsigma.domain.AffinityType;
import org.jclouds.compute.options.TemplateOptions;
import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.io.Payload;
import org.jclouds.scriptbuilder.domain.Statement;
import java.util.Map;
public class CloudSigmaTemplateOptions extends TemplateOptions implements Cloneable {
public static final CloudSigmaTemplateOptions NONE = new CloudSigmaTemplateOptions();
private AffinityType diskDriveAffinity = AffinityType.HDD;
public CloudSigmaTemplateOptions diskDriveAffinity(AffinityType diskDriveAffinity) {
this.diskDriveAffinity = diskDriveAffinity;
return this;
}
public AffinityType getDiskDriveAffinity() {
return diskDriveAffinity;
}
@Override
public CloudSigmaTemplateOptions clone() {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
copyTo(options);
return options;
}
@Override
public void copyTo(TemplateOptions to) {
super.copyTo(to);
if (to instanceof CloudSigmaTemplateOptions) {
CloudSigmaTemplateOptions cTo = CloudSigmaTemplateOptions.class.cast(to);
cTo.diskDriveAffinity(getDiskDriveAffinity());
}
}
public static class Builder {
/**
* @see CloudSigmaTemplateOptions#diskDriveAffinity
*/
public static CloudSigmaTemplateOptions diskDriveAffinity(AffinityType diskDriveAffinity) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.diskDriveAffinity(diskDriveAffinity);
}
// methods that only facilitate returning the correct object type
/**
* @see TemplateOptions#inboundPorts
*/
public static CloudSigmaTemplateOptions inboundPorts(int... ports) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return CloudSigmaTemplateOptions.class.cast(options.inboundPorts(ports));
}
/**
* @see TemplateOptions#port
*/
public static CloudSigmaTemplateOptions blockOnPort(int port, int seconds) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return CloudSigmaTemplateOptions.class.cast(options.blockOnPort(port, seconds));
}
/**
* @see TemplateOptions#installPrivateKey
*/
public static CloudSigmaTemplateOptions installPrivateKey(String rsaKey) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return CloudSigmaTemplateOptions.class.cast(options.installPrivateKey(rsaKey));
}
/**
* @see TemplateOptions#authorizePublicKey
*/
public static CloudSigmaTemplateOptions authorizePublicKey(String rsaKey) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return CloudSigmaTemplateOptions.class.cast(options.authorizePublicKey(rsaKey));
}
/**
* @see TemplateOptions#userMetadata(Map)
*/
public static CloudSigmaTemplateOptions userMetadata(Map<String, String> userMetadata) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return CloudSigmaTemplateOptions.class.cast(options.userMetadata(userMetadata));
}
@Deprecated
public static CloudSigmaTemplateOptions overrideLoginUserWith(String user) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideLoginUserWith(user);
}
public static CloudSigmaTemplateOptions overrideLoginUser(String user) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideLoginUser(user);
}
public static CloudSigmaTemplateOptions overrideLoginPassword(String password) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideLoginPassword(password);
}
public static CloudSigmaTemplateOptions overrideLoginPrivateKey(String privateKey) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideLoginPrivateKey(privateKey);
}
public static CloudSigmaTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideAuthenticateSudo(authenticateSudo);
}
@Deprecated
public static CloudSigmaTemplateOptions overrideLoginCredentialWith(String credential) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideLoginCredentialWith(credential);
}
@Deprecated
public static CloudSigmaTemplateOptions overrideCredentialsWith(Credentials credentials) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideCredentialsWith(credentials);
}
public static CloudSigmaTemplateOptions overrideLoginCredentials(LoginCredentials credentials) {
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
return options.overrideLoginCredentials(credentials);
}
}
// methods that only facilitate returning the correct object type
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions blockOnPort(int port, int seconds) {
return CloudSigmaTemplateOptions.class.cast(super.blockOnPort(port, seconds));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions inboundPorts(int... ports) {
return CloudSigmaTemplateOptions.class.cast(super.inboundPorts(ports));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions authorizePublicKey(String publicKey) {
return CloudSigmaTemplateOptions.class.cast(super.authorizePublicKey(publicKey));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions installPrivateKey(String privateKey) {
return CloudSigmaTemplateOptions.class.cast(super.installPrivateKey(privateKey));
}
/**
* {@inheritDoc}
*/
@Deprecated
@Override
public CloudSigmaTemplateOptions runScript(Payload script) {
return CloudSigmaTemplateOptions.class.cast(super.runScript(script));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions blockUntilRunning(boolean blockUntilRunning) {
return CloudSigmaTemplateOptions.class.cast(super.blockUntilRunning(blockUntilRunning));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions dontAuthorizePublicKey() {
return CloudSigmaTemplateOptions.class.cast(super.dontAuthorizePublicKey());
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions nameTask(String name) {
return CloudSigmaTemplateOptions.class.cast(super.nameTask(name));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions runAsRoot(boolean runAsRoot) {
return CloudSigmaTemplateOptions.class.cast(super.runAsRoot(runAsRoot));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions runScript(Statement script) {
return CloudSigmaTemplateOptions.class.cast(super.runScript(script));
}
/**
* {@inheritDoc}
*/
@Deprecated
@Override
public CloudSigmaTemplateOptions overrideCredentialsWith(Credentials overridingCredentials) {
return CloudSigmaTemplateOptions.class.cast(super.overrideCredentialsWith(overridingCredentials));
}
/**
* {@inheritDoc}
*/
@Deprecated
@Override
public CloudSigmaTemplateOptions overrideLoginUserWith(String loginUser) {
return CloudSigmaTemplateOptions.class.cast(super.overrideLoginUserWith(loginUser));
}
/**
* {@inheritDoc}
*/
@Deprecated
@Override
public CloudSigmaTemplateOptions overrideLoginCredentialWith(String loginCredential) {
return CloudSigmaTemplateOptions.class.cast(super.overrideLoginCredentialWith(loginCredential));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions overrideLoginCredentials(LoginCredentials overridingCredentials) {
return CloudSigmaTemplateOptions.class.cast(super.overrideLoginCredentials(overridingCredentials));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions overrideLoginPassword(String password) {
return CloudSigmaTemplateOptions.class.cast(super.overrideLoginPassword(password));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions overrideLoginPrivateKey(String privateKey) {
return CloudSigmaTemplateOptions.class.cast(super.overrideLoginPrivateKey(privateKey));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions overrideLoginUser(String loginUser) {
return CloudSigmaTemplateOptions.class.cast(super.overrideLoginUser(loginUser));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions overrideAuthenticateSudo(boolean authenticateSudo) {
return CloudSigmaTemplateOptions.class.cast(super.overrideAuthenticateSudo(authenticateSudo));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions userMetadata(Map<String, String> userMetadata) {
return CloudSigmaTemplateOptions.class.cast(super.userMetadata(userMetadata));
}
/**
* {@inheritDoc}
*/
@Override
public CloudSigmaTemplateOptions userMetadata(String key, String value) {
return CloudSigmaTemplateOptions.class.cast(super.userMetadata(key, value));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
CloudSigmaTemplateOptions that = (CloudSigmaTemplateOptions) o;
if (diskDriveAffinity != that.diskDriveAffinity) return false;
return true;
}
@Override
public int hashCode() {
int result = super.hashCode();
result = 31 * result + (diskDriveAffinity != null ? diskDriveAffinity.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "CloudSigmaTemplateOptions{" +
"diskDriveAffinity=" + diskDriveAffinity +
'}';
}
}

View File

@ -18,8 +18,26 @@
*/ */
package org.jclouds.cloudsigma.compute; package org.jclouds.cloudsigma.compute;
import org.jclouds.cloudsigma.CloudSigmaClient;
import org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions;
import org.jclouds.cloudsigma.domain.AffinityType;
import org.jclouds.cloudsigma.domain.Device;
import org.jclouds.cloudsigma.domain.DriveInfo;
import org.jclouds.cloudsigma.domain.ServerInfo;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.util.Set;
import static com.google.common.collect.Iterables.contains;
import static com.google.common.collect.Iterables.get;
import static org.jclouds.cloudsigma.compute.options.CloudSigmaTemplateOptions.Builder.diskDriveAffinity;
import static org.jclouds.compute.predicates.NodePredicates.inGroup;
import static org.testng.Assert.assertTrue;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -31,4 +49,34 @@ public class CloudSigmaZurichComputeServiceLiveTest extends CloudSigmaComputeSer
provider = "cloudsigma-zrh"; provider = "cloudsigma-zrh";
} }
@Test
public void testStartNodeWithSSD() throws RunNodesException {
String group = this.group + "-ssd";
TemplateBuilder builder = client.templateBuilder();
assert builder instanceof CloudSigmaTemplateBuilderImpl;
Template template = builder.options(diskDriveAffinity(AffinityType.SSD)).build();
assert template.getOptions() instanceof CloudSigmaTemplateOptions;
try {
Set<? extends NodeMetadata> nodes = client.createNodesInGroup(group, 1, template);
NodeMetadata node = get(nodes, 0);
CloudSigmaClient api = CloudSigmaClient.class.cast(client.getContext()
.getProviderSpecificContext().getApi());
// Note: I wanted to use node.getHardware().getVolumes() but there is no
// way to go from a Volume to a DriveInfo
ServerInfo serverInfo = api.getServerInfo(node.getId());
Device rootDevice = get(serverInfo.getDevices().values(), 0);
DriveInfo driveInfo = api.getDriveInfo(rootDevice.getDriveUuid());
assertTrue(contains(driveInfo.getTags(), "affinity:ssd"));
} finally {
client.destroyNodesMatching(inGroup(group));
}
}
} }