Zh/Mock 教学

前言
這只是幫助對打包、編譯、測試有興趣，英語程度卻有困難的朋友，一個簡略的 Mock 使用流程；由於我也是翻譯既有英文文檔的原因，一切以英文原版作準：

Using Mock to test package builds

在此謝謝您的耐心閱讀！任何翻譯謬誤或意見回饋敬請不吝指正. 以下為原文翻譯.

本頁收集了 mock 使用者覺得有用的資訊.

甚麼是 Mock ?
Mock 讀取一個 srpm 檔案，然後在一個 chroot 上編譯. 這確保你的 BuildRequires 內容正確，亦即是在沒有遺漏任何依存套件的情況下，無誤地完成編譯.

我如何設立 Mock？
首先，安裝 mock 套件，它由 Fedora 套件集提供.

預設設定
使用 mock 的時候，您可以使用 "-r" 選項選擇特定的測試設定. 如果一個特定設定會被系統使用者經常使用，您可以把它設定為預設：
 * 1) cd /etc/mock
 * 2) ln -s --force SOMECONFIG.cfg default.cfg

設立本地鏡像
如果您需要設立本地鏡像，請閱讀：
 * http://fedoraproject.org/wiki/MockSetupUsingLocalMirror { 現時位於: http://fedoraproject.org/wiki/Docs/Drafts/MockSetupUsingLocalMirror }

在您的 CVS 沙盤 (sandbox) 外使用 Mock
在 mock 群組裏加入您的使用者名稱

用 'rpmbuild -bs' 命令加入您的 srpm 檔案，然後跳到您的 srpm 檔案建立的文件夾位置.

現在您可以輸入以下命令開始 mock

是位於  裏，設定檔案的名稱 (不用包括   延伸檔名).

如果使用 0.8.8 以前的 mock 版本或者帶有 python 2.4 的系統，需要在 x86_64 上編譯 i386 套件的話，於 mock 命令行前置 ：

雖然新版本的 mock 不再需要 setarch 命令, 但是加入了也無傷大雅.

在您的 CVS 沙盤 (sandbox) 使用 Mock
您只需輸入 'make mockbiuld' 開始 mock 編譯. 使用建構 (architecture) 會根據您開始 mock 編譯的文件夾被自動選擇.

mock 0.8.x 或以後版本的快取
Mock 0.8.x 引入三種不同的快取類類： 1) 根目錄快取 (root cache), 2) yum 快取, and 3) ccache.

設定這些快取請閱讀 /etc/mock/defaults.cfg 裏的文檔. 您可以更改儲存快取的文件夾位置，儲存快取的最長時間，及空間使用上限 (限 ccache).

