Issue 312: introductory support for clojure native compute provider

This commit is contained in:
Adrian Cole 2010-10-17 19:35:07 -07:00
parent 49b88183d2
commit 176f528572
5 changed files with 369 additions and 3 deletions

View File

@ -0,0 +1,121 @@
;
;
; Copyright (C) 2010 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.
; ====================================================================
;
(ns org.jclouds.modules
(:require
[clojure.contrib.logging :as logging])
(:import
[org.jclouds.ssh SshClient ExecResponse]
com.google.inject.Module
org.jclouds.net.IPSocket
[org.jclouds.compute ComputeService ComputeServiceContextFactory]
java.util.Set
[org.jclouds.compute.domain NodeMetadata Template]
[com.google.common.base Supplier Predicate]
[org.jclouds.compute.strategy AddNodeWithTagStrategy DestroyNodeStrategy RebootNodeStrategy GetNodeMetadataStrategy ListNodesStrategy]
org.jclouds.compute.domain.NodeMetadataBuilder))
(defn compute-module
[]
(.. (org.jclouds.compute.config.StandaloneComputeServiceContextModule$Builder.)
(defineAddNodeWithTagStrategy (defrecord ClojureAddNodeWithTagStrategy []
AddNodeWithTagStrategy
(^NodeMetadata execute [this ^String tag ^String name ^Template template]
())))
(defineDestroyNodeStrategy (defrecord ClojureDestroyNodeStrategy []
DestroyNodeStrategy
(^NodeMetadata execute [this ^String id]
())))
(defineRebootNodeStrategy (defrecord ClojureRebootNodeStrategy []
RebootNodeStrategy
(^NodeMetadata execute [this ^String id]
())))
(defineGetNodeMetadataStrategy (defrecord ClojureGetNodeMetadataStrategy []
GetNodeMetadataStrategy
(^NodeMetadata execute [this ^String id]
())))
(defineListNodesStrategy (defrecord ClojureListNodesStrategy []
ListNodesStrategy
(^Iterable list [this ]
())
(^Iterable listDetailsOnNodesMatching [this ^Predicate filter]
())
))
;; this needs to return Set<Hardware>
(defineHardwareSupplier
(defrecord HardwareSupplier []
Supplier
(get [this]
())
))
;; this needs to return Set<Image>
(defineImageSupplier (defrecord ImageSupplier []
Supplier
( get [this]
())
))
;; this needs to return Set<Location>
(defineLocationSupplier (defrecord LocationSupplier []
Supplier
( get [this]
())
))
(build)
))
(defn compute-context [module]
(ComputeServiceContextFactory/createStandaloneContext module))
(defrecord NodeListComputeService
[node-list]
org.jclouds.compute.ComputeService
(listNodes [_] node-list)
(getNodeMetadata
[_ id]
(some #(= (.getId %) id) node-list))
(listNodesDetailsMatching
[_ predicate]
(filter #(.apply predicate %) node-list)))
(defn ssh-client-factory
"Pass in a function that reifies org.jclouds.ssh.SshClient"
[ctor]
(reify
org.jclouds.ssh.SshClient$Factory
(^org.jclouds.ssh.SshClient create
[_ ^IPSocket socket ^String username ^String password-or-key]
(ctor socket username password-or-key))
(^org.jclouds.ssh.SshClient create
[_ ^IPSocket socket ^String username ^bytes password-or-key]
(ctor socket username password-or-key))))
(defn ssh-module
"Create a module that specifies the factory for creating an ssh service"
[^org.jclouds.ssh.SshClient$Factory factory]
(let [binder (atom nil)]
(reify
com.google.inject.Module
(configure
[this abinder]
(reset! binder abinder)
(.. @binder (bind org.jclouds.ssh.SshClient$Factory)
(toInstance factory))))))

View File

@ -19,12 +19,25 @@
package org.jclouds.compute.config; package org.jclouds.compute.config;
import java.util.Set;
import org.jclouds.compute.ComputeService; import org.jclouds.compute.ComputeService;
import org.jclouds.compute.ComputeServiceContext; import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.internal.ComputeServiceContextImpl; import org.jclouds.compute.internal.ComputeServiceContextImpl;
import org.jclouds.compute.strategy.AddNodeWithTagStrategy;
import org.jclouds.compute.strategy.DestroyNodeStrategy;
import org.jclouds.compute.strategy.GetNodeMetadataStrategy;
import org.jclouds.compute.strategy.ListNodesStrategy;
import org.jclouds.compute.strategy.RebootNodeStrategy;
import com.google.common.base.Supplier;
import com.google.common.collect.Sets;
import com.google.inject.Module;
import com.google.inject.Scopes; import com.google.inject.Scopes;
import com.google.inject.TypeLiteral; import com.google.inject.TypeLiteral;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
@ -37,4 +50,107 @@ public abstract class StandaloneComputeServiceContextModule extends BaseComputeS
}).to(new TypeLiteral<ComputeServiceContextImpl<ComputeService, ComputeService>>() { }).to(new TypeLiteral<ComputeServiceContextImpl<ComputeService, ComputeService>>() {
}).in(Scopes.SINGLETON); }).in(Scopes.SINGLETON);
} }
public static Builder builder() {
return new Builder();
}
public static class Builder {
private Set<Module> modules = Sets.newLinkedHashSet();
private Class<? extends AddNodeWithTagStrategy> addNodeWithTagStrategy;
private Class<? extends DestroyNodeStrategy> destroyNodeStrategy;
private Class<? extends GetNodeMetadataStrategy> getNodeMetadataStrategy;
private Class<? extends ListNodesStrategy> listNodesStrategy;
private Class<? extends RebootNodeStrategy> rebootNodeStrategy;
private Class<? extends Supplier<Set<? extends Hardware>>> hardwareSupplier;
private Class<? extends Supplier<Set<? extends Image>>> imageSupplier;
public Builder install(Module module) {
this.modules.add(module);
return this;
}
public Builder defineAddNodeWithTagStrategy(Class<? extends AddNodeWithTagStrategy> addNodeWithTagStrategy) {
this.addNodeWithTagStrategy = addNodeWithTagStrategy;
return this;
}
public Builder defineDestroyNodeStrategy(Class<? extends DestroyNodeStrategy> destroyNodeStrategy) {
this.destroyNodeStrategy = destroyNodeStrategy;
return this;
}
public Builder defineGetNodeMetadataStrategy(Class<? extends GetNodeMetadataStrategy> getNodeMetadataStrategy) {
this.getNodeMetadataStrategy = getNodeMetadataStrategy;
return this;
}
public Builder defineListNodesStrategy(Class<? extends ListNodesStrategy> listNodesStrategy) {
this.listNodesStrategy = listNodesStrategy;
return this;
}
public Builder defineRebootNodeStrategy(Class<? extends RebootNodeStrategy> rebootNodeStrategy) {
this.rebootNodeStrategy = rebootNodeStrategy;
return this;
}
public Builder defineHardwareSupplier(Class<? extends Supplier<Set<? extends Hardware>>> hardwareSupplier) {
this.hardwareSupplier = hardwareSupplier;
return this;
}
public Builder defineImageSupplier(Class<? extends Supplier<Set<? extends Image>>> imageSupplier) {
this.imageSupplier = imageSupplier;
return this;
}
public StandaloneComputeServiceContextModule build() {
return new StandaloneComputeServiceContextModule() {
@Override
protected Class<? extends AddNodeWithTagStrategy> defineAddNodeWithTagStrategy() {
return addNodeWithTagStrategy;
}
@Override
protected Class<? extends DestroyNodeStrategy> defineDestroyNodeStrategy() {
return destroyNodeStrategy;
}
@Override
protected Class<? extends GetNodeMetadataStrategy> defineGetNodeMetadataStrategy() {
return getNodeMetadataStrategy;
}
@Override
protected Class<? extends Supplier<Set<? extends Hardware>>> defineHardwareSupplier() {
return hardwareSupplier;
}
@Override
protected Class<? extends Supplier<Set<? extends Image>>> defineImageSupplier() {
return imageSupplier;
}
@Override
protected Class<? extends ListNodesStrategy> defineListNodesStrategy() {
return listNodesStrategy;
}
@Override
protected Class<? extends RebootNodeStrategy> defineRebootNodeStrategy() {
return rebootNodeStrategy;
}
@Override
protected void configure() {
for (Module module : modules)
install(module);
super.configure();
}
};
}
}
} }

