iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 25
0
DevOps

不一樣的 CI/CD 工具:Concourse 初探系列 第 25

25 - 自訂資源 (5)

首先,要讓自訂資源可以被存取,需要先設定 check 方法,讓自訂資源能夠自動的更新。

我們先開設一個專案,並且放入以下檔案。

  • /custom-resource-example
    • Dockerfile
    • /src
      • check
      • in
      • out

今天的主角是 check 這個檔案。

Dockerfile

這次使用 Ruby 來處理,所以只需要將這三個檔案放入 Docker Image 並且可以執行即可。

FROM ruby:2.3-alpine

ENV SOURCE_DIR /usr/src/app
ENV RESOURCE_DIR /opt/resource

ADD src $SOURCE_DIR

RUN mkdir -p $RESOURCE_DIR

RUN ln -s $SOURCE_DIR/check $RESOURCE_DIR/check && \
    ln -s $SOURCE_DIR/in $RESOURCE_DIR/in && \
    ln -s $SOURCE_DIR/out $RESOURCE_DIR/out

RUN chmod +x $RESOURCE_DIR/check && \
    chmod +x $RESOURCE_DIR/in && \
    chmod +x $RESOURCE_DIR/out

每次執行指令時 Concourse 都會呼叫 /opt/resource 裡面的檔案,我們先使用 ADD 將檔案放進去後,再利用 ln -s 建立捷徑讓檔案可以透過 /opt/resource/check 這個路徑被呼叫到。

接著用 chmod +x 將檔案設定為可執行,這樣一來最基本的運作就沒問題了。

如果是用 C/C++ 這類需要編譯的語言撰寫,可以在生成 Docker Image 的時候進行編譯,這篇文章為了容易開發與測試所以採用直接執行 Ruby 的方式。

Check

這次使用的是 Shell Script 的方式執行,所以要先加入下面這行。

#!/usr/bin/env ruby

這是用來表示這個 Script 是一個 Ruby 程式。

這次會用到兩個套件 jsonnet/http 分別用來解析 JSON 以及連到我們的伺服器進行查詢。

require 'json'
require 'net/http`

input = JSON.parse(STDIN.gets)

Concourse 會透過 STDIN 將一段 JSNO 的資料送進來,我們預期會是這樣。

{
  "source" {
    "uri": "http://version-server.example.com"
  },
  "version": {"version": "1.0"}
}

要注意的是 version 會傳入一個 JSON 物件,並且裡面是帶有字串資料的。而這個字串資料是由我們所定義的,像是 git 類型的資源就會傳回 {"ref": "7154fe"} 這樣的資訊作為版本資訊。

source = input["source"]
version = input["version"] || {"version" => "0.0"}

假設是一個新初始化的資源,可能會沒有儲存版本資訊,而傳入 null 進來,所以我們要給一個預設值。
伺服器是用 >= 來比較,所以第一次使用 0.0 當版本,就代表回傳所有可用的版本。

major, minior = version["version"].split(".")

uri = URI(source["uri"] + '/v1/versions')
uri.query = URI.encode_www_form({major: major, minior: minior})

接下來我們先將版本分解為 majorminior 兩個部分,然後透過使用者傳入的 uri 來建構 API 查詢的網址。

res = Net::HTTP.get_response(uri)
new_versions = JSON.parse(res.body)

取得類似 http://version-server.example.com/v1/versions?major=0&minior=0 的網址後,我們就可以送出查詢並且解析回傳的資料。

這邊並沒有做任何錯誤處理,實際使用時最好多做處理會比較保險。

我們預期會取得類似像下面這樣的資料。

[
 "1.0",
 "2.0",
 "2.1"
]
output = []

new_versions.each do |v|
  output << {"version" => v }
end

基本上和我們預期儲存的格式是相同的,所以將所有取得的新版本都寫入進去。

STDOUT.puts output.to_json

最後將版本資訊輸出即可,在設定好 Pipeline 後就能看到類似像這樣的畫面。

http://ithelp.ithome.com.tw/upload/images/20161225/20065771HfQDOCvj3r.png

不過工作會是無法執行的,但是可以正確被觸發(2.0 是第一次啟動的版本,而 2.1 是後來新增的版本)

http://ithelp.ithome.com.tw/upload/images/20161225/20065771mLPfqfl4wZ.png

呈現橘色是因為 in 的指令並沒有做任何東西,所以工作被中止。

完整的 check 程式碼如下。

#!/usr/bin/env ruby

require 'net/http'
require 'json'

input = JSON.parse(STDIN.gets)
source = input["source"] || {}
version = input["version"] || { "version" => "0.0" }

major, minior = version["version"].split(".")

uri = URI(source["uri"] + '/v1/versions')
uri.query = URI.encode_www_form({major: major, minior: minior})

res = Net::HTTP.get_response(uri)
new_versions = JSON.parse(res.body)

output = []

new_versions.each do |v|
  output << {"version" => v }
end

STDOUT.puts output.to_json

到此為止,已經可以正常地取得新版本,下一篇會介紹 in 指令的實作。


上一篇
24 - 自訂資源 (4)
下一篇
26 - 自訂資源 (6)
系列文
不一樣的 CI/CD 工具:Concourse 初探30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言