From 46414e339acaf8060c9e26dcb6b96c3626a9856a Mon Sep 17 00:00:00 2001 From: Nigel Magnay Date: Mon, 16 Jul 2012 16:58:22 +0100 Subject: [PATCH] Initial implementation of controlling SmartOS over SSH connection. This has been implemented mainly to allow jenkins-jclouds integration. Signed-off-by: Nigel Magnay --- labs/pom.xml | 1 + labs/smartos-ssh/README.md | 20 ++ labs/smartos-ssh/pom.xml | 121 +++++++ .../jclouds/smartos/SmartOSApiMetadata.java | 57 ++++ .../SmartOSComputeServiceContextModule.java | 62 ++++ .../smartos/compute/domain/DataSet.java | 141 +++++++++ .../smartos/compute/domain/SmartOSHost.java | 296 ++++++++++++++++++ .../jclouds/smartos/compute/domain/VM.java | 222 +++++++++++++ .../jclouds/smartos/compute/domain/VmNIC.java | 110 +++++++ .../compute/domain/VmSpecification.java | 142 +++++++++ .../compute/functions/DataSetToImage.java | 63 ++++ .../functions/DatacenterToLocation.java | 53 ++++ .../compute/functions/VMToNodeMetadata.java | 150 +++++++++ .../functions/VmSpecificationToHardware.java | 48 +++ .../SmartOSComputeServiceAdapter.java | 128 ++++++++ .../services/org.jclouds.apis.ApiMetadata | 1 + ...nagerComputeServiceContextBuilderTest.java | 88 ++++++ .../SmartOSManagerComputeServiceLiveTest.java | 60 ++++ .../smartos/compute/domain/DataSetTest.java | 36 +++ .../smartos/compute/domain/VMTest.java | 38 +++ labs/smartos-ssh/src/test/resources/log4j.xml | 190 +++++++++++ .../compute/domain/dsadm-list-response.txt | 11 + .../compute/domain/vmadm-list-response.txt | 2 + 23 files changed, 2040 insertions(+) create mode 100644 labs/smartos-ssh/README.md create mode 100644 labs/smartos-ssh/pom.xml create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/SmartOSApiMetadata.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/config/SmartOSComputeServiceContextModule.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/DataSet.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/SmartOSHost.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VM.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmNIC.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmSpecification.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DataSetToImage.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DatacenterToLocation.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VMToNodeMetadata.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VmSpecificationToHardware.java create mode 100644 labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/strategy/SmartOSComputeServiceAdapter.java create mode 100644 labs/smartos-ssh/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata create mode 100644 labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceContextBuilderTest.java create mode 100644 labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceLiveTest.java create mode 100644 labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/DataSetTest.java create mode 100644 labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/VMTest.java create mode 100644 labs/smartos-ssh/src/test/resources/log4j.xml create mode 100644 labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/dsadm-list-response.txt create mode 100644 labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/vmadm-list-response.txt diff --git a/labs/pom.xml b/labs/pom.xml index c5a4f19e2b..6c5b1477d7 100644 --- a/labs/pom.xml +++ b/labs/pom.xml @@ -55,5 +55,6 @@ nodepool rds aws-rds + smartos-ssh diff --git a/labs/smartos-ssh/README.md b/labs/smartos-ssh/README.md new file mode 100644 index 0000000000..7ca7d43352 --- /dev/null +++ b/labs/smartos-ssh/README.md @@ -0,0 +1,20 @@ + +This is designed for interacting with a Joyent SmartOS host, in order to be able to leverage +the lightweight VM support (nee Solaris Zones). + +It is planned to support KVM VMs in the future. + +-------------- + +#Setup + +Have a SmartOS installation, that you know either the root password for, or a secondary account with sufficient +permissions to be able to run the vm tools (vmadm, dsadm). + +That's it! + +-------------- + +#Notes: + +- This is a work in progress, so please report any bugs that you find. diff --git a/labs/smartos-ssh/pom.xml b/labs/smartos-ssh/pom.xml new file mode 100644 index 0000000000..c93ed79778 --- /dev/null +++ b/labs/smartos-ssh/pom.xml @@ -0,0 +1,121 @@ + + + + 4.0.0 + + org.jclouds + jclouds-project + 1.5.0-SNAPSHOT + ../../project/pom.xml + + org.jclouds.labs + smartos-ssh + smartos ssh api + jclouds components to access SmartOS over SSH + bundle + + + https://api.joyentcloud.com + ~6.5 + + FIXME_IDENTITY + FIXME_CREDENTIALS + org.jclouds.joyent.cloudapi.v6_5*;version="${project.version}" + + org.jclouds.rest.internal;version="${project.version}", + org.jclouds*;version="${project.version}", + * + + + + + org.jclouds + jclouds-compute + ${project.version} + + + org.jclouds + jclouds-compute + ${project.version} + test-jar + test + + + org.jclouds + jclouds-core + ${project.version} + test-jar + test + + + org.jclouds.driver + jclouds-slf4j + ${project.version} + test + + + org.jclouds.driver + jclouds-sshj + ${project.version} + test + + + ch.qos.logback + logback-classic + 1.0.0 + test + + + + + + live + + + + org.apache.maven.plugins + maven-surefire-plugin + + + integration + integration-test + + test + + + + ${test.smartos-ssh.endpoint} + ${test.smartos-ssh.api-version} + ${test.smartos-ssh.build-version} + ${test.smartos-ssh.identity} + ${test.smartos-ssh.credential} + + + + + + + + + + + diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/SmartOSApiMetadata.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/SmartOSApiMetadata.java new file mode 100644 index 0000000000..af47bb55b8 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/SmartOSApiMetadata.java @@ -0,0 +1,57 @@ +package org.jclouds.smartos; + +import java.net.URI; + +import org.jclouds.apis.ApiMetadata; +import org.jclouds.apis.internal.BaseApiMetadata; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.smartos.compute.config.SmartOSComputeServiceContextModule; + +/** + * Implementation of {@link ApiMetadata} for SmartOS + * + * @author Nigel Magnay + */ +public class SmartOSApiMetadata extends BaseApiMetadata { + + /** The serialVersionUID */ + private static final long serialVersionUID = 3606170564482119304L; + + public static Builder builder() { + return new Builder(); + } + + @Override + public Builder toBuilder() { + return Builder.class.cast(builder().fromApiMetadata(this)); + } + + public SmartOSApiMetadata() { + super(builder()); + } + + protected SmartOSApiMetadata(Builder builder) { + super(builder); + } + + public static class Builder extends BaseApiMetadata.Builder { + + protected Builder(){ + id("smartos-ssh") + .name("SmartOS SSH API") + .identityName("Username") + .defaultIdentity("root") + .defaultCredential("smartos") + .defaultEndpoint("http://localhost") + .documentation(URI.create("http://http://wiki.smartos.org/display/DOC/How+to+create+a+Virtual+Machine+in+SmartOS")) + .view(ComputeServiceContext.class) + .defaultModule(SmartOSComputeServiceContextModule.class); + } + + @Override + public SmartOSApiMetadata build() { + return new SmartOSApiMetadata(this); + } + + } +} \ No newline at end of file diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/config/SmartOSComputeServiceContextModule.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/config/SmartOSComputeServiceContextModule.java new file mode 100644 index 0000000000..a5fe6c6805 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/config/SmartOSComputeServiceContextModule.java @@ -0,0 +1,62 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute.config; + +import com.google.common.base.Function; +import com.google.inject.TypeLiteral; +import org.jclouds.smartos.compute.domain.DataSet; +import org.jclouds.smartos.compute.domain.SmartOSHost; +import org.jclouds.smartos.compute.domain.VM; +import org.jclouds.smartos.compute.domain.VmSpecification; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.config.ComputeServiceAdapterContextModule; +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.domain.Location; + +import org.jclouds.smartos.compute.functions.DataSetToImage; +import org.jclouds.smartos.compute.functions.DatacenterToLocation; +import org.jclouds.smartos.compute.functions.VMToNodeMetadata; +import org.jclouds.smartos.compute.functions.VmSpecificationToHardware; +import org.jclouds.smartos.compute.strategy.SmartOSComputeServiceAdapter; + +/** + * + * @author Nigel Magnay + */ +public class SmartOSComputeServiceContextModule extends + ComputeServiceAdapterContextModule { + + @Override + protected void configure() { + super.configure(); + bind(new TypeLiteral>() { + }).to(SmartOSComputeServiceAdapter.class); + bind(new TypeLiteral>() { + }).to(VMToNodeMetadata.class); + bind(new TypeLiteral>() { + }).to(DataSetToImage.class); + bind(new TypeLiteral>() { + }).to(VmSpecificationToHardware.class); + bind(new TypeLiteral>() { + }).to(DatacenterToLocation.class); + // to have the compute service adapter override default locations + //install(new LocationsFromComputeServiceAdapterModule(){}); + + } +} \ No newline at end of file diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/DataSet.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/DataSet.java new file mode 100644 index 0000000000..0b766af966 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/DataSet.java @@ -0,0 +1,141 @@ +package org.jclouds.smartos.compute.domain; + +import com.google.common.base.Objects; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +/** + * Dataset is a pre-built image ready to be cloned. + */ +public class DataSet { + private final UUID uuid; + private final String os; + private final String published; + private final String urn; + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromDataSet(this); + } + + public static class Builder { + + public UUID uuid; + public String os; + public String published; + public String urn; + + public Builder uuid(UUID uuid) { + this.uuid = uuid; + return this; + } + + public Builder uuid(String uuid) { + this.uuid = UUID.fromString(uuid); + return this; + } + + public Builder os(String os) { + this.os = os; + return this; + } + + public Builder published(String published) { + this.published = published; + return this; + } + + public Builder urn(String urn) { + this.urn = urn; + return this; + } + + public Builder fromDsadmString(String string) { + String [] sections = string.split(" "); + + uuid ( sections[0] ); + os ( sections[1] ); + published ( sections[2] ); + urn ( sections[3] ); + + return this; + } + + + public DataSet build() { + return new DataSet(uuid, os, published, urn); + } + + public Builder fromDataSet(DataSet in) { + return uuid(in.getUuid()) + .os(in.getOs()) + .published(in.getPublished()) + .urn(in.getUrn()); + } + } + + protected DataSet(UUID uuid, String os, String published, String urn) { + this.uuid = uuid; + this.os = os; + this.published = published; + this.urn = urn; + } + + public UUID getUuid() { + return uuid; + } + + public String getOs() { + return os; + } + + public String getPublished() { + return published; + } + + public String getUrn() { + return urn; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + // UUID is primary key + return uuid.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + return uuid.equals(((DataSet)obj).uuid); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Objects.toStringHelper(this).omitNullValues() + .add("uuid", uuid) + .add("os", os) + .add("published", published) + .add("urn", urn).toString(); + } + +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/SmartOSHost.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/SmartOSHost.java new file mode 100644 index 0000000000..7feb88a9ea --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/SmartOSHost.java @@ -0,0 +1,296 @@ +package org.jclouds.smartos.compute.domain; + +import com.google.common.base.Splitter; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.net.HostAndPort; +import org.jclouds.domain.LoginCredentials; +import org.jclouds.location.Provider; +import org.jclouds.rest.annotations.Credential; +import org.jclouds.rest.annotations.Identity; +import org.jclouds.ssh.SshClient; + +import javax.annotation.Nullable; +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.net.URI; +import java.util.Map; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A host machine that runs smartOS + */ +@Singleton +public class SmartOSHost { + protected final String hostname; + protected final String username; + protected final String password; + + protected SshClient.Factory sshClientFactory; + + private SshClient _connection; + + public static class HostException extends RuntimeException { + public HostException(String s, Throwable throwable) { + super(s, throwable); + } + + public HostException(String s) { + super(s); + } + } + + public static class NoResponseException extends Exception { + public NoResponseException() { + } + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromSmartOSHost(this); + } + + public static class Builder { + protected String hostname; + protected String username; + protected String password; + protected SshClient.Factory sshFactory; + + public Builder hostname(String hostname) { + this.hostname = hostname; + return this; + } + + public Builder username(String username) { + this.username = username; + return this; + } + + public Builder password(String password) { + this.password = password; + return this; + } + + public Builder sshFactory(SshClient.Factory sshFactory) { + this.sshFactory = sshFactory; + return this; + } + + public SmartOSHost build() { + return new SmartOSHost(hostname, username, password, sshFactory); + } + + public Builder fromSmartOSHost(SmartOSHost in) { + return this.hostname ( in.getHostname() ) + .username ( in.getHostname() ) + .password ( in.getPassword() ) + .sshFactory( in.getSshClientFactory() ); + } + } + + @Inject + protected SmartOSHost(@Provider Supplier provider, + @Nullable @Identity String identity, + @Nullable @Credential String credential, + SshClient.Factory sshFactory) { + + this.hostname = provider.get().getHost(); + this.username = identity; + this.password = credential; + this.sshClientFactory = sshFactory; + } + + protected SmartOSHost(String hostname, String username, String password, SshClient.Factory sshClientFactory) { + this.hostname = hostname; + this.username = username; + this.password = password; + this.sshClientFactory = sshClientFactory; + } + + public String getDescription() { + return "SmartOS@" + hostname; + } + + public String getHostname() { + return hostname; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public SshClient.Factory getSshClientFactory() { + return sshClientFactory; + } + + protected SshClient getConnection() { + if (_connection == null) { + + LoginCredentials credentials = new LoginCredentials.Builder() + .user(username) + .password(password) + .build(); + + _connection = getSshClientFactory().create( + HostAndPort.fromParts(hostname, 22), + credentials + ); + + _connection.connect(); + + } + return _connection; + } + + + public String exec(String cmd) { + return getConnection().exec(cmd).getOutput(); + } + + public String vmList() { + return exec("vmadm list -p"); + } + + + public Map getVMIpAddresses(UUID vmId) + { + ImmutableMap.Builder netMapBuilder = ImmutableMap.builder(); + + String response = getConnection().exec("zlogin " + vmId.toString() + " ifconfig -a4").getOutput(); + + if( response.length() == 0) + return ImmutableMap.of(); + + Iterable strings = Splitter.on("\n").split(response); + Pattern inetMatcher = Pattern.compile("inet [0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"); + + String iface = ""; + for(String line : strings ) + { + if( line.length() > 0 && Character.isLetterOrDigit(line.charAt(0)) ) + { + iface = line.substring(0, line.indexOf(":") ); + } + else + { + Matcher matcher = inetMatcher.matcher(line); + if( matcher.find() ) + netMapBuilder.put(iface, matcher.group().substring(5)); + } + } + + return netMapBuilder.build(); + + } + + /** + * What remotely available images are there in the cloud? + * + * @return Collection of datasets + */ + public Iterable getAvailableImages() { + return toSpecList(exec("dsadm avail")); + } + + public Iterable getLocalDatasets() { + return toSpecList(exec("dsadm list")); + } + + public Iterable getVMs() { + return toVMList(exec("vmadm list -p")); + } + + public VM createVM(VmSpecification specification) { + + String response = getConnection().exec("(cat < toVMList(String string) { + try { + BufferedReader r = new BufferedReader(new StringReader(string)); + String line; + ImmutableList.Builder resultBuilder = ImmutableList.builder(); + while ((line = r.readLine()) != null) { + VM vm = VM.builder().host(this).fromVmadmString(line).build(); + + resultBuilder.add(vm); + } + return resultBuilder.build(); + } catch (IOException e) { + throw new HostException("Error parsing response when building VM list", e); + } + } + + public VM getVM(UUID serverId) { + for (VM vm : getVMs()) + if (vm.uuid.equals(serverId)) + return vm; + return null; + } + + public DataSet getDataSet(UUID imageId) { + for (DataSet ds : getLocalDatasets()) { + if (ds.getUuid().equals(imageId)) + return ds; + } + return null; + } + + public void destroyHost(UUID uuid) { + exec("vmadm delete " + uuid.toString()); + } + + public void rebootHost(UUID uuid) { + exec("vmadm reboot " + uuid.toString()); + } + + public void stopHost(UUID uuid) { + exec("vmadm stop -p"); + } + + public void startHost(UUID uuid) { + exec("vmadm start " + uuid.toString()); + } +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VM.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VM.java new file mode 100644 index 0000000000..ec9e6e9007 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VM.java @@ -0,0 +1,222 @@ +package org.jclouds.smartos.compute.domain; + +import com.google.common.base.Objects; +import com.google.common.base.Optional; + +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.UUID; + +/** + * Representing a Virtual Machine (Zone / KVM ) + **/ +public class VM { + + public enum State + { + RUNNING, + STOPPED, + INCOMPLETE + } + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromVM(this); + } + + public static class Builder { + + protected SmartOSHost host; + protected UUID uuid; + protected String type; + protected String ram; + protected State state = State.STOPPED; + protected String alias; + + public Builder uuid(UUID uuid) { + this.uuid = uuid; + return this; + } + + public Builder uuid(String uuid) { + this.uuid = UUID.fromString(uuid); + return this; + } + + public Builder host(SmartOSHost host) { + this.host = host; + return this; + } + + public Builder type(String type) { + this.type = type; + return this; + } + + public Builder ram(String ram) { + this.ram = ram; + return this; + } + + public Builder state(String state) { + this.state = State.valueOf(state.toUpperCase()); + return this; + } + + public Builder state(State state) { + this.state = state; + return this; + } + + public Builder alias(String alias) { + this.alias = alias; + return this; + } + + public Builder fromVmadmString(String string) { + String[] sections = string.split(":"); + + uuid(sections[0]); + + type(sections[1]); + ram(sections[2]); + state(sections[3]); + + if (sections.length > 4) + alias(sections[4]); + + return this; + } + + + public VM build() { + return new VM(host,uuid,type,ram,state,alias); + } + + public Builder fromVM(VM in) { + return host(in.getHost()) + .uuid(in.getUuid()) + .type(in.getType()) + .ram(in.getRam()) + .state(in.getState()) + .alias(in.getAlias()); + } + } + + + protected SmartOSHost host; + protected final UUID uuid; + protected String type; + protected String ram; + protected State state; + protected String alias; + + + public VM(SmartOSHost host, UUID uuid, String type, String ram, State state, String alias) { + this.host = host; + this.uuid = uuid; + this.type = type; + this.ram = ram; + this.state = state; + this.alias = alias; + } + + public State getState() { + return state; + } + + public void destroy() { + host.destroyHost(uuid); + } + + public void reboot() { + host.rebootHost(uuid); + } + + public void stop() { + host.stopHost(uuid); + } + + public void start() { + host.startHost(uuid); + } + + public Optional getPublicAddress() throws InterruptedException { + Map ipAddresses; + + for( int i=0; i<30; i++ ) + { + ipAddresses = host.getVMIpAddresses(uuid); + if( ipAddresses.isEmpty() ) + { + // Got some + String ip = ipAddresses.get("net0"); + if( ip != null && !ip.equals("0.0.0.0")) + return Optional.of(ip); + } + + Thread.sleep(1000); + } + + return Optional.absent(); + } + + public SmartOSHost getHost() { + return host; + } + + public UUID getUuid() { + return uuid; + } + + public String getType() { + return type; + } + + public String getRam() { + return ram; + } + + public String getAlias() { + return alias; + } + + /** + * {@inheritDoc} + */ + @Override + public int hashCode() { + // UUID is primary key + return uuid.hashCode(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + return uuid.equals(((DataSet)obj).getUuid()); + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Objects.toStringHelper(this).omitNullValues() + .add("uuid", uuid) + .add("type", type) + .add("ram", ram) + .add("alias", alias).toString(); + } +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmNIC.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmNIC.java new file mode 100644 index 0000000000..e8caa3a9bf --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmNIC.java @@ -0,0 +1,110 @@ +package org.jclouds.smartos.compute.domain; + +import com.google.common.base.Objects; +import com.google.gson.annotations.SerializedName; +import com.google.inject.name.Named; + +import java.util.UUID; + + +/** + * Specification of a network card. + */ +public class VmNIC { + + @SerializedName("nic_tag") + protected final String tag; + protected final String ip; + protected final String netmask; + protected final String gateway; + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromVmNIC(this); + } + + public static class Builder { + + public String tag = "admin"; + public String ip; + public String netmask; + public String gateway; + + + public Builder simpleDCHPNic() { + tag = "admin"; + ip = "dhcp"; + return this; + } + + public Builder tag(String tag) { + this.tag = tag; + return this; + } + + public Builder ip(String ip) { + this.ip = ip; + return this; + } + + public Builder netmask(String netmask) { + this.netmask = netmask; + return this; + } + + public Builder gateway(String gateway) { + this.gateway = gateway; + return this; + } + + public VmNIC build() { + return new VmNIC(tag,ip,netmask,gateway); + } + + public Builder fromVmNIC(VmNIC in) { + return tag ( in.getTag()) + .ip ( in.getIp() ) + .netmask( in.getNetmask() ) + .gateway( in.getGateway() ); + } + } + + + public VmNIC(String tag, String ip, String netmask, String gateway) { + this.tag = tag; + this.ip = ip; + this.netmask = netmask; + this.gateway = gateway; + } + + public String getTag() { + return tag; + } + + public String getIp() { + return ip; + } + + public String getNetmask() { + return netmask; + } + + public String getGateway() { + return gateway; + } + + /** + * {@inheritDoc} + */ + @Override + public String toString() { + return Objects.toStringHelper(this).omitNullValues() + .add("tag", tag) + .add("ip", ip) + .add("netmask", netmask) + .add("gateway", gateway).toString(); + } +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmSpecification.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmSpecification.java new file mode 100644 index 0000000000..e793816fc7 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/domain/VmSpecification.java @@ -0,0 +1,142 @@ +package org.jclouds.smartos.compute.domain; + + +import com.google.common.collect.ImmutableList; +import com.google.gson.*; +import com.google.gson.annotations.SerializedName; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * Specification of a VM to build, based on a dataset. + */ +public class VmSpecification { + protected final String alias; + protected final String brand; + + @SerializedName("dataset_uuid") + protected final DataSet dataset; + protected final String dnsDomain; + protected final String quota; + + protected final List nics; + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return builder().fromVmSpecification(this); + } + + public static class Builder { + + protected String alias; + protected String brand = "joyent"; + protected DataSet dataset; + protected String dnsDomain = "local"; + protected String quota = "10"; + + protected List nics = new ArrayList(); + + public Builder alias(String alias) { + this.alias = alias; + return this; + } + + public Builder brand(String brand) { + this.brand = brand; + return this; + } + + public Builder dataset(DataSet dataset) { + this.dataset = dataset; + return this; + } + + public Builder dnsDomain(String dnsDomain) { + this.dnsDomain = dnsDomain; + return this; + } + + public Builder quota(String quota) { + this.quota = quota; + return this; + } + + public Builder nics(Collection nic) { + this.nics.addAll(nics); + return this; + } + + public Builder nic(VmNIC nic) { + this.nics.add(nic); + return this; + } + + public VmSpecification build() { + return new VmSpecification(alias, brand, dataset, dnsDomain, quota, nics); + } + + public Builder fromVmSpecification(VmSpecification in) { + return alias (in.getAlias()) + .brand (in.getBrand()) + .dataset (in.getDataset()) + .dnsDomain(in.getDnsDomain()) + .quota (in.getQuota()) + .nics(in.getNics()); + } + } + + protected VmSpecification(String alias, String brand, DataSet dataset, String dnsDomain, String quota, List nics) { + this.alias = alias; + this.brand = brand; + this.dataset = dataset; + this.dnsDomain = dnsDomain; + this.quota = quota; + this.nics = nics; + } + + public String getAlias() { + return alias; + } + + public String getBrand() { + return brand; + } + + public DataSet getDataset() { + return dataset; + } + + public String getDnsDomain() { + return dnsDomain; + } + + public String getQuota() { + return quota; + } + + public List getNics() { + return ImmutableList.copyOf(nics); + } + + public String toJSONSpecification() { + GsonBuilder gson = new GsonBuilder(); + gson.registerTypeAdapter(DataSet.class, new FlattenDataset() ); + Gson g = gson.create(); + + return g.toJson(this); + } + + public class FlattenDataset implements JsonSerializer + { + @Override + public JsonElement serialize(DataSet vmSpecification, Type type, JsonSerializationContext jsonSerializationContext) { + return new JsonPrimitive(dataset.getUuid().toString()); + } + } +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DataSetToImage.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DataSetToImage.java new file mode 100644 index 0000000000..ee90c86d89 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DataSetToImage.java @@ -0,0 +1,63 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute.functions; + +import javax.annotation.Resource; +import javax.inject.Named; +import javax.inject.Singleton; + +import org.jclouds.smartos.compute.domain.DataSet; +import org.jclouds.compute.domain.Image; +import org.jclouds.compute.domain.ImageBuilder; +import org.jclouds.compute.domain.OperatingSystem; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.reference.ComputeServiceConstants; +import org.jclouds.logging.Logger; + +import com.google.common.base.Function; + +/** + * @author Nigel Magnay + */ +@Singleton +public class DataSetToImage implements Function { + @Resource + @Named(ComputeServiceConstants.COMPUTE_LOGGER) + protected Logger logger = Logger.NULL; + + @Override + public Image apply(DataSet from) { + + ImageBuilder builder = new ImageBuilder(); + builder.ids(from.getUuid() + ""); + builder.name(from.getUrn()); + builder.description(from.getUrn()); + builder.status(Image.Status.AVAILABLE); + + OsFamily family; + try { + family = OsFamily.SOLARIS; + builder.operatingSystem(new OperatingSystem.Builder().name(from.getUrn()).description(from.getUrn()).family(family).build()); + } catch (IllegalArgumentException e) { + logger.debug("<< didn't match os(%s)", from); + } + return builder.build(); + } + +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DatacenterToLocation.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DatacenterToLocation.java new file mode 100644 index 0000000000..ea0984c7f8 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/DatacenterToLocation.java @@ -0,0 +1,53 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute.functions; + +import com.google.common.base.Function; +import com.google.common.base.Supplier; +import org.jclouds.smartos.compute.domain.SmartOSHost; +import org.jclouds.domain.Location; +import org.jclouds.domain.LocationBuilder; +import org.jclouds.domain.LocationScope; + +import javax.inject.Inject; +import javax.inject.Provider; +import javax.inject.Singleton; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author Nigel Magnay + */ +@Singleton +public class DatacenterToLocation implements Function { + private final Provider> provider; + + // allow us to lazy discover the provider of a resource + @Inject + public DatacenterToLocation(Provider> provider) { + this.provider = checkNotNull(provider, "provider"); + } + + @Override + public Location apply(SmartOSHost from) { + return new LocationBuilder().scope(LocationScope.ZONE).id(from.getHostname() + "").description(from.getDescription()).parent( + provider.get().get()).build(); + } + +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VMToNodeMetadata.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VMToNodeMetadata.java new file mode 100644 index 0000000000..2780c2df1f --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VMToNodeMetadata.java @@ -0,0 +1,150 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute.functions; + +import com.google.common.base.Function; +import com.google.common.base.Optional; +import com.google.common.base.Supplier; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.sun.corba.se.spi.activation.Server; +import org.jclouds.smartos.compute.domain.VM; +import org.jclouds.collect.FindResourceInSet; +import org.jclouds.collect.Memoized; +import org.jclouds.compute.domain.*; +import org.jclouds.compute.functions.GroupNamingConvention; +import org.jclouds.domain.Credentials; +import org.jclouds.domain.Location; +import org.jclouds.domain.LoginCredentials; +import org.omg.PortableInterceptor.ACTIVE; + +import javax.inject.Inject; +import javax.inject.Singleton; +import java.io.IOException; +import java.util.Collection; +import java.util.Map; +import java.util.Set; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * @author Nigel Magnay + */ +@Singleton +public class VMToNodeMetadata implements Function { + + public static final Map serverStatusToNodeStatus = ImmutableMap + . builder() + .put(VM.State.RUNNING, NodeMetadata.Status.RUNNING)// + .put(VM.State.STOPPED, NodeMetadata.Status.SUSPENDED)// + .put(VM.State.INCOMPLETE, NodeMetadata.Status.PENDING)// + .build(); + + private final FindHardwareForServer findHardwareForServer; + private final FindLocationForServer findLocationForServer; + private final FindImageForServer findImageForServer; + private final Map credentialStore; + private final GroupNamingConvention nodeNamingConvention; + + @Inject + VMToNodeMetadata(Map credentialStore, FindHardwareForServer findHardwareForServer, + FindLocationForServer findLocationForServer, FindImageForServer findImageForServer, + GroupNamingConvention.Factory namingConvention) { + this.nodeNamingConvention = checkNotNull(namingConvention, "namingConvention").createWithoutPrefix(); + this.credentialStore = checkNotNull(credentialStore, "credentialStore"); + this.findHardwareForServer = checkNotNull(findHardwareForServer, "findHardwareForServer"); + this.findLocationForServer = checkNotNull(findLocationForServer, "findLocationForServer"); + this.findImageForServer = checkNotNull(findImageForServer, "findImageForServer"); + } + + @Override + public NodeMetadata apply(VM from) { + // convert the result object to a jclouds NodeMetadata + NodeMetadataBuilder builder = new NodeMetadataBuilder(); + builder.ids(from.getUuid() + ""); + builder.name(from.getAlias()); + builder.location(findLocationForServer.apply(from)); + builder.group(nodeNamingConvention.groupInUniqueNameOrNull(from.getType())); + builder.imageId(from.getType() + ""); + Image image = findImageForServer.apply(from); + if (image != null) + builder.operatingSystem(image.getOperatingSystem()); + builder.hardware(findHardwareForServer.apply(from)); + builder.status(serverStatusToNodeStatus.get(from.getState())); + try { + if( from.getState() == VM.State.RUNNING ) + { + Optional ip = from.getPublicAddress(); + if( ip.isPresent() ) { + builder.publicAddresses(ImmutableSet. of(ip.get())); + builder.privateAddresses(ImmutableSet. of(ip.get())); + } + } + } + catch(Exception ex) + { + // None? + } + //builder.privateAddresses(ImmutableSet. of(from.privateAddress)); + builder.credentials(LoginCredentials.fromCredentials(credentialStore.get(from.getUuid() + ""))); + return builder.build(); + } + + @Singleton + public static class FindHardwareForServer extends FindResourceInSet { + + @Inject + public FindHardwareForServer(@Memoized Supplier> hardware) { + super(hardware); + } + + @Override + public boolean matches(VM from, Hardware input) { + return input.getProviderId().equals(from.getUuid() + ""); + } + } + + @Singleton + public static class FindImageForServer extends FindResourceInSet { + + @Inject + public FindImageForServer(@Memoized Supplier> hardware) { + super(hardware); + } + + @Override + public boolean matches(VM from, Image input) { + return input.getProviderId().equals(from.getUuid() + ""); + } + } + + @Singleton + public static class FindLocationForServer extends FindResourceInSet { + + @Inject + public FindLocationForServer(@Memoized Supplier> hardware) { + super(hardware); + } + + @Override + public boolean matches(VM from, Location input) { + return input.getId().equals(from.getUuid() + ""); + } + } +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VmSpecificationToHardware.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VmSpecificationToHardware.java new file mode 100644 index 0000000000..e789367af1 --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/functions/VmSpecificationToHardware.java @@ -0,0 +1,48 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute.functions; + +import javax.inject.Singleton; + +import org.jclouds.smartos.compute.domain.VmSpecification; +import org.jclouds.compute.domain.Hardware; +import org.jclouds.compute.domain.HardwareBuilder; +import org.jclouds.compute.domain.Processor; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; + +/** + * @author Nigel Magnay + */ +@Singleton +public class VmSpecificationToHardware implements Function { + + @Override + public Hardware apply(VmSpecification from) { + HardwareBuilder builder = new HardwareBuilder(); + builder.ids("AnID"); + builder.name(from.getAlias()); + builder.processors(ImmutableList.of(new Processor(1, 1.0))); + builder.ram(256); + //builder.volumes(ImmutableList. of(new VolumeImpl(from.disk, true, false))); + return builder.build(); + } + +} diff --git a/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/strategy/SmartOSComputeServiceAdapter.java b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/strategy/SmartOSComputeServiceAdapter.java new file mode 100644 index 0000000000..094ad8cffe --- /dev/null +++ b/labs/smartos-ssh/src/main/java/org/jclouds/smartos/compute/strategy/SmartOSComputeServiceAdapter.java @@ -0,0 +1,128 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute.strategy; + +import static com.google.common.base.Preconditions.checkNotNull; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.jclouds.smartos.compute.domain.*; +import org.jclouds.compute.ComputeService; +import org.jclouds.compute.ComputeServiceAdapter; +import org.jclouds.compute.domain.Template; +import org.jclouds.domain.LoginCredentials; + +import com.google.common.collect.ImmutableSet; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * defines the connection between the {@link org.jclouds.smartos.compute.domain.SmartOSHost} implementation and the jclouds + * {@link ComputeService} + * + */ +@Singleton +public class SmartOSComputeServiceAdapter implements ComputeServiceAdapter { + private final SmartOSHost host; + + @Inject + public SmartOSComputeServiceAdapter(SmartOSHost host) { + this.host = checkNotNull(host, "host"); + } + + private SmartOSHost getHost() { + return host; + } + + @Override + public NodeAndInitialCredentials createNodeWithGroupEncodedIntoName(String tag, String name, Template template) { + VmSpecification specification = VmSpecification.builder() + .alias(name) + .dataset(getHost().getDataSet(UUID.fromString(template.getImage().getProviderId()))) + .nic(VmNIC.builder().simpleDCHPNic().build()) + .build(); + + VM from = getHost().createVM(specification); + + return new NodeAndInitialCredentials(from, from.getUuid() + "", LoginCredentials.builder().user("smartos") + .password("smartos").build()); + } + + @Override + public Iterable listHardwareProfiles() { + List specificationList = new ArrayList(); + + VmSpecification vs = VmSpecification.builder() + .alias("Standard Joyent VM") + .nic(VmNIC.builder().simpleDCHPNic().build()) + .build(); + + specificationList.add(vs); + + return specificationList; + } + + @Override + public Iterable listImages() { + return getHost().getLocalDatasets(); + } + + @Override + public DataSet getImage(String id) { + return getHost().getDataSet(UUID.fromString(id)); + } + + @Override + public Iterable listNodes() { + return getHost().getVMs(); + } + + @Override + public Iterable listLocations() { + return ImmutableSet.of(); + } + + @Override + public VM getNode(String id) { + return getHost().getVM(UUID.fromString(id)); + } + + @Override + public void destroyNode(String id) { + getHost().getVM(UUID.fromString(id)).destroy(); + } + + @Override + public void rebootNode(String id) { + getHost().getVM(UUID.fromString(id)).reboot(); + } + + @Override + public void resumeNode(String id) { + getHost().getVM(UUID.fromString(id)).start(); + } + + @Override + public void suspendNode(String id) { + getHost().getVM(UUID.fromString(id)).stop(); + } +} \ No newline at end of file diff --git a/labs/smartos-ssh/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata b/labs/smartos-ssh/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata new file mode 100644 index 0000000000..04d5659a80 --- /dev/null +++ b/labs/smartos-ssh/src/main/resources/META-INF/services/org.jclouds.apis.ApiMetadata @@ -0,0 +1 @@ +org.jclouds.smartos.SmartOSApiMetadata \ No newline at end of file diff --git a/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceContextBuilderTest.java b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceContextBuilderTest.java new file mode 100644 index 0000000000..fe91d429d6 --- /dev/null +++ b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceContextBuilderTest.java @@ -0,0 +1,88 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute; + +import static org.testng.Assert.assertEquals; + +import java.util.Properties; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Module; +import org.jclouds.ContextBuilder; +import org.jclouds.compute.ComputeServiceContext; +import org.jclouds.internal.ContextImpl; +import org.jclouds.rest.internal.BaseRestClientTest; +import org.jclouds.smartos.SmartOSApiMetadata; +import org.jclouds.sshj.config.SshjSshClientModule; +import org.testng.annotations.Test; + +/** + * + * @author Adrian Cole + * + */ +@Test(groups = "unit", testName = "ServerManagerContextBuilderTest") +public class SmartOSManagerComputeServiceContextBuilderTest { + + + @Test + public void testCanBuildWithApiMetadata() { + ComputeServiceContext context = ContextBuilder.newBuilder( + new SmartOSApiMetadata()) + .modules(ImmutableSet.of(getSshModule())) + .build(ComputeServiceContext.class); + context.close(); + } + + @Test + public void testCanBuildById() { + ComputeServiceContext context = ContextBuilder.newBuilder("smartos-ssh") + .modules(ImmutableSet.of(getSshModule())) + .build(ComputeServiceContext.class); + context.close(); + } + + @Test + public void testCanBuildWithOverridingProperties() { + Properties overrides = new Properties(); + overrides.setProperty("smartos-ssh.endpoint", "http://host"); + overrides.setProperty("smartos-ssh.api-version", "1"); + + ComputeServiceContext context = ContextBuilder.newBuilder("smartos-ssh") + .modules(ImmutableSet.of(getSshModule())) + .overrides(overrides).build(ComputeServiceContext.class); + + context.close(); + } + + @Test + public void testUnwrapIsCorrectType() { + ComputeServiceContext context = ContextBuilder.newBuilder("smartos-ssh") + .modules(ImmutableSet.of(getSshModule())) + .build(ComputeServiceContext.class); + + assertEquals(context.unwrap().getClass(), ContextImpl.class); + + context.close(); + } + + protected Module getSshModule() { + return new SshjSshClientModule(); + } +} diff --git a/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceLiveTest.java b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceLiveTest.java new file mode 100644 index 0000000000..df29de6968 --- /dev/null +++ b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/SmartOSManagerComputeServiceLiveTest.java @@ -0,0 +1,60 @@ +/** + * Licensed to jclouds, Inc. (jclouds) under one or more + * contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. jclouds licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.jclouds.smartos.compute; + +import static org.jclouds.compute.util.ComputeServiceUtils.getCores; +import static org.testng.Assert.assertEquals; + +import org.jclouds.compute.domain.NodeMetadata; +import org.jclouds.compute.domain.OsFamily; +import org.jclouds.compute.domain.Template; +import org.jclouds.compute.internal.BaseComputeServiceLiveTest; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +/** + * @author Adrian Cole + */ +@Test(groups = "live", enabled = true, singleThreaded = true) +public class SmartOSManagerComputeServiceLiveTest extends BaseComputeServiceLiveTest { + + public SmartOSManagerComputeServiceLiveTest() { + provider = "smartos-ssh"; + } + + @Test + public void testTemplateBuilder() { + Template defaultTemplate = client.templateBuilder().build(); + assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true); + assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "5.3"); + assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.CENTOS); + assertEquals(defaultTemplate.getLocation().getId(), "1"); + assertEquals(getCores(defaultTemplate.getHardware()), 0.5d); + } + + + // smartos-ssh does not support metadata + @Override + protected void checkUserMetadataInNodeEquals(NodeMetadata node, ImmutableMap userMetadata) { + assert node.getUserMetadata().equals(ImmutableMap. of()) : String.format( + "node userMetadata did not match %s %s", userMetadata, node); + } + +} diff --git a/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/DataSetTest.java b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/DataSetTest.java new file mode 100644 index 0000000000..a64e92ca5a --- /dev/null +++ b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/DataSetTest.java @@ -0,0 +1,36 @@ +package org.jclouds.smartos.compute.domain; + +import com.google.common.collect.ImmutableList; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.*; +import java.util.List; +import java.util.UUID; + +@Test(groups = "unit", testName = "DataSetTest") +public class DataSetTest { + + @Test + public void testParse() throws IOException { + // Response from console from a 'dsadm list' + InputStream is = getClass().getResourceAsStream("dsadm-list-response.txt"); + + BufferedReader r = new BufferedReader(new InputStreamReader(is)); + String line = r.readLine(); // skip line + ImmutableList.Builder resultBuilder = ImmutableList.builder(); + while ((line = r.readLine()) != null) { + DataSet ds = DataSet.builder().fromDsadmString(line).build(); + + resultBuilder.add(ds); + } + List dataSetList = resultBuilder.build(); + + Assert.assertEquals(10, dataSetList.size()); + + Assert.assertEquals(UUID.fromString("c0ffee88-883e-47cf-80d1-ad71cc872180"), dataSetList.get(0).getUuid()); + Assert.assertEquals("nrm:nrm:realtime-jenkins:1.7", dataSetList.get(0).getUrn()); + + + } +} diff --git a/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/VMTest.java b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/VMTest.java new file mode 100644 index 0000000000..3397c48b39 --- /dev/null +++ b/labs/smartos-ssh/src/test/java/org/jclouds/smartos/compute/domain/VMTest.java @@ -0,0 +1,38 @@ +package org.jclouds.smartos.compute.domain; + +import com.google.common.collect.ImmutableList; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.List; +import java.util.UUID; + +@Test(groups = "unit", testName = "VMTest") +public class VMTest { + + @Test + public void testParse() throws IOException { + // Response from console from a 'vmadm list -p' + InputStream is = getClass().getResourceAsStream("vmadm-list-response.txt"); + + BufferedReader r = new BufferedReader(new InputStreamReader(is)); + String line = null; + ImmutableList.Builder resultBuilder = ImmutableList.builder(); + while ((line = r.readLine()) != null) { + VM vm = VM.builder().fromVmadmString(line).build(); + + resultBuilder.add(vm); + } + List vmList = resultBuilder.build(); + + Assert.assertEquals(2, vmList.size()); + + Assert.assertEquals(UUID.fromString("60bd2ae5-4e4d-4952-88f9-1b850259d914"), vmList.get(0).getUuid()); + Assert.assertEquals(VM.State.STOPPED, vmList.get(0).getState()); + + } +} \ No newline at end of file diff --git a/labs/smartos-ssh/src/test/resources/log4j.xml b/labs/smartos-ssh/src/test/resources/log4j.xml new file mode 100644 index 0000000000..b14cdd75a3 --- /dev/null +++ b/labs/smartos-ssh/src/test/resources/log4j.xml @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/dsadm-list-response.txt b/labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/dsadm-list-response.txt new file mode 100644 index 0000000000..3f7cc7302a --- /dev/null +++ b/labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/dsadm-list-response.txt @@ -0,0 +1,11 @@ +UUID OS PUBLISHED URN +c0ffee88-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.7 +c0ffee99-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.7 +bb5aa3d2-cc19-11e1-99e7-a752418da63a smartos 2012-05-02 nrm:nrm:jenkins-slave:1.0 +c0ffee32-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.6.3 +467ca742-4873-11e1-80ea-37290b38d2eb smartos 2012-02-14 sdc:sdc:smartos64:1.5.3 +56108678-1183-11e1-83c3-ff3185a5b47f linux 2011-11-18 sdc:sdc:ubuntu10.04:0.1.0 +f9e4be48-9466-11e1-bc41-9f993f5dff36 smartos 2012-05-02 sdc:sdc:smartos64:1.6.3 +c0ffee64-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 nrm:nrm:realtime-jenkins:1.6 +a9380908-ea0e-11e0-aeee-4ba794c83c33 smartos 2011-09-28 sdc:sdc:percona:1.0.7 +c0ffee00-883e-47cf-80d1-ad71cc872180 smartos 2012-05-02 sdc:sdc:realtime-jenkins:1.6.3 diff --git a/labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/vmadm-list-response.txt b/labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/vmadm-list-response.txt new file mode 100644 index 0000000000..442d0d93ca --- /dev/null +++ b/labs/smartos-ssh/src/test/resources/org/jclouds/smartos/compute/domain/vmadm-list-response.txt @@ -0,0 +1,2 @@ +60bd2ae5-4e4d-4952-88f9-1b850259d914:OS:256:stopped: +a8799014-7680-481f-b7de-76b501dbd803:OS:256:running:instance1-3b5