diff --git a/build/scripts/help.info b/build/scripts/help.info index b99ec057ae45806378aedef2683ef606c29d0331..213989f61ccb579960c7003db6b72070273121da 100644 --- a/build/scripts/help.info +++ b/build/scripts/help.info @@ -7,4 +7,11 @@ (eg: --install-type=A200IA2, when your product is A200I A2 or A200I DK A2) --ce= Only iSula need to specify the container engine(eg: --ce=isula) MUST use with --install or --uninstall - --version Query Ascend-docker-runtime version \ No newline at end of file + --version Query Ascend-docker-runtime version + --install-scene= Installation scenario, only docker or containerd + (eg: --install-scene=docker, default: docker) + --config-file-path Specifies the path of the Docker or containerd configuration file + (eg: --config-file-path=/etc/containerd/config.toml). + If this parameter is not specified, the default configuration file path + of docker or containerd is used. For docker, the path is /etc/docker/daemon.json. + For containerd, the path is /etc/containerd/config.toml. \ No newline at end of file diff --git a/build/scripts/run_main.sh b/build/scripts/run_main.sh index cc9f80b0858697a83e49b6ca49749dbe4916878f..c5b0d43611576da6465e4cbeb2be5fd4021fb45a 100644 --- a/build/scripts/run_main.sh +++ b/build/scripts/run_main.sh @@ -22,6 +22,9 @@ start_script=${start_arg#*--} ASCEND_RUNTIME_CONFIG_DIR=/etc/ascend-docker-runtime.d DOCKER_CONFIG_DIR=/etc/docker +CONTAINERD_CONFIG_DIR=/etc/containerd +CONFIG_FILE_PATH="" +INSTALL_SCENE=docker INSTALL_PATH=/usr/local/Ascend/Ascend-Docker-Runtime readonly INSTALL_LOG_DIR=/var/log/ascend-docker-runtime readonly INSTALL_LOG_PATH=${INSTALL_LOG_DIR}/installer.log @@ -38,7 +41,7 @@ function check_log { check_sub_path ${INSTALL_LOG_DIR} if [[ $? != 0 ]]; then - echo "[ERROR]: ${INSTALL_LOG_DIR} is invalid" + echo "[ERROR] ${INSTALL_LOG_DIR} is invalid" exit 1 fi @@ -69,11 +72,11 @@ function log { function check_path { local path="$1" if [[ ${#path} -gt 1024 ]] || [[ ${#path} -le 0 ]]; then - echo "[ERROR]: parameter is invalid, length not in 1~1024" + echo "[ERROR] parameter is invalid, length not in 1~1024" return 1 fi if [[ -n $(echo "${path}" | grep -Ev '^[a-zA-Z0-9./_-]*$') ]]; then - echo "[ERROR]: parameter is invalid, char not all in 'a-zA-Z0-9./_-'" + echo "[ERROR] parameter is invalid, char not all in 'a-zA-Z0-9./_-'" return 1 fi path=$(realpath -m -s "${path}") @@ -108,16 +111,16 @@ function check_sub_path { function check_path_permission { local path="$1" if [[ -L "${path}" ]]; then - echo "[ERROR]: ${path} is soft link" + echo "[ERROR] ${path} is soft link" return 1 fi if [[ $(stat -c %u "${path}") != 0 ]] || [[ "$(stat -c %g ${path})" != 0 ]]; then - echo "[ERROR]: user or group of ${path} is not root" + echo "[ERROR] user or group of ${path} is not root" return 1 fi local permission=$(stat -c %A "${path}") if [[ $(echo "${permission}" | cut -c6) == w ]] || [[ $(echo "${permission}" | cut -c9) == w ]]; then - echo "[ERROR]: group or other of ${path} has write permisson" + echo "[ERROR] group or other of ${path} has write permisson" return 1 fi } @@ -145,16 +148,22 @@ Options: --ce= Only iSula need to specify the container engine(eg: --ce=isula) MUST use with --install or --uninstall --version Query Ascend-docker-runtime version + --install-scene= Installation scenario, only docker or containerd(eg: --install-scene=docker, default: docker) + --config-file-path Specifies the path of the Docker or containerd configuration file + (eg: --config-file-path=/etc/containerd/config.toml). + If this parameter is not specified, the default configuration file path + of docker or containerd is used. For docker, the path is /etc/docker/daemon.json. + For containerd, the path is /etc/containerd/config.toml. " } function check_platform { plat="$(uname -m)" if [[ $start_script =~ $plat ]]; then - echo "[INFO]: platform($plat) matched!" + echo "[INFO] platform($plat) matched!" return 0 else - echo "[ERROR]: platform($plat) mismatch for $start_script, please check it" + echo "[ERROR] platform($plat) mismatch for $start_script, please check it" return 1 fi } @@ -171,6 +180,8 @@ function save_install_args() { echo -e "a200=${a200}" echo -e "a200isoc=${a200isoc}" echo -e "a200ia2=${a200ia2}" + echo -e "install-scene=${INSTALL_SCENE}" + echo -e "config-file-path=${CONFIG_FILE_PATH}" } > "${INSTALL_PATH}"/ascend_docker_runtime_install.info chmod 640 ${INSTALL_PATH}/ascend_docker_runtime_install.info } @@ -178,26 +189,26 @@ function save_install_args() { function add_so() { check_path "/etc/os-release" if [[ $? != 0 ]]; then - echo "[ERROR]: /etc/os-release is invalid" + echo "[ERROR] /etc/os-release is invalid" return 1 fi if grep -qi "ubuntu" "/etc/os-release"; then - echo "[info]: os is Ubuntu" + echo "[info] os is Ubuntu" echo -e "\n/usr/lib/aarch64-linux-gnu/libcrypto.so.1.1" >> ${ASCEND_RUNTIME_CONFIG_DIR}/base.list echo "/usr/lib/aarch64-linux-gnu/libyaml-0.so.2" >> ${ASCEND_RUNTIME_CONFIG_DIR}/base.list elif grep -qi "euler" "/etc/os-release"; then - echo "[info]: os is Euler/OpenEuler" + echo "[info] os is Euler/OpenEuler" echo -e "\n/usr/lib64/libcrypto.so.1.1" >> ${ASCEND_RUNTIME_CONFIG_DIR}/base.list echo "/usr/lib64/libyaml-0.so.2" >> ${ASCEND_RUNTIME_CONFIG_DIR}/base.list else - echo "[ERROR]: not support this os" + echo "[ERROR] not support this os" return 1 fi } function install() { - echo "[INFO]: installing ascend docker runtime" + echo "[INFO] installing ascend docker runtime" check_platform if [[ $? != 0 ]]; then log "[ERROR]" "install failed, run package and os not matched in arch" @@ -271,38 +282,66 @@ function install() fi chmod 440 ${ASCEND_RUNTIME_CONFIG_DIR}/base.list - echo "[INFO]: install executable files success" - - check_path ${DOCKER_CONFIG_DIR}/daemon.json - if [[ $? != 0 ]]; then - log "[ERROR]" "install failed, ${DOCKER_CONFIG_DIR}/daemon.json is invalid" - exit 1 + echo "[INFO] install executable files success" + + if [[ ${CONFIG_FILE_PATH} == "" ]]; then + if [[ "${INSTALL_SCENE}" == "docker" ]]; then + echo "[INFO] install scene is 'docker'." + check_path ${DOCKER_CONFIG_DIR}/daemon.json + if [[ $? != 0 ]]; then + log "[ERROR]" "install failed, ${DOCKER_CONFIG_DIR}/daemon.json is invalid" + exit 1 + fi + [[ ! -d ${DOCKER_CONFIG_DIR} ]] && mkdir -p -m 750 ${DOCKER_CONFIG_DIR} + + SRC="${DOCKER_CONFIG_DIR}/daemon.json.${PPID}" + DST="${DOCKER_CONFIG_DIR}/daemon.json" + elif [[ "${INSTALL_SCENE}" == "containerd" ]]; then + echo "[INFO] install scene is 'containerd'." + check_path ${CONTAINERD_CONFIG_DIR}/config.toml + if [[ $? != 0 ]]; then + log "[ERROR]" "install failed, ${CONTAINERD_CONFIG_DIR}/config.toml is invalid" + exit 1 + fi + [[ ! -d ${CONTAINERD_CONFIG_DIR} ]] && mkdir -p -m 750 ${CONTAINERD_CONFIG_DIR} + + SRC="${CONTAINERD_CONFIG_DIR}/config.toml.${PPID}" + DST="${CONTAINERD_CONFIG_DIR}/config.toml" + if [ ! -e ${DST} ]; then + echo "[INFO] containerd config file does not exist, default ${DST} will be created" + containerd config default > ${DST} + fi + else + log "[ERROR]" "install failed, invalid value '${INSTALL_SCENE}' of 'install-scene' " + exit 1 + fi + else + SRC="${CONFIG_FILE_PATH}.${PPID}" + DST="${CONFIG_FILE_PATH}" fi - [[ ! -d ${DOCKER_CONFIG_DIR} ]] && mkdir -p -m 750 ${DOCKER_CONFIG_DIR} - SRC="${DOCKER_CONFIG_DIR}/daemon.json.${PPID}" - DST="${DOCKER_CONFIG_DIR}/daemon.json" + + CGROUP_INFO=$(stat -fc %T /sys/fs/cgroup/) # exit when return code is not 0, if use 'set -e' - ./ascend-docker-plugin-install-helper add ${DST} ${SRC} ${INSTALL_PATH}/ascend-docker-runtime ${RESERVEDEFAULT} > /dev/null + ./ascend-docker-plugin-install-helper add ${DST} ${SRC} ${INSTALL_PATH}/ascend-docker-runtime ${RESERVEDEFAULT} ${INSTALL_SCENE} ${CGROUP_INFO} > /dev/null if [[ $? != 0 ]]; then - log "[ERROR]" "install failed, './ascend-docker-plugin-install-helper add ${DST} ${SRC} ${INSTALL_PATH}/ascend-docker-runtime ${RESERVEDEFAULT}' return non-zero" + log "[ERROR]" "install failed, './ascend-docker-plugin-install-helper add ${DST} ${SRC} ${INSTALL_PATH}/ascend-docker-runtime ${RESERVEDEFAULT} ${INSTALL_SCENE} ${CGROUP_INFO}' return non-zero" exit 1 fi - mv -f ${SRC} ${DST} log "[INFO]" "${DST} modify success" chmod 600 ${DST} save_install_args - echo "[INFO]: Ascend Docker Runtime has been installed in: ${INSTALL_PATH}" - echo "[INFO]: The version of Ascend Docker Runtime is: ${PACKAGE_VERSION}" - echo '[INFO]: please reboot daemon and container engine to take effect' + echo "[INFO] Ascend Docker Runtime has been installed in: ${INSTALL_PATH}" + echo "[INFO] The version of Ascend Docker Runtime is: ${PACKAGE_VERSION}" + echo '[INFO] please reboot daemon and container engine to take effect' log "[INFO]" "Ascend Docker Runtime install success" } function uninstall() { - echo "[INFO]: Uninstalling ascend docker runtime ${PACKAGE_VERSION}" + echo "[INFO] uninstalling ascend docker runtime ${PACKAGE_VERSION}" if [ ! -d "${INSTALL_PATH}" ]; then log "[WARNING]" "uninstall skipping, the specified install path does not exist" @@ -315,9 +354,9 @@ function uninstall() exit 1 fi - "${INSTALL_PATH}"/script/uninstall.sh ${ISULA} + "${INSTALL_PATH}"/script/uninstall.sh ${ISULA} ${INSTALL_SCENE} ${CONFIG_FILE_PATH} if [[ $? != 0 ]]; then - log "[ERROR]" "uninstall failed, '${INSTALL_PATH}/script/uninstall.sh ${ISULA}' return non-zero" + log "[ERROR]" "uninstall failed, '${INSTALL_PATH}/script/uninstall.sh ${ISULA} ${INSTALL_SCENE} ${CONFIG_FILE_PATH}' return non-zero" exit 1 fi @@ -326,7 +365,7 @@ function uninstall() function upgrade() { - echo "[INFO]: upgrading ascend docker runtime" + echo "[INFO] upgrading ascend docker runtime" check_platform if [[ $? != 0 ]]; then log "[ERROR]" "upgrade failed, run package and os not matched in arch" @@ -401,12 +440,13 @@ function upgrade() fi chmod 440 ${ASCEND_RUNTIME_CONFIG_DIR}/base.list - echo "[INFO]: Ascend Docker Runtime has been installed in: ${INSTALL_PATH}" - echo '[INFO]: upgrade ascend docker runtime success' - echo "[INFO]: The version of Ascend Docker Runtime is: v${PACKAGE_VERSION}" + echo "[INFO] Ascend Docker Runtime has been installed in: ${INSTALL_PATH}" + echo '[INFO] upgrade ascend docker runtime success' + echo "[INFO] The version of Ascend Docker Runtime is: v${PACKAGE_VERSION}" log "[INFO]" "Ascend Docker Runtime upgrade success" } - +INSTALL_SCENE_FLAG=n +CONFIG_FILE_PATH_FLAG=n INSTALL_FLAG=n INSTALL_PATH_FLAG=n UNINSTALL_FLAG=n @@ -431,6 +471,37 @@ fi while true do case "$3" in + --install-scene=*) + if [ "${INSTALL_SCENE_FLAG}" == "y" ]; then + log "[ERROR]" "failed, '--install-scene' Repeat parameter!" + exit 1 + fi + need_help=n + INSTALL_SCENE_FLAG=y + if [ "$3" == "--install-scene=docker" ]; then + INSTALL_SCENE=docker + elif [ "$3" == "--install-scene=containerd" ]; then + INSTALL_SCENE=containerd + else + log "[ERROR]" "failed, please check the parameter of --install-scene=" + exit 1 + fi + shift + ;; + --config-file-path=*) + if [ "${CONFIG_FILE_PATH_FLAG}" == "y" ]; then + log "[ERROR]" "failed, '--config-file-path' Repeat parameter!" + exit 1 + fi + need_help=n + CONFIG_FILE_PATH_FLAG=y + CONFIG_FILE_PATH=$(echo $3 | cut -d"=" -f2) + if [[ ! -e "$CONFIG_FILE_PATH" ]]; then + log "[ERROR]" "failed, file '$CONFIG_FILE_PATH' does not exist." + exit 1 + fi + shift + ;; --install) if [ "${INSTALL_FLAG}" == "y" ]; then log "[ERROR]" "install failed, '--install' Repeat parameter!" @@ -480,7 +551,7 @@ do ISULA=isula RESERVEDEFAULT=yes else - log "[ERROR]" "failed, Please check the parameter of --ce=" + log "[ERROR]" "failed, please check the parameter of --ce=" exit 1 fi shift @@ -504,7 +575,7 @@ do elif [ "$3" == "--install-type=A200IA2" ]; then a200ia2=y else - log "[ERROR]" "failed, Please check the parameter of --install-type=" + log "[ERROR]" "failed, please check the parameter of --install-type=" exit 1 fi shift @@ -517,7 +588,7 @@ do ;; *) if [ "x$3" != "x" ]; then - log "[ERROR]" "failed, Unsupported parameters: $3" + log "[ERROR]" "failed, unsupported parameters: $3" print_help exit 1 fi diff --git a/build/scripts/uninstall.sh b/build/scripts/uninstall.sh index e6b113cb73172d707acad844ebf84bd84d6b0bb3..2b55cb3744af59513ab8d0c78ad1b804a618bd0f 100644 --- a/build/scripts/uninstall.sh +++ b/build/scripts/uninstall.sh @@ -29,7 +29,7 @@ function check_log { check_sub_path ${INSTALL_LOG_DIR} if [[ $? != 0 ]]; then - echo "[ERROR]: ${INSTALL_LOG_DIR} is invalid" + echo "[ERROR] ${INSTALL_LOG_DIR} is invalid" exit 1 fi @@ -60,11 +60,11 @@ function log { function check_path { local path="$1" if [[ ${#path} -gt 1024 ]] || [[ ${#path} -le 0 ]]; then - echo "[ERROR]: parameter is invalid, length not in 1~1024" + echo "[ERROR] parameter is invalid, length not in 1~1024" return 1 fi if [[ -n $(echo "${path}" | grep -Ev '^[a-zA-Z0-9./_-]*$') ]]; then - echo "[ERROR]: parameter is invalid, char not all in 'a-zA-Z0-9./_-'" + echo "[ERROR] parameter is invalid, char not all in 'a-zA-Z0-9./_-'" return 1 fi path=$(realpath -m -s "${path}") @@ -99,16 +99,16 @@ function check_sub_path { function check_path_permission { local path="$1" if [[ -L "${path}" ]]; then - echo "[ERROR]: ${path} is soft link" + echo "[ERROR] ${path} is soft link" return 1 fi if [[ $(stat -c %u "${path}") != 0 ]] || [[ "$(stat -c %g ${path})" != 0 ]]; then - echo "[ERROR]: user or group of ${path} is not root" + echo "[ERROR] user or group of ${path} is not root" return 1 fi local permission=$(stat -c %A "${path}") if [[ $(echo "${permission}" | cut -c6) == w ]] || [[ $(echo "${permission}" | cut -c9) == w ]]; then - echo "[ERROR]: group or other of ${path} has write permisson" + echo "[ERROR] group or other of ${path} has write permisson" return 1 fi } @@ -123,17 +123,25 @@ fi ROOT=$(cd $(dirname $0); pwd)/.. RESERVEDEFAULT=no -if [ "$*" == "isula" ] ; then +if [ "$1" == "isula" ] ; then DST='/etc/isulad/daemon.json' - echo "[INFO]: You will recover iSula's daemon" + echo "[INFO] You will recover iSula's daemon" RESERVEDEFAULT=yes else DST='/etc/docker/daemon.json' - echo "[INFO]: You will recover Docker's daemon" + echo "[INFO] You will recover Docker's daemon" +fi +INSTALL_SCENE=$2 +if [ "${INSTALL_SCENE}" == "containerd" ] ; then + DST='/etc/containerd/config.toml' +elif [ "${INSTALL_SCENE}" == "" ] ; then + INSTALL_SCENE=docker +fi +CONFIG_FILE_PATH=$3 +if [[ ${CONFIG_FILE_PATH} != "" ]]; then + DST=${CONFIG_FILE_PATH} fi - SRC="${DST}.${PPID}" - if [ ! -f "${DST}" ]; then log "[WARNING]" "uninstall skipping, ${DST} does not exist" exit 0 @@ -144,11 +152,11 @@ if [[ $? != 0 ]]; then log "[ERROR]" "uninstall failed, ${DST} is invalid" exit 1 fi - +CGROUP_INFO=$(stat -fc %T /sys/fs/cgroup/) # exit when return code is not 0, if use 'set -e' -${ROOT}/ascend-docker-plugin-install-helper rm ${DST} ${SRC} ${RESERVEDEFAULT} > /dev/null +${ROOT}/ascend-docker-plugin-install-helper rm ${DST} ${SRC} ${RESERVEDEFAULT} ${INSTALL_SCENE} ${CGROUP_INFO} > /dev/null if [[ $? != 0 ]]; then - log "[ERROR]" "uninstall failed, '${ROOT}/ascend-docker-plugin-install-helper rm ${DST} ${SRC} ${RESERVEDEFAULT}' return non-zero" + log "[ERROR]" "uninstall failed, '${ROOT}/ascend-docker-plugin-install-helper rm ${DST} ${SRC} ${RESERVEDEFAULT} ${INSTALL_SCENE} ${CGROUP_INFO}' return non-zero" exit 1 fi @@ -172,6 +180,6 @@ fi if test -d ${INSTALL_ROOT_PATH} then rm -rf ${INSTALL_ROOT_PATH} - echo "[INFO]: delete ${INSTALL_ROOT_PATH} successful" + echo "[INFO] delete ${INSTALL_ROOT_PATH} successful" fi log "[INFO]" "uninstall.sh exec success" diff --git a/go.mod b/go.mod index ffaf2ab67c2db0fa7c93f4439e15ddf1dd5959d0..354d854f8163127124a136ad456c464bb4d7d658 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/agiledragon/gomonkey/v2 v2.8.0 github.com/containerd/containerd v1.6.24 github.com/opencontainers/runtime-spec v1.0.3-0.20220718201635-a8106e99982b + github.com/pelletier/go-toml v1.9.5 github.com/prashantv/gostub v0.0.0-00010101000000-000000000000 github.com/stretchr/testify v1.8.2 huawei.com/npu-exporter/v5 v5.0.0 @@ -17,11 +18,14 @@ require ( github.com/containerd/cgroups v1.0.4 // indirect github.com/containerd/continuity v0.3.0 // indirect github.com/containerd/ttrpc v1.1.2 // indirect + github.com/containerd/typeurl v1.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect + github.com/imdario/mergo v0.3.12 // indirect github.com/klauspost/compress v1.11.13 // indirect github.com/moby/sys/mountinfo v0.6.2 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect diff --git a/go.sum b/go.sum index 3d095d5425d143212770d3eb1d8220be92afd2e3..f4f96aea0aedd74ad2bb0ce80e24f8f2c31cd4df 100644 --- a/go.sum +++ b/go.sum @@ -191,6 +191,7 @@ github.com/containerd/ttrpc v1.1.2/go.mod h1:XX4ZTnoOId4HklF4edwc4DcqskFZuvXB1Ev github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= github.com/containerd/typeurl v0.0.0-20190911142611-5eb25027c9fd/go.mod h1:GeKYzf2pQcqv7tJ0AoCuuhtnqhva5LNU3U+OyKxxJpk= github.com/containerd/typeurl v1.0.1/go.mod h1:TB1hUtrpaiO88KEK56ijojHS1+NeF0izUACaJW2mdXg= +github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY7aY= github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/containerd/zfs v0.0.0-20200918131355-0a33824f23a2/go.mod h1:8IgZOBdv8fAgXddBT4dBXJPtxyRsejFIpXoklgxgEjw= github.com/containerd/zfs v0.0.0-20210301145711-11e8f1707f62/go.mod h1:A9zfAbMlQwE+/is6hi0Xw8ktpL+6glmqZYtevJgaB8Y= @@ -245,6 +246,7 @@ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= +github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c h1:+pKlWGMw7gf6bQ+oDZB4KHQFypsfjYlq/C4rfL7D3g8= github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c/go.mod h1:Uw6UezgYA44ePAFQYUehOuCzmy5zmg/+nl2ZfMWGkpA= github.com/docker/go-metrics v0.0.0-20180209012529-399ea8c73916/go.mod h1:/u0gXw0Gay3ceNrsHubL3BtdOL2fHf93USgMTe0W5dI= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= @@ -403,6 +405,7 @@ github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/imdario/mergo v0.3.10/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA= @@ -528,6 +531,8 @@ github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3 github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= +github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= +github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1018,6 +1023,7 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/install/main.go b/install/main.go index b14f1f2c296b7cf9383ab5d0ff0203a98c33dda7..571c6924e42114734d6ae40893a3a70ee163b65f 100644 --- a/install/main.go +++ b/install/main.go @@ -17,17 +17,15 @@ package main import ( "context" - "encoding/json" "flag" "fmt" - "io/ioutil" "log" "os" - "path/filepath" "strings" "huawei.com/npu-exporter/v5/common-utils/hwlog" + "ascend-docker-runtime/install/process" "ascend-docker-runtime/mindxcheckutils" ) @@ -51,17 +49,9 @@ const noDefaultTemplate = `{ }` const ( - actionPosition = 0 - srcFilePosition = 1 - destFilePosition = 2 - runtimeFilePosition = 3 - rmCommandLength = 4 - addCommandLength = 5 - addCommand = "add" - maxCommandLength = 65535 - logPath = "/var/log/ascend-docker-runtime/install-helper-run.log" - rmCommand = "rm" - maxFileSize = 1024 * 1024 * 10 + maxCommandLength = 65535 + logPath = "/var/log/ascend-docker-runtime/install-helper-run.log" + installSceneIndexFromEnd = 2 ) var reserveDefaultRuntime = false @@ -83,7 +73,31 @@ func main() { log.Fatalf("command error, please check %s for detail", logPath) } - err, behavior := process() + const helpMessage = "\tadd " + + " \n" + + "\t rm " + + " \n" + "\t -h help command" + helpFlag := flag.Bool("h", false, helpMessage) + flag.Parse() + if *helpFlag { + _, err := fmt.Println(helpMessage) + log.Fatalf("need help, error: %v", err) + } + command := flag.Args() + if len(command) == 0 { + log.Fatalf("error param") + } + var behavior string + hwlog.RunLog.Infof("command: %v", command) + installScene := command[len(command)-installSceneIndexFromEnd] + if installScene == process.InstallSceneDocker { + behavior, err = process.DockerProcess(command) + } else if installScene == process.InstallSceneContainerd { + behavior, err = process.ContainerdProcess(command) + } else { + hwlog.RunLog.Errorf("error param: %v", command[len(command)-1]) + log.Fatalf("error param: %v", command[len(command)-1]) + } if err != nil { hwlog.RunLog.Errorf("%v run script failed: %v", logPrefixWords, err) log.Fatal(fmt.Errorf("error in installation")) @@ -109,195 +123,3 @@ func initLogModule(ctx context.Context) error { } return nil } - -func checkParamAndGetBehavior(action string, command []string) (bool, string) { - correctParam, behavior := false, "" - if action == addCommand && len(command) == addCommandLength { - correctParam = true - behavior = "install" - } - if action == rmCommand && len(command) == rmCommandLength { - correctParam = true - behavior = "uninstall" - } - return correctParam, behavior -} - -func process() (error, string) { - const helpMessage = "\tadd \n" + - "\t rm \n" + - "\t -h help command" - helpFlag := flag.Bool("h", false, helpMessage) - flag.Parse() - if *helpFlag { - _, err := fmt.Println(helpMessage) - return err, "" - } - command := flag.Args() - if len(command) == 0 { - return fmt.Errorf("error param"), "" - } - - action := command[actionPosition] - correctParam, behavior := checkParamAndGetBehavior(action, command) - if !correctParam { - return fmt.Errorf("error param"), "" - } - - srcFilePath := command[srcFilePosition] - if _, err := os.Stat(srcFilePath); os.IsNotExist(err) { - if _, err := mindxcheckutils.RealDirChecker(filepath.Dir(srcFilePath), true, false); err != nil { - return err, behavior - } - } else { - if _, err := mindxcheckutils.RealFileChecker(srcFilePath, true, false, mindxcheckutils.DefaultSize); err != nil { - return err, behavior - } - } - - destFilePath := command[destFilePosition] - if _, err := mindxcheckutils.RealDirChecker(filepath.Dir(destFilePath), true, false); err != nil { - return err, behavior - } - runtimeFilePath := "" - if len(command) == addCommandLength { - runtimeFilePath = command[runtimeFilePosition] - if _, err := mindxcheckutils.RealFileChecker(runtimeFilePath, true, false, mindxcheckutils.DefaultSize); err != nil { - return err, behavior - } - } - - setReserveDefaultRuntime(command) - - // check file permission - writeContent, err := createJsonString(srcFilePath, runtimeFilePath, action) - if err != nil { - return err, behavior - } - return writeJson(destFilePath, writeContent), behavior -} - -func createJsonString(srcFilePath, runtimeFilePath, action string) ([]byte, error) { - var writeContent []byte - if _, err := os.Stat(srcFilePath); err == nil { - daemon, err := modifyDaemon(srcFilePath, runtimeFilePath, action) - if err != nil { - return nil, err - } - writeContent, err = json.MarshalIndent(daemon, "", " ") - if err != nil { - return nil, err - } - } else if os.IsNotExist(err) { - // not existed - if !reserveDefaultRuntime { - writeContent = []byte(fmt.Sprintf(commonTemplate, runtimeFilePath)) - } else { - writeContent = []byte(fmt.Sprintf(noDefaultTemplate, runtimeFilePath)) - } - } else { - return nil, err - } - return writeContent, nil -} - -func writeJson(destFilePath string, writeContent []byte) error { - if _, err := os.Stat(destFilePath); os.IsNotExist(err) { - const perm = 0600 - file, err := os.OpenFile(destFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm) - if err != nil { - return fmt.Errorf("create target file failed") - } - _, err = file.Write(writeContent) - if err != nil { - closeErr := file.Close() - return fmt.Errorf("write target file failed with close err %v", closeErr) - } - err = file.Close() - if err != nil { - return fmt.Errorf("close target file failed") - } - return nil - } else { - return fmt.Errorf("target file already existed") - } -} - -func modifyDaemon(srcFilePath, runtimeFilePath, action string) (map[string]interface{}, error) { - // existed... - daemon, err := loadOriginJson(srcFilePath) - if err != nil { - return nil, err - } - - if _, ok := daemon["runtimes"]; !ok && action == addCommand { - daemon["runtimes"] = map[string]interface{}{} - } - runtimeValue := daemon["runtimes"] - runtimeConfig, runtimeConfigOk := runtimeValue.(map[string]interface{}) - if !runtimeConfigOk && action == addCommand { - return nil, fmt.Errorf("extract runtime failed") - } - if action == addCommand { - if _, ok := runtimeConfig["ascend"]; !ok { - runtimeConfig["ascend"] = map[string]interface{}{} - } - ascendConfig, ok := runtimeConfig["ascend"].(map[string]interface{}) - if !ok { - return nil, fmt.Errorf("extract ascend failed") - } - ascendConfig["path"] = runtimeFilePath - if _, ok := ascendConfig["runtimeArgs"]; !ok { - ascendConfig["runtimeArgs"] = []string{} - } - if !reserveDefaultRuntime { - daemon["default-runtime"] = "ascend" - } - } else if action == rmCommand { - if runtimeConfigOk { - delete(runtimeConfig, "ascend") - } - if value, ok := daemon["default-runtime"]; ok && value == "ascend" { - delete(daemon, "default-runtime") - } - } else { - return nil, fmt.Errorf("param error") - } - return daemon, nil -} - -func loadOriginJson(srcFilePath string) (map[string]interface{}, error) { - if fileInfo, err := os.Stat(srcFilePath); err != nil { - return nil, err - } else if fileInfo.Size() > maxFileSize { - return nil, fmt.Errorf("file size too large") - } - - file, err := os.Open(srcFilePath) - if err != nil { - return nil, fmt.Errorf("open daemon.json failed") - } - content, err := ioutil.ReadAll(file) - if err != nil { - closeErr := file.Close() - return nil, fmt.Errorf("read daemon.json failed, close file err is %v", closeErr) - } - err = file.Close() - if err != nil { - return nil, fmt.Errorf("close daemon.json failed") - } - - var daemon map[string]interface{} - err = json.Unmarshal(content, &daemon) - if err != nil { - return nil, fmt.Errorf("load daemon.json failed") - } - return daemon, nil -} - -func setReserveDefaultRuntime(command []string) { - reserveCmdPostion := len(command) - 1 - if command[reserveCmdPostion] == "yes" { - reserveDefaultRuntime = true - } -} diff --git a/install/process/common.go b/install/process/common.go new file mode 100644 index 0000000000000000000000000000000000000000..0cff12a3f325bff62a5acb347ac661b40335bfec --- /dev/null +++ b/install/process/common.go @@ -0,0 +1,28 @@ +/* Copyright(C) 2024. Huawei Technologies Co.,Ltd. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +func checkParamAndGetBehavior(action string, command []string) (bool, string) { + correctParam, behavior := false, "" + if action == addCommand && len(command) == addCommandLength { + correctParam = true + behavior = "install" + } + if action == rmCommand && len(command) == rmCommandLength { + correctParam = true + behavior = "uninstall" + } + return correctParam, behavior +} diff --git a/install/process/constant.go b/install/process/constant.go new file mode 100644 index 0000000000000000000000000000000000000000..a5a461bd29da930f3791e3845dcc8b7d2f1d588b --- /dev/null +++ b/install/process/constant.go @@ -0,0 +1,76 @@ +/* Copyright(C) 2024. Huawei Technologies Co.,Ltd. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +const commonTemplate = `{ + "runtimes": { + "ascend": { + "path": "%s", + "runtimeArgs": [] + } + }, + "default-runtime": "ascend" +}` + +const noDefaultTemplate = `{ + "runtimes": { + "ascend": { + "path": "%s", + "runtimeArgs": [] + } + } +}` + +const ( + actionPosition = 0 + srcFilePosition = 1 + destFilePosition = 2 + runtimeFilePosition = 3 + rmCommandLength = 6 + addCommandLength = 7 + maxFileSize = 1024 * 1024 * 10 + cgroupInfoIndexFromEnd = 1 +) + +const ( + addCommand = "add" + rmCommand = "rm" + defaultRuntimeKey = "default-runtime" + // InstallSceneDocker is a 'docker' string of scene + InstallSceneDocker = "docker" + // InstallSceneContainerd is a 'containerd' string of scene + InstallSceneContainerd = "containerd" + v1NeedChangeKeyRuntime = "runtime" + v1NeedChangeKeyRuntimeType = "runtime_type" + v1RuntimeType = "io.containerd.runtime.v1.linux" + v1DefaultRuncRuntimeType = "io.containerd.runc.v2" + defaultRuntimeValue = "runc" + v1RuntimeTypeFisrtLevelPlugin = "io.containerd.grpc.v1.cri" + containerdKey = "containerd" + runtimesKey = "runtimes" + runcKey = "runc" + runcOptionsKey = "options" + binaryNameKey = "BinaryName" + cgroupV2InfoStr = "cgroup2fs" +) + +const ( + notFindPluginLogStr = "can not find plugin %v, plugins is: %+v" + notFindOluginErrorStr = "can not find plugin: %v" + convertConfigFailLogStr = "can not convert config %v, config is: %+v" + convertConfigFailErrorStr = "can not convert config %v, config is: %+v" + convertTreeFailLogStr = "failed to convert map to tree, error: %v" + getMapFaileLogStr = "failed to get map, key: %v, error: %v" +) diff --git a/install/process/containerd_process.go b/install/process/containerd_process.go new file mode 100644 index 0000000000000000000000000000000000000000..c471eb41c7056455c309e2f2a7ffca67ef0ddca0 --- /dev/null +++ b/install/process/containerd_process.go @@ -0,0 +1,243 @@ +/* Copyright(C) 2024. Huawei Technologies Co.,Ltd. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package process + +import ( + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/containerd/containerd/services/server/config" + "github.com/pelletier/go-toml" + "huawei.com/npu-exporter/v5/common-utils/hwlog" + + "ascend-docker-runtime/mindxcheckutils" +) + +// ContainerdProcess modifies the containerd configuration file when installing or uninstalling the containerd scenario. +func ContainerdProcess(command []string) (string, error) { + action := command[actionPosition] + correctParam, behavior := checkParamAndGetBehavior(action, command) + if !correctParam { + return "", fmt.Errorf("error param") + } + srcFilePath := command[srcFilePosition] + if _, err := os.Stat(srcFilePath); os.IsNotExist(err) { + if _, err := mindxcheckutils.RealDirChecker(filepath.Dir(srcFilePath), true, false); err != nil { + hwlog.RunLog.Errorf("check failed, error: %v", err) + return behavior, err + } + } else { + if _, err := mindxcheckutils.RealFileChecker(srcFilePath, true, false, mindxcheckutils.DefaultSize); err != nil { + hwlog.RunLog.Errorf("check failed, error: %v", err) + return behavior, err + } + } + destFilePath := command[destFilePosition] + if _, err := mindxcheckutils.RealDirChecker(filepath.Dir(destFilePath), true, false); err != nil { + return behavior, err + } + runtimeFilePath := "" + if len(command) == addCommandLength { + runtimeFilePath = command[runtimeFilePosition] + if _, err := mindxcheckutils.RealFileChecker(runtimeFilePath, true, false, mindxcheckutils.DefaultSize); err != nil { + hwlog.RunLog.Errorf("failed to check, error: %v", err) + return behavior, err + } + } + cgroupInfo := command[len(command)-cgroupInfoIndexFromEnd] + err := editContainerdConfig(srcFilePath, runtimeFilePath, destFilePath, action, cgroupInfo) + if err != nil { + hwlog.RunLog.Errorf("failed to edit containerd config, err: %v", err) + return behavior, err + } + return behavior, nil +} + +func editContainerdConfig(srcFilePath, runtimeFilePath, destFilePath, action, cgroupInfo string) error { + cfg := config.Config{} + if err := config.LoadConfig(srcFilePath, &cfg); err != nil { + hwlog.RunLog.Errorf("failed to load configuration file: %v", err) + return err + } + if strings.Contains(cgroupInfo, cgroupV2InfoStr) { + hwlog.RunLog.Info("it is cgroup v2") + binaryName := "" + if action == addCommand { + binaryName = runtimeFilePath + } + err := changeCgroupV2BinaryNameConfig(&cfg, binaryName) + if err != nil { + hwlog.RunLog.Errorf("failed to change cgroup v2 config, error: %v", err) + return err + } + } else { + hwlog.RunLog.Info("it is cgroup v1") + runtimeValue := defaultRuntimeValue + runtimeType := v1DefaultRuncRuntimeType + if action == addCommand { + runtimeValue = runtimeFilePath + runtimeType = v1RuntimeType + } + err := changeCgroupV1Config(&cfg, runtimeValue, runtimeType) + if err != nil { + hwlog.RunLog.Errorf("failed to change cgroup v1 config, error: %v", err) + return err + } + } + err := writeContainerdConfigToFile(cfg, destFilePath) + if err != nil { + hwlog.RunLog.Errorf("failed to write configuration file: %v", err) + return err + } + return nil +} + +func changeCgroupV2BinaryNameConfig(cfg *config.Config, binaryName string) error { + value, ok := cfg.Plugins[v1RuntimeTypeFisrtLevelPlugin] + if !ok { + hwlog.RunLog.Errorf(notFindPluginLogStr, v1RuntimeTypeFisrtLevelPlugin, cfg.Plugins) + return fmt.Errorf(notFindOluginErrorStr, v1RuntimeTypeFisrtLevelPlugin) + } + valueMap := value.ToMap() + containerdConfig := valueMap[containerdKey] + runtimesConfig, err := getMap(containerdConfig, runtimesKey) + if err != nil { + hwlog.RunLog.Errorf(getMapFaileLogStr, runtimesKey, err) + return err + } + runcConfig, err := getMap(runtimesConfig, runcKey) + if err != nil { + hwlog.RunLog.Errorf(getMapFaileLogStr, runcKey, err) + return err + } + runcOptionsConfig, err := getMap(runcConfig, runcOptionsKey) + if err != nil { + hwlog.RunLog.Errorf(getMapFaileLogStr, runcOptionsKey, err) + return err + } + runcOptionsConfigMap, ok := runcOptionsConfig.(map[string]interface{}) + if !ok { + hwlog.RunLog.Errorf(convertConfigFailLogStr, runcOptionsKey, runcOptionsConfig) + return fmt.Errorf(convertConfigFailErrorStr, runcOptionsKey, runcOptionsConfig) + } + runcOptionsConfigMap[binaryNameKey] = binaryName + newTree, err := toml.TreeFromMap(valueMap) + if err != nil { + hwlog.RunLog.Errorf(convertTreeFailLogStr, err) + return err + } + cfg.Plugins[v1RuntimeTypeFisrtLevelPlugin] = *newTree + return nil +} + +func changeCgroupV1Config(cfg *config.Config, runtimeValue, runtimeType string) error { + err := changeCgroupV1RuntimeConfig(cfg, runtimeValue) + if err != nil { + hwlog.RunLog.Errorf("failed to change cgroup V1 runtime config, error: %v", err) + return err + } + return changeCgroupV1RuntimeTypeConfig(cfg, runtimeType) +} + +func changeCgroupV1RuntimeConfig(cfg *config.Config, runtimeValue string) error { + value, ok := cfg.Plugins[v1RuntimeType] + if !ok { + hwlog.RunLog.Errorf(notFindPluginLogStr, v1RuntimeType, cfg.Plugins) + return fmt.Errorf(notFindOluginErrorStr, v1RuntimeType) + } + valueMap := value.ToMap() + valueMap[v1NeedChangeKeyRuntime] = runtimeValue + newTree, err := toml.TreeFromMap(valueMap) + if err != nil { + hwlog.RunLog.Errorf(convertTreeFailLogStr, err) + return err + } + cfg.Plugins[v1RuntimeType] = *newTree + return nil +} + +func changeCgroupV1RuntimeTypeConfig(cfg *config.Config, runtimeType string) error { + value, ok := cfg.Plugins[v1RuntimeTypeFisrtLevelPlugin] + if !ok { + hwlog.RunLog.Errorf(notFindPluginLogStr, v1RuntimeTypeFisrtLevelPlugin, cfg.Plugins) + return fmt.Errorf(notFindOluginErrorStr, v1RuntimeTypeFisrtLevelPlugin) + } + valueMap := value.ToMap() + containerdConfig := valueMap[containerdKey] + runtimesConfig, err := getMap(containerdConfig, runtimesKey) + if err != nil { + hwlog.RunLog.Errorf(getMapFaileLogStr, runtimesKey, err) + return err + } + runcConfig, err := getMap(runtimesConfig, runcKey) + if err != nil { + hwlog.RunLog.Errorf(getMapFaileLogStr, runcKey, err) + return err + } + runcConfigMap, ok := runcConfig.(map[string]interface{}) + if !ok { + hwlog.RunLog.Errorf(convertConfigFailLogStr, runcKey, runcConfig) + return fmt.Errorf(convertConfigFailErrorStr, runcKey, runcConfig) + } + runcConfigMap[v1NeedChangeKeyRuntimeType] = runtimeType + newTree, err := toml.TreeFromMap(valueMap) + if err != nil { + hwlog.RunLog.Errorf(convertTreeFailLogStr, err) + return err + } + cfg.Plugins[v1RuntimeTypeFisrtLevelPlugin] = *newTree + return nil +} + +func getMap(input interface{}, key string) (interface{}, error) { + inputMap, ok := input.(map[string]interface{}) + if !ok { + hwlog.RunLog.Errorf(convertConfigFailLogStr, key, input) + return nil, fmt.Errorf(convertConfigFailErrorStr, key, input) + } + output, ok := inputMap[key] + if !ok { + hwlog.RunLog.Errorf("can not find config %v, config is: %+v", key, inputMap) + return nil, fmt.Errorf("can not find config: %v", key) + } + return output, nil +} + +func writeContainerdConfigToFile(cfg config.Config, destFilePath string) error { + tomlString, err := toml.Marshal(cfg) + if err != nil { + hwlog.RunLog.Errorf("failed to marshall to toml, error: %v", err) + return err + } + file, err := os.Create(destFilePath) + if err != nil { + hwlog.RunLog.Errorf("failed to create file, error: %v", err) + return err + } + defer func() { + err := file.Close() + if err != nil { + hwlog.RunLog.Errorf("failed to close file, error: %v", err) + } + }() + _, err = file.Write(tomlString) + if err != nil { + hwlog.RunLog.Errorf("failed to write, error: %v", err) + return err + } + return nil +} diff --git a/install/process/docker_process.go b/install/process/docker_process.go new file mode 100644 index 0000000000000000000000000000000000000000..084061ca3871c02816f85f2e9b7f219ca6317c41 --- /dev/null +++ b/install/process/docker_process.go @@ -0,0 +1,207 @@ +/* Copyright(C) 2024. Huawei Technologies Co.,Ltd. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +// Package process deal the docker or containerd scene installation +package process + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + + "ascend-docker-runtime/mindxcheckutils" +) + +var reserveDefaultRuntime = false + +// DockerProcess modifies the docker configuration file when installing or uninstalling the docker scenario. +func DockerProcess(command []string) (string, error) { + + action := command[actionPosition] + correctParam, behavior := checkParamAndGetBehavior(action, command) + if !correctParam { + return "", fmt.Errorf("error param") + } + + srcFilePath := command[srcFilePosition] + if _, err := os.Stat(srcFilePath); os.IsNotExist(err) { + if _, err := mindxcheckutils.RealDirChecker(filepath.Dir(srcFilePath), true, false); err != nil { + return behavior, err + } + } else { + if _, err := mindxcheckutils.RealFileChecker(srcFilePath, true, false, mindxcheckutils.DefaultSize); err != nil { + return behavior, err + } + } + + destFilePath := command[destFilePosition] + if _, err := mindxcheckutils.RealDirChecker(filepath.Dir(destFilePath), true, false); err != nil { + return behavior, err + } + runtimeFilePath := "" + if len(command) == addCommandLength { + runtimeFilePath = command[runtimeFilePosition] + if _, err := mindxcheckutils.RealFileChecker(runtimeFilePath, true, false, mindxcheckutils.DefaultSize); err != nil { + return behavior, err + } + } + + setReserveDefaultRuntime(command) + + // check file permission + writeContent, err := createJsonString(srcFilePath, runtimeFilePath, action) + if err != nil { + return behavior, err + } + return behavior, writeJson(destFilePath, writeContent) +} + +func createJsonString(srcFilePath, runtimeFilePath, action string) ([]byte, error) { + var writeContent []byte + if _, err := os.Stat(srcFilePath); err == nil { + daemon, err := modifyDaemon(srcFilePath, runtimeFilePath, action) + if err != nil { + return nil, err + } + writeContent, err = json.MarshalIndent(daemon, "", " ") + if err != nil { + return nil, err + } + } else if os.IsNotExist(err) { + // not existed + if !reserveDefaultRuntime { + writeContent = []byte(fmt.Sprintf(commonTemplate, runtimeFilePath)) + } else { + writeContent = []byte(fmt.Sprintf(noDefaultTemplate, runtimeFilePath)) + } + } else { + return nil, err + } + return writeContent, nil +} + +func writeJson(destFilePath string, writeContent []byte) error { + if _, err := os.Stat(destFilePath); os.IsNotExist(err) { + const perm = 0600 + file, err := os.OpenFile(destFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm) + if err != nil { + return fmt.Errorf("create target file failed") + } + _, err = file.Write(writeContent) + if err != nil { + closeErr := file.Close() + return fmt.Errorf("write target file failed with close err %v", closeErr) + } + err = file.Close() + if err != nil { + return fmt.Errorf("close target file failed") + } + return nil + } else { + return fmt.Errorf("target file already existed") + } +} + +func modifyDaemon(srcFilePath, runtimeFilePath, action string) (map[string]interface{}, error) { + // existed... + daemon, err := loadOriginJson(srcFilePath) + if err != nil { + return nil, err + } + + if _, ok := daemon["runtimes"]; !ok && action == addCommand { + daemon["runtimes"] = map[string]interface{}{} + } + runtimeValue := daemon["runtimes"] + runtimeConfig, runtimeConfigOk := runtimeValue.(map[string]interface{}) + if !runtimeConfigOk && action == addCommand { + return nil, fmt.Errorf("extract runtime failed") + } + if action == addCommand { + runtimeConfig, daemon, err = addDockerDaemon(runtimeConfig, daemon, runtimeFilePath) + } else if action == rmCommand { + runtimeConfig, daemon, err = rmDockerDaemon(runtimeConfig, daemon, runtimeConfigOk) + } else { + return nil, fmt.Errorf("param error") + } + return daemon, err +} + +func addDockerDaemon(runtimeConfig, daemon map[string]interface{}, runtimeFilePath string, +) (map[string]interface{}, map[string]interface{}, error) { + if _, ok := runtimeConfig["ascend"]; !ok { + runtimeConfig["ascend"] = map[string]interface{}{} + } + ascendConfig, ok := runtimeConfig["ascend"].(map[string]interface{}) + if !ok { + return nil, nil, fmt.Errorf("extract ascend failed") + } + ascendConfig["path"] = runtimeFilePath + if _, ok := ascendConfig["runtimeArgs"]; !ok { + ascendConfig["runtimeArgs"] = []string{} + } + if !reserveDefaultRuntime { + daemon[defaultRuntimeKey] = "ascend" + } + return runtimeConfig, daemon, nil +} + +func rmDockerDaemon(runtimeConfig, daemon map[string]interface{}, runtimeConfigOk bool, +) (map[string]interface{}, map[string]interface{}, error) { + if runtimeConfigOk { + delete(runtimeConfig, "ascend") + } + if value, ok := daemon[defaultRuntimeKey]; ok && value == "ascend" { + delete(daemon, defaultRuntimeKey) + } + return runtimeConfig, daemon, nil +} + +func loadOriginJson(srcFilePath string) (map[string]interface{}, error) { + if fileInfo, err := os.Stat(srcFilePath); err != nil { + return nil, err + } else if fileInfo.Size() > maxFileSize { + return nil, fmt.Errorf("file size too large") + } + + file, err := os.Open(srcFilePath) + if err != nil { + return nil, fmt.Errorf("open daemon.json failed") + } + content, err := ioutil.ReadAll(file) + if err != nil { + closeErr := file.Close() + return nil, fmt.Errorf("read daemon.json failed, close file err is %v", closeErr) + } + err = file.Close() + if err != nil { + return nil, fmt.Errorf("close daemon.json failed") + } + + var daemon map[string]interface{} + err = json.Unmarshal(content, &daemon) + if err != nil { + return nil, fmt.Errorf("load daemon.json failed") + } + return daemon, nil +} + +func setReserveDefaultRuntime(command []string) { + reserveCmdPostion := len(command) - 1 + if command[reserveCmdPostion] == "yes" { + reserveDefaultRuntime = true + } +} diff --git a/install/main_test.go b/install/process/docker_process_test.go similarity index 76% rename from install/main_test.go rename to install/process/docker_process_test.go index ebecd29ebfd95970f001f32aff9d55155a8a9b1a..2742b87fad0097877fc2bcd7d0ec310512a37486 100644 --- a/install/main_test.go +++ b/install/process/docker_process_test.go @@ -13,7 +13,7 @@ */ // Package main -package main +package process import ( "encoding/json" @@ -22,7 +22,8 @@ import ( "testing" ) -const oldString = `{ +const ( + oldString = `{ "runtimes": { "ascend": { "path": "/test/runtime", @@ -31,6 +32,12 @@ const oldString = `{ }, "default-runtime": "ascend" }` + defaultRuntime = `"default-runtime"` + oldJson = "old.json" + createOldFail = "create old failed %s" + updateFail = "update failed %s" + updateFailAndData = "update failed %s, %v" +) func jSONBytesEqual(a, b []byte) (bool, error) { var contentA, contentB interface{} @@ -56,16 +63,16 @@ func TestCreateJsonStringWholeNew(t *testing.T) { func TestCreateJsonStringUpdate(t *testing.T) { const perm = 0600 - if fid, err := os.OpenFile("old.json", os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm); err == nil { + if fid, err := os.OpenFile(oldJson, os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm); err == nil { _, err = fid.Write([]byte(oldString)) closeErr := fid.Close() if err != nil || closeErr != nil { - t.Fatalf("create old failed %s", err) + t.Fatalf(createOldFail, err) } } - data, err := createJsonString("old.json", "/test/runtime1", "add") + data, err := createJsonString(oldJson, "/test/runtime1", "add") if err != nil { - t.Fatalf("update failed %s", err) + t.Fatalf(updateFail, err) } expectString := `{ "runtimes": { @@ -74,10 +81,10 @@ func TestCreateJsonStringUpdate(t *testing.T) { "runtimeArgs": [] } }, - "default-runtime": "ascend" - }` + ` + defaultRuntime + `: "ascend" +}` if eq, err := jSONBytesEqual([]byte(expectString), data); err != nil || !eq { - t.Fatalf("update failed %s, %v", err, string(data)) + t.Fatalf(updateFailAndData, err, string(data)) } } @@ -94,18 +101,18 @@ func TestCreateJsonStringUpdateWithOtherParam(t *testing.T) { "runtimeArgs": [1,2,3] } }, - "default-runtime": "runc" - }` + ` + defaultRuntime + `: "runc" +}` if fid, err := os.OpenFile("old.json", os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm); err == nil { _, err = fid.Write([]byte(oldStringWithParam)) closeErr := fid.Close() if err != nil || closeErr != nil { - t.Fatalf("create old failed %s", err) + t.Fatalf(createOldFail, err) } } - data, err := createJsonString("old.json", "/test/runtime1", "add") + data, err := createJsonString(oldJson, "/test/runtime1", "add") if err != nil { - t.Fatalf("update failed %s", err) + t.Fatalf(updateFail, err) } expectString := `{ "runtimes": { @@ -118,30 +125,30 @@ func TestCreateJsonStringUpdateWithOtherParam(t *testing.T) { "runtimeArgs": [1,2,3] } }, - "default-runtime": "ascend" - }` + ` + defaultRuntime + `: "ascend" +}` if eq, err := jSONBytesEqual([]byte(expectString), data); err != nil || !eq { - t.Fatalf("update failed %s, %v", err, string(data)) + t.Fatalf(updateFailAndData, err, string(data)) } } func TestCreateJsonStrinRm(t *testing.T) { const perm = 0600 - if fid, err := os.OpenFile("old.json", os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm); err == nil { + if fid, err := os.OpenFile(oldJson, os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm); err == nil { _, err = fid.Write([]byte(oldString)) closeErr := fid.Close() if err != nil || closeErr != nil { - t.Fatalf("create old failed %s", err) + t.Fatalf(createOldFail, err) } } - data, err := createJsonString("old.json", "", "rm") + data, err := createJsonString(oldJson, "", "rm") if err != nil { - t.Fatalf("update failed %s", err) + t.Fatalf(updateFail, err) } expectString := `{ "runtimes": {} }` if eq, err := jSONBytesEqual([]byte(expectString), data); err != nil || !eq { - t.Fatalf("update failed %s, %v", err, string(data)) + t.Fatalf(updateFailAndData, err, string(data)) } }