Статьи

Clojure и CloudStack

[Статья изначально написана Себастьеном Гоасгуеном.]

CloStack — это клиент Clojure для Apache CloudStack. Clojure — это динамический язык программирования для виртуальной машины Java (JVM). Он скомпилирован непосредственно в байт-код JVM, но предлагает динамический и интерактивный характер интерпретируемого языка, такого как Python. Clojure является диалектом LISP и, как таковой, является в основном функциональным языком программирования.

Вы можете попробовать Clojure в своем браузере и ознакомиться с его циклом чтения eval (REPL). Чтобы начать, вы можете следовать руководству для не-LISP-программистов через этот веб-REPL.

Чтобы дать вам вкус к этому, вот как вы бы 2и 2:

user=> (+ 2 2)
4

И как бы вы определили функцию:

user=> (defn f [x y]
  #_=> (+ x y))
#'user/f
user=> (f 2 3)
5

Это должно дать вам вкус функционального программирования 🙂

Установить Leinigen

leiningen — это инструмент для простого управления проектами Clojure. С leinего помощью вы можете создать каркас проекта clojure, а также запустить цикл чтения eval (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

Чтобы установить 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 будут загружены все зависимости 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, которые вы можете сделать, откройте вкладку «Функции REPL». Введите listили deи нажмите клавишу табуляции, которую вы должны увидеть:

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-vpns             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-vpn-connections                
list-vpn-customer-gateways          list-vpn-gateways                   list-vpn-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-vpn      delete-security-group         
delete-snapshot               delete-snapshot-policies      delete-ssh-key-pair           delete-static-route           delete-tags                   
delete-template               delete-volume                 delete-vpc                    delete-vpn-connection         delete-vpn-customer-gateway   
delete-vpn-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также известный как идентификатор изображения и 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"}}

И , наконец , уничтожить виртуальную машину вы бы передать 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в своем собственном проекте clojure

Привет, мир в ближайшем будущем

Чтобы написать свой собственный проект clojure, который делает пользователя clostack, используйте leiningenдля создания скелета проекта

lein new toto

Leinавтоматически создаст src/toto/core.cljфайл, отредактируйте его, чтобы заменить функцию fooна -main. Эта фиктивная функция возвращает Hellow World !. Давайте попробуем выполнить это. Сначала нам нужно определить mainпространство имен в project.cljфайле. Отредактируйте это так:

defproject toto «0.1.0-SNAPSHOT»: описание «FIXME: написать описание»: url «http://example.com/FIXME»: license {: name «Eclipse Public License»: url «http: //www.eclipse .org / legal / epl-v10.html «}: main toto.core: зависимости [[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.

Добавление зависимости Clostack

Отредактируйте, 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)
)

Просто запустите этот код clojure lein run joeв исходном коде вашего проекта. И все, вы успешно открыли основы Clojure и использовали клиент CloudStack clostackдля написания своего первого кода Clojure. Теперь для чего-то более значительного, посмотрите на поддон