View File

@ -313,7 +313,7 @@ public class StubComputeServiceDependenciesModule extends AbstractModule {
} }
@Singleton @Singleton
static class StubImageSupplier implements Supplier<Set<? extends Image>> { public static class StubImageSupplier implements Supplier<Set<? extends Image>> {
private final Supplier<Location> defaultLocation; private final Supplier<Location> defaultLocation;
@Inject @Inject
@ -359,7 +359,7 @@ public class StubComputeServiceDependenciesModule extends AbstractModule {
} }
@Singleton @Singleton
static class StubHardwareSupplier implements Supplier<Set<? extends Hardware>> { public static class StubHardwareSupplier implements Supplier<Set<? extends Hardware>> {
static Hardware stub(String type, int cores, int ram, float disk) { static Hardware stub(String type, int cores, int ram, float disk) {
return new org.jclouds.compute.domain.HardwareBuilder().id(type).providerId(type).name(type).processors( return new org.jclouds.compute.domain.HardwareBuilder().id(type).providerId(type).name(type).processors(

View File

@ -0,0 +1,107 @@
;
;
; Copyright (C) 2010 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.
; ====================================================================
;
(ns org.jclouds.ssh-test
(:require
[clojure.contrib.logging :as logging]
[org.jclouds.modules :as modules])
(:import
[org.jclouds.ssh SshClient ExecResponse]
org.jclouds.io.Payload
org.jclouds.net.IPSocket))
(defn instantiate [impl-class & args]
(let [constructor (first
(filter
(fn [c] (= (count args) (count (.getParameterTypes c))))
(.getDeclaredConstructors impl-class)))]
(.newInstance impl-class (object-array args))))
;; define an instance or implementation of the following interfaces:
(defn maybe-invoke [f & args]
(when f
(apply f args)))
(defn default-exec
"Default exec function - replies to ./runscript status by returning 1"
[cmd]
(merge
{:exit 0 :err "stderr" :out "stdout"}
(condp = cmd
"./bootstrap status" {:exit 1 :out "[]"}
{})))
(deftype NoOpClient
[socket username password]
SshClient
(connect [this])
(disconnect [this])
(exec [this cmd]
(logging/info (format "ssh cmd: %s" cmd))
(let [response (default-exec cmd)]
(ExecResponse. (:out response) (:err response) (:exit response))))
(get [this path] )
(^void put [this ^String path ^String content])
(^void put [this ^String path ^org.jclouds.io.Payload content])
(getUsername [this] username)
(getHostAddress [this] (.getAddress socket)) )
(defn no-op-ssh-client
[socket username password]
(NoOpClient. socket username password))
(deftype SshClientFactory
[factory-fn]
org.jclouds.ssh.SshClient$Factory
(^org.jclouds.ssh.SshClient
create
[_ ^IPSocket socket ^String username ^String password-or-key]
(factory-fn socket username password-or-key))
(^org.jclouds.ssh.SshClient
create
[_ ^IPSocket socket ^String username ^bytes password-or-key]
(factory-fn socket username password-or-key)))
(deftype Module
[factory binder]
com.google.inject.Module
(configure
[this abinder]
(reset! binder abinder)
(.. @binder (bind org.jclouds.ssh.SshClient$Factory)
(toInstance factory))))
(defn ssh-test-module
"Create a module that specifies the factory for creating a test service"
[factory]
(let [binder (atom nil)]
(Module. factory binder)))
(defn ssh-test-client
"Create a module that can be passed to a compute-context, and which implements
an ssh client with the provided map of function implementations. Keys are
clojurefied versions of org.jclouds.ssh.SshClient's methods"
[factory-fn]
(ssh-test-module (SshClientFactory. factory-fn)))

View File

@ -19,7 +19,16 @@
package org.jclouds.compute; package org.jclouds.compute;
import org.jclouds.compute.config.StandaloneComputeServiceContextModule;
import org.jclouds.compute.stub.config.StubComputeServiceContextModule; import org.jclouds.compute.stub.config.StubComputeServiceContextModule;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule.StubAddNodeWithTagStrategy;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule.StubDestroyNodeStrategy;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule.StubGetNodeMetadataStrategy;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule.StubHardwareSupplier;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule.StubImageSupplier;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule.StubListNodesStrategy;
import org.jclouds.compute.stub.config.StubComputeServiceDependenciesModule.StubRebootNodeStrategy;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -32,8 +41,21 @@ public class ComputeServiceContextFactoryTest {
@Test @Test
public void testStandalone() { public void testStandalone() {
ComputeServiceContext context = ComputeServiceContextFactory.createStandaloneContext(new StubComputeServiceContextModule()); ComputeServiceContext context = ComputeServiceContextFactory
.createStandaloneContext(new StubComputeServiceContextModule());
context.getComputeService().listNodes(); context.getComputeService().listNodes();
} }
@Test
public void testStandaloneWithBuilder() {
ComputeServiceContext context = ComputeServiceContextFactory
.createStandaloneContext(StandaloneComputeServiceContextModule.builder().install(
new StubComputeServiceDependenciesModule()).defineAddNodeWithTagStrategy(
StubAddNodeWithTagStrategy.class).defineDestroyNodeStrategy(StubDestroyNodeStrategy.class)
.defineGetNodeMetadataStrategy(StubGetNodeMetadataStrategy.class).defineListNodesStrategy(
StubListNodesStrategy.class).defineRebootNodeStrategy(StubRebootNodeStrategy.class)
.defineHardwareSupplier(StubHardwareSupplier.class)
.defineImageSupplier(StubImageSupplier.class).build());
context.getComputeService().listNodes();
}
} }