檢視原始碼 release_handler (sasl v4.2.2)
解壓縮與安裝發行套件
發行處理器程序屬於 SASL 應用程式,負責發行處理,也就是解壓縮、安裝和移除發行套件。
關於發行處理的介紹和範例,請參閱系統文件中的OTP 設計原則。
發行套件是一個壓縮的 tar 檔案,其中包含特定發行版本的程式碼,透過呼叫systools:make_tar/1,2
建立。發行套件應位於先前發行版本的 $ROOT/releases
目錄中,其中 $ROOT
是安裝根目錄,code:root_dir()
。可以使用 SASL 組態參數 releases_dir
或作業系統環境變數 RELDIR
來指定另一個 releases
目錄。發行處理器必須具有此目錄的寫入權限,才能安裝新的發行版本。發行處理器的持久狀態會儲存在一個名為 RELEASES
的檔案中。
發行套件始終包含
- 發行資源檔案,
Name.rel
- 啟動腳本,
Name.boot
.rel
檔案包含有關發行版本的資訊:其名稱、版本,以及它使用的 ERTS 和應用程式版本。
發行套件還可以包含
- 發行升級檔案,
relup
- 系統組態檔案,
sys.config
- 系統組態來源檔案,
sys.config.src
relup
檔案包含有關如何升級到或降級到此發行版本的指示。
可以解壓縮發行套件,這會提取檔案。可以安裝解壓縮的發行版本。然後,透過評估 relup
檔案中的指示,將目前使用的發行版本升級或降級到指定的版本。可以將已安裝的發行版本設為永久。系統中只能存在一個永久發行版本,並且如果系統重新啟動,則使用此發行版本。除了永久發行版本之外,可以移除已安裝的發行版本。移除發行版本時,只會刪除屬於該發行版本的所有檔案。
每個發行版本都有一個狀態,可以是 unpacked
、current
、permanent
或 old
。始終有一個最新的發行版本,其狀態為 permanent
(正常情況)或 current
(已安裝,但尚未設為永久)。下表說明了狀態值的含義
Status Action NextStatus
-------------------------------------------
- unpack unpacked
unpacked install current
remove -
current make_permanent permanent
install other old
remove -
permanent make other permanent old
install permanent
old reboot_old permanent
install current
remove -
發行處理器程序是在每個節點上本地註冊的程序。當在分散式系統中安裝發行版本時,必須呼叫每個節點上的發行處理器。發行版本的安裝可以在節點之間同步。從操作員的角度來看,指定每個節點可能令人不滿意。目標是在系統中安裝一個發行套件,無論有多少個節點。建議編寫軟體管理功能來解決此問題。此類功能可以了解系統架構,因此它可以聯絡每個發行處理器以安裝套件。
為了使發行處理正常運作,執行階段系統必須知道它正在執行的發行版本。它還必須能夠(在執行階段)變更如果系統重新啟動,則要使用的啟動腳本和系統組態檔案。如果將 Erlang 作為嵌入式系統啟動,則會自動處理此問題。請參閱系統文件中的嵌入式系統。在這種情況下,系統組態檔案 sys.config
是強制性的。
安裝新的發行版本可以重新啟動系統。要使用的程式由 SASL 組態參數 start_prg
指定,其預設值為 $ROOT/bin/start
。
在 Windows NT 上重新啟動模擬器時,期望系統是使用 erlsrv
程式(作為服務)啟動的。此外,發行處理器期望服務的名稱為 NodeName
_Release
,其中 NodeName
是 Erlang 節點名稱的第一部分(直到但不包括「@」),Release
是目前的發行版本。此外,發行處理器期望將類似 start_erl.exe
的程式指定為 erlsrv
的「機器」。在重新啟動進行升級期間,會註冊並啟動新的服務。當新的發行版本設為永久時,新的服務會設定為自動,並移除舊的服務。
在無磁碟機器上或使用唯讀檔案系統執行的節點上的發行處理器,必須使用以下 SASL 組態參數進行相應的組態(詳細資訊,請參閱 sasl(6))
masters
- 此節點使用一些主節點來儲存和擷取發行資訊。當此節點寫入發行資訊時,所有主節點都必須處於運作狀態。client_directory
- 必須指定主節點目錄結構中的client_directory
。static_emulator
- 此參數指定 Erlang 模擬器是否靜態安裝在用戶端節點上。具有靜態模擬器的節點無法動態切換到新的模擬器,因為可執行檔案是靜態寫入記憶體的。
當未將 Erlang 作為嵌入式系統執行時,也可以使用發行處理器來解壓縮和安裝發行套件。但是,在這種情況下,如果系統必須重新啟動,則使用者必須以某種方式確保使用正確的啟動腳本和組態檔案。
提供了用於使用與 OTP 中定義的結構不同的檔案結構的函數。這些函數可用於在本機測試發行版本的升級。
常見錯誤原因
{bad_masters, Masters}
- 主節點Masters
未處於運作狀態。{bad_rel_file, File}
- 無法讀取或未包含單一詞彙的指定.rel
檔案File
。{bad_rel_data, Data}
- 指定的.rel
檔案不包含已識別的發行版本規格,而是另一個詞彙Data
。{bad_relup_file, File}
- 指定的relup
檔案Relup
包含錯誤的資料。{cannot_extract_file, Name, Reason}
- 從 tar 檔案提取時發生問題,erl_tar:extract/2
傳回{error, {Name, Reason}}
。{existing_release, Vsn}
- 指定的發行版本Vsn
已在使用中。{Master, Reason, When}
- 某些操作(由詞彙When
指示)在主節點Master
上失敗,且錯誤原因是指定的Reason
。{no_matching_relup, Vsn, CurrentVsn}
- 無法找到在CurrentVsn
和Vsn
之間升級/降級的腳本。{no_such_directory, Path}
- 目錄Path
不存在。{no_such_file, Path}
- 路徑Path
(檔案或目錄)不存在。{no_such_file, {Master, Path}}
- 路徑Path
(檔案或目錄)在主節點Master
上不存在。{no_such_release, Vsn}
- 指定的發行版本Vsn
不存在。{not_a_directory, Path}
-Path
存在,但不是目錄。{Posix, File}
- 某些檔案操作在File
上失敗。Posix
是一個以 Posix 錯誤碼命名的原子,例如enoent
、eacces
或eisdir
。請參閱 Kernel 中的file
。Posix
- 某些檔案操作失敗,與清單中的前一個項目相同。
應用程式升級/降級
應用程式升級/降級區段中的函數可用於測試單一應用程式的升級和降級(而不是升級/降級整個發行版本)。根據應用程式的 .appup 檔案,動態建立與 relup 檔案中指示相對應的腳本,並以與 release_handler 完全相同的方式評估。
警告
這些函數主要用於簡化對 .appup 檔案的測試。它們不在 release_handler 程序的內容中執行。因此,它們不得與呼叫 install_release/1,2 一起使用,因為這會導致 release_handler 最終處於不一致的狀態。
不會更新任何持久資訊,因此這些函數可以在任何 Erlang 節點上使用,無論是否嵌入。此外,使用這些函數不會影響如果重新開機,則會載入哪些程式碼。
如果升級或降級失敗,應用程式可能會最終處於不一致的狀態。
另請參閱
摘要
應用程式升級/降級
根據 .appup
檔案,將應用程式 App
從目前版本降級到位於 Dir
中的先前版本 OldVsn
。
嘗試尋找從目前版本降級到位於 Dir
中的先前版本 OldVsn
的 App
的應用程式降級腳本。
以與 install_release/1,2
完全相同的方式評估應用程式升級或降級腳本 Script
(呼叫 upgrade_script/2
或 downgrade_script/3
的結果)。
根據 .appup
檔案,將應用程式 App
從目前版本升級到位於 Dir
中的新版本。
嘗試尋找從目前版本升級到位於 Dir
中的新版本的 App
的應用程式升級腳本。
函式
檢查指定的發行版本 Vsn
是否可以安裝。
建立一個初始的 RELEASES
檔案,供發行處理器使用。
在發行結構中安裝一個與發行版本相關的檔案。
安裝指定的發行版本 Vsn
。
將指定的發行版本 Vsn
設定為永久。
將舊的發行版本設定為永久,並直接呼叫 init:reboot()
來重新啟動系統。
從系統中移除一個發行版本及其檔案。
使其可以處理在發行處理器之外移除發行版本。
使其可以處理在發行處理器之外解壓縮發行版本。
解壓縮位於 releases
目錄中的發行套件 Name.tar.gz
。
傳回發行處理器所知的所有發行版本。
傳回發行處理器所知的所有具有特定狀態的發行版本。
應用程式升級/降級
-spec downgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason} when App :: atom(), Dir :: string(), Unpurged :: [Module], Module :: atom(), Reason :: term().
與 downgrade_app/3
等效。
-spec downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason} when App :: atom(), Dir :: string(), OldVsn :: string(), Unpurged :: [Module], Module :: atom(), Reason :: term().
根據 .appup
檔案,將應用程式 App
從目前版本降級到位於 Dir
中的先前版本 OldVsn
。
App
是應用程式的名稱,必須已啟動。OldVsn
是先前的應用程式版本,如果 Dir
的格式為 "App-OldVsn"
,則可以省略。Dir
是 App
先前版本的程式庫目錄。對應的模組和舊的 .app
檔案應位於 Dir/ebin
下。.appup
檔案應位於應用程式目前程式庫目錄的 ebin
目錄中 (code:lib_dir(App)
)。
此函式會查看 .appup
檔案,並嘗試使用 downgrade_script/3
尋找降級到先前版本的應用程式的指令碼。此指令碼會使用 eval_appup_script/4
進行評估,方式與 install_release/1,2
完全相同。
傳回下列其中一項
- 如果評估指令碼成功,則傳回
{ok, Unpurged}
,其中Unpurged
是未清除模組的清單 - 如果在指令碼中遇到此指令,則傳回
restart_emulator
- 如果尋找或評估指令碼時發生錯誤,則傳回
{error, Reason}
-spec downgrade_script(App, OldVsn, Dir) -> {ok, Script} when App :: atom(), OldVsn :: string(), Dir :: string(), Script :: Instructions :: term().
嘗試尋找從目前版本降級到位於 Dir
中的先前版本 OldVsn
的 App
的應用程式降級腳本。
然後可以使用 eval_appup_script/4
評估降級指令碼。建議改用 downgrade_app/2,3
,但是此函式 (downgrade_script
) 可用於檢查指令碼的內容。
App
是應用程式的名稱,必須已啟動。Dir
是 App
先前版本的程式庫目錄。對應的模組和舊的 .app
檔案應位於 Dir/ebin
下。.appup
檔案應位於應用程式目前程式庫目錄的 ebin
目錄中 (code:lib_dir(App)
)。
此函式會查看 .appup
檔案,並嘗試尋找從目前應用程式版本降級的指令碼。高階指令會轉換為低階指令。指令的排序方式與產生 relup
檔案時相同。
如果成功,則傳回 {ok, Script}
。有關 Script
的詳細資訊,請參閱 appup(4)
。
失敗:如果找不到指令碼,函式會因適當的錯誤原因而失敗。
-spec eval_appup_script(App, ToVsn, ToDir, Script :: term()) -> {ok, Unpurged} | restart_emulator | {error, Reason} when App :: atom(), ToVsn :: string(), ToDir :: string(), Unpurged :: [Module], Module :: atom(), Reason :: term().
以與 install_release/1,2
完全相同的方式評估應用程式升級或降級腳本 Script
(呼叫 upgrade_script/2
或 downgrade_script/3
的結果)。
App
是應用程式的名稱,必須已啟動。ToVsn
是要升級/降級到的版本,而 ToDir
是此版本的程式庫目錄。對應的模組以及 .app
和 .appup
檔案應位於 Dir/ebin
下。
傳回下列其中一項
- 如果評估指令碼成功,則傳回
{ok, Unpurged}
,其中Unpurged
是未清除模組的清單 - 如果在指令碼中遇到此指令,則傳回
restart_emulator
- 如果尋找或評估指令碼時發生錯誤,則傳回
{error, Reason}
如果在指令碼中找到 restart_new_emulator
指令,則 eval_appup_script/4
會傳回 {error,restart_new_emulator}
。這是因為 restart_new_emulator
需要在執行其餘升級指令之前啟動新版本的模擬器,而這只能由 install_release/1,2
完成。
-spec upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason} when App :: atom(), Dir :: string(), Unpurged :: [Module], Module :: atom(), Reason :: term().
根據 .appup
檔案,將應用程式 App
從目前版本升級到位於 Dir
中的新版本。
App
是應用程式的名稱,必須已啟動。Dir
是 App
新版本的程式庫目錄。對應的模組以及 .app
和 .appup
檔案應位於 Dir/ebin
下。
此函式會查看 .appup
檔案,並嘗試使用 upgrade_script/2
尋找從目前應用程式版本升級的指令碼。此指令碼會使用 eval_appup_script/4
進行評估,方式與 install_release/1,2
完全相同。
傳回下列其中一項
- 如果評估指令碼成功,則傳回
{ok, Unpurged}
,其中Unpurged
是未清除模組的清單 - 如果在指令碼中遇到此指令,則傳回
restart_emulator
- 如果尋找或評估指令碼時發生錯誤,則傳回
{error, Reason}
如果在指令碼中找到 restart_new_emulator
指令,則 upgrade_app/2
會傳回 {error,restart_new_emulator}
。這是因為 restart_new_emulator
需要在執行其餘升級指令之前啟動新版本的模擬器,而這只能由 install_release/1,2
完成。
-spec upgrade_script(App, Dir) -> {ok, NewVsn, Script} when App :: atom(), Dir :: string(), NewVsn :: string(), Script :: Instructions :: term().
嘗試尋找從目前版本升級到位於 Dir
中的新版本的 App
的應用程式升級腳本。
然後可以使用 eval_appup_script/4
評估升級指令碼。建議改用 upgrade_app/2
,但是此函式 (upgrade_script
) 可用於檢查指令碼的內容。
App
是應用程式的名稱,必須已啟動。Dir
是 App
新版本的程式庫目錄。對應的模組以及 .app
和 .appup
檔案應位於 Dir/ebin
下。
此函式會查看 .appup
檔案,並嘗試尋找從目前應用程式版本升級的指令碼。高階指令會轉換為低階指令。指令的排序方式與產生 relup
檔案時相同。
如果成功,則傳回 {ok, NewVsn, Script}
,其中 NewVsn
是新的應用程式版本。有關 Script
的詳細資訊,請參閱 appup(4)
。
失敗:如果找不到指令碼,函式會因適當的錯誤原因而失敗。
函式
-spec check_install_release(Vsn, Opts) -> {ok, OtherVsn, Descr} | {error, Reason} when Vsn :: string(), OtherVsn :: string(), Opts :: [Opt], Opt :: purge, Descr :: term(), Reason :: term().
檢查指定的發行版本 Vsn
是否可以安裝。
發行版本的狀態不能為 current
。如果 relup
檔案或 sys.config
不存在,則會發出警告。如果存在 relup
檔案,則會檢查其內容,如果發現錯誤,則會傳回 {error,Reason}
。還會檢查是否所有必要的應用程式都存在,以及是否可以載入所有新的程式碼;如果發現錯誤,則會傳回 {error,Reason}
。
評估在發行版本升級指令碼中的 point_of_no_return
指令之前發生的所有指令。
傳回與 install_release/1
相同的值。如果找不到 relup
檔案,則 Descr
預設為 ""。
如果指定 purge
選項,則在成功完成所有其他檢查之後,會清除所有可以軟清除的舊程式碼。這對於減少 install_release/1
所需的時間非常有用。
-spec create_RELEASES(Root, RelDir, RelFile, AppDirs) -> ok | {error, Reason} when Root :: string(), RelDir :: string(), RelFile :: string(), AppDirs :: [{App, Vsn, Dir}], App :: atom(), Vsn :: string(), Dir :: string(), Reason :: term().
建立一個初始的 RELEASES
檔案,供發行處理器使用。
此檔案必須存在才能安裝新的發行版本。
Root
是安裝的根目錄 ($ROOT
),如先前所述。RelDir
是要建立 RELEASES
檔案的目錄 (通常為 $ROOT/releases
)。RelFile
是描述初始發行版本的 .rel
檔案的名稱,包括副檔名 .rel
。如果未提供 Root
,則 RELEASES
檔案將與位置無關 (也就是說,除非 AppDirs
中有絕對路徑,否則它不會包含絕對路徑)。如果安裝的 $ROOT
未知,則應將 RELEASES
檔案設定為與位置無關。release_handler
模組會將執行中系統的 RELEASES
檔案中的相對路徑解譯為相對於 $ROOT
。
AppDirs
可用於指定要從何處載入指定應用程式的模組。App
是應用程式的名稱,Vsn
是版本,而 Dir
是 App-Vsn
所在的目錄名稱。對應的模組應位於 Dir/App-Vsn/ebin
下。未在 AppDirs
中指定的應用程式的目錄,會假設位於 $ROOT/lib
中。
-spec install_file(Vsn, File) -> ok | {error, Reason} when Vsn :: string(), File :: string(), Reason :: term().
在發行結構中安裝一個與發行版本相關的檔案。
在安裝新的發行版本時,發行版本相關的檔案必須在發行結構中:start.boot
、relup
和 sys.config
。
例如,當在目標產生這些檔案時,可以呼叫此函式。此函式應在呼叫 set_unpacked/2
之後呼叫。
-spec install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason} when Vsn :: string(), OtherVsn :: string(), Opt :: {error_action, Action} | {code_change_timeout, Timeout} | {suspend_timeout, Timeout} | {update_paths, Bool}, Action :: restart | reboot, Timeout :: default | infinity | pos_integer(), Bool :: boolean(), Descr :: term(), Reason :: {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | {missing_base_app, OtherVsn, App} | {could_not_create_hybrid_boot, term()} | term(), App :: atom().
安裝指定的發行版本 Vsn
。
首先尋找 Vsn
的 relup
檔案,以及此檔案中用於從目前版本升級的指令碼 {UpFromVsn,Descr1,Instructions1}
。如果找不到,此函式會尋找目前版本的 relup
檔案,以及此檔案中用於降級到 Vsn
的指令碼 {Vsn,Descr2,Instructions2}
。
如果找到指令碼,首先會根據屬於發行版本 Vsn
的 .app
檔案和 sys.config
更新應用程式規格。
在應用程式規格更新後,會評估腳本中的指令,如果成功,函數會返回 {ok,OtherVsn,Descr}
。 OtherVsn
和 Descr
是腳本中指定的版本 (UpFromVsn
或 Vsn
) 和描述 (Descr1
或 Descr2
)。
如果返回 {continue_after_restart,OtherVsn,Descr}
,則在執行升級指令之前,模擬器會重新啟動。如果模擬器或任何應用程式 Kernel、STDLIB 或 SASL 更新,就會發生這種情況。重新啟動後,會執行新的模擬器版本和這些核心應用程式。對於所有其他應用程式,舊版本會啟動,並且會像平常一樣執行升級指令來執行升級。
如果發生可恢復的錯誤,函數會返回 {error,Reason}
,並且會還原原始應用程式規格。如果發生不可恢復的錯誤,系統會重新啟動。
選項:
error_action
- 定義如果安裝期間發生錯誤,節點是要重新啟動 (init:restart()
) 還是重新開機 (init:reboot()
)。預設值為restart
。code_change_timeout
- 定義所有呼叫sys:change_code
的逾時時間。如果未指定值或指定default
,則會使用sys
中定義的預設值。suspend_timeout
- 定義所有呼叫sys:suspend
的逾時時間。如果未指定值,則會使用upgrade
或suspend
指令的Timeout
參數定義的值。如果指定default
,則會使用sys
中定義的預設值。{update_paths,Bool}
- 指示是否要更新所有應用程式程式碼路徑 (Bool==true
),或只更新已修改應用程式的程式碼路徑 (Bool==false
,預設值)。此選項僅對預設$ROOT/lib/App-Vsn
以外的其他應用程式目錄有效,也就是在呼叫create_RELEASES/4
或set_unpacked/2
時,在參數AppDirs
中指定的應用程式目錄。範例
在發行版本的目前版本
CurVsn
中,myapp
的應用程式目錄是$ROOT/lib/myapp-1.0
。新的版本NewVsn
在發行處理常式之外解壓縮,並透過以下呼叫通知發行處理常式release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]). => {ok,NewVsn}
如果
NewVsn
安裝時帶有選項{update_paths,true}
,則code:lib_dir(myapp)
會返回/home/user/myapp-1.0
。
注意
如果系統中有許多程序,安裝新的發行版本可能會很耗時。原因是每個程序都必須檢查是否有對舊程式碼的引用,才能清除模組。此檢查可能會導致垃圾收集和資料複製。
為了加快
install_release
的執行速度,請先使用選項purge
呼叫check_install_release
。這會對舊程式碼執行相同的檢查。然後清除所有可以軟清除的模組。清除的模組不再有任何舊程式碼,並且install_release
不需要執行檢查。這不會減少升級的總時間,但允許在開始真正的升級之前,在背景中執行檢查和清除。
注意
當從早於 OTP R15 的版本升級模擬器時,會嘗試將新的應用程式 beam 程式碼載入到舊的模擬器中。有時舊的模擬器無法讀取新的 beam 格式,因此程式碼載入失敗,並且整個升級終止。為了克服這個問題,新的應用程式程式碼應使用舊的模擬器編譯。有關從 OTP R15 之前的版本升級模擬器的更多資訊,請參閱系統文件中的 設計原則。
-spec make_permanent(Vsn) -> ok | {error, Reason} when Vsn :: string(), Reason :: {bad_status, Status :: term()} | term().
將指定的發行版本 Vsn
設定為永久。
-spec reboot_old_release(Vsn) -> ok | {error, Reason} when Vsn :: string(), Reason :: {bad_status, Status :: term()} | term().
將舊的發行版本設定為永久,並直接呼叫 init:reboot()
來重新啟動系統。
發行版本的狀態必須為 old
。
-spec remove_release(Vsn) -> ok | {error, Reason} when Vsn :: string(), Reason :: {permanent, Vsn} | client_node | term().
從系統中移除一個發行版本及其檔案。
發行版本不得為永久發行版本。僅刪除其他發行版本未使用的檔案和目錄。
-spec set_removed(Vsn) -> ok | {error, Reason} when Vsn :: string(), Reason :: {permanent, Vsn} | term().
使其可以處理在發行處理器之外移除發行版本。
告知發行處理常式,發行版本已從系統中移除。此函數不會刪除任何檔案。
-spec set_unpacked(RelFile, AppDirs) -> {ok, Vsn} | {error, Reason} when RelFile :: string(), AppDirs :: [{App, Vsn, Dir}], App :: atom(), Vsn :: string(), Dir :: string(), Reason :: term().
使其可以處理在發行處理器之外解壓縮發行版本。
告知發行處理常式,發行版本已解壓縮。 Vsn
是從發行版本資源檔案 RelFile
中提取的。
AppDirs
可用於指定要從何處載入指定應用程式的模組。App
是應用程式的名稱,Vsn
是版本,而 Dir
是 App-Vsn
所在的目錄名稱。對應的模組應位於 Dir/App-Vsn/ebin
下。未在 AppDirs
中指定的應用程式的目錄,會假設位於 $ROOT/lib
中。
-spec unpack_release(Name) -> {ok, Vsn} | {error, Reason} when Name :: string(), Vsn :: string(), Reason :: client_node | term().
解壓縮位於 releases
目錄中的發行套件 Name.tar.gz
。
對套件執行一些檢查,例如,檢查所有必要的檔案是否存在,並提取其內容。
-spec which_releases() -> [{Name, Vsn, Apps, Status}] when Name :: string(), Vsn :: string(), Apps :: [AppVsn :: string()], Status :: unpacked | current | permanent | old.
傳回發行處理器所知的所有發行版本。
-spec which_releases(Status) -> [{Name, Vsn, Apps, Status}] when Name :: string(), Vsn :: string(), Apps :: [AppVsn :: string()], Status :: unpacked | current | permanent | old.
傳回發行處理器所知的所有具有特定狀態的發行版本。