根目錄快取 (Root cache)
從 mock 0.5 開始，它可以自動快取標準編譯根目錄 (standard buildroot) 裏，一個本地 tar 檔案的每個環境參數 (/var/lib/mock/cache/$CONFIG/root_cache/*). 然後它解開這個 tar 檔案把編譯根目錄 (buildroot) 填入，而不是每次以重新下載準備它. 當在根目錄快取 (root cache) 中觸開了編譯根目錄 (buildroot)，mock 進行一次  以確保編譯根目錄在安裝額外的 BuildRequires 以作套件編譯前，處於最更新的狀態.

根目錄快取在 mock 0.8.x 或以後版本預設開啟. 要關閉它請閱讀 /etc/mock/defaults.cfg 裏的文檔. 根目錄快取能全域或個別 chroot (per-chroot) 關閉. 根目錄快取每十五天會被自動刪除及重新建立，防立它變得太過時.

緊記根目錄快取會影您編譯的重複性，尤其是在 RPMs 會經常更新的環境下 (例如：rawhide)；在重複性最重為重要的環境下，應關閉根目錄快取.

yum 快取
預設 yum 會儲存下載了的 RPM 到 /var/cache/yum 下的文件夾裏. yum 快取提供掛載 /var/cache/yum chroot 到一個 chroot 環境以外的共用文件夾，讓隨後的編譯儲存及重複使用. 這確保 yum 不須在每次編譯的時候從網絡重新下載每個 RPM. 這個功能預設開啟.

ccache
cchache 工具，包裹傳到編譯器（像 'gcc'）的呼叫，然後進行輸出快取. 如果被呼叫同一個程式第二次（帶有一樣的命令參數、 gcc 版本、及 header 檔案），ccache 將會抓取快取的版本，而不會重新編譯.

用 Squid 加快 Mock 下傳套件
上面的編譯根目錄 (buildroots) 快取技巧會比單獨使用 squid 要快，但是您也可以用 squid 作為已快取的編譯根目錄 (buildroot) 的輔助， 尤其是當您有着比較慢的 Internet 連線.

根目錄快取 (root cache) 將會包含標準編譯根目錄套件 (standard buildroot packages). 可是當它變舊，解開它後  可能會必須更新大量套件. 再者，有些套件不在標準編譯根目錄 (standard buildroot) 裏，卻經常需要用到 (e.g. pkgconfig). 這樣每個套件的編譯，可由於 squid 快取提供代替從 Internet 下傳而加快.

squid 套件可從 Fedora 套件集提供安裝.

一些地方需要更改：


 * 最大物件體積 (Maximum Object Size) .  正常來說要 4MB. 不過有些基礎套件像 glibc 可以超過 16MB，如果您要編像 Eclipse 插件將是 60MB. 因此把它設大一些.


 * 快取替換規則 (Cache Replacement Policy) . 正常來說 lru 足夠. 不過在我們的情況，我們希望大型的物件保留時間長一些，儘可能下傳比較小的物件.


 * 快取體積 (Cache Size) . 正常體積為 100MB.  沒有辦法，這個最少要 1GB，假若您定期編譯多個 Fedora 版本及多種架構.

接着啟動 squid ，再設定它在開機時啟動.

要編譯的使用者自動使用 squid 快取，輸入：

如果您只想使用 squid 在特定 mock 設定 (也許您有某些發行版的本地鏡像又不需要 squid 給它們），您可以在 mock 設定檔案的  部分，設立代理伺服器設定；而不用設立   環境變數：

config_opts['yum.conf'] = """ [main] ... proxy=http://localhost:3128/

... """

更改 /etc/mock/*.cfg 以停用鏡像列表
'''不要使用 mirrorservice.org 鏡像; 它以 HTTP header "Cache-Control: no-store" 阻止順流快取. '''

如果您使用 squid ，又不想 mock+squid 用上隨選鏡像下載套件，可以更改 /etc/mock/*.cfg 的設定檔案，在  項使用對您而言最快的鏡像，而不用   裏的鏡像.

使用 tmpfs 減少讀寫儲存器
'''tmpfs 是否仍是首選為未知數，不過現在 autocache 運作良好及成為標準功能了. '''

在有足夠記憶體的時候 (1.5-2 GB) ，使用 tmpfs 能夠有效加速 'prep' 階段. 一台配備 1.5GB 記憶體的 Celeron 2.8 GHz 電腦，再次編譯時填入 buildroot 只須花上 2-5s (秒).

您可以掛載 /var/lib/mock 成 tmpfs，或者在 /var/lib/mock 掛載每一個編譯文件夾成個別 tmpfs 檔案系統. 後者讓您得以使用以上的 autocache 及把它儲存到磁碟，而不是到 tmpfs. 如果您經常刪除及重建 autocaches often，把它們放在 tmpfs 就很合理. 否則，您應該各自編譯文件夾 tmpfs 掛載方式 (per-build-directory tmpfs mounts).

SELinux 下使用 Mock
SELinux 與像 mock 的 chroot-ed 環境下共用，有着一些問題；例如需要用 chroot 文件夾前輟 (directory prefix) 重製 file context，這是系統管理員的惡夢. 雖然這個方法非常簡單，但是它只適用於  規則 (policy): 預先請取一個令所以子進程以為 SELinux 是在關閉狀態的空殼 (dummy). 同時 mock 它以潛水 (unconfined) 進程運行，這樣一般沒有問題.

SELinux 記憶體保護的問題
然而， FC5 以後， SELinux  domain 不再被 SELinux 完全隠藏 (unconfined)； 記憶體保護 就是為了保護使用者進程免於各種入侵而被編寫. 這表示最少兩類在 FC5 上使用 mock 的問題： 1. 當 正在為遺產 (legacy) 發行版編譯套件，編譯過程會牽涉讀取舊的共用函數庫 (libraries) ,它們都沒有各自像「可執行碼」及「可寫入資料」的區分 (sections). 這引致在  domain 運作的進程試圖讀取一個函數庫的時候得到   回絶，除非該函數庫被標示了. 1. 當使用 mono 編譯套件（這也許也適用於 java ），  進程會如常地運行它自身比較少限制的 domain  ；在 mock 下運行，   在   domain 裏運行，這樣會招致   與   回絶. 雖則這些檢查可以經由 SELinux booleans 關閉，這不是對每個進程應有的對待. 有另一個方法，就是確保所有檔案都已經在 chroot 被正確標示，與及 SELinux domain 在需要的時候轉移. 然而，由於進程在 mock 下運行是由處於 SELinux 關閉狀態的空殼 (dummy)  指示，從而讓這方法不可行.

mock 用 SELinux 規則 (policy) 組件
以下解決問題的方法，在建立一個 mock 用的 SELinux 規則 (policy) 的同時有以下兩個考量：
 * 1) 它在自身的 domain  運作，就像其他如果運行的進程一樣不被限制 (unconstrained)；這代表它准許
 * 2) 它用特別的 context type   標示經已安裝在   (就是   設立它的 chroot 環境的位置) 的檔案，讓   domain 內的進程得到   允許.

這個解決方法足夠地放鬆 SELinux 保護讓 mock 能夠工作，不用妥協對一般 unconfined domain 的負擔.

安裝規則 (policy) 組件：

Compliling targeted mock module /usr/bin/checkmodule: loading policy configuration from tmp/mock.tmp /usr/bin/checkmodule: policy configuration loaded /usr/bin/checkmodule: writing binary representation (version 5) to tmp/mock.mod Creating targeted mock.pp policy package rm tmp/mock.mod.fc tmp/mock.mod
 * 開啟一個用以儲存規則 (policy) 檔案的文件夾，例如  ，再進入那個文件夾.
 * 下傳 [[Image:PackageMaintainers_MockTricks_mock.if]], [[Image:PackageMaintainers_MockTricks_mock.fc]], and [[Image:PackageMaintainers_MockTricks_mock.te]] 到這個文件夾.
 * 如似下編譯及安裝規則 (policy) 組件：
 * 1) make -f /usr/share/selinux/devel/Makefile

如果規則 (policy) 組件在  套件安裝之前讀取, 在安裝的時候   會被標示為   及   會被標示為. 否則，就必須使用  修復檔案 contexts：
 * 1) restorecon -R /var/lib/mock /usr/bin/mock

作為一個 chroot 沙盤 (sandbox) 工具使用 mock
Mock 可以用來建立 chroots 測試東西，不只是用來編譯套件. 以下為扼要步驟：


 * 建立一個設定檔案，指到您選擇的一個或多個包含您測試套件的 repo.
 * mock -r <設定檔名稱> init
 * /usr/sbin/mock-helper yum --installroot /var/lib/mock/<設定檔名稱>/root install <您的套件名稱>
 * mock -r <設定檔名稱> shell

為甚麼不直接 chroot 而要 mock 代勞 (shell)？要 mock 代勞 (to "shell") 讓 mock 建立您大概會在 chroot 裏需要的掛載點 (mountpoints). 如果您想手動管理每個掛載，您可以放心去做.