[原文由Sebastien Goasguen撰写]
CloStack是Apache CloudStack的Clojure客户端。Clojure是一种执行于Java虚拟机(JVM)上的动态编程语言。它直接编译成JVM字节码,但仍具有像Python这样的解释型语言的动态和交互性。Clojure是LISP的一种变体,因此基本上可以看作一种函数式编程语言。
您可以在浏览器中尝试使用Clojure,并熟悉它的交互式解释器(REPL)。您可以通过这个基于Web的REPL来跟随这个针对无LISP编程经验者编写的教程。
您可以通过一个计算2+2的例子来直观感受一下:
user =>(+ 2 2)
4
再看一个定义函数的例子:
user=> (defn f [x y]
#_=> (+ x y))
#'user/f
user=> (f 2 3)
5
现在您应该大概了解函数式编程是怎么样的了 :)
Leiningen是一个帮助你轻松管理Clojure项目的工具。你可以使用lein
来创建Clojure项目的骨架,或者启动交互式解释器(REPL)来对代码进行测试。
安装Leiningen的最新版本很简单,下载此脚本并将其设置在您的系统执行路径中。使其可执行即可。
第一次运行lein repl
时它将会自我引导:
$ lein repl
Downloading Leiningen to /Users/sebgoa/.lein/self-installs/leiningen-2.3.4-standalone.jar now...
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 13.0M 100 13.0M 0 0 1574k 0 0:00:08 0:00:08 --:--:-- 2266k
nREPL server started on port 58633 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> exit
Bye for now!
要安装CloStack,请克隆这个github代码库并运行lein repl
:
git clone https://github.com/pyr/clostack.git
$ lein repl
Retrieving codox/codox/0.6.4/codox-0.6.4.pom from clojars
Retrieving codox/codox.leiningen/0.6.4/codox.leiningen-0.6.4.pom from clojars
Retrieving leinjacker/leinjacker/0.4.1/leinjacker-0.4.1.pom from clojars
Retrieving org/clojure/core.contracts/0.0.1/core.contracts-0.0.1.pom from central
Retrieving org/clojure/core.unify/0.5.3/core.unify-0.5.3.pom from central
Retrieving org/clojure/clojure/1.4.0/clojure-1.4.0.pom from central
Retrieving org/clojure/core.contracts/0.0.1/core.contracts-0.0.1.jar from central
Retrieving org/clojure/core.unify/0.5.3/core.unify-0.5.3.jar from central
Retrieving org/clojure/clojure/1.4.0/clojure-1.4.0.jar from central
Retrieving codox/codox/0.6.4/codox-0.6.4.jar from clojars
Retrieving codox/codox.leiningen/0.6.4/codox.leiningen-0.6.4.jar from clojars
Retrieving leinjacker/leinjacker/0.4.1/leinjacker-0.4.1.jar from clojars
Retrieving org/clojure/clojure/1.3.0/clojure-1.3.0.pom from central
Retrieving org/clojure/data.json/0.2.2/data.json-0.2.2.pom from central
Retrieving http/async/client/http.async.client/0.5.2/http.async.client-0.5.2.pom from clojars
Retrieving com/ning/async-http-client/1.7.10/async-http-client-1.7.10.pom from central
Retrieving io/netty/netty/3.4.4.Final/netty-3.4.4.Final.pom from central
Retrieving org/clojure/data.json/0.2.2/data.json-0.2.2.jar from central
Retrieving com/ning/async-http-client/1.7.10/async-http-client-1.7.10.jar from central
Retrieving io/netty/netty/3.4.4.Final/netty-3.4.4.Final.jar from central
Retrieving http/async/client/http.async.client/0.5.2/http.async.client-0.5.2.jar from clojars
nREPL server started on port 58655 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> exit
第一次启动REPL时,lein会下载所有clostack
的依赖库。
clostack
导出一些环境变量来定义您将要使用的云,即:
export CLOUDSTACK_ENDPOINT=http://localhost:8080/client/api
export CLOUDSTACK_API_KEY=HGWEFHWERH8978yg98ysdfghsdfgsagf
export CLOUDSTACK_API_SECRET=fhdsfhdf869guh3guwghseruig
然后重新启动REPL:
$lein repl
nREPL server started on port 59890 on host 127.0.0.1
REPL-y 0.3.0
Clojure 1.5.1
Docs: (doc function-name-here)
(find-doc "part-of-name-here")
Source: (source function-name-here)
Javadoc: (javadoc java-object-or-class-here)
Exit: Control+D or (exit) or (quit)
Results: Stored in vars *1, *2, *3, an exception in *e
user=> (use 'clostack.client)
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
nil
会有警告消息显示“clostack应被用作clojure项目中的库“。您可以放心地忽略它。 为您的CloudStack端点定义一个客户端:
user=> (def cs (http-client))
#'user/cs
并像这样调用一个应用程序接口(API):
user=> (list-zones cs)
{:listzonesresponse {:count 1, :zone [{:id "1128bd56-b4d9-4ac6-a7b9-c715b187ce11", :name "CH-GV2", :networktype "Basic", :securitygroupsenabled true, :allocationstate "Enabled", :zonetoken "ccb0a60c-79c8-3230-ab8b-8bdbe8c45bb7", :dhcpprovider "VirtualRouter", :localstorageenabled true}]}}
要知道您可以进行哪些API调用,可以使用Tab键。REPL支持自动补全。例如,输入list
或de
,然后按Tab键,您将看到:
user=> (list
list list* list-accounts list-async-jobs
list-capabilities list-disk-offerings list-event-types list-events
list-firewall-rules list-hypervisors list-instance-groups list-ip-forwarding-rules
list-iso-permissions list-isos list-lb-stickiness-policies list-load-balancer-rule-instances
list-load-balancer-rules list-network-ac-ls list-network-offerings list-networks
list-os-categories list-os-types list-port-forwarding-rules list-private-gateways
list-project-accounts list-project-invitations list-projects list-public-ip-addresses
list-remote-access-V**s list-resource-limits list-security-groups list-service-offerings
list-snapshot-policies list-snapshots list-ssh-key-pairs list-static-routes
list-tags list-template-permissions list-templates list-virtual-machines
list-volumes list-vp-cs list-vpc-offerings list-V**-connections
list-V**-customer-gateways list-V**-gateways list-V**-users list-zones
list?
user=> (de
dec dec' decimal? declare def
default-data-readers definline definterface defmacro defmethod
defmulti defn defn- defonce defprotocol
defrecord defreq defstruct deftype delay
delay? delete-account-from-project delete-firewall-rule delete-instance-group delete-ip-forwarding-rule
delete-iso delete-lb-stickiness-policy delete-load-balancer-rule delete-network delete-network-acl
delete-port-forwarding-rule delete-project delete-project-invitation delete-remote-access-V** delete-security-group
delete-snapshot delete-snapshot-policies delete-ssh-key-pair delete-static-route delete-tags
delete-template delete-volume delete-vpc delete-V**-connection delete-V**-customer-gateway
delete-V**-gateway deliver denominator deploy-virtual-machine deref
derive descendants destroy-virtual-machine destructure detach-iso
detach-volume
使用以下语法来将参数传递给函数:
user =>(list-templates cs:templatefilter“executable”)
要部署虚拟机,您需要获得serviceofferingid
或实例类型、templateid
或称图像ID,以及zoneid
。函数调用方式与CloudMonkey非常相似,并返回jobid
。
user=> (deploy-virtual-machine cs :serviceofferingid "71004023-bb72-4a97-b1e9-bc66dfce9470" :templateid "1d961c82-7c8c-4b84-b61b-601876dab8d0" :zoneid "1128bd56-b4d9-4ac6-a7b9-c715b187ce11")
{:deployvirtualmachineresponse {:id "d0a887d2-e20b-4b25-98b3-c2995e4e428a", :jobid "21d20b5c-ea6e-4881-b0b2-0c2f9f1fb6be"}}
您可以将其他参数传递给deploy-virtual-machine
调用,例如keypair
和securitygroupname
:
user=> (deploy-virtual-machine cs :serviceofferingid "71004023-bb72-4a97-b1e9-bc66dfce9470" :templateid "1d961c82-7c8c-4b84-b61b-601876dab8d0" :zoneid "1128bd56-b4d9-4ac6-a7b9-c715b187ce11" :keypair "exoscale")
{:deployvirtualmachineresponse {:id "b5fdc41f-e151-43e7-a036-4d87b8536408", :jobid "418026fc-1009-4e7a-9721-7c9ad47b49e4"}}
要查询异步作业,可以使用query-async-job
api调用:
user=> (query-async-job-result cs :jobid "418026fc-1009-4e7a-9721-7c9ad47b49e4")
{:queryasyncjobresultresponse {:jobid "418026fc-1009-4e7a-9721-7c9ad47b49e4", :jobprocstatus 0, :jobinstancetype "VirtualMachine", :accountid "b8c0baab-18a1-44c0-ab67-e24049212925", :jobinstanceid "b5fdc41f-e151-43e7-a036-4d87b8536408", :created "2013-12-16T12:25:21+0100", :jobstatus 0, :jobresultcode 0, :cmd "com.cloud.api.commands.DeployVMCmd", :userid "968f6b4e-b382-4802-afea-dd731d4cf9b9"}}
最后,要销毁虚拟机,您可以将虚拟机(VM)的id
传递给destroy-virtual-machine
,如下所示:
user=> (destroy-virtual-machine cs :id "d0a887d2-e20b-4b25-98b3-c2995e4e428a")
{:destroyvirtualmachineresponse {:jobid "8fc8a8cf-9b54-435c-945d-e3ea2f183935"}}
有了这些简单的基础知识,您就可以继续探索clostack
和CloudStack API了。
CloStack
使用 leiningen来
创建一个项目骨架,以此来开发您的使用了Clostack的Clojure项目。
lein new toto
Lein
会自动创建一个src/toto/core.clj
文件。编辑它,把foo
替换为-main
。这个极为简单的函数将返回Hello World !
。我们尝试执行它。首先我们需要main
在project.clj
文件中定义命名空间。把它编辑成这样:
defproject toto“0.1.0-SNAPSHOT”:description“FIXME:write description”:url“http://example.com/FIXME”:license {:name“Eclipse Public License”:url“http://www.eclipse .org / legal / epl-v10.html“}:main toto.core:dependencies [[org.clojure / clojure”1.5.1“]])
注意 :main toto.core
你现在可以执行代码lein run john
。事实上,如果你检查-main
函数,src/toto/core.clj
,你会看到它需要一个参数。你应该能够惊奇地看到以下输出:
$ lein run john
john Hello, World!
现在添加CloStack依赖库并修改main
函数以返回CloudStack云的区域。
编辑project.clj
,添加一个clostack
的依赖项和一些日志包:
:dependencies [[org.clojure/clojure "1.5.1"]
[clostack "0.1.3"]
[org.clojure/tools.logging "0.2.6"]
[org.slf4j/slf4j-log4j12 "1.6.4"]
[log4j/apache-log4j-extras "1.0"]
[log4j/log4j "1.2.16"
:exclusions [javax.mail/mail
javax.jms/jms
com.sun.jdkmk/jmxtools
com.sun.jmx/jmxri]]])
lein
应该已经创建了一个resources
目录。在此目录下,创建一个如下所示的log4j.properties
文件:
$ more log4j.properties
# Root logger option
log4j.rootLogger=INFO, stdout
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
关于日志记录的讨论超出了本教程的范围。我们增加此项,只是出于这个例子的完整性的考虑。
现在,您可以编辑src/toto/core.clj
,并且加入一些基本的调用。
(ns testclostack.core
(:require [clostack.client :refer [http-client list-zones]]))
(defn foo
"I don't do a whole lot."
[x]
(println x "Hello, World!"))
(def cs (http-client))
(defn -main [args]
(println (list-zones cs))
(println args "Hey Wassup")
(foo args)
)
只需lein run joe
在项目的源代码中运行这个clojure代码即可。至此,您已经成功了解了Clojure的基础知识,并使用CloudStack客户端clostack
编写了您的第一段Clojure代码。现在,来了解一下更重要的Pallet吧。