#!/bin/bash set -euo pipefail self=$(basename ${0}) self=${self/.*bash} version=2506.4 # == Funções Gerais ============================================================================== # function self.check_essential { # We need at least some programs installed local _essential=" \ libarchive-tools:bsdtar \ curl:curl \ git-core:git \ iproute2:ip \ iputils-ping:ping \ jq:jq \ python3-yaml:jq \ locales:locale-gen \ openssh-server:sshd \ sudo:sudo \ unzip:unzip \ tzdata:tzconfig \ " local _not_found= for _prog in ${_essential}; do if [[ -z "$(which ${_prog/*:})" ]]; then _not_found+=" ${_prog}" fi done if [[ ! -z "$_not_found" ]]; then clear echo -e "Os seguintes pacotes/programas são necessários para o instalador:\n" _pkgs= for _prog in ${_not_found}; do echo " - ${_prog/:*}: ${_prog/*:}" _pkgs+="${_prog/:*} " done read -p \ $"Aperte ENTER para instalar os pacotes agora [CTRL+C para cancelar]: " apt-get update apt-get install -yq ${_pkgs} fi } self.check_essential # -- Import functions from local or remote scripts function import { case ${1} in http?://*|ftp?://*) _tmpfile=$(mktemp /tmp/${self}.import.XXXXX) curl -ks ${1} -o ${_tmpfile} \ && source ${_tmpfile} \ && rm -f ${_tmpfile} ;; *) source ${1} ;; esac return ${?} } # -- YAML Parser : parsers.yaml file.yml key function parsers.yaml { local \ out= err= parse() { python3 -c "import yaml; \ f=yaml.safe_load(open('${1}'))['${2//\./\'][\'}']; \ print('\n'.join(str(i) for i in f) if type(f)==list else f); \ " } if res=$(parse $@ 2>&1); then out=${res} && echo ${out} else err=$(: "${res//*\}"; echo "${_//:\ /: \[}]") ${ui}.status error "%s ${U_SUBITEM} %s " "${1##*\/} ${err}" $"NotFound" fi } # == UI =======================================================================+================= # # -- Import UI from dbtool ui=${ui:-cli} dbtool=https://raw.githubusercontent.com/infra7ti/dbtool/refs/heads/main import ${dbtool}/lib/ui/${ui}.bash function cli.clear { clear } function cli.status { ${ui}.${@:1:1} && ${ui}.print "${@:2}" echo; return 0 } function cli.title { ${ui}.color blue ${ui}.emphasis "$(${ui}.subitem "${@^^}")" ${ui}.color none ${ui}.line } function cli.subtitle { ${ui}.subitem "${@^^} \n" printf "%0.s$(echo -ne "\u2508${NO_FMT}")" {1..80} echo } function cli.prompt { read -p "$(${ui}.status tab "${1}")" ${2:-} k echo ${k} } # == 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 sed -i "s/#\s\(${_locale}.UTF-8\)/\1/" /etc/locale.gen done ${ui}.color gold locale-gen --keep-existing | while read line; do ${ui}.status tab "${line}" done update-locale LANG=pt_BR.UTF-8 ${ui}.color none; echo } function system.check_net { _exit= function _get_external_ip { local _ip="$(curl -ks${1} --fail https://ifconfig.me/ || echo none)" case ${_ip} in none) echo "$(${ui}.color red)${_ip}$(${ui}.color gold)" ;; *) echo "$(${ui}.color green)${_ip}$(${ui}.color gold)" ;; esac if [[ "${_ip}" == "none" ]]; then return ${1}; fi } ${ui}.status info $"Estado da Conexão à Internet:" ${ui}.color gold ${ui}.status tab $"IPv4 público: %s" "$(_get_external_ip 4)" ${ui}.status tab $"IPv6 público: %s" "$(_get_external_ip 6)" ${ui}.color none; echo } function system.setup_ntp { ${ui}.status info $"Configurando fuso e hora do sistema ..." ${ui}.color gold if [[ ! -z "$(pidof systemd)" ]]; then sudo timedatectl set-local-rtc 0 sudo timedatectl set-timezone America/Sao_Paulo sudo timedatectl set-ntp true fi sudo DEBIAN_FRONTEND=noninteractive \ dpkg-reconfigure tzdata 2>&1 | while read line; do \ ${ui}.status tab "$([ ! -z "${line}" ] && echo ${line})"; \ done; ${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.create_user { local _user=${@:1:1} local _groups=${@:2:1} if ! [[ $(id -u ${_user} 2>/dev/null) ]]; then useradd -m -d /home/${_user} -U -s /bin/bash -G ${_groups} ${_user} else usermod -s /bin/bash -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 ======================================================== # function system.install_pkgs { import /etc/os-release local _os_id=${ID} case ${_os_id} in ubuntu|debian) ${ui}.status info $"Instalando os pacotes ..." \ && sudo apt-get -qq update \ && ${ui}.color gold \ && ( \ sudo apt-get -q -y install --no-install-suggests "${@}" 2>&1 \ | while read line; do \ ${ui}.status tab "${line}"; \ done \ ) \ && ${ui}.color none \ && ${ui}.status info $"Pacotes instalados com sucesso!" \ || ${ui}.status info $"Erro ao instalar os pacotes!" ;; *) ${ui}.status warn $"Não implementado." check_os ;; esac return 0 } function system.remove_pkgs { import /etc/os-release local _os_id=${ID} case ${_os_id} in ubuntu|debian) ${ui}.status info $"Removendo os pacotes ..." \ && ${ui}.color gold \ && ( \ sudo apt-get -q -y purge --autoremove "${@}" 2>&1 \ | while read line; do \ ${ui}.status tab "${line}"; \ done \ ) \ && ${ui}.color none \ && ${ui}.status info $"Pacotes removidos com sucesso!" \ || ${ui}.status info $"Erro ao remover os pacotes!" ;; *) ${ui}.status warn $"Não implementado." check_os ;; esac return 0 } function system.install_postgres { local _pg_version=${1:-17} local _citus_version=${2} local POSTRES_PACKAGES=" libjemalloc2 \ postgresql-${_pg_version} \ " ${ui}.subtitle "PostgreSQL" ${ui}.status info $"Habilitando repositório: PostgreSQL-PGDG ..." if [[ ! -f "/etc/apt/sources.list.d/pgdg.list" ]]; then sudo install -d /usr/share/postgresql-common/pgdg \ && sudo curl -kso /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc \ --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc \ && sudo sh -c " \ echo 'deb [signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] \ https://apt.postgresql.org/pub/repos/apt ${VERSION_CODENAME}-pgdg main' \ > /etc/apt/sources.list.d/pgdg.list" fi ${ui}.color gold ${ui}.status tab "The repository is set up! You can now install packages." ${ui}.color none local _pg_shared_preload= if [[ ! -z "${_citus_version}" ]]; then ${ui}.status info $"Habilitando repositório: PostgreSQL-Citus ..." if [[ ! -f "/etc/apt/sources.list.d/citusdata_community.list" ]]; then ${ui}.color gold sudo curl -ks https://install.citusdata.com/community/deb.sh | bash 2>&1 \ | while read line; do \ ${ui}.status tab "${line}"; \ done ${ui}.color none else ${ui}.color gold ${ui}.status tab "The repository is set up! You can now install packages." ${ui}.color none fi POSTRES_PACKAGES+=" postgresql-${_pg_version}-citus-${_citus_version/*-}" _pg_shared_preload+="citus" fi system.install_pkgs ${POSTRES_PACKAGES} pg_conftool ${_pg_version} main set listen_addresses '*' pg_conftool ${_pg_version} main set log_timezone 'America/Sao_Paulo' pg_conftool ${_pg_version} main set shared_preload_libraries ${_pg_shared_preload} local _pg_hba_file="/etc/postgresql/${_pg_version}/main/pg_hba.conf" sudo cat <<-EOF | sed 's/^\s*\(.*\)/\1/g' > ${_pg_hba_file} # Local Administrative User local all postgres peer # "local" is for Unix domain socket connections only local all all scram-sha-256 # IPv4 local connections: host all all 127.0.0.1/32 scram-sha-256 host all all 0.0.0.0/0 scram-sha-256 # IPv6 local connections: host all all ::1/128 scram-sha-256 host all all ::/0 scram-sha-256 # Allow replication connections from localhost, by a user with the # replication privilege. #local replication all scram-sha-256 #host replication all 127.0.0.1/32 scram-sha-256 #host replication all ::1/128 scram-sha-256 EOF ${ui}.status info $"Reiniciando o cluster [%s/%s] ... " ${_pg_version} "main" pg_ctlcluster ${_pg_version} main restart ${ui}.color gold pg_lsclusters ${_pg_version} main | while read line; do \ case "$line" in \ *online*) ${ui}.color green ;; \ *down*) ${ui}.color red ;; \ esac; \ ${ui}.status tab "${line}"; \ done ${ui}.color none echo } function system.install_pyenv { local _pyenv_root=${@:1:1} local _py_version=${@:2:1} PYENV_PACKAGES=" \ gcc \ libc6-dev \ libreadline-dev \ libssl-dev \ libbz2-dev \ zlib1g-dev \ libsqlite3-dev \ make \ " ${ui}.subtitle "PyEnv (Python Environment)" export PYENV_ROOT="${_pyenv_root:-/usr/local/share/pyenv}" useradd -M -d ${PYENV_ROOT} -s /bin/bash -r -U pyenv >/dev/null 2>&1 || : [[ -d "${PYENV_ROOT}" ]] && \ ${ui}.status info $"PyEnv já está configurado!\n" && \ return 0 system.install_pkgs ${PYENV_PACKAGES} #rm -rf ${PYENV_ROOT} ${ui}.status info $"Instalando PyENV [%s] ..." ${PYENV_ROOT} ${ui}.color gold curl -ks https://pyenv.run | bash 2>&1 \ | while read line; do \ case "${line}" in \ Cloning*) ${ui}.status tab "${line}";; \ esac; \ done ${ui}.color none ${ui}.status info $"Executando PyEnv Doctor [%s] ..." ${PYENV_ROOT} ${ui}.color gold __pyenv=${PYENV_ROOT}/bin/pyenv ${__pyenv} doctor 2>&1 \ | while read line; do \ case "${line}" in \ Congratulations*) ${ui}.color green && ${ui}.status tab "${line}";; \ warning*|WARNING*) ${ui}.color orange && ${ui}.status tab "${line}";; \ *error:*) ${ui}.color red && ${ui}.status tab "${line}";; \ *) ${ui}.status tab "${line}";; \ esac \ done || exit ${?} ${ui}.color none ${ui}.status info $"Instalando Python [%s] ..." ${_py_version} ${ui}.color gold ${__pyenv} install ${_py_version} \ | while read line; do \ case "${line}" in \ warning*|WARNING*) ${ui}.color orange && ${ui}.status tab "${line}";; \ error*|ERROR*) ${ui}.color red && ${ui}.status tab "${line}";; \ *) ${ui}.status tab "${line}";; \ esac \ done || exit ${?} ${ui}.color none chgrp -R pyenv ${PYENV_ROOT} chmod -R g+rw ${PYENV_ROOT} system.remove_pkgs ${PYENV_PACKAGES} echo cat <<-EOF | sed 's/^\s*\(.*\)/\1/g' > /etc/profile.d/pyenv.sh export PYENV_ROOT="${PYENV_ROOT}" [[ -d \$PYENV_ROOT/bin ]] && export PATH="\$PYENV_ROOT/bin:\$PATH" eval "\$(pyenv init - bash)" eval "\$(pyenv virtualenv-init -)" EOF } # == Installer =================================================================================== # function installer.configure { local _passphrase ${ui}.prompt $"Frase secreta para acesso aos downloads: " _passphrase PRIVKEY_PASSPHRASE="${_passphrase}" ! [[ "X" == "${PRIVKEY_PASSPHRASE}X" ]] && \ ${ui}.status info $"Frase secreta armazenada com sucesso." ${_passphrase} } function installer.download { local _src="${1:-}" local _dst="${2:-${CACHEDIR}/$(basename ${1})}" local _quiet=${3:-} local _repo_home="dl.sigsolucoes.net.br:/pub/" local _repo_user="dl" local _token=$(mktemp /tmp/${self}.dl.XXXXXX) local _token_pass=${PRIVKEY_PASSPHRASE} local _seek=$(($(grep -anE "^exit 0" ${0} | cut -d: -f1) - ${LINENO} + 1)) local _message="$(tail -n +$(( ${LINENO} + ${_seek} )) ${0})" [[ -z "${_quiet}" ]] && ${ui}.status info $"Fazendo download [${_src}]" (echo ${_message} | base64 -d \ | bsdtar --passphrase ${_token_pass} -C $(dirname ${_token}) -xOf - > ${_token} \ && chmod 0400 ${_token} \ && scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no \ -qi ${_token} "${_repo_user}@${_repo_home}/${_src}" "${_dst}" \ && color=green || color=red; \ ${ui}.color ${color}; \ ! [[ "${_quiet}" == "silent" ]] \ && echo "${_src}" | sed "s/^\(.*\)/\ \ $(${ui}.item '')\1/g"; \ ${ui}.color none; \ ) rm -f ${_token} } function installer.download_metadata { local \ _metadata_uri="installer/config/sig-installer" \ _metadata_name="${1:-products}" installer.download \ "${_metadata_uri}/${_metadata_name}.yml" \ "${metadata_cache}/${_metadata_name}.yml" \ silent } function installer.load_products { local \ _product_metadata="${metadata_cache}/products.yml" \ _version_metadata="${metadata_cache}/versions.yml" \ _id _prod _products _products=$( \ parsers.yaml "${_product_metadata}" "products" \ | sed "s/'/\"/g" \ | jq "to_entries[] | select(.value.restricted|not) | .key" \ | sed 's/"//g' | sort ) echo "${_products}" } function installer.product.menu { metadata_cache="${CACHEDIR}" local \ _product_metadata="${metadata_cache}/products.yml" \ _version_metadata="${metadata_cache}/versions.yml" \ _products _prod_variant _prod_name _prod_color \ _prod_version _id _prod ${ui}.clear ${ui}.init "%s [VERSÃO: %s] - CONFIGURAÇÃO DE PRODUTOS\n" ${self^^} ${version} PRIVKEY_PASSPHRASE=Sig%$ºluc03s while [[ -z "${PRIVKEY_PASSPHRASE}" ]]; do installer.configure done ${ui}.status info $"Atualizando metadados de produtos... \n" installer.download_metadata products installer.download_metadata versions installer.download_metadata repos _products="$(installer.load_products)" #${ui}.title $"Produtos:"; ${ui}.title $"Instalar/Atualizar Produtos:" _id=1 declare -A products for _prod in ${_products}; do products[${_id}]="${_prod}" _prod_variant=$(parsers.yaml "${_product_metadata}" "products.${_prod}.variant") _prod_name=$(parsers.yaml "${_product_metadata}" "products.${_prod}.name") _prod_color=$(parsers.yaml "${_product_metadata}" "products.${_prod}.color") _prod_version=$(parsers.yaml "${_version_metadata}" "products.${_prod}-${_prod_variant}") ${ui}.status tab "$( \ ${ui}.color blue)${_id}.$(${ui}.color none) $( \ ${ui}.print \ "%s (%s) [%s: %s]" \ "${F_BOLD}Sig${NO_FMT}$(${ui}.color ${_prod_color})${_prod_name#Sig*}${NO_FMT}" \ ${_prod_variant^} \ $"VERSÃO" $(${ui}.color orange)${_prod_version#*/}$(${ui}.color none) \ )" let _id=_id+1 done; echo ${ui}.subtitle $"Configurações:" ${ui}.status tab "$( \ ${ui}.color blue)C.$(${ui}.color none) $( \ ${ui}.print $"Configuração do Instalador" \ )" ${ui}.status tab "$( \ ${ui}.color blue)Q.$(${ui}.color none) $( \ ${ui}.print $"Limpar downloads e Sair" \ )" ${ui}.line ${ui}.prompt $"Selecione a opção: " id case ${id} in Q|q) rm -rf ${CACHEDIR} && exit 0 ;; C|c) installer.configure ;; *) true ;; esac [[ ${products[${id}]+x} ]] || return 0 PRODUCT=${products[$id]} } # == Products ==================================================================================== # function product.get_requires { import /etc/os-release local _os_id=${ID} _get_product_requires() { local \ _prod_metadata="${CACHEDIR}/products.yml" \ _version_metadata="${CACHEDIR}/versions.yml" \ _prod_name _prod_variant _prod_color _prod_paths \ _prod_requires _prod_buildreq _prod_config _prod_version \ _rq _br _pkg _repo ! [[ "X" == "${PRODUCT:-${1}}X" ]] || return 1 _prod_requires=$(parsers.yaml ${_prod_metadata} "products.${PRODUCT}.requires") _prod_buildreq=$(parsers.yaml ${_prod_metadata} "products.${PRODUCT}.buildrequires") # Not used here: #_prod_name=$(parsers.yaml ${_prod_metadata} "products.${PRODUCT}.name") #_prod_variant=$(parsers.yaml ${_prod_metadata} "products.${PRODUCT}.variant") #_prod_color=$(parsers.yaml ${_prod_metadata} "products.${PRODUCT}.color") #_prod_paths=$(parsers.yaml ${_prod_metadata} "products.${PRODUCT}.paths") #_prod_config=$(parsers.yaml ${_prod_metadata} "products.${PRODUCT}.config") #_prod_version=$(parsers.yaml ${_version_metadata} "products.${PRODUCT}-${_prod_variant}") for _rq in ${_prod_requires}; do [[ "${_rq}" =~ "${_os_id}" ]] && : "${_rq#*/}"; REQUIRES+="${_%~*} " done for _br in ${_prod_buildreq}; do [[ "${_br}" =~ "${_os_id}" ]] && : "${_br#*/}"; BUILD_REQUIRES+="${_%~*} " done for _pkg in ${_prod_requires} ${_prod_buildreq}; do : "${_pkg%"${_pkg##*\/}"}"; _repo=${_%\/*} case ${_repo} in ""|default) continue ;; local) echo "${_pkg}" >> ${CACHEDIR}/${PRODUCT}.local.build ;; sig) DOWNLOADS+="${_pkg} " ;; *) ! [[ "${REPOS}" =~ "${_repo}" ]] && REPOS+="${_repo} " esac done } _get_product_repos_requires() { local \ repo_metadata="${CACHEDIR}/repos.yml" \ _repo _repo_summary _repo_type _repo_dists \ _repo_requires _repo_buildreq _repo_script \ _rq _br for _repo in ${REPOS}; do _repo_requires=$(parsers.yaml ${repo_metadata} "repos.${_repo}.requires") _repo_buildreq=$(parsers.yaml ${repo_metadata} "repos.${_repo}.buildrequires") # Not used here: #_repo_summary=$(parsers.yaml ${repo_metadata} "repos.${_repo}.summary") #_repo_type=$(parsers.yaml ${repo_metadata} "repos.${_repo}.type") #_repo_dists=$(parsers.yaml ${repo_metadata} "repos.${_repo}.dists") #_repo_script=$(parsers.yaml ${repo_metadata} "repos.${_repo}.run") done for _rq in ${_repo_requires:-}; do [[ "${_rq}" =~ "${_os_id}" ]] && : "${_rq#*/}"; REQUIRES+="${_%~*} " done for _br in ${_repo_buildreq:-}; do [[ "${_br}" =~ "${_os_id}" ]] && : "${_br#*/}"; BUILD_REQUIRES+="${_%~*} " done } _get_product_requires _get_product_repos_requires #DEBUG=1 #${ui}.status info "%s: %s\n" $"Requires" "${REQUIRES}" #${ui}.status info "%s: %s\n" $"BuildRequires" "${BUILD_REQUIRES}" #${ui}.status info "%s: %s\n" $"Repos" "${REPOS}" #[[ ${DEBUG:-0} -gt 0 ]] && sleep 10 #return 0 } function product.setup_repos { local \ _repo _repo_name _repo_summary \ _repo_script _product.repo.get_property() { local \ __repo_metadata="${CACHEDIR}/repos.yml" \ __repo="${1:-}" \ __repo_property="${2:-}" echo "$(parsers.yaml ${__repo_metadata} "repos.${__repo}.${__repo_property}")" } for _repo in ${REPOS}; do _repo_name=${_repo} _repo_summary="$(_product.repo.get_property ${_repo} summary)" _repo_type=$(_product.repo.get_property ${_repo} type) ${ui}.status info $"Configurando Repositório [%s]" ${_repo_name} ${ui}.status tab $"Sumário: ${_repo_summary}\n" case ${_repo_type} in local) true ;; run) _repo_script=$(_product.repo.get_property ${_repo} run) ;; deb) echo "Não implementado" ;; rpm-md) echo "Não Implementado" ;; *) true ;; esac eval $(echo "${_repo_script}") done } function product.get_property { local \ _prod_variant \ _prod_verpath _get_property() { metadata_cache="${CACHEDIR}" local \ _product_metadata="${metadata_cache}/products.yml" \ _version_metadata="${metadata_cache}/versions.yml" \ _key=${PRODUCT}${1:-} echo $(parsers.yaml "${_product_metadata}" \ "products.${_key}") } _prod_variant=$(_get_property .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=$(_get_property -${_prod_variant}) \ || _prod_verpath=$(_get_property) case "${1:-}" in name) echo "$(_get_property .name)" ;; version) echo "$(basename ${_prod_verpath})" ;; variant) echo "$(_get_property .variant)" ;; dowload_uri) continue ;; cache_file) continue ;; *) true ;; esac } 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" [[ -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}" \ "products.${PRODUCT}") _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}" } #[[ "${@}" =~ '(ext=tar\.[bgxz]{2}\d*)' ]] \ # && _ext="${BASH_REMATCH[1]}" _prod_download_uri="$(_get_download_uri ${_prod_root} \ ${PRODUCT} ${_prod_verpath} ${_ext})" _prod_output_file="$(_get_output_file ${PRODUCT} \ ${_prod_verpath} ${_ext})" mkdir -p $(dirname ${_prod_output_file}) ${ui}.status info $"Fazendo download dos arquivos ..." installer.download \ "${_prod_download_uri}" \ "${_prod_output_file}" \ --quiet 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 done exit 1 chmod g+rx,o+rx ${CACHEDIR} ${ui}.status info $"Download concluído." #${ui}.prompt $"Pressione uma tecla para continuar ... " } function product.install { ${ui}.clear ${ui}.init $"%s [VERSÃO: %s] - INSTALAÇÃO DO PRODUTO\n" ${self^^} ${version} ${ui}.title "$(product.get_property name)" mkdir -p /srv/sig ln -snf /srv/sig /sig # -- Instalando pacotes necessários system.install_pkgs ${BUILD_REQUIRES} _pdpy=$(parsers.yaml ${CACHEDIR}/products.yml "products.${PRODUCT}.python") _name=$(parsers.yaml ${CACHEDIR}/products.yml "products.${PRODUCT}.name") _libs=$(parsers.yaml ${CACHEDIR}/products.yml "products.${PRODUCT}.download") _pdpv=$(parsers.yaml ${CACHEDIR}/versions.yml "products.python${_pdpy/.*}.${PRODUCT}") 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 ${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 \ "${CACHEDIR}/${PRODUCT}/${_lib}-${_lbpv#*/}.tar.gz" if [[ "${_lib}" == "kiwi" ]]; then _f=/srv/sig/${PRODUCT}/.local/lib/python2.7/site-packages/kiwi/__installed__.py find $(dirname ${_f})/ -name *.pyc -delete download "installer/config/${PRODUCT}/__installed__.py" "${_f}" \ && chown -R ${PRODUCT}:${PRODUCT} "${_f}" \ && chmod 644 ${_f} \ && touch ${_f} fi done case "${PRODUCT}" in sigerp) _date=$(date +%Y%m%d%H%M%S) _pdpy=$(parsers.yaml ${CACHEDIR}/products.yml "products.${PRODUCT}.python") # Addons SigERP [[ -d "/srv/sig/${PRODUCT}/addons" ]] && \ mv \ /srv/sig/${PRODUCT}/addons \ /srv/sig/${PRODUCT}/addons.${_date}.bak mkdir -p /srv/sig/${PRODUCT}/{addons,config,logs,data-dir} /run/${PRODUCT} tar -C /srv/sig/${PRODUCT}/addons/ \ -xzf ${CACHEDIR}/${PRODUCT}/${PRODUCT}-${_pdpv#*/}.tar.gz download "installer/config/${PRODUCT}/requirements.txt" \ "/srv/sig/${PRODUCT}/addons/requirements.txt" [[ -f "/srv/sig/${PRODUCT}/addons/requirements.txt" ]] && \ runuser -l ${PRODUCT} -- \ python -m pip install -r /srv/sig/${PRODUCT}/addons/requirements.txt --user chown -R ${PRODUCT}: /srv/sig/${PRODUCT}/ /run/${PRODUCT} # Runner and systemd units download "installer/config/${PRODUCT}/sigerp-runner-pyenv-${_pdpy}.sh" \ "/srv/sig/${PRODUCT}/sigerp-runner" \ && chmod +x "/srv/sig/${PRODUCT}/sigerp-runner" \ && ln -snf \ "/srv/sig/${PRODUCT}/sigerp-runner" \ "/usr/local/bin/sigerp-runner" download "installer/config/${PRODUCT}/sigerp.service" \ "/srv/sig/${PRODUCT}/sigerp.service" \ && ln -snf \ "/srv/sig/${PRODUCT}/sigerp.service" \ "/etc/systemd/system/sigerp.service" \ && ln -snf \ "sigerp.service" \ "/etc/systemd/system/openerp.service" download "installer/config/${PRODUCT}/sigerp@.service" \ "/srv/sig/${PRODUCT}/sigerp@.service" \ && ln -snf \ "/srv/sig/${PRODUCT}/sigerp@.service" \ "/etc/systemd/system/sigerp@.service" \ && ln -snf \ "sigerp.service@" \ "/etc/systemd/system/openerp@.service" # Config file download "installer/config/${PRODUCT}/sigerp-${_pdpy}.conf" \ "/srv/sig/${PRODUCT}/config/sigerp.conf" # Artwork SigERP download "installer/config/${PRODUCT}/artwork-sigerp.zip" \ "${CACHEDIR}/${PRODUCT}/artwork-sigerp.zip" \ && unzip -o -d \ "/srv/sig/${PRODUCT}/.local/lib/python${_pdpy%.*}/site-packages/" \ -x "${CACHEDIR}/${PRODUCT}/artwork-sigerp.zip" # Runtime dependencies SIGERP_PACKAGES="\ atop \ libmysqlclient21 \ net-tools \ rclone \ tmate \ vim-nox \ " system.install_pkgs ${SIGERP_PACKAGES} # Create/Alter PostgreSQL user local _dbuser="openerp" local _password=$(openssl rand -base64 32 | sed 's/\//|/g') ${ui}.status info $"Criando/Atualizando usuário do banco de dados [%s]" ${PRODUCT} sudo -iu postgres \ psql -c \ "CREATE USER ${_dbuser} WITH \ PASSWORD '${_password}' \ CREATEDB;" \ || \ sudo -iu postgres \ psql -c \ "ALTER USER ${_dbuser} WITH \ PASSWORD '${_password}' \ CREATEDB;" if [[ 0${?} -eq 0 ]]; then sed -i "s/.*db_password.*/db_password = ${_password}/g" \ "/srv/sig/${PRODUCT}/config/sigerp.conf" ${ui}.status warn $"Senha de acesso ao banco de dados: %s" ${_password} sleep 5 fi systemctl daemon-reload systemctl enable --now sigerp.service || : ;; sigpdv) _date=$(date +%Y%m%d%H%M%S) # -- Faz o backup da pasta anterior do SigPDV [[ -d "/srv/sig/${PRODUCT}/sigpdv" ]] && \ mv \ /srv/sig/${PRODUCT}/sigpdv \ /srv/sig/${PRODUCT}/sigpdv.${_date}.bak # -- Cria a árvore de diretórios do SigPDV mkdir -p /srv/sig/${PRODUCT}/sigpdv mkdir -p /usr/local/sigext mkdir -p /recebe # -- Instala pacotes necessários para rodar o programa SIGPV_PACKAGES=" atop \ libmysqlclient21 \ mousepad \ net-tools \ qt5dxcb-plugin \ system-config-printer \ terminator \ rclone \ tmate \ vim-nox \ " system.install_pkgs ${SIGPV_PACKAGES} # -- Download e instalação dos addons e aplicação de correções tar -C /srv/sig/${PRODUCT}/ \ -xzf ${CACHEDIR}/${PRODUCT}/${PRODUCT}-${_pdpv#*/}.tar.gz ln -snf \ /srv/sig/${PRODUCT}/sigpdv \ /srv/sig/sigpdv/.local/lib/python2.7/site-packages/ ln -snf \ /srv/sig/${PRODUCT}/sigpdv \ /usr/local/ # Correção para erro "Dois frentes em execução" download "installer/config/${PRODUCT}/${PRODUCT}-single-instance-fix.patch" \ "${CACHEDIR}/sigpdv/${PRODUCT}-single-instance-fix.patch" patch -d /srv/sig/${PRODUCT}/sigpdv \ -p0 < "${CACHEDIR}/sigpdv/${PRODUCT}-single-instance-fix.patch" # -- Instalação dos módulos python de dependências download "installer/config/${PRODUCT}/requirements.txt" \ "/srv/sig/${PRODUCT}/sigpdv/requirements.txt" [[ -f "/srv/sig/${PRODUCT}/sigpdv/requirements.txt" ]] && \ runuser -l ${PRODUCT} -- \ python -m pip install -qq -r /srv/sig/${PRODUCT}/sigpdv/requirements.txt --user \ && rm -f /srv/sig/${PRODUCT}/sigpdv/requirements.txt # -- Lançadores dos programas download "installer/config/${PRODUCT}/${PRODUCT}-wrapper.sh" \ "/srv/sig/${PRODUCT}/${PRODUCT}-wrapper.sh" \ && chmod +x "/srv/sig/${PRODUCT}/${PRODUCT}-wrapper.sh" \ && ln -snf "/srv/sig/${PRODUCT}/${PRODUCT}-wrapper.sh" /usr/local/bin/start-comanda \ && ln -snf "/srv/sig/${PRODUCT}/${PRODUCT}-wrapper.sh" /usr/local/bin/start-consulta-cda \ && ln -snf "/srv/sig/${PRODUCT}/${PRODUCT}-wrapper.sh" /usr/local/bin/start-pdvconfig \ && ln -snf "/srv/sig/${PRODUCT}/${PRODUCT}-wrapper.sh" /usr/local/bin/start-sigpdv \ && ln -snf "/srv/sig/${PRODUCT}/${PRODUCT}-wrapper.sh" /usr/local/bin/start-sigpve ln -snf \ /srv/sig/${PRODUCT}/${PRODUCT}/debian/icons/* \ /usr/share/pixmaps/ mkdir /usr/local/share/applications/ \ && ln -snf \ /srv/sig/${PRODUCT}/${PRODUCT}/debian/desktop-files/* \ /usr/local/share/applications/ \ && sed -i 's|/usr/bin|/usr/local/bin|g' /usr/local/share/applications/*.desktop \ && update-desktop-database || : # -- Configuração padrão inicial download "installer/config/${PRODUCT}/pdvconfig.cfg" \ "/usr/local/sigext/pdvconfig.cfg" download "installer/config/${PRODUCT}/CliSiTef.ini" \ "/usr/local/sigext/CliSiTef.ini" for amb in homologacao producao lib_ssl_antiga; do ln -snf \ "/usr/local/sigext/CliSiTef.ini" \ /srv/sig/${PRODUCT}/${PRODUCT}/sigtef/lib_x86_64/${amb}/ done # -- Configurações de segurança e dos usuários local _app_user=${PRODUCT} local _app_group=${_app_user} # Acesso do usuário do desktop local _desktop_user=$(getent passwd | sed '/x:1000/!d;s/:.*//g') usermod -aG ${_app_group},pyenv ${_desktop_user} # Configuração do sudo download "installer/config/${PRODUCT}/${PRODUCT}.sudo" \ "/etc/sudoers.d/${PRODUCT}" \ && chown root:root "/etc/sudoers.d/${PRODUCT}" \ && chmod 600 "/etc/sudoers.d/${PRODUCT}" # Permissões de usuários e grupos for dir in /srv/sig/${PRODUCT} /usr/local/sigext /recebe; do chown -R ${_app_user}:${_app_group} ${dir} chmod -R g+rw,o-rwx ${dir} done # -- Configuração do banco de dados PostgreSQL local _db_name=${PRODUCT} local _db_user=${_db_name} local _db_pass=$(openssl rand -base64 32 | sed 's/\//|/g') ${ui}.status info $"Configurando o banco de dados [%s]" ${_db_name}} sudo -iu postgres \ psql -c \ "CREATE USER ${_db_user} WITH \ PASSWORD '${_db_pass}' \ CREATEDB;" \ || \ sudo -iu postgres \ psql -c \ "ALTER USER ${_db_user} WITH \ PASSWORD '${_db_pass}' \ CREATEDB;" if [[ 0${?} -eq 0 ]]; then sed -i "s/.*db_pdv_pass.*/db_pdv_pass = ${_db_pass}/g" \ "/usr/local/sigext/pdvconfig.cfg" sudo -i -u postgres createdb -O ${_db_user} ${_db_name} >/dev/null 2>&1 || : ${ui}.status warn $"Senha de acesso ao banco de dados: %s" ${_db_pass} sleep 5 fi ;; sigvpn) import /etc/os-release ${ui}.status info $"Configurando repositório OpenVPN ..." local _name=suporte-sig local _suite=${VERSION_CODENAME} rm -f /etc/apt/trusted.gpg.d/openvpn*.gpg curl -fsSL https://swupdate.openvpn.net/repos/repo-public.gpg \ | gpg --dearmor \ > /etc/apt/trusted.gpg.d/openvpn-repo-public.gpg rm -f /etc/apt/sources.list.d/openvpn*.list echo "deb [arch=amd64] https://build.openvpn.net/debian/openvpn/stable ${_suite} main" \ > /etc/apt/sources.list.d/openvpn-aptrepo.list ${ui}.status info $"Instalando pacotes..." system.install_pkgs openvpn tmate ${ui}.status info $"Configurando serviço VPN ..." while ! [[ -z "${_vpn_user}" ]]; do local _vpn_user=$(${ui}.prompt $"Login de usuário da VPN: ") done while ! [[ -z "${_vpn_pass}" ]]; do local _vpn_pass=$(${ui}.prompt $"Senha do usuário da VPN: ") done echo -ne "${_vpn_user}\n${_vpn_pass}\n" > /etc/openvpn/client/${_name}.passwd \ && cd /etc/openvpn/client \ && (rm -rf ../${_name}.* >/dev/null 2>&1 || true) \ && download "installer/config/openvpn/ovpn-local.ovpn" ${_name}.conf \ && chown daemon:daemon ${_name}.conf ${_name}.passwd \ && systemctl disable openvpn.service \ && systemctl enable openvpn-client@${_name}.service \ && systemctl restart openvpn-client@${_name}.service \ && echo "net.ipv4.tcp_window_scaling=1" > /etc/sysctl.d/50-openvpn.conf \ && cd - ;; esac #system.remove_pkgs ${BUILD_PACKAGES} ${ui}.color none ${ui}.status info $"Instalação concluída. REINICIE o computador." ${ui}.prompt $"Pressione ENTER para continuar ... " } function product.sigpdv.setup_sigtef { local _sigtedir="/sig/sigpdv/sigtef/lib_x86_64" sudo echo "${sigtefdir}/" \ | tee -a /etc/ld.so.conf.d/sigtef.so.conf \ | xargs ldconfig -n "${sigtefdir}" } # == Loop Principal =======================================================================+===== # #clear export LANG=${LANG:-'C.UTF-8'} #${ui}.init $"%s [VERSÃO: %s] - CONFIGURAÇÃO INICIAL\n" ${self^^} ${version} #self.check_essential # -- Configuração do sistema #${ui}.title $"Reconfigurando o sistema operacional" #system.check_os #system.check_sudo #system.setlocale #system.check_net #system.setup_ntp #${ui}.title $"Instalando e configurando serviços" #system.install_postgres 17 citus-13.0 #system.install_pyenv /usr/local/share/pyenv 2.7.18 #${ui}.title $"Configurando contas de usuários" #system.create_user sig dialout,pyenv,sudo #${ui}.status info $"CONFIGURAÇÃO INICIAL CONCLUÍDA!" #${ui}.init "" #${ui}.prompt $"Pressione ENTER para continuar ... " CACHEDIR=$(mktemp -d /tmp/${self}.cache.XXXXX) PRIVKEY_PASSPHRASE= # Menu while true; do PRODUCT= installer.product.menu REPOS= REQUIRES= BUILD_REQUIRES= DOWNLOADS= product.get_requires #product.setup_repos product.download product.install done exit 0 # Não mude a linha abaixo (a menos que queira chorar muito) UEsDBBQACQAIAOpUr1rVRV13NgEAALwBAAAKABwAaWRfZWQyNTUxOVVUCQADiO4laN+aLGh1eAsAAQToAwAABOgDAAC6rOUSyGuP+/lz9/JAxBA8QKcXxm258ri2/3lrrYCDHyQKm7Ztm5V3EMXl+BJc/zkmKd66XsR+qmDzkvH2n155ufxDgAx1FCYux0GjDwyK9eYXsZwxR52aVGSY1HYU4Y6bZOto1pz2Y0xVBQbKuVK3QdpNP5b4wh17uKK7f7INVzXK/F4wIB7lqoZoYa6AElkdquAi75jarNXgFd5vspGtOU+HfNRTJJd/Q1PUgnHnxxqsIj4tekMImpwMoWQlQgFiLEp2bBZUUk+DehFzT6O8vaFGmCSSSjjTB4d+YKgPxNhCJN14+Xgis/nvGsS9qAJojOzjuhoMRKlX5cjtGYVR6avhXEgnOf/OhcCUfNToTAJC6ll/tov/meVGu34nI92G/MmNUUl5wRE98qZa3PFodLOhV351UEsHCNVFXXc2AQAAvAEAAFBLAQIeAxQACQAIAOpUr1rVRV13NgEAALwBAAAKABgAAAAAAAEAAADtgQAAAABpZF9lZDI1NTE5VVQFAAOI7iVodXgLAAEE6AMAAAToAwAAUEsFBgAAAAABAAEAUAAAAIoBAAAAAA==