/optにインストールしてsudo sdkでパッケージ管理したい

f:id:orangeclover:20191208224339p:plain

やりたいこと

  • apt、yumのパッケージ管理と同じように、インストール、アンインストールはroot権限で実行する
  • /opt/sdkmanにインストールして、複数ユーザーで共有する (/optは755)
  • インストールしたパッケージは一般ユーザーで使用できる

sdkmanのインストール

まずは、sdkmanで/opt/sdkmanにインストールする。

export SDKMAN_DIR="/opt/sdkman" && curl -s "https://get.sdkman.io" | sudo -E bash
  • 結果
 Please open a new terminal, or run the following in the existing one:
 
     source "/opt/sdkman/bin/sdkman-init.sh"
 
 Then issue the following command:
 
     sdk help
 
 Enjoy!!!

トラブルシューティング

sdk: コマンドが見つかりません

  • 現象
$ sudo sdk install java 11.0.5-opensudo sdk install java 11.0.5-open
sudo: sdk: コマンドが見つかりません
  • 原因
$ type sdk|head -2
sdk は関数です
sdk () 

sdkはコマンドでもシェルでもなく、組み込みの関数なのでsudoできない

  • 対処
    functionを引き継いで実行する
function sdkx { 
    sudo bash -c "$(declare -f sdk);sdk $*";
}

___sdkman_check_candidates_cache: コマンドが見つかりません

  • 現象
$ sudox sdk install java 11.0.5-open
environment: 行 40: ___sdkman_check_candidates_cache: コマンドが見つかりません
  • 原因
$ rg  ___sdkman_check_candidates_cache /opt/sdkman/
/opt/sdkman/src/sdkman-main.sh
55:             ___sdkman_check_candidates_cache "$SDKMAN_CANDIDATES_CACHE" || return 1

