From 56079c46be5da9f172ab25542d7f090680cd746a Mon Sep 17 00:00:00 2001 From: Christian Tosta <7252968+christiantosta@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:15:56 -0300 Subject: [PATCH] Implementado downloads (parcial) e plugin PIP --- sig-installer-dev | 308 ++++++++++++++++++++++++++++------------------ 1 file changed, 188 insertions(+), 120 deletions(-) diff --git a/sig-installer-dev b/sig-installer-dev index 5fd6d48..896319b 100755 --- a/sig-installer-dev +++ b/sig-installer-dev @@ -2,7 +2,7 @@ set -euo pipefail self=$(: "${0/*\/}"; echo ${_%%.*sh}) -version=2506.90 +version=2508.01 : ${LANG:=C.UTF-8} @@ -167,7 +167,7 @@ function self.check_essential { fi } -function self.get_token() { +function self.get_token { local _passphrase="Sig%$ºluc03s" tail -n +$(( \ @@ -202,32 +202,12 @@ function parsers.yaml { out=${res} && echo ${out} else err=$(: "${res//*\}"; echo "${_//:\ /: \[}]") - ${ui}.status error "%s ${U_ITEM} %s " "${1##*\/} ${err}" $"NotFound" + ${ui}.status error "%s ${U_ITEM} %s" "${1##*\/} ${err}" $"NotFound" fi } # == Configuração do Sistema====================================================================== # -function system.check_os { - import /etc/os-release - local _os_name=${NAME} - local _suite=${VERSION_CODENAME} - case ${_suite} in - noble|jammy) (${ui}.status info $"SO homologado: %s(%s)" ${_os_name} ${_suite}) ;; - bookworm) (${ui}.status info $"SO homologado: %s(%s)" ${_os_name} ${_suite}) ;; - trixie|*) (${ui}.status error $"SO não homologado: %s(%s)" ${_os_name} ${_suite} && exit 1) ;; - esac - return 0 -} - -function system.check_sudo { - # Check if user has sudo access - if ! [[ (0$(id -u) -eq 0 || "$(groups)" =~ "sudo") ]]; then - ${ui}.status error $"Por favor use um usuário com privilégios de sudo" - sleep 10 && exit 1 - fi -} - function system.setlocale { ${ui}.status info $"Configurando locales do sistema ..." for _locale in C en_US pt_BR; do @@ -275,31 +255,40 @@ function system.setup_ntp { ${ui}.color none; } -function system.create_group { - local _group=${@:1:1} - local _opts=${@:2} - - # Create the Group - if ! [[ $(id -g ${_group} 2>/dev/null) ]]; then - groupadd ${_opts} ${_group} - fi +function system.setup_sshd { + echo "UseDNS no" > /etc/sshd_config.d/no_dns.conf + systemctl rertart ssh.service } +# function system.create_group { +# local _group=${@:1:1} +# local _opts=${@:2} +# +# # Create the Group +# if ! [[ $(id -g ${_group} 2>/dev/null) ]]; then +# groupadd ${_opts} ${_group} +# fi +# } + function system.create_user { local _user=${@:1:1} local _groups=${@:2:1} + local _opts=${@:3} if ! [[ $(id -u ${_user} 2>/dev/null) ]]; then - useradd -m -d /home/${_user} -U -s /bin/bash -G ${_groups} ${_user} + if [[ "${_opts}" =~ "-r" ]] || [[ "${_opts}" =~ "--system" ]]; then + ${ui}.status info $"Creating system user: %s" ${_user} + useradd -M -U -G ${_groups} ${_opts} ${_user} + else + ${ui}.status info $"Creating user: %s" ${_user} + useradd -m -d /home/${_user} -U -G ${_groups} ${_opts} ${_user} + fi else - usermod -s /bin/bash -aG ${_groups} ${_user} + ${ui}.status info $"Updating group membership for user: %s" ${_user} + usermod -aG ${_groups} ${_user} fi } -function system.setup_openssh { - echo "UseDNS no" > /etc/sshd_config.d/no_dns.conf - systemctl rertart ssh.service -} # == Instalação de Pacotes e Aplicativos ======================================================== # @@ -584,6 +573,83 @@ function plugin.pyenv { ${ui}.writeln } +function plugin.pip { + local _metadata_cache="${CACHEDIR}" + local _version_metadata="${_metadata_cache}/versions.yml" + #local _py_version=${@:1:1} + + # Retorna com erro se o produto não estiver definido + [[ -z "${PRODUCT}" ]] && return 1 + local _product_cache="${CACHEDIR}/${PRODUCT}" + + local __pip="runuser -l ${PRODUCT} -- python -m pip" + local _pip_log="$(mktemp ${_product_cache}/${self}.pip.XXXXX)" + + _pip.download() { + for _pkg in ${DOWNLOADS}; do + local _pkg_name=$(: "${_pkg%:*}"; echo "${_#*\/}") + + # Tratamento de variantes do pacote: + local _pkg_verpath _pkg_variant=$(: "${_pkg#*/}"; echo "${_#*:}") + if ! [[ "${_pkg_name}" == "${_pkg_variant}" ]]; then + # true: _pkg_verpath vem da chave yaml - + _pkg_verpath=$(parsers.yaml "${_version_metadata}" \ + "downloads.${_pkg_name}-${_pkg_variant}") + else + # false: _pkg_verpath vem da chave yaml + _pkg_verpath=$(parsers.yaml "${_version_metadata}" \ + "downloads.${_pkg_name}") + fi + + local _ext="tar.gz" + local _pkg_root="software/libs" + local _pkg_download_uri="$(product.get_download_uri ${_pkg_root} \ + ${_pkg_name} ${_pkg_verpath} ${_ext})" + local _pkg_output_file="$(product.get_output_file ${_pkg_name} \ + ${_pkg_verpath} ${_ext})" + + installer.download \ + "${_pkg_download_uri}" \ + "${_pkg_output_file}" \ + --quiet && \ + echo "file://${_pkg_output_file}" >> "${_product_cache}/requirements-local.txt" + done + } + + _pip.install() { + local _pip_opts=" \ + --disable-pip-version-check + " + # Instala pacotes e módulos do python + ( + ${__pip} ${_pip_opts} install --upgrade --user pip setuptools \ + && find "${_product_cache}"/ -maxdepth 1 -name "requirements*.txt" \ + | xargs ${__pip} install -r + ) 2>&1 \ + | tee -a ${_pip_log} \ + | ${ui}.subprocess.output 10 \ + && ( + local _line; grep -iE 'installed|up-to-date' "${_pip_log}" \ + | while read _line; do \ + ${ui}.tab 2 + ${ui}.item "$(${ui}.color green "${_line}${EL}")" + done + ) \ + || ${ui}.subprocess.failure "Falha ao executar o PIP" ${_pip_log} PIP 100 + ${ui}.clear + ${ui}.writeln + } + + ${ui}.status info $"Fazendo download dos pacotes python ..." + _pip.download + ${ui}.writeln + + ${ui}.status info $"Instalando módulos python ..." + ${ui}.get_cursor + _pip.install + ${ui}.writeln +} + # == Installer =================================================================================== # function installer.configure { @@ -600,7 +666,7 @@ function installer.download { local _dst="${2:-${CACHEDIR}/$(basename ${1})}" local _quiet=${3:-} - local _repo_home="dl.sigsolucoes.net.br:/pub/" + local _repo_home="dl.sigsolucoes.net.br:/pub" local _repo_user="dl" local _token=$(mktemp /tmp/${self}.dl.XXXXXX) @@ -613,6 +679,7 @@ function installer.download { # | bsdtar --passphrase ${_token_pass} -C $(dirname ${_token}) -xOf - > ${_token} \ (self.get_token > ${_token} \ && chmod 0400 ${_token} \ + && mkdir -p $(dirname "${_dst}") \ && scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \ -qi ${_token} "${_repo_user}@${_repo_home}/${_src}" "${_dst}" \ && color=green || color=red; \ @@ -733,85 +800,80 @@ function installer.product.menu { # == Products ==================================================================================== # function product.download { - metadata_cache="${CACHEDIR}" - - local \ - _product_metadata="${metadata_cache}/products.yml" \ - _version_metadata="${metadata_cache}/versions.yml" \ - _prod_variant _prod_verpath _prod_download_uri \ - _prod_root="software" _prod_output_dir _prod_file _lib \ - _lib_root="software/libs" _lib_name _lib_variant _lib_verpath \ - _lib_path _lib_download_uri _lib_file _ext="tar.gz" + local metadata_cache="${CACHEDIR}" + local _version_metadata="${metadata_cache}/versions.yml" + local _prod_files="${1:-}" + # Retorna com erro se o produto não estiver definido [[ -z "${PRODUCT}" ]] && return 1 - _prod_variant=$(parsers.yaml "${_product_metadata}" \ - "products.${PRODUCT}.variant") - - # Treat if product has variants: - # true: verpath field comes from yaml key - - # false: verpath field comes from yaml key - ! [[ "${PRODUCT}" == "${_prod_variant}" ]] \ - && _prod_verpath=$(parsers.yaml "${_version_metadata}" \ - "products.${PRODUCT}-${_prod_variant}") \ - || _prod_verpath=$(parsers.yaml "${_version_metadata}" \ + # Tratamento de variantes do produto: + local _prod_verpath _prod_variant=$(product.get_property variant) + if ! [[ "${PRODUCT}" == "${_prod_variant}" ]]; then + # true: _prod_verpath vem da chave yaml - + _prod_verpath=$(parsers.yaml "${_version_metadata}" \ + "products.${PRODUCT}-${_prod_variant}") + else + # false: _prod_verpath vem da chave yaml + _prod_verpath=$(parsers.yaml "${_version_metadata}" \ "products.${PRODUCT}") + fi - _get_download_uri() { - local _p=$(dirname "${3}") - - ! [[ "${_p}" == "." ]] && _p="${_p}/" || _p= - echo "${1}/${2}/${_p}${2}-${3/*\/}.${4:-tar.gz}" - } - - _get_output_file() { - echo "${metadata_cache}/${PRODUCT}/${1}-${2/*\/}.${3:-tar.gz}" - } - + # Define a extensão do arquivo principal do produto + local _ext="tar.gz" #[[ "${@}" =~ '(ext=tar\.[bgxz]{2}\d*)' ]] \ # && _ext="${BASH_REMATCH[1]}" - _prod_download_uri="$(_get_download_uri ${_prod_root} \ + local _prod_root="software" + local _prod_download_uri="$(product.get_download_uri ${_prod_root} \ ${PRODUCT} ${_prod_verpath} ${_ext})" - _prod_output_file="$(_get_output_file ${PRODUCT} \ + local _prod_output_file="$(product.get_output_file ${PRODUCT} \ ${_prod_verpath} ${_ext})" + # Download do arquivo principal do produto mkdir -p $(dirname ${_prod_output_file}) - ${ui}.status info $"Fazendo download dos arquivos ..." + ${ui}.status info $"Fazendo download do produto ..." installer.download \ "${_prod_download_uri}" \ "${_prod_output_file}" \ --quiet + #${ui}.writeln - for _lib in ${DOWNLOADS}; do - _lib_name=$(: "${_lib%:*}"; echo "${_#*\/}") - _lib_variant=$(: "${_lib#*/}"; echo "${_#*:}") - - # Treat if library has variants: - # true: verpath field comes from yaml key - - # false: verpath field comes from yaml key - ! [[ "${_lib_name}" == "${_lib_variant}" ]] \ - && _lib_verpath=$(parsers.yaml "${_version_metadata}" \ - "downloads.${_lib_name}-${_lib_variant}") \ - || _lib_verpath=$(parsers.yaml "${_version_metadata}" \ - "downloads.${_lib_name}") - - _lib_download_uri="$(_get_download_uri ${_lib_root} \ - ${_lib_name} ${_lib_verpath} ${_ext})" - _lib_output_file="$(_get_output_file ${_lib_name} \ - ${_lib_verpath} ${_ext})" - - installer.download \ - "${_lib_download_uri}" \ - "${_lib_output_file}" \ - --quiet + # Download dos arquivos adicionais + local _files_root="installer" + local _keys=$(echo ${_prod_files//\'/\"} | jq 'keys_unsorted[]') + local _k; for _k in ${_keys[*]}; do + local _files=$(echo ${_prod_files//\'/\"} \ + | jq ".${_k} |= join(\" \")" \ + | jq ".${_k}" + ) + local _file; for _file in ${_files}; do + installer.download \ + "${_files_root}/config/${PRODUCT}/${_file//\"}" \ + "${CACHEDIR}/${PRODUCT}/${_file//\"}" \ + --quiet + done done + exit 1 + chmod g+rx,o+rx ${CACHEDIR} - ${ui}.status info $"Download concluído." + #${ui}.status info $"Download concluído." #${ui}.prompt $"Pressione uma tecla para continuar ... " } +function product.get_download_uri { + local _p=$(dirname "${3}") + + ! [[ "${_p}" == "." ]] && _p="${_p}/" || _p= + echo "${1}/${2}/${_p}${2}-${3/*\/}.${4:-tar.gz}" +} + +function product.get_output_file { + local metadata_cache="${CACHEDIR}" + echo "${metadata_cache}/${PRODUCT}/${1}-${2/*\/}.${3:-tar.gz}" +} + function product.get_property { local \ _prod_variant \ @@ -842,7 +904,7 @@ function product.get_property { name) echo "$(_get_property .name)" ;; version) echo "$(basename ${_prod_verpath})" ;; variant) echo "$(_get_property .variant)" ;; - *) echo "$(_get_property ."${1:-}")" || : ;; + *) echo "$(_get_property ."${1:-}")" ;; esac } @@ -885,7 +947,7 @@ function product.get_requires { case ${_repo} in ""|default) continue ;; local) echo "${_pkg}" >> ${CACHEDIR}/${PRODUCT}.local.build ;; - sig) DOWNLOADS+="${_pkg} " ;; + sig|pip) DOWNLOADS+="${_pkg} " ;; *) ! [[ "${REPOS}" =~ "${_repo}" ]] && REPOS+="${_repo} " esac done @@ -930,7 +992,7 @@ function product.get_requires { } function product.install { - metadata_cache="${CACHEDIR}" + local metadata_cache="${CACHEDIR}" cli.section "%s [VERSÃO: %s] - INSTALAÇÃO DO PRODUTOS${EL}\n" \ ${self^^} \ @@ -939,29 +1001,40 @@ function product.install { ${ui}.title $"Produto: " "$(product.get_property name)" ${ui}.subtitle $"Configuração Geral" + # -- Configura região e idioma do sistema #system.setlocale pt_BR.UTF-8 - # TODO: move to PIP plugin - #product.download - - _paths="$(product.get_property paths)" - _keys="$(echo "${_paths//\'/\"}" | jq 'keys_unsorted[]')" + # -- Cria/atualiza usuário e grupos do produto + local _user="$(product.get_property user.name)" + local _shell="$(product.get_property user.shell)" + local _home="$(product.get_property paths.home)" + local _groups="$(product.get_property user.groups)" + system.create_user "${_user}" ${_groups//\ /,} -s "${_shell}" -d "${_home}" -r + chown -R "${_user}:" "${_home}" + # -- Cria filesystem (diretórios) do produto + local _paths="$(product.get_property paths)" + local _keys="$(echo "${_paths//\'/\"}" | jq 'keys_unsorted[]')" ${ui}.status info $"Criando diretórios e links ... " - for _k in ${_keys[*]}; do - _dir=$(echo "${_paths//\'/\"}" | jq ".${_k}") - mkdir -p ${_dir} \ - && (${ui}.tab; ${ui}.item "${_dir//\"/}") + local _k; for _k in ${_keys[*]}; do + local _dir=$(echo "${_paths//\'/\"}" | jq ".${_k}" | sed 's/\"//g') + mkdir -p "${_dir}" \ + && (${ui}.tab; ${ui}.item "${_dir//\"/}") \ + && chown -R "${_user}:" "${_dir}" done - ln -snf /srv/sig /sig ${ui}.writeln + # -- Faz download do produto e arquivos relacionados + local _files="$(product.get_property files)" + product.download "${_files}" + unset _files + # -- Configurando repositórios product.setup_repos ${REPOS} # -- Instalando pacotes necessários - system.install_pkgs ${BUILD_REQUIRES} - ${ui}.prompt "Aguarde ou pressione ENTER para continuar ..." -s -t 10 || : +#DEV## system.install_pkgs ${BUILD_REQUIRES} +#DEV## ${ui}.prompt "Aguarde ou pressione ENTER para continuar ..." -s -t 10 || : # -- Compilando requisitos não empacotados _builds=$(grep "^local/" ${metadata_cache}/${PRODUCT}.local.build) @@ -975,26 +1048,20 @@ function product.install { _k_args=${_args#*@} ;; esac - ${ui}.set_cursor 0 8 - ${ui}.get_cursor - ${ui}.clear + if ! [[ "no-clear" =~ "${_k_args}" ]]; then + ${ui}.set_cursor 0 8 + ${ui}.get_cursor + ${ui}.clear + fi ${ui}.subtitle $"Executando plugin: "${_args%@*} ${_callback} ${_k_args//;/\ } ${ui}.prompt "Aguarde ou pressione ENTER para continuar ..." -s -t 10 || : done ## -- SIG ----------------------------- # - # TODO: Pyenv -> Use .python-version on user home! -# useradd -m -d /srv/sig/${PRODUCT} -s /bin/bash -G pyenv -r -U ${PRODUCT} 2>/dev/null || : -# cat /etc/skel/.bashrc > /srv/sig/${PRODUCT}/.bashrc -# echo -e "\n# Load Python ${_pdpy}\npyenv local ${_pdpy} >/dev/null 2>&1" >> /srv/sig/${PRODUCT}/.bashrc -# echo ${_pdpy} > /srv/sig/${PRODUCT}/.python-version -# # # Pip modules # ${ui}.status info $"Instalando produto [%s] ..." "${_name}" # ${ui}.color gold -# runuser -l ${PRODUCT} -- python -m pip install --upgrade --user pip -# runuser -l ${PRODUCT} -- python -m pip install --upgrade --user setuptools # for _lib in ${_libs}; do # _lbpv=$(parsers.yaml ${CACHEDIR}/versions.yml libs.python${_pdpy/.*}.${_lib}) # runuser -l ${PRODUCT} -- python -m pip install --user \ @@ -1115,6 +1182,7 @@ self.check_essential #${ui}.title $"Reconfigurando o sistema operacional" #system.check_net #system.setup_ntp +#system.setup_sshd #${ui}.title $"Configurando contas de usuários" #system.create_user sig dialout,pyenv,sudo