added tags to nodemetadata, revised byon to be persistable to blobstore

This commit is contained in:
Adrian Cole 2011-05-16 00:46:02 -07:00
parent ddc514d602
commit 08ee5d5c8d
28 changed files with 767 additions and 155 deletions

View File

@ -44,6 +44,7 @@ public class Node {
private String osFamily; private String osFamily;
private String osDescription; private String osDescription;
private String osVersion; private String osVersion;
private boolean os64Bit;
private String group; private String group;
private Set<String> tags = ImmutableSet.of(); private Set<String> tags = ImmutableSet.of();
private String username; private String username;
@ -96,6 +97,11 @@ public class Node {
return this; return this;
} }
public Builder os64Bit(boolean os64Bit) {
this.os64Bit = os64Bit;
return this;
}
public Builder group(String group) { public Builder group(String group) {
this.group = group; this.group = group;
return this; return this;
@ -128,13 +134,13 @@ public class Node {
public Node build() { public Node build() {
return new Node(id, name, description, hostname, locationId, osArch, osFamily, osDescription, osVersion, return new Node(id, name, description, hostname, locationId, osArch, osFamily, osDescription, osVersion,
group, tags, username, credential, credentialUrl, sudoPassword); os64Bit, group, tags, username, credential, credentialUrl, sudoPassword);
} }
} }
public Node(String id, String name, String description, String hostname, String locationId, String osArch, public Node(String id, String name, String description, String hostname, String locationId, String osArch,
String osFamily, String osDescription, String osVersion, String group, Iterable<String> tags, String osFamily, String osDescription, String osVersion, boolean os64Bit, String group,
String username, String credential, URI credentialUrl, String sudoPassword) { Iterable<String> tags, String username, String credential, URI credentialUrl, String sudoPassword) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.description = description; this.description = description;
@ -144,6 +150,7 @@ public class Node {
this.osFamily = osFamily; this.osFamily = osFamily;
this.osDescription = osDescription; this.osDescription = osDescription;
this.osVersion = osVersion; this.osVersion = osVersion;
this.os64Bit = os64Bit;
this.group = group; this.group = group;
this.tags = ImmutableSet.copyOf(tags); this.tags = ImmutableSet.copyOf(tags);
this.username = username; this.username = username;
@ -161,6 +168,7 @@ public class Node {
private final String osFamily; private final String osFamily;
private final String osDescription; private final String osDescription;
private final String osVersion; private final String osVersion;
private final boolean os64Bit;
private final String group; private final String group;
private final Set<String> tags; private final Set<String> tags;
private final String username; private final String username;
@ -208,6 +216,10 @@ public class Node {
return osVersion; return osVersion;
} }
public boolean isOs64Bit() {
return os64Bit;
}
public Set<String> getTags() { public Set<String> getTags() {
Set<String> tagSet = new HashSet<String>(); Set<String> tagSet = new HashSet<String>();
for (String tag : tags) for (String tag : tags)
@ -227,15 +239,15 @@ public class Node {
return credentialUrl; return credentialUrl;
} }
public String getSudoPassword() {
return sudoPassword;
}
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hashCode(id); return Objects.hashCode(id);
} }
public String getSudoPassword() {
return sudoPassword;
}
@Override @Override
public boolean equals(Object that) { public boolean equals(Object that) {
if (that == null) if (that == null)
@ -247,9 +259,10 @@ public class Node {
public String toString() { public String toString() {
return Objects.toStringHelper(this).add("id", id).add("name", name).add("description", description).add( return Objects.toStringHelper(this).add("id", id).add("name", name).add("description", description).add(
"locationId", locationId).add("hostname", hostname).add("osArch", osArch).add("osFamily", osFamily).add( "locationId", locationId).add("hostname", hostname).add("osArch", osArch).add("osFamily", osFamily).add(
"osDescription", osDescription).add("osVersion", osVersion).add("group", group).add("tags", tags).add( "osDescription", osDescription).add("osVersion", osVersion).add("os64Bit", os64Bit).add("group", group)
"username", username).add("hasCredential", credential != null || credentialUrl != null).add( .add("tags", tags).add("username", username).add("hasCredential",
"hasSudoPassword", sudoPassword != null).toString(); credential != null || credentialUrl != null).add("hasSudoPassword", sudoPassword != null)
.toString();
} }
} }

View File

@ -25,7 +25,7 @@ import java.util.Map;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.byon.Node; import org.jclouds.byon.Node;
import org.jclouds.byon.functions.NodesFromYaml; import org.jclouds.byon.functions.NodesFromYamlStream;
import org.jclouds.byon.internal.BYONComputeServiceAdapter; import org.jclouds.byon.internal.BYONComputeServiceAdapter;
import org.jclouds.byon.suppliers.NodesParsedFromSupplier; import org.jclouds.byon.suppliers.NodesParsedFromSupplier;
import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty; import org.jclouds.byon.suppliers.SupplyFromProviderURIOrNodesProperty;
@ -72,7 +72,7 @@ public class BYONComputeServiceContextModule extends
}).to(SupplyFromProviderURIOrNodesProperty.class); }).to(SupplyFromProviderURIOrNodesProperty.class);
// TODO make this somehow overridable via user request // TODO make this somehow overridable via user request
bind(new TypeLiteral<Function<InputStream, Map<String, Node>>>() { bind(new TypeLiteral<Function<InputStream, Map<String, Node>>>() {
}).to(NodesFromYaml.class); }).to(NodesFromYamlStream.class);
} }
} }

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.byon.config;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.google.common.annotations.Beta;
/**
* designates the module configures a {@code Map<String, Node>}
*
* @author Adrian Cole
*
*/
@Beta
@Retention(RUNTIME)
@Target(TYPE)
public @interface ConfiguresNodeStore {
}

View File

@ -0,0 +1,92 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.byon.config;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Singleton;
import org.jclouds.byon.Node;
import org.jclouds.byon.domain.YamlNode;
import org.jclouds.collect.TransformingMap;
import org.jclouds.io.CopyInputStreamInputSupplierMap;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.io.InputSupplier;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
@ConfiguresNodeStore
@Beta
public class YamlNodeStoreModule extends AbstractModule {
private static final Map<String, InputSupplier<InputStream>> BACKING = new ConcurrentHashMap<String, InputSupplier<InputStream>>();
private final Map<String, InputStream> backing;
public YamlNodeStoreModule(Map<String, InputStream> backing) {
this.backing = backing;
}
public YamlNodeStoreModule() {
this(null);
}
@Override
protected void configure() {
bind(new TypeLiteral<Function<YamlNode, InputStream>>() {
}).toInstance(org.jclouds.byon.domain.YamlNode.yamlNodeToInputStream);
bind(new TypeLiteral<Function<InputStream, YamlNode>>() {
}).toInstance(org.jclouds.byon.domain.YamlNode.inputStreamToYamlNode);
bind(new TypeLiteral<Function<Node, YamlNode>>() {
}).toInstance(org.jclouds.byon.domain.YamlNode.nodeToYamlNode);
bind(new TypeLiteral<Function<YamlNode, Node>>() {
}).toInstance(org.jclouds.byon.domain.YamlNode.toNode);
if (backing != null) {
bind(new TypeLiteral<Map<String, InputStream>>() {
}).toInstance(backing);
} else {
bind(new TypeLiteral<Map<String, InputSupplier<InputStream>>>() {
}).toInstance(BACKING);
bind(new TypeLiteral<Map<String, InputStream>>() {
}).to(new TypeLiteral<CopyInputStreamInputSupplierMap>() {
});
}
}
@Provides
@Singleton
protected Map<String, Node> provideNodeStore(Map<String, YamlNode> backing,
Function<Node, YamlNode> yamlSerializer, Function<YamlNode, Node> yamlDeserializer) {
return new TransformingMap<String, YamlNode, Node>(backing, yamlDeserializer, yamlSerializer);
}
@Provides
@Singleton
protected Map<String, YamlNode> provideYamlStore(Map<String, InputStream> backing,
Function<YamlNode, InputStream> yamlSerializer, Function<InputStream, YamlNode> yamlDeserializer) {
return new TransformingMap<String, InputStream, YamlNode>(backing, yamlDeserializer, yamlSerializer);
}
}

View File

@ -0,0 +1,199 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.byon.domain;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import org.jclouds.byon.Node;
import org.jclouds.util.Strings2;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Loader;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.io.Closeables;
/**
* Serializes to the following
*
* <pre>
* id: cluster-1
* name: cluster-1
* description: xyz
* hostname: cluster-1.mydomain.com
* location_id: virginia
* os_arch: x86
* os_family: linux
* os_description: redhat
* os_version: 5.3
* os_64bit: 5.3
* group: hadoop
* tags:
* - vanilla
* username: kelvin
* credential: password_or_rsa
* or
* credential_url: password_or_rsa_file ex. resource:///id_rsa will get the classpath /id_rsa; file://path/to/id_rsa
* sudo_password: password
* </pre>
*
* @author Kelvin Kakugawa
* @author Adrian Cole
*/
public class YamlNode {
public String id;
public String name;
public String description;
public String hostname;
public String location_id;
public String os_arch;
public String os_family;
public String os_description;
public String os_version;
public boolean os_64bit;
public String group;
public List<String> tags = Lists.newArrayList();
public String username;
public String credential;
public String credential_url;
public String sudo_password;
public static Function<YamlNode, Node> toNode = new Function<YamlNode, Node>() {
@Override
public Node apply(YamlNode arg0) {
if (arg0 == null)
return null;
return Node.builder().id(arg0.id).name(arg0.name).description(arg0.description).locationId(arg0.location_id)
.hostname(arg0.hostname).osArch(arg0.os_arch).osFamily(arg0.os_family).osDescription(
arg0.os_description).osVersion(arg0.os_version).os64Bit(arg0.os_64bit).group(arg0.group)
.tags(arg0.tags).username(arg0.username).credential(arg0.credential).credentialUrl(
arg0.credential_url != null ? URI.create(arg0.credential_url) : null).sudoPassword(
arg0.sudo_password).build();
}
};
public Node toNode() {
return toNode.apply(this);
}
public static Function<InputStream, YamlNode> inputStreamToYamlNode = new Function<InputStream, YamlNode>() {
@Override
public YamlNode apply(InputStream in) {
if (in == null)
return null;
// note that snakeyaml also throws nosuchmethod error when you use the non-deprecated
// constructor
try {
return (YamlNode) new Yaml(new Loader(new Constructor(YamlNode.class))).load(in);
} finally {
Closeables.closeQuietly(in);
}
}
};
public static YamlNode fromYaml(InputStream in) {
return inputStreamToYamlNode.apply(in);
}
public static Function<YamlNode, InputStream> yamlNodeToInputStream = new Function<YamlNode, InputStream>() {
@Override
public InputStream apply(YamlNode in) {
if (in == null)
return null;
Builder<String, Object> prettier = ImmutableMap.<String, Object> builder();
if (in.id != null)
prettier.put("id", in.id);
if (in.name != null)
prettier.put("name", in.name);
if (in.description != null)
prettier.put("description", in.description);
if (in.hostname != null)
prettier.put("hostname", in.hostname);
if (in.location_id != null)
prettier.put("location_id", in.location_id);
if (in.os_arch != null)
prettier.put("os_arch", in.os_arch);
if (in.os_family != null)
prettier.put("os_family", in.os_family);
if (in.os_description != null)
prettier.put("os_description", in.os_description);
if (in.os_version != null)
prettier.put("os_version", in.os_version);
if (in.os_64bit)
prettier.put("os_64bit", in.os_64bit);
if (in.group != null)
prettier.put("group", in.group);
if (in.tags.size() != 0)
prettier.put("tags", in.tags);
if (in.username != null)
prettier.put("username", in.username);
if (in.credential != null)
prettier.put("credential", in.credential);
if (in.credential_url != null)
prettier.put("credential_url", in.credential_url);
if (in.sudo_password != null)
prettier.put("sudo_password", in.sudo_password);
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
return Strings2.toInputStream(new Yaml(options).dump(prettier.build()));
}
};
public InputStream toYaml() {
return yamlNodeToInputStream.apply(this);
}
public static YamlNode fromNode(Node in) {
return nodeToYamlNode.apply(in);
}
public static Function<Node, YamlNode> nodeToYamlNode = new Function<Node, YamlNode>() {
@Override
public YamlNode apply(Node arg0) {
if (arg0 == null)
return null;
YamlNode yaml = new YamlNode();
yaml.id = arg0.getId();
yaml.name = arg0.getName();
yaml.description = arg0.getDescription();
yaml.hostname = arg0.getHostname();
yaml.location_id = arg0.getLocationId();
yaml.os_arch = arg0.getOsArch();
yaml.os_family = arg0.getOsFamily();
yaml.os_description = arg0.getOsDescription();
yaml.os_version = arg0.getOsVersion();
yaml.os_64bit = arg0.isOs64Bit();
yaml.group = arg0.getGroup();
yaml.tags = ImmutableList.copyOf(arg0.getTags());
yaml.username = arg0.getUsername();
yaml.credential = arg0.getCredential();
yaml.credential_url = arg0.getCredentialUrl() != null ? arg0.getCredentialUrl().toASCIIString() : null;
yaml.sudo_password = arg0.getSudoPassword();
return yaml;
}
};
}

View File

@ -81,7 +81,7 @@ public class NodeToNodeMetadata implements Function<Node, NodeMetadata> {
builder.name(from.getName()); builder.name(from.getName());
builder.location(findLocationWithId(from.getLocationId())); builder.location(findLocationWithId(from.getLocationId()));
builder.group(from.getGroup()); builder.group(from.getGroup());
// TODO add tags! builder.tags(from.getTags());
builder.operatingSystem(OperatingSystem.builder().arch(from.getOsArch()).family( builder.operatingSystem(OperatingSystem.builder().arch(from.getOsArch()).family(
OsFamily.fromValue(from.getOsFamily())).description(from.getOsDescription()) OsFamily.fromValue(from.getOsFamily())).description(from.getOsDescription())
.version(from.getOsVersion()).build()); .version(from.getOsVersion()).build());

View File

@ -21,13 +21,13 @@ package org.jclouds.byon.functions;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.byon.Node; import org.jclouds.byon.Node;
import org.jclouds.byon.domain.YamlNode;
import org.yaml.snakeyaml.Loader; import org.yaml.snakeyaml.Loader;
import org.yaml.snakeyaml.TypeDescription; import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
@ -35,7 +35,6 @@ import org.yaml.snakeyaml.constructor.Constructor;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
/** /**
@ -66,38 +65,14 @@ import com.google.common.collect.Maps;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton @Singleton
public class NodesFromYaml implements Function<InputStream, Map<String, Node>> { public class NodesFromYamlStream implements Function<InputStream, Map<String, Node>> {
/** /**
* Type-safe config class for YAML * Type-safe config class for YAML
* *
*/ */
public static class Config { public static class Config {
public List<CrappyNode> nodes; public List<YamlNode> nodes;
}
// crappy, as snakeyaml..
// 1. complains on illegalaccesserror for extends Constructor.ConstructMapping, so we can't use a
// real constructor
// 2. cannot set non-public fields, or fill non-public classes
// 3. doesn't support a SerializedName annotation, so your fields need to be named the same as
// the text
public static class CrappyNode {
public String id;
public String name;
public String description;
public String hostname;
public String location_id;
public String os_arch;
public String os_family;
public String os_description;
public String os_version;
public String group;
public List<String> tags = Lists.newArrayList();
public String username;
public String credential;
public String credential_url;
public String sudo_password;
} }
@Override @Override
@ -105,12 +80,12 @@ public class NodesFromYaml implements Function<InputStream, Map<String, Node>> {
Constructor constructor = new Constructor(Config.class); Constructor constructor = new Constructor(Config.class);
TypeDescription nodeDesc = new TypeDescription(CrappyNode.class); TypeDescription nodeDesc = new TypeDescription(YamlNode.class);
nodeDesc.putListPropertyType("tags", String.class); nodeDesc.putListPropertyType("tags", String.class);
constructor.addTypeDescription(nodeDesc); constructor.addTypeDescription(nodeDesc);
TypeDescription configDesc = new TypeDescription(Config.class); TypeDescription configDesc = new TypeDescription(Config.class);
configDesc.putListPropertyType("nodes", CrappyNode.class); configDesc.putListPropertyType("nodes", YamlNode.class);
constructor.addTypeDescription(configDesc); constructor.addTypeDescription(configDesc);
// note that snakeyaml also throws nosuchmethod error when you use the non-deprecated // note that snakeyaml also throws nosuchmethod error when you use the non-deprecated
// constructor // constructor
@ -119,19 +94,7 @@ public class NodesFromYaml implements Function<InputStream, Map<String, Node>> {
checkState(config != null, "missing config: class"); checkState(config != null, "missing config: class");
checkState(config.nodes != null, "missing nodes: collection"); checkState(config.nodes != null, "missing nodes: collection");
return Maps.uniqueIndex(Iterables.transform(config.nodes, new Function<CrappyNode, Node>() { return Maps.uniqueIndex(Iterables.transform(config.nodes, YamlNode.toNode), new Function<Node, String>() {
@Override
public Node apply(CrappyNode arg0) {
return Node.builder().id(arg0.id).name(arg0.name).description(arg0.description)
.locationId(arg0.location_id).hostname(arg0.hostname).osArch(arg0.os_arch)
.osFamily(arg0.os_family).osDescription(arg0.os_description).osVersion(arg0.os_version).group(
arg0.group).tags(arg0.tags).username(arg0.username).credential(arg0.credential)
.credentialUrl(arg0.credential_url != null ? URI.create(arg0.credential_url) : null).sudoPassword(
arg0.sudo_password).build();
}
}), new Function<Node, String>() {
public String apply(Node node) { public String apply(Node node) {
return node.getId(); return node.getId();
} }

View File

@ -0,0 +1,163 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.byon.config;
import static org.testng.Assert.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.jclouds.byon.Node;
import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.util.Strings2;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.yaml.snakeyaml.Yaml;
import com.google.common.io.InputSupplier;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
@Test(groups = "unit", singleThreaded = true)
public class YamlNodeStoreModuleTest {
Yaml json = createInjector().getInstance(Yaml.class);
@DataProvider(name = "names")
public Object[][] createData() {
return new Object[][] { { "instance1", "bear" }, { "instance2", "apple" }, { "instance2", "francis" },
{ "instance4", "robot" } };
}
@Test(dataProvider = "names")
public void deleteObject(String id, String name) throws InterruptedException, IOException {
Injector injector = createInjector();
Map<String, InputStream> map = getMap(injector);
check(map, getStore(injector), "i-20312", id, name);
}
public void testProvidedMapWithValue() throws IOException {
Map<String, InputStream> map = new CopyInputStreamInputSupplierMap(
new ConcurrentHashMap<String, InputSupplier<InputStream>>());
map.put("test", new ByteArrayInputStream("id: instance1\nname: instancename\n".getBytes()));
checkConsistent(map, getStore(createInjectorWithProvidedMap(map)), "test", "instance1", "instancename");
checkConsistent(map, getStore(createInjectorWithProvidedMap(map)), "test", "instance1", "instancename");
remove(map, getStore(createInjectorWithProvidedMap(map)), "test");
}
public void testProvidedConsistentAcrossRepeatedWrites() throws IOException {
Map<String, InputStream> map = new CopyInputStreamInputSupplierMap(
new ConcurrentHashMap<String, InputSupplier<InputStream>>());
Injector injector = createInjectorWithProvidedMap(map);
assertEquals(injector.getInstance(Key.get(new TypeLiteral<Map<String, InputStream>>() {
})), map);
Map<String, Node> store = getStore(injector);
for (int i = 0; i < 10; i++)
check(map, store, "test" + i, "instance1" + i, "instancename" + i);
}
public void testProvidedConsistentAcrossMultipleInjectors() throws IOException {
Map<String, InputStream> map = new CopyInputStreamInputSupplierMap(
new ConcurrentHashMap<String, InputSupplier<InputStream>>());
put(map, getStore(createInjectorWithProvidedMap(map)), "test", "instance1", "instancename");
checkConsistent(map, getStore(createInjectorWithProvidedMap(map)), "test", "instance1", "instancename");
checkConsistent(map, getStore(createInjectorWithProvidedMap(map)), "test", "instance1", "instancename");
remove(map, getStore(createInjectorWithProvidedMap(map)), "test");
}
public void testDefaultConsistentAcrossMultipleInjectors() throws IOException {
Map<String, InputStream> map = getMap(createInjector());
put(map, getStore(createInjector()), "test", "instance1", "instancename");
checkConsistent(map, getStore(createInjector()), "test", "instance1", "instancename");
checkConsistent(map, getStore(createInjector()), "test", "instance1", "instancename");
remove(map, getStore(createInjector()), "test");
}
protected Map<String, Node> getStore(Injector injector) {
return injector.getInstance(Key.get(new TypeLiteral<Map<String, Node>>() {
}));
}
protected Map<String, InputStream> getMap(Injector injector) {
return injector.getInstance(Key.get(new TypeLiteral<Map<String, InputStream>>() {
}));
}
protected Injector createInjectorWithProvidedMap(Map<String, InputStream> map) {
return Guice.createInjector(new YamlNodeStoreModule(map));
}
protected Injector createInjector() {
return Guice.createInjector(new YamlNodeStoreModule());
}
protected void check(Map<String, InputStream> map, Map<String, Node> store, String key, String id, String name)
throws IOException {
put(map, store, key, id, name);
checkConsistent(map, store, key, id, name);
remove(map, store, key);
}
protected void remove(Map<String, InputStream> map, Map<String, Node> store, String key) {
store.remove(key);
assertEquals(store.size(), 0);
assertEquals(map.size(), 0);
assertEquals(store.get(key), null);
assertEquals(map.get(key), null);
}
protected void checkConsistent(Map<String, InputStream> map, Map<String, Node> store, String key, String id,
String name) throws IOException {
assertEquals(store.size(), 1);
assertEquals(map.size(), 1);
// checkRepeatedRead
assertEquals(store.get(key), Node.builder().id(id).name(name).build());
assertEquals(store.get(key), Node.builder().id(id).name(name).build());
// checkRepeatedRead
checkToYaml(map, key, id, name);
checkToYaml(map, key, id, name);
}
protected void checkToYaml(Map<String, InputStream> map, String key, String id, String name) throws IOException {
assertEquals(Strings2.toStringAndClose(map.get(key)), String.format("id: %s\nname: %s\n", id, name));
}
protected void put(Map<String, InputStream> map, Map<String, Node> store, String key, String id, String name) {
assertEquals(store.size(), 0);
assertEquals(map.size(), 0);
store.put(key, Node.builder().id(id).name(name).build());
}
}

View File

@ -41,22 +41,22 @@ public class NodesFromYamlTest {
.toString(); .toString();
public static final Node TEST1 = new Node("cluster-1", "cluster-1", "accounting analytics cluster", public static final Node TEST1 = new Node("cluster-1", "cluster-1", "accounting analytics cluster",
"cluster-1.mydomain.com", null, "x86", "rhel", "redhat", "5.3", "hadoop", ImmutableList.of("vanilla"), "cluster-1.mydomain.com", null, "x86", "rhel", "redhat", "5.3", false, "hadoop", ImmutableList.of("vanilla"),
"myUser", key, null, "happy bear"); "myUser", key, null, "happy bear");
public static final Node TEST2 = new Node("cluster-1", "cluster-1", "accounting analytics cluster", public static final Node TEST2 = new Node("cluster-1", "cluster-1", "accounting analytics cluster",
"cluster-1.mydomain.com", "virginia", "x86", "rhel", "redhat", "5.3", "hadoop", "cluster-1.mydomain.com", "virginia", "x86", "rhel", "redhat", "5.3", false, "hadoop",
ImmutableList.of("vanilla"), "myUser", key, null, "happy bear"); ImmutableList.of("vanilla"), "myUser", key, null, "happy bear");
public static final Node TEST3 = new Node("cluster-2", "cluster-2", "accounting analytics cluster", public static final Node TEST3 = new Node("cluster-2", "cluster-2", "accounting analytics cluster",
"cluster-2.mydomain.com", "maryland", "x86", "rhel", "redhat", "5.3", "hadoop", "cluster-2.mydomain.com", "maryland", "x86", "rhel", "redhat", "5.3", false, "hadoop",
ImmutableList.of("vanilla"), "myUser", key, null, "happy bear"); ImmutableList.of("vanilla"), "myUser", key, null, "happy bear");
@Test @Test
public void testNodesParse() throws Exception { public void testNodesParse() throws Exception {
InputStream is = getClass().getResourceAsStream("/test1.yaml"); InputStream is = getClass().getResourceAsStream("/test1.yaml");
NodesFromYaml parser = new NodesFromYaml(); NodesFromYamlStream parser = new NodesFromYamlStream();
assertEquals(parser.apply(is), ImmutableMap.of(TEST1.getId(), TEST1)); assertEquals(parser.apply(is), ImmutableMap.of(TEST1.getId(), TEST1));
} }
@ -65,7 +65,7 @@ public class NodesFromYamlTest {
public void testNodesParseLocation() throws Exception { public void testNodesParseLocation() throws Exception {
InputStream is = getClass().getResourceAsStream("/test_location.yaml"); InputStream is = getClass().getResourceAsStream("/test_location.yaml");
NodesFromYaml parser = new NodesFromYaml(); NodesFromYamlStream parser = new NodesFromYamlStream();
assertEquals(parser.apply(is), ImmutableMap.of(TEST2.getId(), TEST2, TEST3.getId(), TEST3)); assertEquals(parser.apply(is), ImmutableMap.of(TEST2.getId(), TEST2, TEST3.getId(), TEST3));
} }
@ -74,14 +74,14 @@ public class NodesFromYamlTest {
public void testNodesParseWhenCredentialInUrl() throws Exception { public void testNodesParseWhenCredentialInUrl() throws Exception {
InputStream is = getClass().getResourceAsStream("/test_with_url.yaml"); InputStream is = getClass().getResourceAsStream("/test_with_url.yaml");
NodesFromYaml parser = new NodesFromYaml(); NodesFromYamlStream parser = new NodesFromYamlStream();
assertEquals(parser.apply(is), ImmutableMap.of(TEST1.getId(), TEST1)); assertEquals(parser.apply(is), ImmutableMap.of(TEST1.getId(), TEST1));
} }
@Test(expectedExceptions = IllegalStateException.class) @Test(expectedExceptions = IllegalStateException.class)
public void testMustParseSomething() throws Exception { public void testMustParseSomething() throws Exception {
new NodesFromYaml().apply(Strings2.toInputStream("")); new NodesFromYamlStream().apply(Strings2.toInputStream(""));
} }
} }

View File

@ -18,7 +18,7 @@
*/ */
package org.jclouds.byon.suppliers; package org.jclouds.byon.suppliers;
import org.jclouds.byon.functions.NodesFromYaml; import org.jclouds.byon.functions.NodesFromYamlStream;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -33,7 +33,7 @@ public class NodesParsedFromSupplierTest {
@Test(expectedExceptions = IllegalStateException.class) @Test(expectedExceptions = IllegalStateException.class)
public void testMustParseSomething() throws Exception { public void testMustParseSomething() throws Exception {
new NodesParsedFromSupplier(Suppliers.ofInstance(Strings2.toInputStream("nodes:\n")), new NodesFromYaml()).get(); new NodesParsedFromSupplier(Suppliers.ofInstance(Strings2.toInputStream("nodes:\n")), new NodesFromYamlStream()).get();
} }
} }

View File

@ -65,7 +65,7 @@ public class Volume implements Comparable<Volume> {
} }
public static enum Status { public static enum Status {
CREATING, AVAILABLE, IN_USE, DELETING, UNRECOGNIZED; CREATING, AVAILABLE, IN_USE, DELETING, ERROR, UNRECOGNIZED;
public String value() { public String value() {
return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name()); return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_HYPHEN, name());
} }

View File

@ -66,7 +66,7 @@ import static org.testng.Assert.assertEquals;
* @author Adrian Cole * @author Adrian Cole
*/ */
// NOTE:without testName, this will not call @Before* and fail w/NPE during surefire // NOTE:without testName, this will not call @Before* and fail w/NPE during surefire
@Test(groups = "unit", testName = "NovaAsyncClientTest") @Test(groups = "unit", singleThreaded = true, testName = "NovaAsyncClientTest")
public class NovaAsyncClientTest extends RestClientTest<NovaAsyncClient> { public class NovaAsyncClientTest extends RestClientTest<NovaAsyncClient> {
private static final Class<? extends ListOptions[]> listOptionsVarargsClass = new ListOptions[]{}.getClass(); private static final Class<? extends ListOptions[]> listOptionsVarargsClass = new ListOptions[]{}.getClass();
private static final Class<? extends CreateServerOptions[]> createServerOptionsVarargsClass = new CreateServerOptions[]{} private static final Class<? extends CreateServerOptions[]> createServerOptionsVarargsClass = new CreateServerOptions[]{}

View File

@ -18,6 +18,10 @@
*/ */
package org.jclouds.compute.domain; package org.jclouds.compute.domain;
import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.compute.domain.internal.ComputeMetadataImpl; import org.jclouds.compute.domain.internal.ComputeMetadataImpl;
import org.jclouds.domain.ResourceMetadata; import org.jclouds.domain.ResourceMetadata;
@ -30,24 +34,23 @@ import com.google.inject.ImplementedBy;
@ImplementedBy(ComputeMetadataImpl.class) @ImplementedBy(ComputeMetadataImpl.class)
public interface ComputeMetadata extends ResourceMetadata<ComputeType> { public interface ComputeMetadata extends ResourceMetadata<ComputeType> {
/** /**
* Type of the resource, ex node, image, size * @return Type of the resource, ex node, image, size
*
*/ */
@Override @Override
public ComputeType getType(); public ComputeType getType();
/** /**
* id of the server within the naming scope it was created. potentially generated by the service. * @return id of the server within the naming scope it was created. potentially generated by the
* * service.
*/ */
@Override @Override
public String getProviderId(); public String getProviderId();
/** /**
* user defined name of the server. * @return user defined name of the server.
*
*/ */
@Override @Override
@Nullable
public String getName(); public String getName();
/** /**
@ -56,7 +59,12 @@ public interface ComputeMetadata extends ResourceMetadata<ComputeType> {
* a node or image is region based, the id will likely include both the region and the * a node or image is region based, the id will likely include both the region and the
* provider-supplied id encoded to avoid collisions. * provider-supplied id encoded to avoid collisions.
* *
* @return unique id within your account on the provider
*/ */
public String getId(); public String getId();
/**
* @return tags describing this resource, if supported
*/
public Set<String> getTags();
} }

View File

@ -22,11 +22,14 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.jclouds.compute.domain.internal.ComputeMetadataImpl; import org.jclouds.compute.domain.internal.ComputeMetadataImpl;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.ResourceMetadataBuilder; import org.jclouds.domain.ResourceMetadataBuilder;
import com.google.common.collect.ImmutableSet;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -34,9 +37,9 @@ import org.jclouds.domain.ResourceMetadataBuilder;
public class ComputeMetadataBuilder extends ResourceMetadataBuilder<ComputeType> { public class ComputeMetadataBuilder extends ResourceMetadataBuilder<ComputeType> {
protected String id; protected String id;
protected ComputeType type; protected ComputeType type;
protected Set<String> tags = ImmutableSet.<String>of();
public ComputeMetadataBuilder(ComputeType type) { public ComputeMetadataBuilder(ComputeType type) {
super();
this.type = checkNotNull(type, "type"); this.type = checkNotNull(type, "type");
} }
@ -45,6 +48,11 @@ public class ComputeMetadataBuilder extends ResourceMetadataBuilder<ComputeType>
return this; return this;
} }
public ComputeMetadataBuilder tags(Set<String> tags) {
this.tags = ImmutableSet.<String> copyOf(checkNotNull(tags, "tags"));
return this;
}
/** /**
* set id and providerId to the same value; * set id and providerId to the same value;
*/ */
@ -79,11 +87,11 @@ public class ComputeMetadataBuilder extends ResourceMetadataBuilder<ComputeType>
} }
public ComputeMetadata build() { public ComputeMetadata build() {
return new ComputeMetadataImpl(type, providerId, name, id, location, uri, userMetadata); return new ComputeMetadataImpl(type, providerId, name, id, location, uri, userMetadata, tags);
} }
public static ComputeMetadataBuilder fromComputeMetadata(ComputeMetadata in) { public static ComputeMetadataBuilder fromComputeMetadata(ComputeMetadata in) {
return new ComputeMetadataBuilder(in.getType()).id(in.getId()).location(in.getLocation()).name(in.getName()) return new ComputeMetadataBuilder(in.getType()).id(in.getId()).location(in.getLocation()).name(in.getName())
.uri(in.getUri()).userMetadata(in.getUserMetadata()); .uri(in.getUri()).userMetadata(in.getUserMetadata()).tags(in.getTags());
} }
} }

View File

@ -25,6 +25,7 @@ import static org.jclouds.compute.predicates.ImagePredicates.any;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.jclouds.compute.domain.internal.HardwareImpl; import org.jclouds.compute.domain.internal.HardwareImpl;
import org.jclouds.compute.predicates.ImagePredicates; import org.jclouds.compute.predicates.ImagePredicates;
@ -88,6 +89,11 @@ public class HardwareBuilder extends ComputeMetadataBuilder {
return HardwareBuilder.class.cast(super.id(id)); return HardwareBuilder.class.cast(super.id(id));
} }
@Override
public HardwareBuilder tags(Set<String> tags) {
return HardwareBuilder.class.cast(super.tags(tags));
}
@Override @Override
public HardwareBuilder ids(String id) { public HardwareBuilder ids(String id) {
return HardwareBuilder.class.cast(super.ids(id)); return HardwareBuilder.class.cast(super.ids(id));
@ -120,14 +126,14 @@ public class HardwareBuilder extends ComputeMetadataBuilder {
@Override @Override
public Hardware build() { public Hardware build() {
return new HardwareImpl(providerId, name, id, location, uri, userMetadata, processors, ram, volumes, return new HardwareImpl(providerId, name, id, location, uri, userMetadata, tags, processors, ram, volumes,
supportsImage); supportsImage);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static HardwareBuilder fromHardware(Hardware in) { public static HardwareBuilder fromHardware(Hardware in) {
return new HardwareBuilder().id(in.getId()).providerId(in.getProviderId()).location(in.getLocation()).name( return new HardwareBuilder().id(in.getId()).providerId(in.getProviderId()).location(in.getLocation()).name(
in.getName()).uri(in.getUri()).userMetadata(in.getUserMetadata()).processors( in.getName()).uri(in.getUri()).userMetadata(in.getUserMetadata()).tags(in.getTags()).processors(
List.class.cast(in.getProcessors())).ram(in.getRam()).volumes(List.class.cast(in.getVolumes())) List.class.cast(in.getProcessors())).ram(in.getRam()).volumes(List.class.cast(in.getVolumes()))
.supportsImage(in.supportsImage()); .supportsImage(in.supportsImage());
} }

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -74,6 +75,10 @@ public class ImageBuilder extends ComputeMetadataBuilder {
return ImageBuilder.class.cast(super.id(id)); return ImageBuilder.class.cast(super.id(id));
} }
public ImageBuilder tags(Set<String> tags) {
return ImageBuilder.class.cast(super.tags(tags));
}
@Override @Override
public ImageBuilder ids(String id) { public ImageBuilder ids(String id) {
return ImageBuilder.class.cast(super.ids(id)); return ImageBuilder.class.cast(super.ids(id));
@ -106,13 +111,13 @@ public class ImageBuilder extends ComputeMetadataBuilder {
@Override @Override
public Image build() { public Image build() {
return new ImageImpl(providerId, name, id, location, uri, userMetadata, operatingSystem, description, version, return new ImageImpl(providerId, name, id, location, uri, userMetadata, tags, operatingSystem, description, version,
adminPassword, defaultCredentials); adminPassword, defaultCredentials);
} }
public static ImageBuilder fromImage(Image image) { public static ImageBuilder fromImage(Image image) {
return new ImageBuilder().providerId(image.getProviderId()).name(image.getName()).id(image.getId()).location( return new ImageBuilder().providerId(image.getProviderId()).name(image.getName()).id(image.getId()).location(
image.getLocation()).uri(image.getUri()).userMetadata(image.getUserMetadata()).version( image.getLocation()).uri(image.getUri()).userMetadata(image.getUserMetadata()).tags(image.getTags()).version(
image.getVersion()).description(image.getDescription()).operatingSystem(image.getOperatingSystem()) image.getVersion()).description(image.getDescription()).operatingSystem(image.getOperatingSystem())
.adminPassword(image.getAdminPassword()).defaultCredentials(image.getDefaultCredentials()); .adminPassword(image.getAdminPassword()).defaultCredentials(image.getDefaultCredentials());
} }

View File

@ -113,6 +113,11 @@ public class NodeMetadataBuilder extends ComputeMetadataBuilder {
return NodeMetadataBuilder.class.cast(super.id(id)); return NodeMetadataBuilder.class.cast(super.id(id));
} }
@Override
public NodeMetadataBuilder tags(Set<String> tags) {
return NodeMetadataBuilder.class.cast(super.tags(tags));
}
@Override @Override
public NodeMetadataBuilder ids(String id) { public NodeMetadataBuilder ids(String id) {
return NodeMetadataBuilder.class.cast(super.ids(id)); return NodeMetadataBuilder.class.cast(super.ids(id));
@ -145,17 +150,17 @@ public class NodeMetadataBuilder extends ComputeMetadataBuilder {
@Override @Override
public NodeMetadata build() { public NodeMetadata build() {
return new NodeMetadataImpl(providerId, name, id, location, uri, userMetadata, group, hardware, imageId, os, state, return new NodeMetadataImpl(providerId, name, id, location, uri, userMetadata, tags, group, hardware, imageId,
loginPort, publicAddresses, privateAddresses, adminPassword, credentials); os, state, loginPort, publicAddresses, privateAddresses, adminPassword, credentials);
} }
public static NodeMetadataBuilder fromNodeMetadata(NodeMetadata node) { public static NodeMetadataBuilder fromNodeMetadata(NodeMetadata node) {
return new NodeMetadataBuilder().providerId(node.getProviderId()).name(node.getName()).id(node.getId()).location( return new NodeMetadataBuilder().providerId(node.getProviderId()).name(node.getName()).id(node.getId()).location(
node.getLocation()).uri(node.getUri()).userMetadata(node.getUserMetadata()).group(node.getGroup()).hardware( node.getLocation()).uri(node.getUri()).userMetadata(node.getUserMetadata()).tags(node.getTags()).group(
node.getHardware()).imageId(node.getImageId()).operatingSystem(node.getOperatingSystem()).state( node.getGroup()).hardware(node.getHardware()).imageId(node.getImageId()).operatingSystem(
node.getState()).loginPort(node.getLoginPort()).publicAddresses(node.getPublicAddresses()) node.getOperatingSystem()).state(node.getState()).loginPort(node.getLoginPort()).publicAddresses(
.privateAddresses(node.getPrivateAddresses()).adminPassword(node.getAdminPassword()).credentials( node.getPublicAddresses()).privateAddresses(node.getPrivateAddresses()).adminPassword(
node.getCredentials()); node.getAdminPassword()).credentials(node.getCredentials());
} }
} }

View File

@ -22,12 +22,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set;
import org.jclouds.compute.domain.ComputeMetadata; import org.jclouds.compute.domain.ComputeMetadata;
import org.jclouds.compute.domain.ComputeType; import org.jclouds.compute.domain.ComputeType;
import org.jclouds.domain.Location; import org.jclouds.domain.Location;
import org.jclouds.domain.internal.ResourceMetadataImpl; import org.jclouds.domain.internal.ResourceMetadataImpl;
import com.google.common.collect.ImmutableSet;
/** /**
* @author Adrian Cole * @author Adrian Cole
* @author Ivan Meredith * @author Ivan Meredith
@ -37,12 +40,14 @@ public class ComputeMetadataImpl extends ResourceMetadataImpl<ComputeType> imple
private static final long serialVersionUID = 7374704415964898694L; private static final long serialVersionUID = 7374704415964898694L;
private final String id; private final String id;
private final ComputeType type; private final ComputeType type;
protected final Set<String> tags;
public ComputeMetadataImpl(ComputeType type, String providerId, String name, String id, Location location, URI uri, public ComputeMetadataImpl(ComputeType type, String providerId, String name, String id, Location location, URI uri,
Map<String, String> userMetadata) { Map<String, String> userMetadata, Set<String> tags) {
super(providerId, name, location, uri, userMetadata); super(providerId, name, location, uri, userMetadata);
this.id = checkNotNull(id, "id"); this.id = checkNotNull(id, "id");
this.type = checkNotNull(type, "type"); this.type = checkNotNull(type, "type");
this.tags = ImmutableSet.<String> copyOf(checkNotNull(tags, "tags"));
} }
/** /**
@ -61,6 +66,14 @@ public class ComputeMetadataImpl extends ResourceMetadataImpl<ComputeType> imple
return id; return id;
} }
/**
* {@inheritDoc}
*/
@Override
public Set<String> getTags() {
return tags;
}
@Override @Override
public int hashCode() { public int hashCode() {
final int prime = 31; final int prime = 31;

View File

@ -25,6 +25,7 @@ import static org.jclouds.compute.util.ComputeServiceUtils.getSpace;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -53,9 +54,9 @@ public class HardwareImpl extends ComputeMetadataImpl implements Hardware {
private final Predicate<Image> supportsImage; private final Predicate<Image> supportsImage;
public HardwareImpl(String providerId, String name, String id, @Nullable Location location, URI uri, public HardwareImpl(String providerId, String name, String id, @Nullable Location location, URI uri,
Map<String, String> userMetadata, Iterable<? extends Processor> processors, int ram, Map<String, String> userMetadata, Set<String> tags, Iterable<? extends Processor> processors, int ram,
Iterable<? extends Volume> volumes, Predicate<Image> supportsImage) { Iterable<? extends Volume> volumes, Predicate<Image> supportsImage) {
super(ComputeType.HARDWARE, providerId, name, id, location, uri, userMetadata); super(ComputeType.HARDWARE, providerId, name, id, location, uri, userMetadata, tags);
this.processors = ImmutableList.copyOf(checkNotNull(processors, "processors")); this.processors = ImmutableList.copyOf(checkNotNull(processors, "processors"));
this.ram = ram; this.ram = ram;
this.volumes = ImmutableList.copyOf(checkNotNull(volumes, "volumes")); this.volumes = ImmutableList.copyOf(checkNotNull(volumes, "volumes"));
@ -106,7 +107,7 @@ public class HardwareImpl extends ComputeMetadataImpl implements Hardware {
@Override @Override
public String toString() { public String toString() {
return "[id=" + getId() + ", providerId=" + getProviderId() + ", name=" + getName() + ", processors=" return "[id=" + getId() + ", providerId=" + getProviderId() + ", name=" + getName() + ", processors="
+ processors + ", ram=" + ram + ", volumes=" + volumes + ", supportsImage=" + supportsImage + "]"; + processors + ", ram=" + ram + ", volumes=" + volumes + ", supportsImage=" + supportsImage + ", tags=" + tags + "]";
} }
/** /**

View File

@ -22,6 +22,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import java.util.Map; import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable; import javax.annotation.Nullable;
@ -47,9 +48,9 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
private final Credentials defaultCredentials; private final Credentials defaultCredentials;
public ImageImpl(String providerId, String name, String id, Location location, URI uri, public ImageImpl(String providerId, String name, String id, Location location, URI uri,
Map<String, String> userMetadata, OperatingSystem operatingSystem, String description, Map<String, String> userMetadata, Set<String> tags, OperatingSystem operatingSystem, String description,
@Nullable String version, @Nullable String adminPassword, @Nullable Credentials defaultCredentials) { @Nullable String version, @Nullable String adminPassword, @Nullable Credentials defaultCredentials) {
super(ComputeType.IMAGE, providerId, name, id, location, uri, userMetadata); super(ComputeType.IMAGE, providerId, name, id, location, uri, userMetadata, tags);
this.operatingSystem = checkNotNull(operatingSystem, "operatingSystem"); this.operatingSystem = checkNotNull(operatingSystem, "operatingSystem");
this.version = version; this.version = version;
this.description = checkNotNull(description, "description"); this.description = checkNotNull(description, "description");
@ -102,7 +103,7 @@ public class ImageImpl extends ComputeMetadataImpl implements Image {
return "[id=" + getId() + ", name=" + getName() + ", operatingSystem=" + operatingSystem + ", description=" return "[id=" + getId() + ", name=" + getName() + ", operatingSystem=" + operatingSystem + ", description="
+ description + ", version=" + version + ", location=" + getLocation() + ", loginUser=" + description + ", version=" + version + ", location=" + getLocation() + ", loginUser="
+ ((defaultCredentials != null) ? defaultCredentials.identity : null) + ", userMetadata=" + ((defaultCredentials != null) ? defaultCredentials.identity : null) + ", userMetadata="
+ getUserMetadata() + "]"; + getUserMetadata() + ", tags=" + tags + "]";
} }
@Override @Override

View File

@ -63,11 +63,11 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
private final OperatingSystem os; private final OperatingSystem os;
public NodeMetadataImpl(String providerId, String name, String id, Location location, URI uri, public NodeMetadataImpl(String providerId, String name, String id, Location location, URI uri,
Map<String, String> userMetadata, @Nullable String group, @Nullable Hardware hardware, Map<String, String> userMetadata, Set<String> tags, @Nullable String group, @Nullable Hardware hardware,
@Nullable String imageId, @Nullable OperatingSystem os, NodeState state, int loginPort, @Nullable String imageId, @Nullable OperatingSystem os, NodeState state, int loginPort,
Iterable<String> publicAddresses, Iterable<String> privateAddresses, @Nullable String adminPassword, Iterable<String> publicAddresses, Iterable<String> privateAddresses, @Nullable String adminPassword,
@Nullable Credentials credentials) { @Nullable Credentials credentials) {
super(ComputeType.NODE, providerId, name, id, location, uri, userMetadata); super(ComputeType.NODE, providerId, name, id, location, uri, userMetadata, tags);
this.group = group; this.group = group;
this.hardware = hardware; this.hardware = hardware;
this.imageId = imageId; this.imageId = imageId;
@ -175,7 +175,7 @@ public class NodeMetadataImpl extends ComputeMetadataImpl implements NodeMetadat
+ getOperatingSystem() + ", state=" + getState() + ", loginPort=" + getLoginPort() + getOperatingSystem() + ", state=" + getState() + ", loginPort=" + getLoginPort()
+ ", privateAddresses=" + privateAddresses + ", publicAddresses=" + publicAddresses + ", hardware=" + ", privateAddresses=" + privateAddresses + ", publicAddresses=" + publicAddresses + ", hardware="
+ getHardware() + ", loginUser=" + ((credentials != null) ? credentials.identity : null) + getHardware() + ", loginUser=" + ((credentials != null) ? credentials.identity : null)
+ ", userMetadata=" + getUserMetadata() + "]"; + ", userMetadata=" + getUserMetadata() + ", tags=" + tags + "]";
} }
@Override @Override

View File

@ -23,6 +23,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.io.Payload; import org.jclouds.io.Payload;
@ -31,6 +32,7 @@ import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
/** /**
* Contains options supported in the {@code ComputeService#runNodesWithTag} operation. <h2> * Contains options supported in the {@code ComputeService#runNodesWithTag} operation. <h2>
@ -70,6 +72,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
to.blockOnPort(this.getPort(), this.getSeconds()); to.blockOnPort(this.getPort(), this.getSeconds());
if (this.isIncludeMetadata()) if (this.isIncludeMetadata())
to.withMetadata(); to.withMetadata();
if (this.getTags().size() > 0)
to.tags(getTags());
if (!this.shouldBlockUntilRunning()) if (!this.shouldBlockUntilRunning())
to.blockUntilRunning(false); to.blockUntilRunning(false);
if (!this.shouldBlockOnComplete()) if (!this.shouldBlockOnComplete())
@ -276,6 +280,8 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
protected Statement script; protected Statement script;
protected Set<String> tags = ImmutableSet.of();
protected String privateKey; protected String privateKey;
protected String publicKey; protected String publicKey;
@ -292,6 +298,10 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
return script; return script;
} }
public Set<String> getTags() {
return tags;
}
public String getPrivateKey() { public String getPrivateKey() {
return privateKey; return privateKey;
} }
@ -350,7 +360,7 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
*/ */
public TemplateOptions installPrivateKey(String privateKey) { public TemplateOptions installPrivateKey(String privateKey) {
checkArgument(checkNotNull(privateKey, "privateKey").startsWith("-----BEGIN RSA PRIVATE KEY-----"), checkArgument(checkNotNull(privateKey, "privateKey").startsWith("-----BEGIN RSA PRIVATE KEY-----"),
"key should start with -----BEGIN RSA PRIVATE KEY-----"); "key should start with -----BEGIN RSA PRIVATE KEY-----");
this.privateKey = privateKey; this.privateKey = privateKey;
return this; return this;
} }
@ -403,6 +413,14 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
} }
} }
/**
* assigns tags to the created nodes
*/
public TemplateOptions tags(Iterable<String> tags) {
this.tags = ImmutableSet.copyOf(checkNotNull(tags, "tags"));
return this;
}
/** /**
* Opens the set of ports to public access. * Opens the set of ports to public access.
*/ */
@ -461,6 +479,14 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
return options.inboundPorts(ports); return options.inboundPorts(ports);
} }
/**
* @see TemplateOptions#tags
*/
public static TemplateOptions tags(Iterable<String> tags) {
TemplateOptions options = new TemplateOptions();
return options.tags(tags);
}
/** /**
* @see TemplateOptions#blockUntilRunning * @see TemplateOptions#blockUntilRunning
*/ */
@ -556,9 +582,9 @@ public class TemplateOptions extends RunScriptOptions implements Cloneable {
@Override @Override
public String toString() { public String toString() {
return "[inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null) + ", publicKey=" return "[inboundPorts=" + Arrays.toString(inboundPorts) + ", privateKey=" + (privateKey != null) + ", publicKey="
+ (publicKey != null) + ", runScript=" + (script != null) + ", blockUntilRunning=" + blockUntilRunning + (publicKey != null) + ", runScript=" + (script != null) + ", blockUntilRunning=" + blockUntilRunning
+ ", blockOnComplete=" + blockOnComplete + ", port:seconds=" + port + ":" + seconds + ", blockOnComplete=" + blockOnComplete + ", port:seconds=" + port + ":" + seconds
+ ", metadata/details: " + includeMetadata + "]"; + ", metadata/details: " + includeMetadata + "]";
} }
public TemplateOptions blockUntilRunning(boolean blockUntilRunning) { public TemplateOptions blockUntilRunning(boolean blockUntilRunning) {

View File

@ -45,8 +45,9 @@ import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.ImmutableList.Builder;
/** /**
* *
@ -85,6 +86,7 @@ public class StubComputeServiceAdapter implements JCloudsNativeComputeServiceAda
String id = idProvider.get() + ""; String id = idProvider.get() + "";
builder.ids(id); builder.ids(id);
builder.name(name); builder.name(name);
builder.tags(template.getOptions().getTags());
builder.group(group); builder.group(group);
builder.location(location.get()); builder.location(location.get());
builder.imageId(template.getImage().getId()); builder.imageId(template.getImage().getId());
@ -110,18 +112,19 @@ public class StubComputeServiceAdapter implements JCloudsNativeComputeServiceAda
@Override @Override
public Iterable<Image> listImages() { public Iterable<Image> listImages() {
Credentials defaultCredentials = new Credentials("root", null); Credentials defaultCredentials = new Credentials("root", null);
Set<Image> images = Sets.newLinkedHashSet(); // initializing as a List, as ImmutableSet does not allow you to put duplicates
Builder<Image> images = ImmutableList.<Image>builder();
int id = 1; int id = 1;
for (boolean is64Bit : new boolean[] { true, false }) for (boolean is64Bit : new boolean[] { true, false })
for (Entry<OsFamily, Map<String, String>> osVersions : this.osToVersionMap.entrySet()) { for (Entry<OsFamily, Map<String, String>> osVersions : this.osToVersionMap.entrySet()) {
for (String version : Sets.newLinkedHashSet(osVersions.getValue().values())) { for (String version : ImmutableSet.copyOf(osVersions.getValue().values())) {
String desc = String.format("stub %s %s", osVersions.getKey(), is64Bit); String desc = String.format("stub %s %s", osVersions.getKey(), is64Bit);
images.add(new ImageBuilder().ids(id++ + "").name(osVersions.getKey().name()).location(location.get()) images.add(new ImageBuilder().ids(id++ + "").name(osVersions.getKey().name()).location(location.get())
.operatingSystem(new OperatingSystem(osVersions.getKey(), desc, version, null, desc, is64Bit)) .operatingSystem(new OperatingSystem(osVersions.getKey(), desc, version, null, desc, is64Bit))
.description(desc).defaultCredentials(defaultCredentials).build()); .description(desc).defaultCredentials(defaultCredentials).build());
} }
} }
return images; return images.build();
} }
@Override @Override

View File

@ -0,0 +1,47 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.io;
import java.io.InputStream;
import java.util.Map;
import javax.inject.Inject;
import org.jclouds.collect.InputSupplierMap;
import com.google.common.annotations.Beta;
import com.google.common.io.InputSupplier;
/**
*
* @author Adrian Cole
*/
@Beta
public class CopyInputStreamInputSupplierMap extends InputSupplierMap<String, InputStream> {
@Inject
public CopyInputStreamInputSupplierMap(Map<String, InputSupplier<InputStream>> toMap,
CopyInputStreamIntoSupplier putFunction) {
super(toMap, putFunction);
}
public CopyInputStreamInputSupplierMap(Map<String, InputSupplier<InputStream>> toMap) {
super(toMap, new CopyInputStreamIntoSupplier());
}
}

View File

@ -0,0 +1,64 @@
/**
*
* Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed 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.io;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.Resource;
import org.jclouds.logging.Logger;
import com.google.common.annotations.Beta;
import com.google.common.base.Function;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import com.google.common.io.InputSupplier;
/**
*
* @author Adrian Cole
*/
@Beta
public class CopyInputStreamIntoSupplier implements Function<InputStream, InputSupplier<InputStream>> {
@Resource
protected Logger logger = Logger.NULL;
@SuppressWarnings("unchecked")
@Override
public InputSupplier<InputStream> apply(InputStream from) {
if (from == null)
return new InputSupplier<InputStream>() {
@Override
public InputStream getInput() throws IOException {
return null;
}
};
try {
return InputSupplier.class.cast(ByteStreams.newInputStreamSupplier(ByteStreams.toByteArray(from)));
} catch (Exception e) {
logger.warn(e, "ignoring problem retrieving credentials");
return null;
} finally {
Closeables.closeQuietly(from);
}
}
}

View File

@ -20,7 +20,6 @@ package org.jclouds.rest.config;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -29,9 +28,9 @@ import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.collect.InputSupplierMap;
import org.jclouds.collect.TransformingMap; import org.jclouds.collect.TransformingMap;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.json.Json; import org.jclouds.json.Json;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.ConfiguresCredentialStore; import org.jclouds.rest.ConfiguresCredentialStore;
@ -39,8 +38,6 @@ import org.jclouds.util.Strings2;
import com.google.common.annotations.Beta; import com.google.common.annotations.Beta;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.io.ByteStreams;
import com.google.common.io.Closeables;
import com.google.common.io.InputSupplier; import com.google.common.io.InputSupplier;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Provides; import com.google.inject.Provides;
@ -97,48 +94,6 @@ public class CredentialStoreModule extends AbstractModule {
} }
} }
@Singleton
public static class CopyInputStreamInputSupplierMap extends InputSupplierMap<String, InputStream> {
@Singleton
public static class CopyInputStreamIntoSupplier implements Function<InputStream, InputSupplier<InputStream>> {
@Resource
protected Logger logger = Logger.NULL;
@SuppressWarnings("unchecked")
@Override
public InputSupplier<InputStream> apply(InputStream from) {
if (from == null)
return new InputSupplier<InputStream>() {
@Override
public InputStream getInput() throws IOException {
return null;
}
};
try {
return InputSupplier.class.cast(ByteStreams.newInputStreamSupplier(ByteStreams.toByteArray(from)));
} catch (Exception e) {
logger.warn(e, "ignoring problem retrieving credentials");
return null;
} finally {
Closeables.closeQuietly(from);
}
}
}
@Inject
public CopyInputStreamInputSupplierMap(Map<String, InputSupplier<InputStream>> toMap,
CopyInputStreamIntoSupplier putFunction) {
super(toMap, putFunction);
}
public CopyInputStreamInputSupplierMap(Map<String, InputSupplier<InputStream>> toMap) {
super(toMap, new CopyInputStreamIntoSupplier());
}
}
@Singleton @Singleton
public static class CredentialsFromJsonInputStream implements Function<InputStream, Credentials> { public static class CredentialsFromJsonInputStream implements Function<InputStream, Credentials> {
@Resource @Resource

View File

@ -28,10 +28,10 @@ import java.util.concurrent.ConcurrentHashMap;
import org.jclouds.crypto.PemsTest; import org.jclouds.crypto.PemsTest;
import org.jclouds.domain.Credentials; import org.jclouds.domain.Credentials;
import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.json.Json; import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule; import org.jclouds.json.config.GsonModule;
import org.jclouds.rest.config.CredentialStoreModule; import org.jclouds.rest.config.CredentialStoreModule;
import org.jclouds.rest.config.CredentialStoreModule.CopyInputStreamInputSupplierMap;
import org.jclouds.util.Strings2; import org.jclouds.util.Strings2;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -46,7 +46,7 @@ import com.google.inject.TypeLiteral;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", sequential = true) @Test(groups = "unit", singleThreaded = true)
public class CredentialStoreModuleTest { public class CredentialStoreModuleTest {
Json json = createInjector().getInstance(Json.class); Json json = createInjector().getInstance(Json.class);

View File

@ -125,11 +125,11 @@ public class AWSEC2ImageParserTest {
assertEquals( assertEquals(
new Gson().toJson(Iterables.get(result, 1)), new Gson().toJson(Iterables.get(result, 1)),
"{\"operatingSystem\":{\"family\":\"UBUNTU\",\"arch\":\"paravirtual\",\"version\":\"9.10\",\"description\":\"411009282317/RightImage_Ubuntu_9.10_x64_v4.5.3_EBS_Alpha\",\"is64Bit\":true},\"version\":\"4.5.3_EBS_Alpha\",\"description\":\"RightImage_Ubuntu_9.10_x64_v4.5.3_EBS_Alpha\",\"defaultCredentials\":{\"identity\":\"root\"},\"id\":\"us-east-1/ami-c19db6b5\",\"type\":\"IMAGE\",\"providerId\":\"ami-c19db6b5\",\"location\":{\"scope\":\"REGION\",\"id\":\"us-east-1\",\"description\":\"us-east-1\",\"iso3166Codes\":[],\"metadata\":{}},\"userMetadata\":{\"owner\":\"411009282317\",\"rootDeviceType\":\"ebs\"}}"); "{\"operatingSystem\":{\"family\":\"UBUNTU\",\"arch\":\"paravirtual\",\"version\":\"9.10\",\"description\":\"411009282317/RightImage_Ubuntu_9.10_x64_v4.5.3_EBS_Alpha\",\"is64Bit\":true},\"version\":\"4.5.3_EBS_Alpha\",\"description\":\"RightImage_Ubuntu_9.10_x64_v4.5.3_EBS_Alpha\",\"defaultCredentials\":{\"identity\":\"root\"},\"id\":\"us-east-1/ami-c19db6b5\",\"type\":\"IMAGE\",\"tags\":[],\"providerId\":\"ami-c19db6b5\",\"location\":{\"scope\":\"REGION\",\"id\":\"us-east-1\",\"description\":\"us-east-1\",\"iso3166Codes\":[],\"metadata\":{}},\"userMetadata\":{\"owner\":\"411009282317\",\"rootDeviceType\":\"ebs\"}}");
assertEquals( assertEquals(
new Gson().toJson(Iterables.get(result, 2)), new Gson().toJson(Iterables.get(result, 2)),
"{\"operatingSystem\":{\"family\":\"WINDOWS\",\"arch\":\"hvm\",\"version\":\"2003\",\"description\":\"411009282317/RightImage Windows_2003_i386_v5.4.3\",\"is64Bit\":false},\"version\":\"5.4.3\",\"description\":\"Built by RightScale\",\"defaultCredentials\":{\"identity\":\"root\"},\"id\":\"us-east-1/ami-710c2605\",\"type\":\"IMAGE\",\"providerId\":\"ami-710c2605\",\"location\":{\"scope\":\"REGION\",\"id\":\"us-east-1\",\"description\":\"us-east-1\",\"iso3166Codes\":[],\"metadata\":{}},\"userMetadata\":{\"owner\":\"411009282317\",\"rootDeviceType\":\"ebs\"}}"); "{\"operatingSystem\":{\"family\":\"WINDOWS\",\"arch\":\"hvm\",\"version\":\"2003\",\"description\":\"411009282317/RightImage Windows_2003_i386_v5.4.3\",\"is64Bit\":false},\"version\":\"5.4.3\",\"description\":\"Built by RightScale\",\"defaultCredentials\":{\"identity\":\"root\"},\"id\":\"us-east-1/ami-710c2605\",\"type\":\"IMAGE\",\"tags\":[],\"providerId\":\"ami-710c2605\",\"location\":{\"scope\":\"REGION\",\"id\":\"us-east-1\",\"description\":\"us-east-1\",\"iso3166Codes\":[],\"metadata\":{}},\"userMetadata\":{\"owner\":\"411009282317\",\"rootDeviceType\":\"ebs\"}}");
} }
public void testParseAmznImage() { public void testParseAmznImage() {