執行固定的管理員操作
root 操作讓你的 App 以 root 執行一小組 shell 指令碼。指令碼寫在你的專案裡,由管理員核准一次,之後你的後端用 root.run 依名稱執行。App 無法執行不在核准範圍內的任何東西,也無法傳入引數。
建立含此能力的新專案,或把它加進既有的 native-go 專案:
synopkgland init -t native-go --with root-ops my-appsynopkgland add root-ops兩者都會把 capabilities: {rootOps: true} 寫入 dsm-package.yaml。os_min_ver 必須至少是 7.1-42661:init 預設就是這個值,而 add root-ops 會把較低的值提高到它並印出此變更。新專案含有範例 root/whoami.sh,它會印出程序的使用者 id:
#!/bin/shset -euid -urootOps: true 至少需要一個 root/<name>.sh。有 root/ 目錄卻沒有 rootOps: true,check 會失敗。
| 規則 | 值 |
|---|---|
| 檔名 | ^[a-z][a-z0-9_]{0,31}\.sh$,例如 restart_service.sh |
root/ 內的其他檔案 | 不允許 |
| 檔案類型 | 一般檔案。不可是符號連結或目錄。 |
| 大小 | 最多 16 KiB(16384 位元組) |
| 第一行 | 必須剛好是 #!/bin/sh,後面接換行 |
| 內容 | UTF-8 文字,不含 NUL 位元組 |
| 引數 | 無。指令碼以不帶引數的 /bin/sh 執行。 |
| 環境 | PATH=/usr/syno/bin:/usr/syno/sbin:/usr/bin:/bin、LANG=C、HOME=/。工作目錄為 /。 |
| 執行時間 | 20 秒,逾時即停止 |
| 輸出 | 標準輸出與標準錯誤合併,最多回傳 1 MiB。 |
管理員在 App 的「管理員設定」面板,用 DSM 密碼核准套件一次。Vue UI 使用 SDK 的 ExecutorSettings,DSM 視窗不會另外加入自己的面板。產生的 Vue 專案在 ExecutorGate.vue 用 SDK 的 ExecutorApproval 接管頁面,直到 executor 核准為止,並加上 preload:頁面在 executor 第一次讀取狀態期間先隱藏掛載,自己的讀取與核對並行。掛載時會自行開對話框的頁面,要等 SDK 的 useExecutorPreload() 變成 false。plain UI 則由 DSM 視窗顯示核准面板,文字跟隨 DSM 語言,管理員在面板內輸入密碼;密碼空白時不會送出。核准會記錄每個 root/*.sh 檔案的 digest(SHA-256),因此只有管理員核准過的那些指令碼可以執行。
Vue 核准畫面會先說明 App 為何需要系統權限,再請求密碼。ExecutorApproval 使用置中的 consent 卡片;ExecutorSettings 與 ExecutorNotice 對話框使用 inline 版面。管理員輸入目前登入的 DSM 帳號密碼,再按「核准」。密碼由 DSM 直接驗證,不會傳給 App 服務或儲存。「關於這次核准」可展開查看宣告工作限制、更新行為與解除安裝步驟。一般使用者只會看到請管理員核准的指引,沒有密碼欄。
空白送出會在欄位下顯示提示,不送出請求。密碼遭拒時,錯誤會顯示在欄位下,保留輸入供重試;其他設定失敗保留具體錯誤訊息。ExecutorApproval、ExecutorNotice、ExecutorSettings 的 purpose 可提供 App 自己需要系統權限的用途;AppShell 內建通知使用通用用途。背景存檔會自動提供離線檔案工作的用途。
下列變更會強制重新核准:
| 變更 | 需要重新核准 |
|---|---|
修改任何 root/*.sh 檔案 | 是 |
新增或移除 root/*.sh 檔案 | 是 |
修改 dsm-package.yaml 的 entry | 是 |
修改 delegate 的 scope、destinations、operations 或 lifetime | 是 |
| 只改版本號或 UI | 否 |
在管理員核准前,synopkgland status 會顯示 needs-admin-approval;核准與已安裝的套件相符時顯示 ready。
executor 會自己核對核准任務:啟動時一次,通過後每 10 分鐘、失敗後每 1 分鐘再核對。executor.status 以 tasks 回報結果(checking、ready、stale 或 failed)。釘選中、執行中的 executor 回報 ready 時,DSM 視窗直接向管理員顯示 App,不自己讀取任務排程表與 EventScheduler。其他管理員在核對之後更改的任務,會在下一次核對(最晚 15 分鐘後)被發現;在那之前,被更改的 control 任務仍會在下一次 start、stop 或 purge 前被擋下。核准、control 任務的 start、stop 與 purge,以及範圍選擇,一律先讀回兩個任務。
DSM 7.1
Section titled “DSM 7.1”DSM 7.1 沒有 SYNO.Core.TaskScheduler.Root 與 SYNO.Core.EventScheduler.Root,所以在 DSM 7.1 上核准改用較舊的 API:
| 步驟 | DSM 7.1 | DSM 7.2 以後 |
|---|---|---|
| 確認密碼 | PasswordConfirm v1 | PasswordConfirm v2,會回傳一次性 token |
| 建立 task | EventScheduler create v1 與 TaskScheduler create v3 | EventScheduler.Root 與 TaskScheduler.Root,並帶上 token |
| 讀回 task | TaskScheduler list v2 與 get v3 | TaskScheduler list v3 與 get v4 |
App、status、deploy 與卸載只有在 DSM 對排程讀取或密碼確認回應「不支援的版本」時,才改用 DSM 7.1 的 API:錯誤 104(版本高於該 API 的最高版本,例如 PasswordConfirm v2 與 TaskScheduler get v4)或錯誤 103(該版本沒有這個 method,例如 TaskScheduler list v3)。其他錯誤,例如密碼錯誤(3121)、權限或 session 錯誤,會直接回報,不會換版本重試;建立 task 也一律不重試。兩條路徑都會讀回兩個 task,擁有者、類型與指令碼完全相符前不會執行任何東西。
如果核准在建立了一個 task 之後中斷,例如 boot task 已建立而 control task 沒有,App 會刪除這次核准建立的 task,不會留下沒有 control task 的 root 開機 task。兩個 task 都已建立並讀回,但 executor 之後沒有啟動或沒有回報正常時,也一樣會刪除:executor 沒有執行就沒有 task 清單,卸載會找不到它們。先前核准建立的 task 會保留。核准失敗時,App 的設定畫面會顯示原因與 DSM 錯誤碼;密碼錯誤或核准已撤回之後,視窗面板與設定畫面仍提供再次核准。
在 DSM 7.1 上密碼仍會被確認,但 DSM 不會把建立 root task 綁定到這次確認。任何已登入的管理員 session 不透過你的 App 也能在 DSM 7.1 上建立 root task。這次確認記錄的是管理員的同意,不是 DSM 7.2 以後那種由伺服器強制的證明。
DSM 7.1 路徑已依 DSM 7.1.1-42962 實測的 API 組合與錯誤碼測試;加入 104 回退後尚未在 NAS 上驗證。
| 事件 | 影響 |
|---|---|
| 停止套件 | root 操作暫停,核准保留。 |
| 升級 | 只有已核准的政策與指令碼仍然相符時才會恢復(符合 INFO 錨點的新 executor 不需核准),否則 App 停在 needs-admin-approval。 |
| 解除安裝 | 核准、root 任務與這個 App 的應用程式權限規則都會被移除,portal 網址也會停止。重新安裝需要重新核准。請見資料與移除。 |
產生的 root.run 路由存在於 native-go 專案。產生的 UI 沒有對應的按鈕,請從你自己的 UI 程式碼呼叫。只有管理員可以呼叫。
const result = await ctx.call<{ output: string }>('root.run', { name: 'whoami' })name 是不含 .sh 的檔名。結果是 { output },即指令碼合併後的輸出。
executor.status 會回報核准是否為 ready,並附 tasks(executor 自己對核准任務的核對結果),所有已登入的使用者都能呼叫。套件停止,或升級後等待核准時,executor 會暫停,狀態為 ready: false、state: "paused",下一步寫在 next:啟動套件,或在套件執行中時重新核准;只有 root 能讀的 /usr/local/etc/synopkgland/<package>/executor.log 會寫明原因。
| 限制 | 值 |
|---|---|
| 最低 DSM 版本 | 7.1-42661 |
| 架構 | x86_64、aarch64 與 armv7。armv7 尚未在 NAS 上驗證。 |
| 指令碼大小 | 16 KiB |
| 執行時間 | 20 秒 |
| 回傳的輸出 | 1 MiB |
| 引數 | 無 |
誰能呼叫 root.run | 管理員 |
| 症狀或錯誤碼 | 原因 | 解法 |
|---|---|---|
root.run 回傳 internal | root 操作的每一種失敗,到 App 端都是 internal:名稱不明、結束碼非 0、逾時、尚未核准,或執行器未運作。 | 檢查 synopkgland status,用 sh 手動執行指令碼,並讓它在 20 秒內完成。 |
admin_required | 呼叫者不是管理員。 | 用管理員的工作階段呼叫 root.run。 |
session_required | 沒有有效的 DSM 工作階段。 | 重新登入 DSM。 |
STANDALONE_ROOT_OPS_UNUSED | 有 root/,但缺少 rootOps: true。 | 加入能力,或刪除 root/。 |
synopkgland status 顯示 needs-admin-approval | 尚未核准,或指令碼或政策已改變。 | 管理員在「管理員設定」重新核准。 |
check 拒絕某個指令碼 | 名稱、大小或第一行違反上表的規則。 | 修正該檔案。 |
| 解除安裝很久 | executor 透過 DSM 刪除 boot 與 control 工作,再刪除其受保護的資料夾。 | 在系統記錄中找 synopkgland-executor 行:task cleanup timing 列出每個工作的查詢、刪除與驗證時間,purge timing 列出工作與檔案階段,都附套件名稱。DSM 7.1 上這些行只在 journal,不在 /var/log/messages:執行 journalctl -t synopkgland-executor。 |
所有錯誤碼請見錯誤碼。