/opt/sdkman/src/sdkman-cache.sh
19:function ___sdkman_check_candidates_cache {

sdk()は呼べるけど、そこから呼んでいる___sdkman_check_candidates_cache()が呼べない。

  • 対処
    全関数を引き継いで実行する
function sdkx {
    sudo bash -c "$(`declare -F`);sdk $*"; 
}

引数リストが長すぎます

  • 現象
$ sdkx install java 11.0.5-open
bash: /usr/bin/sudo: 引数リストが長すぎます
  • 原因
    .bashrcに関数を定義してるから、declare -f funcが大量に実行されるから 制限に引っかかってしまう

  • 対処
    sdk関連の関数だけ抽出して引き継いで実行する

function sdkx {
    sudo bash -c "$(`declare -F|grep sdk`);sdk $*"
}

expected a proper numerical parameter

  • 現象
$ sdkx install java 11.0.5-open
curl: option --connect-timeout: expected a proper numerical parameter
curl: try 'curl --help' or 'curl --manual' for more information
curl: option --connect-timeout: expected a proper numerical parameter
curl: try 'curl --help' or 'curl --manual' for more information
==== INTERNET NOT REACHABLE! ===================================================

 Some functionality is disabled or only partially available.
 If this persists, please enable the offline mode:

   $ sdk offline

================================================================================

Invalid command: install

Usage: sdk <command> [candidate] [version]
       sdk offline <enable|disable>

   commands:
       install   or i    <candidate> [version] [local-path]
       uninstall or rm   <candidate> <version>
       list      or ls   [candidate]
       use       or u    <candidate> <version>
       default   or d    <candidate> [version]
       current   or c    [candidate]
       upgrade   or ug   [candidate]
       version   or v
       broadcast or b
       help      or h
       offline           [enable|disable]
       selfupdate        [force]
       update
       flush             <broadcast|archives|temp>

   candidate  :  the SDK to install: groovy, scala, grails, gradle, kotlin, etc.
                 use list command for comprehensive list of candidates
                 eg: $ sdk list
   version    :  where optional, defaults to latest stable if not provided
                 eg: $ sdk install groovy
   local-path :  optional path to an existing local installation
                 eg: $ sdk install groovy 2.4.13-local /opt/groovy-2.4.13


Stop! java is not a valid candidate.
  • 原因
orangeclover@ponkan ~ 
$ rg connect-timeout /opt/sdkman/
/opt/sdkman/src/sdkman-utils.sh
71:             curl --insecure --silent --location --connect-timeout ${sdkman_curl_connect_timeout} --max-time ${sdkman_curl_max_time} "$1"
73:             curl --silent --location --connect-timeout ${sdkman_curl_connect_timeout} --max-time ${sdkman_curl_max_time} "$1"

/opt/sdkman/bin/sdkman-init.sh
97:# set curl connect-timeout and max-time

環境変数が引き継がれていない

  • 対処
    sudo -E で環境変数sdk関連の関数だけ抽出して引き継いで実行する
function sdkx {
    sudo -E bash -c "$(`declare -F|grep sdk`);sdk $*";
}

expected a proper numerical parameter(エラーが変わらず)

  • 現象
orangeclover@ponkan ~ 
$ sdkx install java 11.0.5-open
curl: option --connect-timeout: expected a proper numerical parameter
curl: try 'curl --help' or 'curl --manual' for more information
curl: option --connect-timeout: expected a proper numerical parameter
curl: try 'curl --help' or 'curl --manual' for more information
==== INTERNET NOT REACHABLE! ===================================================

 Some functionality is disabled or only partially available.
 If this persists, please enable the offline mode:

   $ sdk offline

================================================================================
  • 原因
orangeclover@ponkan ~ 
$ rg sdkman_curl_connect_timeout /opt/sdkman
/opt/sdkman/etc/config
4:sdkman_curl_connect_timeout=7

/opt/sdkman/bin/sdkman-init.sh
98:if [[ -z "$sdkman_curl_connect_timeout" ]]; then sdkman_curl_connect_timeout=7; fi

/opt/sdkman/src/sdkman-utils.sh
71:             curl --insecure --silent --location --connect-timeout ${sdkman_curl_connect_timeout} --max-time ${sdkman_curl_max_time} "$1"
73:             curl --silent --location --connect-timeout ${sdkman_curl_connect_timeout} --max-time ${sdkman_curl_max_time} "$1"

sdkman_curl_connect_timeoutは環境変数じゃなくて、ロカール変数かグローバル変数か。

  • 対処
    変数をexport する?環境変数にはしたくないな。 組み込みコマンドのdeclareが実行できるんだからsource sdkman-init.shを実行すればいいのか。
function sdkx {
    sudo -E bash -c "source $SDKMAN_DIR/bin/sdkman-init.sh;sdk $*"
}

これでインストールできた!!

一般ユーザーで実行すると「許可がありません」

  • 現象
orangeclover@ponkan ~/
$ sdk list java
tee: /opt/sdkman/var/version: 許可がありません
tee: /opt/sdkman/var/broadcast_id: 許可がありません
tee: /opt/sdkman/var/broadcast: 許可がありません
  • 原因
    /opt/sdkman/var配下の書き込み処理がある

  • 対処

sudo chmod +g,o+w /opt/sdkman/var/

まとめ

  1. 以下でsdkmanのインストール
export SDKMAN_DIR="/opt/sdkman" && curl -s "https://get.sdkman.io" | sudo -E bash
  1. 以下の権限を変更する
sudo chmod +g,o+w /opt/sdkman/var/
  1. 以下でパッケージ管理を行う
function sdkx {
    sudo -E bash -c "source $SDKMAN_DIR/bin/sdkman-init.sh;sdk $*"
}
  • 使い分け
    install、uninstall、default、upgrade、selfupdateはsdkx
    use、current、version、helpはsdk

残課題

  • flush、offline、broadcastはsdkで一般ユーザーで実行できてしまう
    flushは/opt/sdkman/var配下のファイルを再作成するので、再度アクセス権変更が必要になる