mirror of https://github.com/apache/jclouds.git
JCLOUDS-381. Allow explicit naming of nodes via TemplateOptions.
This commit is contained in:
parent
3ecbf90847
commit
23e43b2c8d
|
@ -18,6 +18,7 @@ package org.jclouds.cloudservers.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.addMetadataAndParseTagsFromCommaDelimitedValue;
|
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
|
||||||
|
import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
@ -111,7 +112,7 @@ public class ServerToNodeMetadata implements Function<Server, NodeMetadata> {
|
||||||
builder.location(new LocationBuilder().scope(LocationScope.HOST).id(from.getHostId()).description(
|
builder.location(new LocationBuilder().scope(LocationScope.HOST).id(from.getHostId()).description(
|
||||||
from.getHostId()).parent(location.get()).build());
|
from.getHostId()).parent(location.get()).build());
|
||||||
addMetadataAndParseTagsFromCommaDelimitedValue(builder, from.getMetadata());
|
addMetadataAndParseTagsFromCommaDelimitedValue(builder, from.getMetadata());
|
||||||
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getName()));
|
builder.group(groupFromMapOrName(from.getMetadata(), from.getName(), nodeNamingConvention));
|
||||||
builder.imageId(from.getImageId() + "");
|
builder.imageId(from.getImageId() + "");
|
||||||
builder.operatingSystem(parseOperatingSystem(from));
|
builder.operatingSystem(parseOperatingSystem(from));
|
||||||
builder.hardware(parseHardware(from));
|
builder.hardware(parseHardware(from));
|
||||||
|
|
|
@ -34,6 +34,7 @@ import org.jclouds.cloudservers.domain.Server;
|
||||||
import org.jclouds.cloudservers.options.ListOptions;
|
import org.jclouds.cloudservers.options.ListOptions;
|
||||||
import org.jclouds.compute.ComputeServiceAdapter;
|
import org.jclouds.compute.ComputeServiceAdapter;
|
||||||
import org.jclouds.compute.domain.Template;
|
import org.jclouds.compute.domain.Template;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
import org.jclouds.domain.Location;
|
import org.jclouds.domain.Location;
|
||||||
import org.jclouds.domain.LoginCredentials;
|
import org.jclouds.domain.LoginCredentials;
|
||||||
|
|
||||||
|
@ -59,6 +60,7 @@ public class CloudServersComputeServiceAdapter implements ComputeServiceAdapter<
|
||||||
@Override
|
@Override
|
||||||
public NodeAndInitialCredentials<Server> createNodeWithGroupEncodedIntoName(String group, String name,
|
public NodeAndInitialCredentials<Server> createNodeWithGroupEncodedIntoName(String group, String name,
|
||||||
Template template) {
|
Template template) {
|
||||||
|
template.getOptions().userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group);
|
||||||
Server server = client
|
Server server = client
|
||||||
.createServer(name, Integer.parseInt(template.getImage().getProviderId()), Integer.parseInt(template
|
.createServer(name, Integer.parseInt(template.getImage().getProviderId()), Integer.parseInt(template
|
||||||
.getHardware().getProviderId()), withMetadata(metadataAndTagsAsCommaDelimitedValue(template.getOptions())));
|
.getHardware().getProviderId()), withMetadata(metadataAndTagsAsCommaDelimitedValue(template.getOptions())));
|
||||||
|
|
|
@ -106,6 +106,14 @@ public class CloudSigmaTemplateOptions extends TemplateOptions implements Clonea
|
||||||
return CloudSigmaTemplateOptions.class.cast(options.userMetadata(userMetadata));
|
return CloudSigmaTemplateOptions.class.cast(options.userMetadata(userMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static CloudSigmaTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
|
||||||
|
return CloudSigmaTemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
public static CloudSigmaTemplateOptions overrideLoginUser(String user) {
|
public static CloudSigmaTemplateOptions overrideLoginUser(String user) {
|
||||||
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
|
CloudSigmaTemplateOptions options = new CloudSigmaTemplateOptions();
|
||||||
return options.overrideLoginUser(user);
|
return options.overrideLoginUser(user);
|
||||||
|
@ -262,6 +270,14 @@ public class CloudSigmaTemplateOptions extends TemplateOptions implements Clonea
|
||||||
return CloudSigmaTemplateOptions.class.cast(super.userMetadata(key, value));
|
return CloudSigmaTemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CloudSigmaTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return CloudSigmaTemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o) return true;
|
if (this == o) return true;
|
||||||
|
|
|
@ -104,7 +104,9 @@ public class VirtualMachineToNodeMetadata implements Function<VirtualMachine, No
|
||||||
// on hosts not started with jclouds
|
// on hosts not started with jclouds
|
||||||
builder.hostname(from.getDisplayName());
|
builder.hostname(from.getDisplayName());
|
||||||
builder.location(FluentIterable.from(locations.get()).firstMatch(idEquals(from.getZoneId())).orNull());
|
builder.location(FluentIterable.from(locations.get()).firstMatch(idEquals(from.getZoneId())).orNull());
|
||||||
if (from.getDisplayName() != null) {
|
if (from.getGroup() != null) {
|
||||||
|
builder.group(from.getGroup());
|
||||||
|
} else if (from.getDisplayName() != null) {
|
||||||
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getDisplayName()));
|
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getDisplayName()));
|
||||||
}
|
}
|
||||||
Image image = FluentIterable.from(images.get()).firstMatch(new Predicate<Image>() {
|
Image image = FluentIterable.from(images.get()).firstMatch(new Predicate<Image>() {
|
||||||
|
|
|
@ -401,6 +401,14 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea
|
||||||
CloudStackTemplateOptions options = new CloudStackTemplateOptions();
|
CloudStackTemplateOptions options = new CloudStackTemplateOptions();
|
||||||
return CloudStackTemplateOptions.class.cast(options.userMetadata(key, value));
|
return CloudStackTemplateOptions.class.cast(options.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static CloudStackTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
CloudStackTemplateOptions options = new CloudStackTemplateOptions();
|
||||||
|
return CloudStackTemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods that only facilitate returning the correct object type
|
// methods that only facilitate returning the correct object type
|
||||||
|
@ -452,4 +460,12 @@ public class CloudStackTemplateOptions extends TemplateOptions implements Clonea
|
||||||
public CloudStackTemplateOptions userMetadata(String key, String value) {
|
public CloudStackTemplateOptions userMetadata(String key, String value) {
|
||||||
return CloudStackTemplateOptions.class.cast(super.userMetadata(key, value));
|
return CloudStackTemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CloudStackTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return CloudStackTemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,6 +165,8 @@ public class CloudStackComputeServiceAdapter implements
|
||||||
OptionsConverter optionsConverter = optionsConverters.get(zone.getNetworkType());
|
OptionsConverter optionsConverter = optionsConverters.get(zone.getNetworkType());
|
||||||
options = optionsConverter.apply(templateOptions, networks, zoneId, options);
|
options = optionsConverter.apply(templateOptions, networks, zoneId, options);
|
||||||
|
|
||||||
|
options.group(group);
|
||||||
|
|
||||||
if (templateOptions.getIpOnDefaultNetwork() != null) {
|
if (templateOptions.getIpOnDefaultNetwork() != null) {
|
||||||
options.ipOnDefaultNetwork(templateOptions.getIpOnDefaultNetwork());
|
options.ipOnDefaultNetwork(templateOptions.getIpOnDefaultNetwork());
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,19 +94,20 @@ public class CloudStackComputeServiceAdapterExpectTest extends BaseCloudStackCom
|
||||||
|
|
||||||
public void testCreateNodeWithGroupEncodedIntoName() {
|
public void testCreateNodeWithGroupEncodedIntoName() {
|
||||||
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
||||||
.endpoint("http://localhost:8080/client/api")
|
.endpoint("http://localhost:8080/client/api")
|
||||||
.addQueryParam("response", "json")
|
.addQueryParam("response", "json")
|
||||||
.addQueryParam("command", "deployVirtualMachine")
|
.addQueryParam("command", "deployVirtualMachine")
|
||||||
.addQueryParam("zoneid", "1")
|
.addQueryParam("zoneid", "1")
|
||||||
.addQueryParam("serviceofferingid", "1")
|
.addQueryParam("serviceofferingid", "1")
|
||||||
.addQueryParam("templateid", "4")
|
.addQueryParam("templateid", "4")
|
||||||
.addQueryParam("displayname", "test-e92")
|
.addQueryParam("displayname", "test-e92")
|
||||||
.addQueryParam("name", "test-e92")
|
.addQueryParam("name", "test-e92")
|
||||||
.addQueryParam("networkids", "204")
|
.addQueryParam("networkids", "204")
|
||||||
.addQueryParam("apiKey", "APIKEY")
|
.addQueryParam("group", "test")
|
||||||
.addQueryParam("signature", "wJ%2BiflOS3am5qcjQOd8Y/Pw8/Dc%3D")
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
.addHeader("Accept", "application/json")
|
.addQueryParam("signature", "M2Wx0CgOeH9vYHhbcbblwziqpwI%3D")
|
||||||
.build();
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||||
.put(listTemplates, listTemplatesResponse)
|
.put(listTemplates, listTemplatesResponse)
|
||||||
|
@ -136,20 +137,21 @@ public class CloudStackComputeServiceAdapterExpectTest extends BaseCloudStackCom
|
||||||
|
|
||||||
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPair() throws IOException {
|
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPair() throws IOException {
|
||||||
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
||||||
.endpoint("http://localhost:8080/client/api")
|
.endpoint("http://localhost:8080/client/api")
|
||||||
.addQueryParam("response", "json")
|
.addQueryParam("response", "json")
|
||||||
.addQueryParam("command", "deployVirtualMachine")
|
.addQueryParam("command", "deployVirtualMachine")
|
||||||
.addQueryParam("zoneid", "1")
|
.addQueryParam("zoneid", "1")
|
||||||
.addQueryParam("serviceofferingid", "1")
|
.addQueryParam("serviceofferingid", "1")
|
||||||
.addQueryParam("templateid", "4")
|
.addQueryParam("templateid", "4")
|
||||||
.addQueryParam("displayname", "test-e92")
|
.addQueryParam("displayname", "test-e92")
|
||||||
.addQueryParam("name", "test-e92")
|
.addQueryParam("name", "test-e92")
|
||||||
.addQueryParam("networkids", "204")
|
.addQueryParam("networkids", "204")
|
||||||
.addQueryParam("keypair", "mykeypair")
|
.addQueryParam("group", "test")
|
||||||
.addQueryParam("apiKey", "APIKEY")
|
.addQueryParam("keypair", "mykeypair")
|
||||||
.addQueryParam("signature", "hI/U4cWXdU6KTZKbJvzPCmOpGmU%3D")
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
.addHeader("Accept", "application/json")
|
.addQueryParam("signature", "D3qQlTNjxrBXeG82C7YPrwU1jMc%3D")
|
||||||
.build();
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||||
.put(listTemplates, listTemplatesResponse)
|
.put(listTemplates, listTemplatesResponse)
|
||||||
|
@ -182,20 +184,21 @@ public class CloudStackComputeServiceAdapterExpectTest extends BaseCloudStackCom
|
||||||
|
|
||||||
public void testCreateNodeWithGroupEncodedIntoNameWithGenerateKeyPair() throws IOException {
|
public void testCreateNodeWithGroupEncodedIntoNameWithGenerateKeyPair() throws IOException {
|
||||||
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
||||||
.endpoint("http://localhost:8080/client/api")
|
.endpoint("http://localhost:8080/client/api")
|
||||||
.addQueryParam("response", "json")
|
.addQueryParam("response", "json")
|
||||||
.addQueryParam("command", "deployVirtualMachine")
|
.addQueryParam("command", "deployVirtualMachine")
|
||||||
.addQueryParam("zoneid", "1")
|
.addQueryParam("zoneid", "1")
|
||||||
.addQueryParam("serviceofferingid", "1")
|
.addQueryParam("serviceofferingid", "1")
|
||||||
.addQueryParam("templateid", "4")
|
.addQueryParam("templateid", "4")
|
||||||
.addQueryParam("displayname", "test-e92")
|
.addQueryParam("displayname", "test-e92")
|
||||||
.addQueryParam("name", "test-e92")
|
.addQueryParam("name", "test-e92")
|
||||||
.addQueryParam("networkids", "204")
|
.addQueryParam("networkids", "204")
|
||||||
.addQueryParam("keypair", "jclouds-test")
|
.addQueryParam("group", "test")
|
||||||
.addQueryParam("apiKey", "APIKEY")
|
.addQueryParam("keypair", "jclouds-test")
|
||||||
.addQueryParam("signature", "4M9C8IjohDDKFMAXQSX3mjXpYvM%3D")
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
.addHeader("Accept", "application/json")
|
.addQueryParam("signature", "kfU/J/REa4DdYj0b/pSjuB3h3Qc%3D")
|
||||||
.build();
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||||
.put(listTemplates, listTemplatesResponse)
|
.put(listTemplates, listTemplatesResponse)
|
||||||
|
@ -227,20 +230,21 @@ public class CloudStackComputeServiceAdapterExpectTest extends BaseCloudStackCom
|
||||||
|
|
||||||
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPairDefaultSecurityGroup() throws IOException {
|
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPairDefaultSecurityGroup() throws IOException {
|
||||||
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
||||||
.endpoint("http://localhost:8080/client/api")
|
.endpoint("http://localhost:8080/client/api")
|
||||||
.addQueryParam("response", "json")
|
.addQueryParam("response", "json")
|
||||||
.addQueryParam("command", "deployVirtualMachine")
|
.addQueryParam("command", "deployVirtualMachine")
|
||||||
.addQueryParam("zoneid", "2")
|
.addQueryParam("zoneid", "2")
|
||||||
.addQueryParam("serviceofferingid", "1")
|
.addQueryParam("serviceofferingid", "1")
|
||||||
.addQueryParam("templateid", "241")
|
.addQueryParam("templateid", "241")
|
||||||
.addQueryParam("displayname", "test-e92")
|
.addQueryParam("displayname", "test-e92")
|
||||||
.addQueryParam("name", "test-e92")
|
.addQueryParam("name", "test-e92")
|
||||||
.addQueryParam("networkids", "204")
|
.addQueryParam("networkids", "204")
|
||||||
.addQueryParam("keypair", "mykeypair")
|
.addQueryParam("group", "test")
|
||||||
.addQueryParam("apiKey", "APIKEY")
|
.addQueryParam("keypair", "mykeypair")
|
||||||
.addQueryParam("signature", "Ar2B/ZVxMO2078cP0XliWWR4cQ0%3D")
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
.addHeader("Accept", "application/json")
|
.addQueryParam("signature", "5qkUSGh0y%2BP/t04/j3%2BEN9PAeFI%3D")
|
||||||
.build();
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||||
.put(listTemplates, listTemplatesResponse)
|
.put(listTemplates, listTemplatesResponse)
|
||||||
|
@ -285,11 +289,12 @@ public class CloudStackComputeServiceAdapterExpectTest extends BaseCloudStackCom
|
||||||
.addQueryParam("displayname", "test-e92")
|
.addQueryParam("displayname", "test-e92")
|
||||||
.addQueryParam("name", "test-e92")
|
.addQueryParam("name", "test-e92")
|
||||||
.addQueryParam("networkids", "204")
|
.addQueryParam("networkids", "204")
|
||||||
|
.addQueryParam("group", "test")
|
||||||
.addQueryParam("keypair", "mykeypair")
|
.addQueryParam("keypair", "mykeypair")
|
||||||
.addQueryParam("diskofferingid", "5678")
|
.addQueryParam("diskofferingid", "5678")
|
||||||
.addQueryParam("size", "10")
|
.addQueryParam("size", "10")
|
||||||
.addQueryParam("apiKey", "APIKEY")
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
.addQueryParam("signature", "FWWCEpsrbbjxiqoQve302rrfOjI%3D")
|
.addQueryParam("signature", "lDzBXtVKCktueskyI/haID9ohJU%3D")
|
||||||
.addHeader("Accept", "application/json")
|
.addHeader("Accept", "application/json")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -330,21 +335,22 @@ public class CloudStackComputeServiceAdapterExpectTest extends BaseCloudStackCom
|
||||||
|
|
||||||
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPairGenerateSecurityGroup() throws IOException {
|
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPairGenerateSecurityGroup() throws IOException {
|
||||||
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
||||||
.endpoint("http://localhost:8080/client/api")
|
.endpoint("http://localhost:8080/client/api")
|
||||||
.addQueryParam("response", "json")
|
.addQueryParam("response", "json")
|
||||||
.addQueryParam("command", "deployVirtualMachine")
|
.addQueryParam("command", "deployVirtualMachine")
|
||||||
.addQueryParam("zoneid", "2")
|
.addQueryParam("zoneid", "2")
|
||||||
.addQueryParam("serviceofferingid", "1")
|
.addQueryParam("serviceofferingid", "1")
|
||||||
.addQueryParam("templateid", "241")
|
.addQueryParam("templateid", "241")
|
||||||
.addQueryParam("displayname", "test-e92")
|
.addQueryParam("displayname", "test-e92")
|
||||||
.addQueryParam("name", "test-e92")
|
.addQueryParam("name", "test-e92")
|
||||||
.addQueryParam("networkids", "204")
|
.addQueryParam("networkids", "204")
|
||||||
.addQueryParam("keypair", "mykeypair")
|
.addQueryParam("group", "test")
|
||||||
.addQueryParam("securitygroupids", "30")
|
.addQueryParam("keypair", "mykeypair")
|
||||||
.addQueryParam("apiKey", "APIKEY")
|
.addQueryParam("securitygroupids", "30")
|
||||||
.addQueryParam("signature", "yNAiMYw3RstNj979udttALOHxfU%3D")
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
.addHeader("Accept", "application/json")
|
.addQueryParam("signature", "rz8V/tMk/UbxUhNqp7Bq3CrSg/k%3D")
|
||||||
.build();
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||||
.put(listTemplates, listTemplatesResponse)
|
.put(listTemplates, listTemplatesResponse)
|
||||||
|
@ -386,23 +392,24 @@ public class CloudStackComputeServiceAdapterExpectTest extends BaseCloudStackCom
|
||||||
|
|
||||||
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPairAssignedToAccountAndDomain() throws IOException {
|
public void testCreateNodeWithGroupEncodedIntoNameWithKeyPairAssignedToAccountAndDomain() throws IOException {
|
||||||
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
HttpRequest deployVM = HttpRequest.builder().method("GET")
|
||||||
.endpoint("http://localhost:8080/client/api")
|
.endpoint("http://localhost:8080/client/api")
|
||||||
.addQueryParam("response", "json")
|
.addQueryParam("response", "json")
|
||||||
.addQueryParam("command", "deployVirtualMachine")
|
.addQueryParam("command", "deployVirtualMachine")
|
||||||
.addQueryParam("zoneid", "1")
|
.addQueryParam("zoneid", "1")
|
||||||
.addQueryParam("serviceofferingid", "1")
|
.addQueryParam("serviceofferingid", "1")
|
||||||
.addQueryParam("templateid", "4")
|
.addQueryParam("templateid", "4")
|
||||||
.addQueryParam("displayname", "test-e92")
|
.addQueryParam("displayname", "test-e92")
|
||||||
.addQueryParam("name", "test-e92")
|
.addQueryParam("name", "test-e92")
|
||||||
.addQueryParam("account", "account") //
|
.addQueryParam("account", "account") //
|
||||||
.addQueryParam("domainid", "domainId") //
|
.addQueryParam("domainid", "domainId") //
|
||||||
.addQueryParam("networkids", "204")
|
.addQueryParam("networkids", "204")
|
||||||
.addQueryParam("keypair", "mykeypair")
|
.addQueryParam("group", "test")
|
||||||
.addQueryParam("apiKey", "APIKEY")
|
.addQueryParam("keypair", "mykeypair")
|
||||||
.addQueryParam("signature", "ly5Pip8ICOoVTmNLdDBTc3gbKlA%3D")
|
.addQueryParam("apiKey", "APIKEY")
|
||||||
.addHeader("Accept", "application/json")
|
.addQueryParam("signature", "hGV6gZZakwvNKhTJurkm48%2Bzgso%3D")
|
||||||
.build();
|
.addHeader("Accept", "application/json")
|
||||||
|
.build();
|
||||||
|
|
||||||
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
Map<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder()
|
||||||
.put(listTemplates, listTemplatesResponse)
|
.put(listTemplates, listTemplatesResponse)
|
||||||
.put(listOsTypes, listOsTypesResponse)
|
.put(listOsTypes, listOsTypesResponse)
|
||||||
|
|
|
@ -32,6 +32,7 @@ import static org.jclouds.ec2.reference.EC2Constants.PROPERTY_EC2_GENERATE_INSTA
|
||||||
import static org.jclouds.ec2.util.Tags.resourceToTagsAsMap;
|
import static org.jclouds.ec2.util.Tags.resourceToTagsAsMap;
|
||||||
import static org.jclouds.util.Predicates2.retry;
|
import static org.jclouds.util.Predicates2.retry;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -96,6 +97,7 @@ import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableMultimap;
|
import com.google.common.collect.ImmutableMultimap;
|
||||||
import com.google.common.collect.ImmutableMultimap.Builder;
|
import com.google.common.collect.ImmutableMultimap.Builder;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.util.concurrent.ListeningExecutorService;
|
import com.google.common.util.concurrent.ListeningExecutorService;
|
||||||
|
@ -153,8 +155,9 @@ public class EC2ComputeService extends BaseComputeService {
|
||||||
|
|
||||||
if (client.getTagApiForRegion(region).isPresent()) {
|
if (client.getTagApiForRegion(region).isPresent()) {
|
||||||
Map<String, String> common = metadataAndTagsAsValuesOfEmptyString(template.getOptions());
|
Map<String, String> common = metadataAndTagsAsValuesOfEmptyString(template.getOptions());
|
||||||
if (common.size() > 0 || generateInstanceNames) {
|
if (generateInstanceNames || !common.isEmpty() || !template.getOptions().getNodeNames().isEmpty()) {
|
||||||
return addTagsToInstancesInRegion(common, nodes, region, group);
|
return addTagsAndNamesToInstancesInRegion(common, template.getOptions().getNodeNames(),
|
||||||
|
nodes, region, group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nodes;
|
return nodes;
|
||||||
|
@ -167,17 +170,23 @@ public class EC2ComputeService extends BaseComputeService {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private Set<NodeMetadata> addTagsToInstancesInRegion(Map<String, String> common, Set<? extends NodeMetadata> input,
|
private Set<NodeMetadata> addTagsAndNamesToInstancesInRegion(Map<String, String> common, Set<String> nodeNames,
|
||||||
String region, String group) {
|
Set<? extends NodeMetadata> input, String region,
|
||||||
|
String group) {
|
||||||
Map<String, ? extends NodeMetadata> instancesById = Maps.uniqueIndex(input, instanceId);
|
Map<String, ? extends NodeMetadata> instancesById = Maps.uniqueIndex(input, instanceId);
|
||||||
ImmutableSet.Builder<NodeMetadata> builder = ImmutableSet.<NodeMetadata> builder();
|
ImmutableSet.Builder<NodeMetadata> builder = ImmutableSet.<NodeMetadata> builder();
|
||||||
|
|
||||||
if (generateInstanceNames && !common.containsKey("Name")) {
|
if (generateInstanceNames && !common.containsKey("Name")) {
|
||||||
for (Map.Entry<String, ? extends NodeMetadata> entry : instancesById.entrySet()) {
|
for (Map.Entry<String, ? extends NodeMetadata> entry : instancesById.entrySet()) {
|
||||||
String id = entry.getKey();
|
String id = entry.getKey();
|
||||||
NodeMetadata instance = entry.getValue();
|
String name;
|
||||||
|
if (!nodeNames.isEmpty()) {
|
||||||
|
name = Iterables.get(nodeNames, 0);
|
||||||
|
} else {
|
||||||
|
name = id.replaceAll(".*-", group + "-");
|
||||||
|
}
|
||||||
Map<String, String> tags = ImmutableMap.<String, String> builder().putAll(common)
|
Map<String, String> tags = ImmutableMap.<String, String> builder().putAll(common)
|
||||||
.put("Name", id.replaceAll(".*-", group + "-")).build();
|
.put("Name", name).build();
|
||||||
logger.debug(">> applying tags %s to instance %s in region %s", tags, id, region);
|
logger.debug(">> applying tags %s to instance %s in region %s", tags, id, region);
|
||||||
client.getTagApiForRegion(region).get().applyToResources(tags, ImmutableSet.of(id));
|
client.getTagApiForRegion(region).get().applyToResources(tags, ImmutableSet.of(id));
|
||||||
builder.add(addTagsForInstance(tags, instancesById.get(id)));
|
builder.add(addTagsForInstance(tags, instancesById.get(id)));
|
||||||
|
|
|
@ -324,6 +324,14 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
|
||||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||||
return EC2TemplateOptions.class.cast(options.userMetadata(userMetadata));
|
return EC2TemplateOptions.class.cast(options.userMetadata(userMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static EC2TemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||||
|
return EC2TemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
public static EC2TemplateOptions overrideLoginUser(String user) {
|
public static EC2TemplateOptions overrideLoginUser(String user) {
|
||||||
EC2TemplateOptions options = new EC2TemplateOptions();
|
EC2TemplateOptions options = new EC2TemplateOptions();
|
||||||
|
@ -521,6 +529,14 @@ public class EC2TemplateOptions extends TemplateOptions implements Cloneable {
|
||||||
return EC2TemplateOptions.class.cast(super.userMetadata(key, value));
|
return EC2TemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public EC2TemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return EC2TemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,10 +15,13 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.jclouds.ec2.compute;
|
package org.jclouds.ec2.compute;
|
||||||
|
|
||||||
import static org.jclouds.ec2.compute.options.EC2TemplateOptions.Builder.blockUntilRunning;
|
import static org.jclouds.ec2.compute.options.EC2TemplateOptions.Builder.blockUntilRunning;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
import static org.testng.Assert.assertNotNull;
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
|
||||||
import org.jclouds.compute.ComputeService;
|
import org.jclouds.compute.ComputeService;
|
||||||
import org.jclouds.compute.domain.NodeMetadata;
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
import org.jclouds.ec2.compute.internal.BaseEC2ComputeServiceExpectTest;
|
import org.jclouds.ec2.compute.internal.BaseEC2ComputeServiceExpectTest;
|
||||||
|
@ -28,6 +31,7 @@ import org.testng.annotations.Test;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableMap.Builder;
|
import com.google.common.collect.ImmutableMap.Builder;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,12 +61,63 @@ public class EC2ComputeServiceExpectTest extends BaseEC2ComputeServiceExpectTest
|
||||||
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build());
|
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build());
|
||||||
|
|
||||||
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
|
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
|
||||||
blockUntilRunning(false).overrideLoginUser("ec2-user")));
|
blockUntilRunning(false).overrideLoginUser("ec2-user")));
|
||||||
assertEquals(node.getCredentials().getUser(), "ec2-user");
|
assertEquals(node.getCredentials().getUser(), "ec2-user");
|
||||||
System.out.println(node.getImageId());
|
System.out.println(node.getImageId());
|
||||||
assertNotNull(node.getCredentials().getPrivateKey());
|
assertNotNull(node.getCredentials().getPrivateKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testCreateNodeWithSpecifiedName() throws Exception {
|
||||||
|
HttpRequest createNamedTagsRequest =
|
||||||
|
formSigner.filter(HttpRequest.builder()
|
||||||
|
.method("POST")
|
||||||
|
.endpoint("https://ec2.us-east-1.amazonaws.com/")
|
||||||
|
.addHeader("Host", "ec2.us-east-1.amazonaws.com")
|
||||||
|
.payload(
|
||||||
|
payloadFromStringWithContentType(
|
||||||
|
"Action=CreateTags" +
|
||||||
|
"&ResourceId.1=i-2baa5550" +
|
||||||
|
"&Signature=Trp5e5%2BMqeBeBZbLYa9s9gxahQ9nkx6ETfsGl82IV8Y%3D" +
|
||||||
|
"&SignatureMethod=HmacSHA256" +
|
||||||
|
"&SignatureVersion=2" +
|
||||||
|
"&Tag.1.Key=Name" +
|
||||||
|
"&Tag.1.Value=test-node" +
|
||||||
|
"&Timestamp=2012-04-16T15%3A54%3A08.897Z" +
|
||||||
|
"&Version=2010-08-31" +
|
||||||
|
"&AWSAccessKeyId=identity",
|
||||||
|
"application/x-www-form-urlencoded"))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
HttpResponse describeNamedInstanceResponse =
|
||||||
|
HttpResponse.builder().statusCode(200)
|
||||||
|
.payload(payloadFromResourceWithContentType(
|
||||||
|
"/describe_instances_running-named.xml", MediaType.APPLICATION_XML)).build();
|
||||||
|
|
||||||
|
|
||||||
|
Builder<HttpRequest, HttpResponse> requestResponseMap = ImmutableMap.<HttpRequest, HttpResponse> builder();
|
||||||
|
requestResponseMap.put(describeRegionsRequest, describeRegionsResponse);
|
||||||
|
requestResponseMap.put(describeAvailabilityZonesRequest, describeAvailabilityZonesResponse);
|
||||||
|
requestResponseMap.put(describeImagesRequest, describeImagesResponse);
|
||||||
|
requestResponseMap.put(createKeyPairRequest, createKeyPairResponse);
|
||||||
|
requestResponseMap.put(createSecurityGroupRequest, createSecurityGroupResponse);
|
||||||
|
requestResponseMap.put(describeSecurityGroupRequest, describeSecurityGroupResponse);
|
||||||
|
requestResponseMap.put(authorizeSecurityGroupIngressRequest22, authorizeSecurityGroupIngressResponse);
|
||||||
|
requestResponseMap.put(authorizeSecurityGroupIngressRequestGroup, authorizeSecurityGroupIngressResponse);
|
||||||
|
requestResponseMap.put(runInstancesRequest, runInstancesResponse);
|
||||||
|
requestResponseMap.put(describeInstanceRequest, describeNamedInstanceResponse);
|
||||||
|
requestResponseMap.put(describeInstanceMultiIdsRequest, describeInstanceMultiIdsResponse);
|
||||||
|
requestResponseMap.put(describeImageRequest, describeImagesResponse);
|
||||||
|
requestResponseMap.put(createNamedTagsRequest, createTagsResponse);
|
||||||
|
|
||||||
|
ComputeService apiThatCreatesNode = requestsSendResponses(requestResponseMap.build());
|
||||||
|
|
||||||
|
NodeMetadata node = Iterables.getOnlyElement(apiThatCreatesNode.createNodesInGroup("test", 1,
|
||||||
|
blockUntilRunning(false).overrideLoginUser("ec2-user").nodeNames(ImmutableSet.of("test-node"))));
|
||||||
|
assertEquals(node.getCredentials().getUser(), "ec2-user");
|
||||||
|
assertNotNull(node.getCredentials().getPrivateKey());
|
||||||
|
assertEquals(node.getName(), "test-node");
|
||||||
|
}
|
||||||
|
|
||||||
//FIXME - issue-1051
|
//FIXME - issue-1051
|
||||||
@Test(enabled = false)
|
@Test(enabled = false)
|
||||||
public void testCreateNodeWithGeneratedKeyPairAndOverriddenLoginUserWithTemplateBuilder() throws Exception {
|
public void testCreateNodeWithGeneratedKeyPairAndOverriddenLoginUserWithTemplateBuilder() throws Exception {
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<DescribeInstancesResponse xmlns="http://ec2.amazonaws.com/doc/2011-05-15/">
|
||||||
|
<requestId>f6d3252e-35e5-4ef5-b2c5-62da95dd829b</requestId>
|
||||||
|
<reservationSet>
|
||||||
|
<item>
|
||||||
|
<reservationId>r-205ad944</reservationId>
|
||||||
|
<ownerId>993194456877</ownerId>
|
||||||
|
<groupSet>
|
||||||
|
<item>
|
||||||
|
<groupId>sg-3c6ef654</groupId>
|
||||||
|
<groupName>jclouds#mygroup2</groupName>
|
||||||
|
</item>
|
||||||
|
</groupSet>
|
||||||
|
<instancesSet>
|
||||||
|
<item>
|
||||||
|
<instanceId>i-2baa5550</instanceId>
|
||||||
|
<imageId>ami-aecd60c7</imageId>
|
||||||
|
<instanceState>
|
||||||
|
<code>16</code>
|
||||||
|
<name>running</name>
|
||||||
|
</instanceState>
|
||||||
|
<privateDnsName>ip-10-28-89-195.ec2.internal</privateDnsName>
|
||||||
|
<dnsName>ec2-50-16-1-166.compute-1.amazonaws.com</dnsName>
|
||||||
|
<reason/>
|
||||||
|
<keyName>jclouds#mygroup2#81</keyName>
|
||||||
|
<amiLaunchIndex>0</amiLaunchIndex>
|
||||||
|
<productCodes/>
|
||||||
|
<instanceType>t1.micro</instanceType>
|
||||||
|
<launchTime>2012-08-02T04:28:30.000Z</launchTime>
|
||||||
|
<placement>
|
||||||
|
<availabilityZone>us-east-1e</availabilityZone>
|
||||||
|
<groupName/>
|
||||||
|
<tenancy>default</tenancy>
|
||||||
|
</placement>
|
||||||
|
<kernelId>aki-88aa75e1</kernelId>
|
||||||
|
<monitoring>
|
||||||
|
<state>disabled</state>
|
||||||
|
</monitoring>
|
||||||
|
<privateIpAddress>10.28.89.195</privateIpAddress>
|
||||||
|
<ipAddress>50.16.1.166</ipAddress>
|
||||||
|
<groupSet>
|
||||||
|
<item>
|
||||||
|
<groupId>sg-3c6ef654</groupId>
|
||||||
|
<groupName>jclouds#mygroup2</groupName>
|
||||||
|
</item>
|
||||||
|
</groupSet>
|
||||||
|
<architecture>x86_64</architecture>
|
||||||
|
<rootDeviceType>ebs</rootDeviceType>
|
||||||
|
<rootDeviceName>/dev/sda1</rootDeviceName>
|
||||||
|
<blockDeviceMapping>
|
||||||
|
<item>
|
||||||
|
<deviceName>/dev/sda1</deviceName>
|
||||||
|
<ebs>
|
||||||
|
<volumeId>vol-f2d7c993</volumeId>
|
||||||
|
<status>attached</status>
|
||||||
|
<attachTime>2012-08-02T04:28:56.000Z</attachTime>
|
||||||
|
<deleteOnTermination>true</deleteOnTermination>
|
||||||
|
</ebs>
|
||||||
|
</item>
|
||||||
|
</blockDeviceMapping>
|
||||||
|
<virtualizationType>paravirtual</virtualizationType>
|
||||||
|
<clientToken/>
|
||||||
|
<tagSet>
|
||||||
|
<item>
|
||||||
|
<key>Name</key>
|
||||||
|
<value>test-node</value>
|
||||||
|
</item>
|
||||||
|
</tagSet>
|
||||||
|
<hypervisor>xen</hypervisor>
|
||||||
|
</item>
|
||||||
|
</instancesSet>
|
||||||
|
</item>
|
||||||
|
</reservationSet>
|
||||||
|
</DescribeInstancesResponse>
|
|
@ -120,6 +120,8 @@ public class ElasticStackComputeServiceAdapter implements
|
||||||
throw new IllegalStateException("could not image drive in time!");
|
throw new IllegalStateException("could not image drive in time!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template.getOptions().userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, tag);
|
||||||
|
|
||||||
Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
|
Server toCreate = small(name, drive.getUuid(), defaultVncPassword).mem(template.getHardware().getRam())
|
||||||
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed()))
|
.cpu((int) (template.getHardware().getProcessors().get(0).getSpeed()))
|
||||||
.tags(template.getOptions().getTags()).userMetadata(template.getOptions().getUserMetadata()).build();
|
.tags(template.getOptions().getTags()).userMetadata(template.getOptions().getUserMetadata()).build();
|
||||||
|
|
|
@ -18,6 +18,7 @@ package org.jclouds.elasticstack.compute.functions;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static org.jclouds.compute.predicates.ImagePredicates.idEquals;
|
import static org.jclouds.compute.predicates.ImagePredicates.idEquals;
|
||||||
|
import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -92,7 +93,7 @@ public class ServerInfoToNodeMetadata implements Function<ServerInfo, NodeMetada
|
||||||
builder.ids(from.getUuid());
|
builder.ids(from.getUuid());
|
||||||
builder.name(from.getName());
|
builder.name(from.getName());
|
||||||
builder.location(locationSupplier.get());
|
builder.location(locationSupplier.get());
|
||||||
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getName()));
|
builder.group(groupFromMapOrName(from.getUserMetadata(), from.getName(), nodeNamingConvention));
|
||||||
builder.tags(from.getTags());
|
builder.tags(from.getTags());
|
||||||
builder.userMetadata(from.getUserMetadata());
|
builder.userMetadata(from.getUserMetadata());
|
||||||
String imageId = getImageIdFromServer.apply(from);
|
String imageId = getImageIdFromServer.apply(from);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static com.google.common.collect.Iterables.filter;
|
||||||
import static com.google.common.collect.Iterables.find;
|
import static com.google.common.collect.Iterables.find;
|
||||||
import static com.google.common.collect.Iterables.transform;
|
import static com.google.common.collect.Iterables.transform;
|
||||||
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
|
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
|
||||||
|
import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName;
|
||||||
|
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -100,8 +101,8 @@ public class ServerInZoneToNodeMetadata implements Function<ServerInZone, NodeMe
|
||||||
builder.hostname(from.getName());
|
builder.hostname(from.getName());
|
||||||
builder.location(from.getHostId() != null ? new LocationBuilder().scope(LocationScope.HOST).id(from.getHostId())
|
builder.location(from.getHostId() != null ? new LocationBuilder().scope(LocationScope.HOST).id(from.getHostId())
|
||||||
.description(from.getHostId()).parent(zone).build() : zone);
|
.description(from.getHostId()).parent(zone).build() : zone);
|
||||||
|
builder.group(groupFromMapOrName(from.getMetadata(), from.getName(), nodeNamingConvention));
|
||||||
addMetadataAndParseTagsFromCommaDelimitedValue(builder, from.getMetadata());
|
addMetadataAndParseTagsFromCommaDelimitedValue(builder, from.getMetadata());
|
||||||
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getName()));
|
|
||||||
builder.imageId(ZoneAndId.fromZoneAndId(serverInZone.getZone(), from.getImage().getId()).slashEncode());
|
builder.imageId(ZoneAndId.fromZoneAndId(serverInZone.getZone(), from.getImage().getId()).slashEncode());
|
||||||
builder.operatingSystem(findOperatingSystemForServerOrNull(serverInZone));
|
builder.operatingSystem(findOperatingSystemForServerOrNull(serverInZone));
|
||||||
builder.hardware(findHardwareForServerOrNull(serverInZone));
|
builder.hardware(findHardwareForServerOrNull(serverInZone));
|
||||||
|
|
|
@ -299,6 +299,14 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
||||||
return NovaTemplateOptions.class.cast(options.userMetadata(userMetadata));
|
return NovaTemplateOptions.class.cast(options.userMetadata(userMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static NovaTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
NovaTemplateOptions options = new NovaTemplateOptions();
|
||||||
|
return NovaTemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see TemplateOptions#overrideLoginUser
|
* @see TemplateOptions#overrideLoginUser
|
||||||
*/
|
*/
|
||||||
|
@ -494,6 +502,15 @@ public class NovaTemplateOptions extends TemplateOptions implements Cloneable {
|
||||||
return NovaTemplateOptions.class.cast(super.userMetadata(key, value));
|
return NovaTemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public NovaTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return NovaTemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User data as bytes (not base64-encoded)
|
* User data as bytes (not base64-encoded)
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.jclouds.compute.config.CustomizationResponse;
|
||||||
import org.jclouds.compute.domain.NodeMetadata;
|
import org.jclouds.compute.domain.NodeMetadata;
|
||||||
import org.jclouds.compute.domain.Template;
|
import org.jclouds.compute.domain.Template;
|
||||||
import org.jclouds.compute.functions.GroupNamingConvention;
|
import org.jclouds.compute.functions.GroupNamingConvention;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
|
import org.jclouds.compute.strategy.CreateNodeWithGroupEncodedIntoName;
|
||||||
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
|
import org.jclouds.compute.strategy.CustomizeNodeAndAddToGoodMapOrPutExceptionIntoBadMap;
|
||||||
import org.jclouds.compute.strategy.ListNodesStrategy;
|
import org.jclouds.compute.strategy.ListNodesStrategy;
|
||||||
|
@ -142,6 +143,7 @@ public class ApplyNovaTemplateOptionsCreateNodesWithGroupEncodedIntoNameThenAddT
|
||||||
templateOptions.securityGroupNames(securityGroupName);
|
templateOptions.securityGroupNames(securityGroupName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
templateOptions.userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group);
|
||||||
|
|
||||||
return super.execute(group, count, mutableTemplate, goodNodes, badNodes, customizationResponses);
|
return super.execute(group, count, mutableTemplate, goodNodes, badNodes, customizationResponses);
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,7 +239,8 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
|
||||||
.addHeader("X-Auth-Token", authToken)
|
.addHeader("X-Auth-Token", authToken)
|
||||||
.payload(
|
.payload(
|
||||||
payloadFromStringWithContentType(
|
payloadFromStringWithContentType(
|
||||||
"{\"server\":{\"name\":\"test-1\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"key_name\":\"jclouds-test-0\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
|
"{\"server\":{\"name\":\"test-1\",\"imageRef\":\"14\",\"flavorRef\":\"1\"," +
|
||||||
|
"\"metadata\":{\"jclouds-group\":\"test\"},\"key_name\":\"jclouds-test-0\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
|
||||||
"application/json")).build();
|
"application/json")).build();
|
||||||
|
|
||||||
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
|
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
|
||||||
|
@ -293,7 +294,8 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
|
||||||
.addHeader("X-Auth-Token", authToken)
|
.addHeader("X-Auth-Token", authToken)
|
||||||
.payload(
|
.payload(
|
||||||
payloadFromStringWithContentType(
|
payloadFromStringWithContentType(
|
||||||
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"key_name\":\"fooPair\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
|
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\"," +
|
||||||
|
"\"metadata\":{\"jclouds-group\":\"test\"},\"key_name\":\"fooPair\",\"security_groups\":[{\"name\":\"jclouds-test\"}]}}",
|
||||||
"application/json")).build();
|
"application/json")).build();
|
||||||
|
|
||||||
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
|
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
|
||||||
|
@ -343,7 +345,8 @@ public class NovaComputeServiceExpectTest extends BaseNovaComputeServiceExpectTe
|
||||||
.addHeader("X-Auth-Token", authToken)
|
.addHeader("X-Auth-Token", authToken)
|
||||||
.payload(
|
.payload(
|
||||||
payloadFromStringWithContentType(
|
payloadFromStringWithContentType(
|
||||||
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\",\"key_name\":\"fooPair\",\"security_groups\":[{\"name\":\"mygroup\"}]}}",
|
"{\"server\":{\"name\":\"test-0\",\"imageRef\":\"14\",\"flavorRef\":\"1\"," +
|
||||||
|
"\"metadata\":{\"jclouds-group\":\"test\"},\"key_name\":\"fooPair\",\"security_groups\":[{\"name\":\"mygroup\"}]}}",
|
||||||
"application/json")).build();
|
"application/json")).build();
|
||||||
|
|
||||||
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
|
HttpResponse createdServer = HttpResponse.builder().statusCode(202).message("HTTP/1.1 202 Accepted")
|
||||||
|
|
|
@ -21,6 +21,7 @@ import static com.google.common.base.Predicates.not;
|
||||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||||
import static com.google.common.collect.Iterables.filter;
|
import static com.google.common.collect.Iterables.filter;
|
||||||
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
|
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
|
||||||
|
import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName;
|
||||||
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getCredentialsFrom;
|
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getCredentialsFrom;
|
||||||
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getIpsFromVApp;
|
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.getIpsFromVApp;
|
||||||
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.toComputeOs;
|
import static org.jclouds.vcloud.compute.util.VCloudComputeUtils.toComputeOs;
|
||||||
|
@ -44,6 +45,7 @@ import org.jclouds.vcloud.domain.VApp;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
/** @author Adrian Cole */
|
/** @author Adrian Cole */
|
||||||
@Singleton
|
@Singleton
|
||||||
|
@ -73,19 +75,26 @@ public class VAppToNodeMetadata implements Function<VApp, NodeMetadata> {
|
||||||
builder.ids(from.getHref().toASCIIString());
|
builder.ids(from.getHref().toASCIIString());
|
||||||
builder.uri(from.getHref());
|
builder.uri(from.getHref());
|
||||||
builder.name(from.getName());
|
builder.name(from.getName());
|
||||||
|
String groupName = "";
|
||||||
|
Map<String, String> metadataMap;
|
||||||
|
|
||||||
if (!isNullOrEmpty(from.getDescription())
|
if (!isNullOrEmpty(from.getDescription())
|
||||||
&& from.getDescription().indexOf('=') != -1
|
&& from.getDescription().indexOf('=') != -1
|
||||||
&& from.getDescription().indexOf('\n') != -1) {
|
&& from.getDescription().indexOf('\n') != -1) {
|
||||||
try {
|
try {
|
||||||
addMetadataAndParseTagsFromCommaDelimitedValue(builder,
|
metadataMap = Splitter.on('\n').withKeyValueSeparator("=").split(from.getDescription());
|
||||||
Splitter.on('\n').withKeyValueSeparator("=").split(from.getDescription()));
|
|
||||||
|
addMetadataAndParseTagsFromCommaDelimitedValue(builder, metadataMap);
|
||||||
} catch (IllegalArgumentException iae) {
|
} catch (IllegalArgumentException iae) {
|
||||||
// no op
|
// no op
|
||||||
|
metadataMap = ImmutableMap.of();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
metadataMap = ImmutableMap.of();
|
||||||
}
|
}
|
||||||
builder.hostname(from.getName());
|
builder.hostname(from.getName());
|
||||||
builder.location(findLocationForResourceInVDC.apply(from.getVDC()));
|
builder.location(findLocationForResourceInVDC.apply(from.getVDC()));
|
||||||
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getName()));
|
builder.group(groupFromMapOrName(metadataMap, from.getName(), nodeNamingConvention));
|
||||||
builder.operatingSystem(toComputeOs(from, null));
|
builder.operatingSystem(toComputeOs(from, null));
|
||||||
builder.hardware(hardwareForVApp.apply(from));
|
builder.hardware(hardwareForVApp.apply(from));
|
||||||
builder.status(vAppStatusToNodeStatus.get(from.getStatus()));
|
builder.status(vAppStatusToNodeStatus.get(from.getStatus()));
|
||||||
|
|
|
@ -223,6 +223,14 @@ public class VCloudTemplateOptions extends TemplateOptions implements Cloneable
|
||||||
return VCloudTemplateOptions.class.cast(options.userMetadata(key, value));
|
return VCloudTemplateOptions.class.cast(options.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static VCloudTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
VCloudTemplateOptions options = new VCloudTemplateOptions();
|
||||||
|
return VCloudTemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -316,4 +324,12 @@ public class VCloudTemplateOptions extends TemplateOptions implements Cloneable
|
||||||
return VCloudTemplateOptions.class.cast(super.userMetadata(key, value));
|
return VCloudTemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public VCloudTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return VCloudTemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,6 +124,7 @@ public class InstantiateVAppTemplateWithGroupEncodedIntoNameThenCustomizeDeployA
|
||||||
// per above check, we know there is only a single VM
|
// per above check, we know there is only a single VM
|
||||||
Vm vm = get(vAppResponse.getChildren(), 0);
|
Vm vm = get(vAppResponse.getChildren(), 0);
|
||||||
|
|
||||||
|
template.getOptions().userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group);
|
||||||
VCloudTemplateOptions vOptions = VCloudTemplateOptions.class.cast(template.getOptions());
|
VCloudTemplateOptions vOptions = VCloudTemplateOptions.class.cast(template.getOptions());
|
||||||
|
|
||||||
// note we cannot do tasks in parallel or VCD will throw "is busy" errors
|
// note we cannot do tasks in parallel or VCD will throw "is busy" errors
|
||||||
|
|
|
@ -82,6 +82,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
to.userMetadata(this.getUserMetadata());
|
to.userMetadata(this.getUserMetadata());
|
||||||
if (this.getTags().size() > 0)
|
if (this.getTags().size() > 0)
|
||||||
to.tags(getTags());
|
to.tags(getTags());
|
||||||
|
if (!this.getNodeNames().isEmpty())
|
||||||
|
to.nodeNames(getNodeNames());
|
||||||
if (!this.shouldBlockUntilRunning())
|
if (!this.shouldBlockUntilRunning())
|
||||||
to.blockUntilRunning(false);
|
to.blockUntilRunning(false);
|
||||||
if (!this.shouldBlockOnComplete())
|
if (!this.shouldBlockOnComplete())
|
||||||
|
@ -296,6 +298,16 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
throw new IllegalArgumentException("tags are immutable");
|
throw new IllegalArgumentException("tags are immutable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<String> getNodeNames() {
|
||||||
|
return delegate.getNodeNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
throw new IllegalArgumentException("nodeNames are immutable");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getGroups() {
|
public Set<String> getGroups() {
|
||||||
return delegate.getGroups();
|
return delegate.getGroups();
|
||||||
|
@ -303,12 +315,12 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateOptions securityGroups(Iterable<String> securityGroups) {
|
public TemplateOptions securityGroups(Iterable<String> securityGroups) {
|
||||||
throw new IllegalArgumentException("tags are immutable");
|
throw new IllegalArgumentException("security groups are immutable");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TemplateOptions securityGroups(String... securityGroups) {
|
public TemplateOptions securityGroups(String... securityGroups) {
|
||||||
throw new IllegalArgumentException("tags are immutable");
|
throw new IllegalArgumentException("security groups are immutable");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -348,7 +360,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
|
|
||||||
protected Map<String, String> userMetadata = Maps.newLinkedHashMap();
|
protected Map<String, String> userMetadata = Maps.newLinkedHashMap();
|
||||||
|
|
||||||
@Override
|
protected Set<String> nodeNames = ImmutableSet.of();
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object o) {
|
||||||
if (this == o)
|
if (this == o)
|
||||||
return true;
|
return true;
|
||||||
|
@ -356,15 +369,16 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
return false;
|
return false;
|
||||||
TemplateOptions that = TemplateOptions.class.cast(o);
|
TemplateOptions that = TemplateOptions.class.cast(o);
|
||||||
return super.equals(that) && equal(this.inboundPorts, that.inboundPorts) && equal(this.script, that.script)
|
return super.equals(that) && equal(this.inboundPorts, that.inboundPorts) && equal(this.script, that.script)
|
||||||
&& equal(this.publicKey, that.publicKey) && equal(this.privateKey, that.privateKey)
|
&& equal(this.publicKey, that.publicKey) && equal(this.privateKey, that.privateKey)
|
||||||
&& equal(this.blockUntilRunning, that.blockUntilRunning) && equal(this.tags, that.tags)
|
&& equal(this.blockUntilRunning, that.blockUntilRunning) && equal(this.tags, that.tags)
|
||||||
&& equal(this.securityGroups, that.securityGroups) && equal(this.userMetadata, that.userMetadata);
|
&& equal(this.securityGroups, that.securityGroups) && equal(this.userMetadata, that.userMetadata)
|
||||||
|
&& equal(this.nodeNames, that.nodeNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hashCode(super.hashCode(), inboundPorts, script, publicKey, privateKey, blockUntilRunning, tags,
|
return Objects.hashCode(super.hashCode(), inboundPorts, script, publicKey, privateKey, blockUntilRunning, tags,
|
||||||
securityGroups, userMetadata);
|
securityGroups, userMetadata, nodeNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -382,6 +396,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
toString.add("blockUntilRunning", blockUntilRunning);
|
toString.add("blockUntilRunning", blockUntilRunning);
|
||||||
if (tags.size() != 0)
|
if (tags.size() != 0)
|
||||||
toString.add("tags", tags);
|
toString.add("tags", tags);
|
||||||
|
if (!nodeNames.isEmpty())
|
||||||
|
toString.add("nodeNames", nodeNames);
|
||||||
if (securityGroups.size() != 0)
|
if (securityGroups.size() != 0)
|
||||||
toString.add("securityGroups", securityGroups);
|
toString.add("securityGroups", securityGroups);
|
||||||
if (userMetadata.size() != 0)
|
if (userMetadata.size() != 0)
|
||||||
|
@ -401,6 +417,10 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<String> getNodeNames() {
|
||||||
|
return nodeNames;
|
||||||
|
}
|
||||||
|
|
||||||
public Set<String> getGroups() {
|
public Set<String> getGroups() {
|
||||||
return securityGroups;
|
return securityGroups;
|
||||||
}
|
}
|
||||||
|
@ -475,6 +495,19 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* specifies names to be used for the created nodes.
|
||||||
|
*
|
||||||
|
* Note that this does not guarantee uniqueness - if there are already existing nodes with a name
|
||||||
|
* specified here, there will still be a new node created with the same name. Also, if more
|
||||||
|
* nodes are to be created than there are names, subsequent names will use the default naming strategy
|
||||||
|
* for that cloud.
|
||||||
|
*/
|
||||||
|
public TemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
this.nodeNames = ImmutableSet.copyOf(checkNotNull(nodeNames, "nodeNames"));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* assigns the created nodes to these security groups
|
* assigns the created nodes to these security groups
|
||||||
*/
|
*/
|
||||||
|
@ -561,6 +594,14 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
|
||||||
return options.tags(tags);
|
return options.tags(tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames
|
||||||
|
*/
|
||||||
|
public static TemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
TemplateOptions options = new TemplateOptions();
|
||||||
|
return options.nodeNames(nodeNames);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see TemplateOptions#securityGroups
|
* @see TemplateOptions#securityGroups
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -48,10 +48,10 @@ public interface ComputeServiceConstants {
|
||||||
|
|
||||||
public static final String COMPUTE_LOGGER = "jclouds.compute";
|
public static final String COMPUTE_LOGGER = "jclouds.compute";
|
||||||
public static final String LOCAL_PARTITION_GB_PATTERN = "disk_drive/%s/gb";
|
public static final String LOCAL_PARTITION_GB_PATTERN = "disk_drive/%s/gb";
|
||||||
|
public static final String NODE_GROUP_KEY = "jclouds-group";
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
public static class NamingConvention {
|
public static class NamingConvention {
|
||||||
|
|
||||||
@Inject(optional = true)
|
@Inject(optional = true)
|
||||||
public final Supplier<String> randomSuffix = new Supplier<String>() {
|
public final Supplier<String> randomSuffix = new Supplier<String>() {
|
||||||
final SecureRandom random = new SecureRandom();
|
final SecureRandom random = new SecureRandom();
|
||||||
|
|
|
@ -48,6 +48,8 @@ import org.jclouds.compute.strategy.ListNodesStrategy;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.collect.Multimap;
|
import com.google.common.collect.Multimap;
|
||||||
import com.google.common.util.concurrent.Futures;
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
@ -169,9 +171,13 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the next node names that can be used. These will be derived from the group and the
|
* Find the next node names that can be used. If the nodeNames template option is not specified
|
||||||
* template. We will pre-allocate a specified quantity, and attempt to verify that there is no
|
* or is empty, these will be derived from the group and the template. We will pre-allocate a
|
||||||
* name conflict with the current service.
|
* specified quantity, and attempt to verify that there is no name conflict with the current
|
||||||
|
* service. If the nodeNames option is specified, names from that will be used instead, without
|
||||||
|
* any check for name conflicts.
|
||||||
|
* If there are insufficient names in nodeNames, subsequent names will be generated in the
|
||||||
|
* default format.
|
||||||
*
|
*
|
||||||
* @param group
|
* @param group
|
||||||
* @param count
|
* @param count
|
||||||
|
@ -180,6 +186,12 @@ public class CreateNodesWithGroupEncodedIntoNameThenAddToSet implements CreateNo
|
||||||
*/
|
*/
|
||||||
protected Set<String> getNextNames(final String group, final Template template, int count) {
|
protected Set<String> getNextNames(final String group, final Template template, int count) {
|
||||||
Set<String> names = newLinkedHashSet();
|
Set<String> names = newLinkedHashSet();
|
||||||
|
Set<String> nodeNames = template.getOptions().getNodeNames();
|
||||||
|
if (nodeNames.size() >= count) {
|
||||||
|
return ImmutableSet.copyOf(Iterables.limit(nodeNames, count));
|
||||||
|
} else {
|
||||||
|
names.addAll(nodeNames);
|
||||||
|
}
|
||||||
Iterable<? extends ComputeMetadata> currentNodes = listNodesStrategy.listNodes();
|
Iterable<? extends ComputeMetadata> currentNodes = listNodesStrategy.listNodes();
|
||||||
int maxTries = 100;
|
int maxTries = 100;
|
||||||
int currentTries = 0;
|
int currentTries = 0;
|
||||||
|
|
|
@ -40,12 +40,13 @@ import org.jclouds.compute.domain.NodeMetadataBuilder;
|
||||||
import org.jclouds.compute.domain.OsFamily;
|
import org.jclouds.compute.domain.OsFamily;
|
||||||
import org.jclouds.compute.domain.Processor;
|
import org.jclouds.compute.domain.Processor;
|
||||||
import org.jclouds.compute.domain.Volume;
|
import org.jclouds.compute.domain.Volume;
|
||||||
|
import org.jclouds.compute.functions.GroupNamingConvention;
|
||||||
import org.jclouds.compute.options.TemplateOptions;
|
import org.jclouds.compute.options.TemplateOptions;
|
||||||
|
import org.jclouds.compute.reference.ComputeServiceConstants;
|
||||||
import org.jclouds.http.HttpRequest;
|
import org.jclouds.http.HttpRequest;
|
||||||
import org.jclouds.scriptbuilder.domain.Statement;
|
import org.jclouds.scriptbuilder.domain.Statement;
|
||||||
import org.jclouds.scriptbuilder.domain.Statements;
|
import org.jclouds.scriptbuilder.domain.Statements;
|
||||||
|
|
||||||
import com.google.common.base.Function;
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
|
@ -282,4 +283,12 @@ public class ComputeServiceUtils {
|
||||||
|
|
||||||
return portRanges;
|
return portRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String groupFromMapOrName(Map<String, String> metadataMap, String nodeName, GroupNamingConvention namingConvention) {
|
||||||
|
if (metadataMap.get(ComputeServiceConstants.NODE_GROUP_KEY) != null) {
|
||||||
|
return metadataMap.get(ComputeServiceConstants.NODE_GROUP_KEY);
|
||||||
|
} else {
|
||||||
|
return namingConvention.groupInUniqueNameOrNull(nodeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -484,6 +484,12 @@ public class StubComputeServiceIntegrationTest extends BaseComputeServiceLiveTes
|
||||||
super.testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired();
|
super.testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired")
|
||||||
|
public void testCreateTwoNodesWithOneSpecifiedName() throws Exception {
|
||||||
|
super.testCreateTwoNodesWithOneSpecifiedName();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired")
|
@Test(enabled = true, dependsOnMethods = "testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired")
|
||||||
public void testCredentialsCache() throws Exception {
|
public void testCredentialsCache() throws Exception {
|
||||||
super.testCredentialsCache();
|
super.testCredentialsCache();
|
||||||
|
|
|
@ -35,6 +35,7 @@ import static java.util.logging.Logger.getAnonymousLogger;
|
||||||
import static org.jclouds.compute.options.RunScriptOptions.Builder.nameTask;
|
import static org.jclouds.compute.options.RunScriptOptions.Builder.nameTask;
|
||||||
import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript;
|
import static org.jclouds.compute.options.RunScriptOptions.Builder.wrapInInitScript;
|
||||||
import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts;
|
import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts;
|
||||||
|
import static org.jclouds.compute.options.TemplateOptions.Builder.nodeNames;
|
||||||
import static org.jclouds.compute.options.TemplateOptions.Builder.overrideLoginCredentials;
|
import static org.jclouds.compute.options.TemplateOptions.Builder.overrideLoginCredentials;
|
||||||
import static org.jclouds.compute.options.TemplateOptions.Builder.runAsRoot;
|
import static org.jclouds.compute.options.TemplateOptions.Builder.runAsRoot;
|
||||||
import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
|
import static org.jclouds.compute.predicates.NodePredicates.TERMINATED;
|
||||||
|
@ -44,6 +45,7 @@ import static org.jclouds.compute.predicates.NodePredicates.runningInGroup;
|
||||||
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
|
import static org.jclouds.compute.util.ComputeServiceUtils.getCores;
|
||||||
import static org.jclouds.util.Predicates2.retry;
|
import static org.jclouds.util.Predicates2.retry;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertFalse;
|
||||||
import static org.testng.Assert.assertNotNull;
|
import static org.testng.Assert.assertNotNull;
|
||||||
import static org.testng.Assert.assertTrue;
|
import static org.testng.Assert.assertTrue;
|
||||||
import static org.testng.Assert.fail;
|
import static org.testng.Assert.fail;
|
||||||
|
@ -362,6 +364,30 @@ public abstract class BaseComputeServiceLiveTest extends BaseComputeServiceConte
|
||||||
checkOsMatchesTemplate(node2);
|
checkOsMatchesTemplate(node2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(enabled = true, dependsOnMethods = "testCreateTwoNodesWithRunScript")
|
||||||
|
public void testCreateTwoNodesWithOneSpecifiedName() throws Exception {
|
||||||
|
Set<? extends NodeMetadata> nodes;
|
||||||
|
try {
|
||||||
|
nodes = newTreeSet(client.createNodesInGroup(group, 2, nodeNames(ImmutableSet.of("first-node"))));
|
||||||
|
} catch (RunNodesException e) {
|
||||||
|
nodes = newTreeSet(concat(e.getSuccessfulNodes(), e.getNodeErrors().keySet()));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(nodes.size(), 2, "expected two nodes but was " + nodes);
|
||||||
|
NodeMetadata node1 = Iterables.getFirst(nodes, null);
|
||||||
|
NodeMetadata node2 = Iterables.getLast(nodes, null);
|
||||||
|
// credentials aren't always the same
|
||||||
|
// assertEquals(node1.getCredentials(), node2.getCredentials());
|
||||||
|
|
||||||
|
assertTrue(node1.getName().equals("first-node") || node2.getName().equals("first-node"),
|
||||||
|
"one node should be named 'first-node'");
|
||||||
|
assertFalse(node1.getName().equals("first-node") && node2.getName().equals("first-node"),
|
||||||
|
"one node should be named something other than 'first-node");
|
||||||
|
|
||||||
|
this.nodes.addAll(nodes);
|
||||||
|
}
|
||||||
|
|
||||||
private Template refreshTemplate() {
|
private Template refreshTemplate() {
|
||||||
return template = addRunScriptToTemplate(buildTemplate(client.templateBuilder()));
|
return template = addRunScriptToTemplate(buildTemplate(client.templateBuilder()));
|
||||||
}
|
}
|
||||||
|
@ -391,7 +417,7 @@ public abstract class BaseComputeServiceLiveTest extends BaseComputeServiceConte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(enabled = true, dependsOnMethods = "testCreateTwoNodesWithRunScript")
|
@Test(enabled = true, dependsOnMethods = "testCreateTwoNodesWithOneSpecifiedName")
|
||||||
public void testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired() throws Exception {
|
public void testCreateAnotherNodeWithANewContextToEnsureSharedMemIsntRequired() throws Exception {
|
||||||
initializeContext();
|
initializeContext();
|
||||||
|
|
||||||
|
|
|
@ -21,12 +21,17 @@ import static org.jclouds.compute.options.TemplateOptions.Builder.blockOnPort;
|
||||||
import static org.jclouds.compute.options.TemplateOptions.Builder.blockUntilRunning;
|
import static org.jclouds.compute.options.TemplateOptions.Builder.blockUntilRunning;
|
||||||
import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts;
|
import static org.jclouds.compute.options.TemplateOptions.Builder.inboundPorts;
|
||||||
import static org.jclouds.compute.options.TemplateOptions.Builder.installPrivateKey;
|
import static org.jclouds.compute.options.TemplateOptions.Builder.installPrivateKey;
|
||||||
|
import static org.jclouds.compute.options.TemplateOptions.Builder.nodeNames;
|
||||||
import static org.testng.Assert.assertEquals;
|
import static org.testng.Assert.assertEquals;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests possible uses of TemplateOptions and TemplateOptions.Builder.*
|
* Tests possible uses of TemplateOptions and TemplateOptions.Builder.*
|
||||||
*
|
*
|
||||||
|
@ -184,4 +189,11 @@ public class TemplateOptionsTest {
|
||||||
TemplateOptions options = blockUntilRunning(false);
|
TemplateOptions options = blockUntilRunning(false);
|
||||||
assertEquals(options.shouldBlockUntilRunning(), false);
|
assertEquals(options.shouldBlockUntilRunning(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNodeNames() {
|
||||||
|
Set<String> nodeNames = ImmutableSet.of("first-node", "second-node");
|
||||||
|
TemplateOptions options = nodeNames(nodeNames);
|
||||||
|
assertTrue(options.getNodeNames().containsAll(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,6 +480,14 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
|
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
|
||||||
return options.blockUntilRunning(blockUntilRunning);
|
return options.blockUntilRunning(blockUntilRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static AWSEC2TemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
AWSEC2TemplateOptions options = new AWSEC2TemplateOptions();
|
||||||
|
return AWSEC2TemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods that only facilitate returning the correct object type
|
// methods that only facilitate returning the correct object type
|
||||||
|
@ -508,6 +516,14 @@ public class AWSEC2TemplateOptions extends EC2TemplateOptions implements Cloneab
|
||||||
return AWSEC2TemplateOptions.class.cast(super.userMetadata(key, value));
|
return AWSEC2TemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public AWSEC2TemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return AWSEC2TemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -111,6 +111,7 @@ public class GleSYSComputeServiceAdapter implements ComputeServiceAdapter<Server
|
||||||
|
|
||||||
CreateServerOptions createServerOptions = new CreateServerOptions();
|
CreateServerOptions createServerOptions = new CreateServerOptions();
|
||||||
createServerOptions.ip(templateOptions.getIp());
|
createServerOptions.ip(templateOptions.getIp());
|
||||||
|
template.getOptions().userMetadata(ComputeServiceConstants.NODE_GROUP_KEY, group);
|
||||||
|
|
||||||
Map<String, String> md = metadataAndTagsAsCommaDelimitedValue(template.getOptions());
|
Map<String, String> md = metadataAndTagsAsCommaDelimitedValue(template.getOptions());
|
||||||
if (md.size() > 0) {
|
if (md.size() > 0) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkState;
|
||||||
import static com.google.common.base.Strings.isNullOrEmpty;
|
import static com.google.common.base.Strings.isNullOrEmpty;
|
||||||
import static com.google.common.io.BaseEncoding.base16;
|
import static com.google.common.io.BaseEncoding.base16;
|
||||||
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
|
import static org.jclouds.compute.util.ComputeServiceUtils.addMetadataAndParseTagsFromCommaDelimitedValue;
|
||||||
|
import static org.jclouds.compute.util.ComputeServiceUtils.groupFromMapOrName;
|
||||||
import static org.jclouds.location.predicates.LocationPredicates.idEquals;
|
import static org.jclouds.location.predicates.LocationPredicates.idEquals;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -109,15 +110,18 @@ public class ServerDetailsToNodeMetadata implements Function<ServerDetails, Node
|
||||||
builder.hostname(from.getHostname());
|
builder.hostname(from.getHostname());
|
||||||
Location location = FluentIterable.from(locations.get()).firstMatch(idEquals(from.getDatacenter())).orNull();
|
Location location = FluentIterable.from(locations.get()).firstMatch(idEquals(from.getDatacenter())).orNull();
|
||||||
checkState(location != null, "no location matched ServerDetails %s", from);
|
checkState(location != null, "no location matched ServerDetails %s", from);
|
||||||
builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getHostname()));
|
|
||||||
|
Map<String, String> metadataMap;
|
||||||
|
|
||||||
// TODO: get glesys to stop stripping out equals and commas!
|
// TODO: get glesys to stop stripping out equals and commas!
|
||||||
if (!isNullOrEmpty(from.getDescription()) && from.getDescription().matches("^[0-9A-Fa-f]+$")) {
|
if (!isNullOrEmpty(from.getDescription()) && from.getDescription().matches("^[0-9A-Fa-f]+$")) {
|
||||||
String decoded = new String(base16().lowerCase().decode(from.getDescription()), UTF_8);
|
String decoded = new String(base16().lowerCase().decode(from.getDescription()), UTF_8);
|
||||||
addMetadataAndParseTagsFromCommaDelimitedValue(builder,
|
metadataMap = Splitter.on('\n').withKeyValueSeparator("=").split(decoded);
|
||||||
Splitter.on('\n').withKeyValueSeparator("=").split(decoded));
|
addMetadataAndParseTagsFromCommaDelimitedValue(builder, metadataMap);
|
||||||
|
} else {
|
||||||
|
metadataMap = ImmutableMap.of();
|
||||||
}
|
}
|
||||||
|
builder.group(groupFromMapOrName(metadataMap, from.getHostname(), nodeNamingConvention));
|
||||||
builder.imageId(from.getTemplateName() + "");
|
builder.imageId(from.getTemplateName() + "");
|
||||||
builder.operatingSystem(parseOperatingSystem(from));
|
builder.operatingSystem(parseOperatingSystem(from));
|
||||||
builder.hardware(new HardwareBuilder().ids(from.getId() + "").ram(from.getMemorySizeMB())
|
builder.hardware(new HardwareBuilder().ids(from.getId() + "").ram(from.getMemorySizeMB())
|
||||||
|
|
|
@ -209,6 +209,14 @@ public class GleSYSTemplateOptions extends TemplateOptions implements Cloneable
|
||||||
GleSYSTemplateOptions options = new GleSYSTemplateOptions();
|
GleSYSTemplateOptions options = new GleSYSTemplateOptions();
|
||||||
return GleSYSTemplateOptions.class.cast(options.userMetadata(key, value));
|
return GleSYSTemplateOptions.class.cast(options.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static GleSYSTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
GleSYSTemplateOptions options = new GleSYSTemplateOptions();
|
||||||
|
return GleSYSTemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods that only facilitate returning the correct object type
|
// methods that only facilitate returning the correct object type
|
||||||
|
@ -261,6 +269,14 @@ public class GleSYSTemplateOptions extends TemplateOptions implements Cloneable
|
||||||
return GleSYSTemplateOptions.class.cast(super.userMetadata(key, value));
|
return GleSYSTemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GleSYSTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return GleSYSTemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ToStringHelper string() {
|
public ToStringHelper string() {
|
||||||
ToStringHelper stringHelper = super.string();
|
ToStringHelper stringHelper = super.string();
|
||||||
|
|
|
@ -97,6 +97,14 @@ public class GoGridTemplateOptions extends TemplateOptions implements Cloneable
|
||||||
GoGridTemplateOptions options = new GoGridTemplateOptions();
|
GoGridTemplateOptions options = new GoGridTemplateOptions();
|
||||||
return GoGridTemplateOptions.class.cast(options.userMetadata(key, value));
|
return GoGridTemplateOptions.class.cast(options.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static GoGridTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
GoGridTemplateOptions options = new GoGridTemplateOptions();
|
||||||
|
return GoGridTemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods that only facilitate returning the correct object type
|
// methods that only facilitate returning the correct object type
|
||||||
|
@ -148,4 +156,12 @@ public class GoGridTemplateOptions extends TemplateOptions implements Cloneable
|
||||||
public GoGridTemplateOptions userMetadata(String key, String value) {
|
public GoGridTemplateOptions userMetadata(String key, String value) {
|
||||||
return GoGridTemplateOptions.class.cast(super.userMetadata(key, value));
|
return GoGridTemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public GoGridTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return GoGridTemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,6 +130,14 @@ public class SoftLayerTemplateOptions extends TemplateOptions implements Cloneab
|
||||||
SoftLayerTemplateOptions options = new SoftLayerTemplateOptions();
|
SoftLayerTemplateOptions options = new SoftLayerTemplateOptions();
|
||||||
return SoftLayerTemplateOptions.class.cast(options.userMetadata(key, value));
|
return SoftLayerTemplateOptions.class.cast(options.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TemplateOptions#nodeNames(Iterable)
|
||||||
|
*/
|
||||||
|
public static SoftLayerTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
SoftLayerTemplateOptions options = new SoftLayerTemplateOptions();
|
||||||
|
return SoftLayerTemplateOptions.class.cast(options.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// methods that only facilitate returning the correct object type
|
// methods that only facilitate returning the correct object type
|
||||||
|
@ -181,4 +189,12 @@ public class SoftLayerTemplateOptions extends TemplateOptions implements Cloneab
|
||||||
public SoftLayerTemplateOptions userMetadata(String key, String value) {
|
public SoftLayerTemplateOptions userMetadata(String key, String value) {
|
||||||
return SoftLayerTemplateOptions.class.cast(super.userMetadata(key, value));
|
return SoftLayerTemplateOptions.class.cast(super.userMetadata(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SoftLayerTemplateOptions nodeNames(Iterable<String> nodeNames) {
|
||||||
|
return SoftLayerTemplateOptions.class.cast(super.nodeNames(nodeNames));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue