CloudStack 作為一個功能強大的雲端平台,提供豐富的 API 供開發者使用。本文將介紹如何運用 Clojure、Ruby 和 EC2Stack 等工具與 CloudStack API 互動,實作自動化管理和資源調配。首先,我們會使用 Clojure 的 Leiningen 建立專案,並透過 CloStack 函式庫操作 CloudStack。接著,我們將示範如何使用 Ruby 的 StackerBee gem 與 CloudStack API 互動,簡化 Ruby 開發者的操作流程。最後,我們將介紹 EC2Stack,它能將 CloudStack 介面轉換成 AWS EC2 相容的介面,讓熟悉 AWS 生態的開發者也能輕鬆上手 CloudStack。

透過 Clojure 的 Leiningen,我們可以輕鬆管理 Clojure 專案及其相依性。CloStack 提供了便捷的函式,讓我們可以直接在 Clojure 環境中與 CloudStack API 互動。例如,使用 list-zones 可以列出可用的區域,deploy-virtual-machine 可以佈署虛擬機器,而 query-async-job-result 則可以查詢非同步任務的狀態。對於 Ruby 開發者,StackerBee 提供了友善的 Ruby 介面,簡化了與 CloudStack API 的互動。透過簡單的指令安裝 StackerBee gem 後,即可使用 Ruby 指令碼操作 CloudStack 資源,例如列出虛擬機器、SSH 金鑰對等。EC2Stack 則是一個以 Python 開發的工具,它能將 CloudStack 介面轉換成 AWS EC2 相容的介面,讓習慣使用 AWS CLI 或 Boto 等工具的開發者,也能無縫地操作 CloudStack。


### Leiningen:Clojure 專案的得力助手

Leiningen 是一款便捷的 Clojure 專案管理工具。透過 Leiningen,你能夠輕鬆建立 Clojure 專案的骨架,並啟動 REPL (Read-Eval-Print Loop) 環境來測試程式碼。

安裝 Leiningen 最新版本非常簡單:下載指令碼,使其可執行,並將其新增到你的路徑中即可。

第一次執行 `lein repl` 時,Leiningen 會自動進行初始化:

```bash
$ 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!

現在你已經擁有自己的 Clojure REPL,可以開始體驗一下。以下是如何計算 2 加 2 的方法:

user=> (+ 2 2)
4

以及如何定義一個函式:

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

這應該能讓你初步體驗函式式程式設計的魅力。

CloStack 初體驗:Clojure 的 CloudStack 客戶端

接著讓我們開始使用 CloStack。與之前安裝其他套件一樣,先克隆 GitHub 倉函式庫,然後啟動 lein repl

$ git clone https://github.com/pyr/clostack.git
$ cd clostack
$ lein repl

第一次啟動 REPL 時,lein 會下載所有 clostack 的依賴項。

為了進行你的第一次 clostack 呼叫,需要匯出一些環境變數來定義你的雲端端點和 API 金鑰:

$ export CLOUDSTACK_ENDPOINT=http://localhost:8080/client/api
$ export CLOUDSTACK_API_KEY=HGWEFHWERH8978yg98ysdfghsdfgsagf
$ export CLOUDSTACK_API_SECRET=fhdsfhdf869guh3guwghseruig

然後重新啟動 REPL 並匯入 clostack 客戶端:

$ 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
user=> (def cs (http-client))
#'user/cs

你可以放心地忽略警告訊息,它僅表示 clostack 旨在作為 Clojure 專案中的一個函式庫使用。定義一個到你的 CloudStack 端點的客戶端,並進行你的第一次 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",
:dhcpprovider "VirtualRouter",
:localstorageenabled true}]}}

為了探索你可以進行的 API 呼叫,REPL 具有 Tab 鍵自動完成功能(就像 CloudMonkey 和 libcloud IPython shell 一樣)。輸入 listde 並按下 Tab 鍵。你應該會看到以下內容:

user=> (list
list list*
list-capabilities list-disk-offerings
list-firewall-rules list-hypervisors
list-iso-permissions list-isos
list-load-balancer-rules list-network-ac-ls
list-os-categories list-os-types
list-project-accounts list-project-invitations
list-remote-access-vpns list-resource-limits
list-snapshot-policies list-snapshots
list-tags list-template-permissions
list-volumes list-vp-cs
list-vpn-customer-gateways list-vpn-gateway
list?
user=> (de
dec dec'
default-data-readers definline
defmulti defn
defrecord defreq
delay? delete-account-from-project
delete-iso delete-lb-stickiness-policy
delete-port-forwarding-rule delete-project
delete-snapshot delete-snapshot-policies
delete-template delete-volume
delete-vpn-gateway deliver
derive descendants
detach-volume

要將引數傳遞給呼叫,請遵循以下語法:

user=> (list-templates cs :templatefilter "executable")

到目前為止,這應該看起來非常熟悉,但 Clojure 的函式式程式設計方面一開始可能會讓你感到困惑。堅持下去!

使用 CloStack 啟動虛擬機器:問題與解決

接下來,我們將探討如何使用 CloStack 在雲端中啟動虛擬機器。


```text

### 利用 CloStack 佈署虛擬機器:一步步

在雲端環境中,佈署虛擬機器是驗證雲端服務是否正常運作的基礎。透過 CloStack,我們可以輕鬆完成這個任務。

**解決方案**

首先,你需要取得區域(zone)、範本(template)和服務方案(service offering)的 UUID。接著,呼叫 `deploy-virtual-machine` 函式。這個操作是非同步的,你可以使用 `query-async-job` 函式查詢任務狀態。

**實作步驟**

1.  **取得必要 ID**
    *   `serviceofferingid`:服務方案 ID,決定虛擬機器的規格。
    *   `templateid`:範本 ID,也就是虛擬機器的作業系統映像檔。
    *   `zoneid`:區域 ID,指定虛擬機器佈署的地理位置。
2.  **佈署虛擬機器**
    使用以下程式碼佈署虛擬機器:

    ```clojure
    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"}}
    ```

    *   `cs` 變數代表 CloudStack 的連線物件。
    *   這個函式會回傳一個包含 VM ID 和任務 ID  Map

3.  **加入額外引數**
    你可以加入 `keypair`  `securitygroupname` 等引數:

    ```clojure
    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"}}
    ```

4.  **查詢非同步任務**
    使用 `query-async-job-result` 函式查詢任務狀態:

    ```clojure
    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"}}
    ```

    *   `jobstatus`  `0` 表示任務成功。

5.  **銷毀虛擬機器**
    使用 `destroy-virtual-machine` 函式銷毀虛擬機器:

    ```clojure
    user=> (destroy-virtual-machine cs :id "d0a887d2-e20b-4b25-98b3-c2995e4e428a")
    {:destroyvirtualmachineresponse {:jobid "8fc8a8cf-9b54-435c-945d-e3ea2f183935"}}
    ```

    *   傳入虛擬機器的 `id` 即可。

### 在 Clojure 專案中使用 CloStack

如果你想在自己的 Clojure 專案中使用 CloStack,可以參考以下步驟。

**解決方案**

使用 Leiningen 建立新專案的骨架,並編輯專案依賴,加入 CloStack 和一些日誌函式庫。

**實作步驟**

1.  **建立專案**
    使用 `lein new` 建立專案:

    ```bash
    $ lein new foobar
    ```

    這會建立 `src/foobar/core.clj` 檔案。

2.  **修改 `core.clj`**
     `foobar` 函式替換為 `-main` 函式,並讓它回傳 "Hello, world!"

3.  **編輯 `project.clj`**
     `project.clj` 檔案中定義 `main` 名稱空間:

    ```clojure
    defproject foobar "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 foobar.core
      :dependencies [[org.clojure/clojure "1.5.1"]])
    ```

    注意 `:main foobar.core`

4.  **執行程式碼**
    使用 `lein run` 執行程式碼:

    ```bash
    $ lein run john
    john Hello, world!
    ```

5.  **加入 CloStack 依賴**
    編輯 `project.clj`,加入 CloStack 和一些日誌套件:

    ```clojure
    :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]]])
    ```

6.  **建立 `log4j.properties`**
     `resources` 目錄中建立 `log4j.properties` 檔案:

    ```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
    ```

7.  **修改 `core.clj`**
    編輯 `src/foobar/core.clj`,加入一些基本的 CloStack 呼叫:

    ```clojure
    (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))
    ```

8.  **執行程式碼**
    在專案目錄中執行 `lein run joe`

透過這些步驟,你就能成功地在 Clojure 專案中使用 CloStack,並探索更多 Clojure  CloudStack API 的可能性。

**玄貓小提示**

在實際專案中,玄貓建議你將 CloudStack 的連線資訊(例如 API 網址、API 金鑰等)儲存在環境變數或設定檔中,避免硬編碼在程式碼中,以提高程式碼的安全性與可維護性。

### 雲資源協調新選擇:Pallet 的 Clojure 實力

除了現有的工具,Pallet 也是一個值得關注的雲資源組態與自動化框架。它使用 Clojure 開發,為雲端環境的管理提供另一種選擇。

### Ruby 開發者的福音:StackerBee 與 CloudStack API 的完美結合

身為 Ruby 開發者,當你想用熟悉的語言來自動化 CloudStack 上的任務時,可能會發現 Fog 對於最新 CloudStack API 的支援有所不足。這時,StackerBee 這個新興的 Ruby 客戶端,就能派上用場。它能與所有版本的 CloudStack API 協同運作,讓 Ruby 開發者也能輕鬆管理雲端資源。

#### 如何使用 StackerBee?

首先,透過簡單的指令安裝 StackerBee Ruby gem:

