原本的解決方案不符現在需求、也不適合大規模重構
隨著時間推移,業務型態也跟著逐漸改變。從只需要單純大量測試原生 Ubuntu 逐漸轉變到現在發展中、需要測試各種 Ubuntu 在各種平台上的表現。原本負責大量原生 Ubuntu 批次安裝與測試的 checkbox-satellite project ,其最初的設計似乎並沒有考慮到這些使用情境。與其大規模的重構來符合一個當初設想外的使用情境,或許是發展另外一套解決方案的時候了。
想克服的問題:分開安裝與系統調整兩個動作
我在最初構思新的解決方案的時候,最想解決的問題是 checkbox-satellite 因為奠基於 d-i 的成熟技術所帶來的限制。因為採用 d-i,所以 checkbox-satellite 可以說是不得不將安裝(provisioning)與調整系統(使系統能夠自我自動測試)兩個動作,透過 preseed、early command file 和 late command file 等等好用與成熟的機制高度地綁在一起。好處是這個 preseed 機制在 Debian 和 Ubuntu 社群長久的發展下,功能已經非常穩定、成熟與強大,完全能夠勝任快速開發安裝與調整原生 Ubuntu 的重責大任,缺點則是 checkbox-satellite 當用於非原生 Ubuntu 或是非支援 d-i 機制的 images 時,就要另外發展安裝(provisioning)與調整系統(使系統能夠自我自動測試)兩個動作的需求。
於是我設計了一套基本上是 master-client 式的 client-server model,將 provisioning 和 system configuration 分開,master 只需要分別在不同的階段去觸發這兩個動作、client 只需要針對觸發做回應即可,藉此來 decouple。我很快就意識到這是一個很直覺、所以應該會被大量實做的概念,例如 Puppet[1]、OpenLMI[2]和接下來要聊聊的 Testflinger[3]。
Testflinger 的工作模式:server、agent、cli
Testflinger 很自然地也是採用 master-client 的設計,不過可以再細分為 server、agent 與 cli。定位如下:
- Testflinger server:負責接收來自 cli 的任務請求、指派任務給 agent 與回收 agent 執行結果。
- Testflinger agent:負責去認領在 server 上面還沒有被處理的任務。實際與測試目標溝通、執行測試任務、回收測試結果並回報給 server。
- Testflinger cli:負責觸發任務請求。
所以很自然地,deployment 會像這樣:
- Testflinger server:裝在某台可以收、送 Restful 通訊機制的 server 即可。該 server 必須要有 Redis server 服務,因為 Testflinger server 透過 Redis 來管理任務佇列。
- Testflinger agent:裝在某台可以收、送 Restful 通訊機制的機器上即可。通常會設定固定排程讓 agent 定期去 server 上查看有沒有還沒被認領的工作。
- Testflinger cli:裝在某台可以收、送 Restful 通訊機制的機器上即可。通常是自己的筆電。
因此,所有的測試目標只要是能夠運作 ssh server(或任何其他能夠收到來自 agent 訊息的管道)以及 shell(或是任何其他能夠執行來自 agent 指令的方式)即可。至此 system configuration 的問題已經解決;只要是能夠透過 command line 完成的 configuration,使用這種工作模型,應該都可以滿足。
所以我們只剩下 provisioning 這個問題:那測試目標要怎麼預先準備好 ssh server 和 shell 呢?
使用 MAAS 安裝測試目標
MAAS 提供 bare metal provisioning 的一系列解決方案。因此直接使用 MAAS 將「安裝」這個動作本身,成為一個 Testflinger agent 指派的任務即可。只是 Testflinger agent 驅動的「測試目標」其實變成 MAAS controller,「測試內容」變成「觸發 MAAS controller 去安裝目標機器」。
將 Jenkins 做為 Testflinger cli 觸發來源
從以上討論,其實就暗示了 Testflinger 本質上是「安裝與觸發系統工作」的機制,這套機制如果配合其他的排程機制,基本上就是一套完整的自動化測試解決方案。例如我們可以考慮使用 Jenkins 定期透過 Testflinger cli 發出測試請求、並且回收統整 Testflinger server 的執行結果。
[1] https://docs.puppet.com/puppetserver/latest/services_master_puppetserver.html
[2] http://www.openlmi.org/
[3] 當然還有其他可能的解決方案,例如 Ansible、Chef、Salt 等等。我認為其中最重要的概念是區分自己要做的是「system configuration」還是「application configuration」,而去選擇最適合自己使用情境的。