```bash
$ sudo gem install stacker_bee

StackerBee 的官方網站提供了豐富的檔案,展示了各種可行的操作,包括使用 read-eval-print loop (REPL)。以下是一個範例指令碼,它會回傳虛擬機器的名稱和 SSH 金鑰對的名稱(當然,你也可以使用 create APIs 來建立磁碟區、伺服器、金鑰對等):

#!/usr/bin/env ruby
require 'stacker_bee'

cloud_stack = StackerBee::Client.new(
  url: 'https://api.exoscale.ch/compute',
  api_key: '<your API key>',
  secret_key: '<your API secret key>',
  ssl_verify: false
)

vms = cloud_stack.list_virtual_machines()
vms.each { |vm| puts vm[:displayname] }

keys = cloud_stack.list_ssh_key_pairs()
keys.each { |key| puts key[:name] }

內容解密

  1. #!/usr/bin/env ruby: 定義 Ruby 指令碼的執行環境。
  2. require 'stacker_bee': 引入 StackerBee 函式庫,以便使用其功能。
  3. StackerBee::Client.new(...): 建立 StackerBee 客戶端物件,並設定 API 網址、金鑰和金鑰。
  4. cloud_stack.list_virtual_machines(): 呼叫 API 取得虛擬機器列表。
  5. vms.each { |vm| puts vm[:displayname] }: 迭代虛擬機器列表,並印出每個虛擬機器的顯示名稱。
  6. cloud_stack.list_ssh_key_pairs(): 呼叫 API 取得 SSH 金鑰對列表。
  7. keys.each { |key| puts key[:name] }: 迭代金鑰對列表,並印出每個金鑰對的名稱。

StackerBee 的一個亮點是其 API 版本可組態性。透過 CloudMonkey 的 listApis 指令,你可以取得一個包含所有可用 API 描述的 JSON 檔案。StackerBee 可以利用這個 JSON 檔案來建構可用的方法。只需將 api_path 設定為包含所有 API 回應的 JSON 檔案位置即可:

StackerBee::Client.api_path = '/path/to/your/listApis/response.json'

CloudStack 的 AWS EC2 介面:EC2Stack 安裝與組態

CloudStack 提供了一個名為 awsapi 的原生 EC2 查詢介面,可以直接在管理伺服器上執行。此外,CloudStack 的提交者 Ian Duffy 和他的朋友 Darren Brogan,在他們的三年級專案中建立了一個名為 EC2Stack 的新專案。EC2Stack 根據他們之前使用 gstack(參見 Recipe 4.7)的經驗,gstack 是 CloudStack 的 GCE 介面,他們編寫了一個全新的 EC2 介面來連線 CloudStack。

這個介面使用 Flask 微框架,並且完全以 Python 編寫。它還提供了一個 Vagrant box 以方便測試,大量的單元測試,以及透過 Travis CI 進行的自動建置測試(pep8、pylint 和覆寫率)。作為 Google Summer of Code 2014 的一部分,Darren Brogan 正在使用額外的 API 和單元測試來增強 EC2Stack。

為什麼需要 EC2Stack?

如果你希望你的 CloudStack 雲端具有 AWS EC2 相容的介面,以便使用 AWS CLI 或 Python Boto(Recipe 4.4)等 AWS 客戶端,那麼 EC2Stack 將會是一個理想的選擇。

如何安裝 EC2Stack?

你可以從 Python 套件索引下載 EC2Stack,或者透過克隆 GitHub 儲存函式庫從原始碼安裝它。

以下是使用 pip 安裝 EC2Stack 的簡單方法:

$ sudo pip install ec2stack

如果你想從原始碼安裝並檢查程式碼,可以克隆 Git 儲存函式庫並手動安裝:

$ git clone https://github.com/BroganD1993/ec2stack.git
$ sudo python ./setup.py install

安裝完成後,你的路徑中將會出現 ec2stackec2stack-configure 這兩個二進位制檔案。在執行應用程式之前,你需要先進行組態。以下是一個使用 exoscale 進行設定的範例:

$ ec2stack-configure
EC2Stack bind address [0.0.0.0]:
EC2Stack bind port [5000]:
Cloudstack host [localhost]: api.exoscale.ch
Cloudstack port [8080]: 443
Cloudstack protocol [http]: https
Cloudstack path [/client/api]: /compute
Cloudstack custom disk offering name [Custom]:
Cloudstack default zone name: CH-GV2
Do you wish to input instance type mappings? (Yes/No): Yes
Insert the AWS EC2 instance type you wish to map: m1.small
Insert the name of the instance type you wish to map this to: Tiny
Do you wish to add more mappings? (Yes/No): No
INFO [alembic.migration] Context impl SQLiteImpl.
INFO [alembic.migration] Will assume non-transactional DDL.

請注意,我們在 AWS m1.small 例項型別和 exoscale 中的 Tiny 例項型別之間建立了一個對映。你可以新增更多對映。

現在你可以執行 ec2stack 了。這個設定過程會在前景執行應用程式。由於它是一個 Flask 應用程式,你可以透過多種方式將其佈署為服務。Flask 檔案提供了許多有用的技巧。為了進行測試,你可以在前景執行它;EC2Stack 將會監聽請求,並準備將它們轉發到你的 CloudStack 雲端:

$ ec2stack
* Running on http://0.0.0.0:5000/
* Restarting with reloader

使用 AWS CLI 操作 EC2Stack

在 EC2Stack 執行後,你就可以使用 AWS CLI 來呼叫你的 CloudStack 雲端。

玄貓認為 EC2Stack 提供了一個橋樑,讓習慣 AWS 生態的開發者能夠更輕鬆地轉移到 CloudStack 環境。