Pos teste de instalação

This commit is contained in:
2026-05-07 14:20:40 -03:00
parent 5d92a6c99a
commit ed7e5f55cb
5 changed files with 83 additions and 32 deletions
+1
View File
@@ -7,3 +7,4 @@ config_nodes.json
mapa_dispositivos.json mapa_dispositivos.json
license.key license.key
app_secret.key app_secret.key
installer/vfire-stack.env
+4
View File
@@ -49,6 +49,10 @@ cp installer/vfire-stack.env.example installer/vfire-stack.env
Edite `installer/vfire-stack.env`. Edite `installer/vfire-stack.env`.
Observacoes importantes:
- `ZABBIX_ADMIN_PASSWORD` deve respeitar a politica da interface do Zabbix. Evite senhas contendo `zabbix`, `admin` ou `administrator`.
- Se quiser instalar em modo laboratorio usando a chave legada embutida, ajuste `ALLOW_LEGACY_LICENSE_KEY=1`. Nesse caso o instalador publica `VFM_ALLOW_LEGACY_LICENSE_KEY=1` no servico do app.
Campos minimos que voce deve revisar: Campos minimos que voce deve revisar:
- `PUBLIC_HOSTNAME` - `PUBLIC_HOSTNAME`
+66 -22
View File
@@ -110,7 +110,7 @@ load_config() {
assert_command_dependencies() { assert_command_dependencies() {
local cmd local cmd
for cmd in curl jq gpg wget rsync python3 psql runuser systemctl ss; do for cmd in apt-get python3 runuser systemctl; do
command -v "${cmd}" >/dev/null 2>&1 || die "Comando obrigatorio ausente: ${cmd}" command -v "${cmd}" >/dev/null 2>&1 || die "Comando obrigatorio ausente: ${cmd}"
done done
} }
@@ -118,9 +118,13 @@ assert_command_dependencies() {
assert_ports_available() { assert_ports_available() {
local port local port
[[ "${DRY_RUN}" == "1" ]] && return 0 [[ "${DRY_RUN}" == "1" ]] && return 0
command -v ss >/dev/null 2>&1 || return 0
if [[ "${VFM_APP_PORT}" == "${ZABBIX_WEB_PORT}" || "${VFM_APP_PORT}" == "${GRAFANA_PORT}" || "${ZABBIX_WEB_PORT}" == "${GRAFANA_PORT}" ]]; then
die "As portas configuradas para V-Fire Monitor, Zabbix e Grafana precisam ser distintas."
fi
for port in "${VFM_APP_PORT}" "${ZABBIX_WEB_PORT}" "${GRAFANA_PORT}"; do for port in "${VFM_APP_PORT}" "${ZABBIX_WEB_PORT}" "${GRAFANA_PORT}"; do
if ss -ltn "( sport = :${port} )" | tail -n +2 | grep -q .; then if ss -ltn "( sport = :${port} )" | tail -n +2 | grep -q .; then
die "Porta ${port} ja esta em uso." log "Porta ${port} ja esta em uso. O instalador vai prosseguir para permitir reexecucoes e atualizacoes."
fi fi
done done
} }
@@ -136,9 +140,9 @@ apt_install() {
write_zabbix_repo() { write_zabbix_repo() {
run_cmd install -d -m 0755 /usr/share/keyrings run_cmd install -d -m 0755 /usr/share/keyrings
if [[ "${DRY_RUN}" == "1" ]]; then if [[ "${DRY_RUN}" == "1" ]]; then
printf '[dry-run] curl -fsSL https://repo.zabbix.com/zabbix-official-repo.key | gpg --dearmor -o %s\n' "${ZABBIX_APT_KEYRING}" printf '[dry-run] curl -fsSL https://repo.zabbix.com/zabbix-official-repo.key | gpg --dearmor --yes -o %s\n' "${ZABBIX_APT_KEYRING}"
else else
curl -fsSL "https://repo.zabbix.com/zabbix-official-repo.key" | gpg --dearmor -o "${ZABBIX_APT_KEYRING}" curl -fsSL "https://repo.zabbix.com/zabbix-official-repo.key" | gpg --dearmor --yes -o "${ZABBIX_APT_KEYRING}"
fi fi
run_cmd chmod 0644 "${ZABBIX_APT_KEYRING}" run_cmd chmod 0644 "${ZABBIX_APT_KEYRING}"
cat >"${ZABBIX_APT_LIST}" <<EOF cat >"${ZABBIX_APT_LIST}" <<EOF
@@ -226,6 +230,7 @@ PORT=${VFM_APP_PORT}
VFM_TRUST_PROXY=0 VFM_TRUST_PROXY=0
VFM_SESSION_COOKIE_SECURE=0 VFM_SESSION_COOKIE_SECURE=0
VFM_WAITRESS_THREADS=8 VFM_WAITRESS_THREADS=8
VFM_ALLOW_LEGACY_LICENSE_KEY=${ALLOW_LEGACY_LICENSE_KEY}
${VFM_APP_SECRET:+VFM_APP_SECRET=${VFM_APP_SECRET}} ${VFM_APP_SECRET:+VFM_APP_SECRET=${VFM_APP_SECRET}}
${VFM_LICENSE_MASTER_KEY:+VFM_LICENSE_MASTER_KEY=${VFM_LICENSE_MASTER_KEY}} ${VFM_LICENSE_MASTER_KEY:+VFM_LICENSE_MASTER_KEY=${VFM_LICENSE_MASTER_KEY}}
EOF EOF
@@ -304,6 +309,28 @@ configure_zabbix() {
set_ini_value "/etc/zabbix/zabbix_server.conf" "DBUser" "${ZABBIX_DB_USER}" set_ini_value "/etc/zabbix/zabbix_server.conf" "DBUser" "${ZABBIX_DB_USER}"
set_ini_value "/etc/zabbix/zabbix_server.conf" "DBPassword" "${ZABBIX_DB_PASSWORD}" set_ini_value "/etc/zabbix/zabbix_server.conf" "DBPassword" "${ZABBIX_DB_PASSWORD}"
run_cmd install -d -m 0750 /etc/zabbix/web
cat > /etc/zabbix/web/zabbix.conf.php <<EOF
<?php
// Zabbix GUI configuration file generated by V-Fire installer.
\$DB['TYPE'] = 'POSTGRESQL';
\$DB['SERVER'] = 'localhost';
\$DB['PORT'] = '0';
\$DB['DATABASE'] = '${ZABBIX_DB_NAME}';
\$DB['USER'] = '${ZABBIX_DB_USER}';
\$DB['PASSWORD'] = '${ZABBIX_DB_PASSWORD}';
\$DB['SCHEMA'] = '';
\$ZBX_SERVER = 'localhost';
\$ZBX_SERVER_PORT = '10051';
\$ZBX_SERVER_NAME = '${ZABBIX_MONITORED_HOST}';
\$IMAGE_FORMAT_DEFAULT = IMAGE_FORMAT_PNG;
EOF
run_cmd chown root:www-data /etc/zabbix/web/zabbix.conf.php
run_cmd chmod 0640 /etc/zabbix/web/zabbix.conf.php
if [[ -f /etc/zabbix/nginx.conf ]]; then if [[ -f /etc/zabbix/nginx.conf ]]; then
sed -i -E "s|^[[:space:]]*#[[:space:]]*listen[[:space:]]+8080;| listen ${ZABBIX_WEB_PORT};|" /etc/zabbix/nginx.conf sed -i -E "s|^[[:space:]]*#[[:space:]]*listen[[:space:]]+8080;| listen ${ZABBIX_WEB_PORT};|" /etc/zabbix/nginx.conf
sed -i -E "s|^[[:space:]]*#[[:space:]]*server_name[[:space:]]+example.com;| server_name _;|" /etc/zabbix/nginx.conf sed -i -E "s|^[[:space:]]*#[[:space:]]*server_name[[:space:]]+example.com;| server_name _;|" /etc/zabbix/nginx.conf
@@ -321,12 +348,13 @@ configure_grafana() {
run_cmd install -d -m 0755 /etc/grafana/provisioning/datasources run_cmd install -d -m 0755 /etc/grafana/provisioning/datasources
run_cmd install -d -m 0755 /etc/grafana/provisioning/dashboards run_cmd install -d -m 0755 /etc/grafana/provisioning/dashboards
run_cmd install -d -m 0755 "${GRAFANA_DASHBOARD_DIR}" run_cmd install -d -m 0755 "${GRAFANA_DASHBOARD_DIR}"
run_cmd install -d -o grafana -g grafana -m 0755 /var/lib/grafana/plugins
if [[ "${GRAFANA_INSTALL_ZABBIX_PLUGIN}" == "1" ]]; then if [[ "${GRAFANA_INSTALL_ZABBIX_PLUGIN}" == "1" ]]; then
if [[ "${DRY_RUN}" == "1" ]]; then if [[ "${DRY_RUN}" == "1" ]]; then
printf '[dry-run] grafana-cli plugins install alexanderzobnin-zabbix-app\n' printf '[dry-run] grafana cli --homepath /usr/share/grafana --pluginsDir /var/lib/grafana/plugins plugins install alexanderzobnin-zabbix-app\n'
else else
grafana-cli plugins install alexanderzobnin-zabbix-app || true grafana cli --homepath /usr/share/grafana --pluginsDir /var/lib/grafana/plugins plugins install alexanderzobnin-zabbix-app || true
fi fi
fi fi
@@ -370,6 +398,7 @@ EOF
run_cmd cp "${APP_HOME}/dashboards/grafana/vfire-floorplan-starter.json" "${GRAFANA_DASHBOARD_DIR}/vfire-floorplan-starter.json" run_cmd cp "${APP_HOME}/dashboards/grafana/vfire-floorplan-starter.json" "${GRAFANA_DASHBOARD_DIR}/vfire-floorplan-starter.json"
run_cmd chown -R grafana:grafana "${GRAFANA_DASHBOARD_DIR}" run_cmd chown -R grafana:grafana "${GRAFANA_DASHBOARD_DIR}"
run_cmd chown -R grafana:grafana /var/lib/grafana/plugins
} }
restart_core_services() { restart_core_services() {
@@ -403,8 +432,28 @@ wait_for_http() {
zabbix_api_request() { zabbix_api_request() {
local payload="$1" local payload="$1"
local auth_token="${2:-}"
local curl_args=(-fsS -H 'Content-Type: application/json-rpc')
[[ "${DRY_RUN}" == "1" ]] && return 0 [[ "${DRY_RUN}" == "1" ]] && return 0
curl -fsS -H 'Content-Type: application/json-rpc' -d "${payload}" "http://127.0.0.1:${ZABBIX_WEB_PORT}/api_jsonrpc.php" if [[ -n "${auth_token}" ]]; then
curl_args+=(-H "Authorization: Bearer ${auth_token}")
fi
curl "${curl_args[@]}" -d "${payload}" "http://127.0.0.1:${ZABBIX_WEB_PORT}/api_jsonrpc.php"
}
zabbix_error_message() {
local response="$1"
printf '%s' "${response}" | jq -r '.error.data // .error.message // empty'
}
zabbix_require_success() {
local response="$1"
local context="$2"
local error_message
error_message="$(zabbix_error_message "${response}")"
if [[ -n "${error_message}" ]]; then
die "${context}: ${error_message}"
fi
} }
configure_zabbix_admin_password() { configure_zabbix_admin_password() {
@@ -418,26 +467,26 @@ configure_zabbix_admin_password() {
user_id="$(printf '%s' "${auth_response}" | jq -r '.result.userid // empty')" user_id="$(printf '%s' "${auth_response}" | jq -r '.result.userid // empty')"
if [[ -n "${auth_token}" && -n "${user_id}" && "${ZABBIX_ADMIN_PASSWORD}" != "zabbix" ]]; then if [[ -n "${auth_token}" && -n "${user_id}" && "${ZABBIX_ADMIN_PASSWORD}" != "zabbix" ]]; then
zabbix_api_request "$(jq -cn \ auth_response="$(zabbix_api_request "$(jq -cn \
--arg auth "${auth_token}" \
--arg userid "${user_id}" \ --arg userid "${user_id}" \
--arg current "zabbix" \ --arg current "zabbix" \
--arg passwd "${ZABBIX_ADMIN_PASSWORD}" \ --arg passwd "${ZABBIX_ADMIN_PASSWORD}" \
'{jsonrpc:"2.0",method:"user.update",params:{userid:$userid,current_passwd:$current,passwd:$passwd},auth:$auth,id:1}')" >/dev/null '{jsonrpc:"2.0",method:"user.update",params:{userid:$userid,current_passwd:$current,passwd:$passwd},id:1}')" "${auth_token}" || true)"
zabbix_api_request "$(jq -cn --arg auth "${auth_token}" '{jsonrpc:"2.0",method:"user.logout",params:[],auth:$auth,id:1}')" >/dev/null || true zabbix_require_success "${auth_response}" "Falha ao atualizar a senha administrativa do Zabbix"
return 0 return 0
fi fi
auth_payload="$(jq -cn --arg username "${ZABBIX_ADMIN_USERNAME}" --arg password "${ZABBIX_ADMIN_PASSWORD}" '{jsonrpc:"2.0",method:"user.login",params:{username:$username,password:$password},id:1}')" auth_payload="$(jq -cn --arg username "${ZABBIX_ADMIN_USERNAME}" --arg password "${ZABBIX_ADMIN_PASSWORD}" '{jsonrpc:"2.0",method:"user.login",params:{username:$username,password:$password},id:1}')"
auth_response="$(zabbix_api_request "${auth_payload}" || true)" auth_response="$(zabbix_api_request "${auth_payload}" || true)"
zabbix_require_success "${auth_response}" "Falha ao autenticar na API do Zabbix com as credenciais administrativas configuradas"
auth_token="$(printf '%s' "${auth_response}" | jq -r '.result // empty')" auth_token="$(printf '%s' "${auth_response}" | jq -r '.result // empty')"
[[ -n "${auth_token}" ]] || die "Nao foi possivel autenticar na API do Zabbix com as credenciais administrativas configuradas." [[ -n "${auth_token}" ]] || die "Nao foi possivel autenticar na API do Zabbix com as credenciais administrativas configuradas."
zabbix_api_request "$(jq -cn --arg auth "${auth_token}" '{jsonrpc:"2.0",method:"user.logout",params:[],auth:$auth,id:1}')" >/dev/null || true
} }
zabbix_login() { zabbix_login() {
local response local response
response="$(zabbix_api_request "$(jq -cn --arg username "${ZABBIX_ADMIN_USERNAME}" --arg password "${ZABBIX_ADMIN_PASSWORD}" '{jsonrpc:"2.0",method:"user.login",params:{username:$username,password:$password},id:1}')")" response="$(zabbix_api_request "$(jq -cn --arg username "${ZABBIX_ADMIN_USERNAME}" --arg password "${ZABBIX_ADMIN_PASSWORD}" '{jsonrpc:"2.0",method:"user.login",params:{username:$username,password:$password},id:1}')")"
zabbix_require_success "${response}" "Falha ao obter token da API do Zabbix"
printf '%s' "${response}" | jq -r '.result // empty' printf '%s' "${response}" | jq -r '.result // empty'
} }
@@ -451,8 +500,7 @@ zabbix_get_single_id() {
--arg method "${method}" \ --arg method "${method}" \
--arg key "${filter_key}" \ --arg key "${filter_key}" \
--arg value "${filter_value}" \ --arg value "${filter_value}" \
--arg auth "${auth}" \ '{jsonrpc:"2.0",method:$method,params:{output:["'"${id_key}"'"],filter:{($key):[$value]}},id:1}')" "${auth}" \
'{jsonrpc:"2.0",method:$method,params:{output:["'"${id_key}"'"],filter:{($key):[$value]}},auth:$auth,id:1}')" \
| jq -r ".result[0].${id_key} // empty" | jq -r ".result[0].${id_key} // empty"
} }
@@ -462,9 +510,8 @@ import_zabbix_template() {
[[ -f "${ZABBIX_TEMPLATE_FILE}" ]] || die "Template do Zabbix nao encontrado: ${ZABBIX_TEMPLATE_FILE}" [[ -f "${ZABBIX_TEMPLATE_FILE}" ]] || die "Template do Zabbix nao encontrado: ${ZABBIX_TEMPLATE_FILE}"
source="$(cat "${ZABBIX_TEMPLATE_FILE}")" source="$(cat "${ZABBIX_TEMPLATE_FILE}")"
zabbix_api_request "$(jq -cn \ zabbix_api_request "$(jq -cn \
--arg auth "${auth}" \
--arg source "${source}" \ --arg source "${source}" \
'{jsonrpc:"2.0",method:"configuration.import",params:{format:"yaml",source:$source,rules:{template_groups:{createMissing:true,updateExisting:true},templates:{createMissing:true,updateExisting:true},discoveryRules:{createMissing:true,updateExisting:true,deleteMissing:false},items:{createMissing:true,updateExisting:true,deleteMissing:false},triggers:{createMissing:true,updateExisting:true,deleteMissing:false},valueMaps:{createMissing:true,updateExisting:true,deleteMissing:false},templateDashboards:{createMissing:true,updateExisting:true,deleteMissing:false}}},auth:$auth,id:1}')" >/dev/null '{jsonrpc:"2.0",method:"configuration.import",params:{format:"yaml",source:$source,rules:{template_groups:{createMissing:true,updateExisting:true},templates:{createMissing:true,updateExisting:true},discoveryRules:{createMissing:true,updateExisting:true,deleteMissing:false},items:{createMissing:true,updateExisting:true,deleteMissing:false},triggers:{createMissing:true,updateExisting:true,deleteMissing:false},valueMaps:{createMissing:true,updateExisting:true,deleteMissing:false},templateDashboards:{createMissing:true,updateExisting:true,deleteMissing:false}}},id:1}')" "${auth}" >/dev/null
} }
ensure_zabbix_host_group() { ensure_zabbix_host_group() {
@@ -475,7 +522,7 @@ ensure_zabbix_host_group() {
printf '%s' "${group_id}" printf '%s' "${group_id}"
return 0 return 0
fi fi
zabbix_api_request "$(jq -cn --arg auth "${auth}" --arg name "${ZABBIX_HOST_GROUP}" '{jsonrpc:"2.0",method:"hostgroup.create",params:{name:$name},auth:$auth,id:1}')" | jq -r '.result.groupids[0]' zabbix_api_request "$(jq -cn --arg name "${ZABBIX_HOST_GROUP}" '{jsonrpc:"2.0",method:"hostgroup.create",params:{name:$name},id:1}')" "${auth}" | jq -r '.result.groupids[0]'
} }
ensure_zabbix_monitored_host() { ensure_zabbix_monitored_host() {
@@ -489,22 +536,20 @@ ensure_zabbix_monitored_host() {
host_id="$(zabbix_get_single_id "host.get" "host" "${ZABBIX_MONITORED_HOST}" "hostid" "${auth}")" host_id="$(zabbix_get_single_id "host.get" "host" "${ZABBIX_MONITORED_HOST}" "hostid" "${auth}")"
if [[ -n "${host_id}" ]]; then if [[ -n "${host_id}" ]]; then
zabbix_api_request "$(jq -cn \ zabbix_api_request "$(jq -cn \
--arg auth "${auth}" \
--arg hostid "${host_id}" \ --arg hostid "${host_id}" \
--arg host "${ZABBIX_MONITORED_HOST}" \ --arg host "${ZABBIX_MONITORED_HOST}" \
--arg group_id "${group_id}" \ --arg group_id "${group_id}" \
--arg template_id "${template_id}" \ --arg template_id "${template_id}" \
'{jsonrpc:"2.0",method:"host.update",params:{hostid:$hostid,host:$host,name:$host,status:0,groups:[{groupid:$group_id}],templates:[{templateid:$template_id}]},auth:$auth,id:1}')" >/dev/null '{jsonrpc:"2.0",method:"host.update",params:{hostid:$hostid,host:$host,name:$host,status:0,groups:[{groupid:$group_id}],templates:[{templateid:$template_id}]},id:1}')" "${auth}" >/dev/null
printf '%s' "${host_id}" printf '%s' "${host_id}"
return 0 return 0
fi fi
zabbix_api_request "$(jq -cn \ zabbix_api_request "$(jq -cn \
--arg auth "${auth}" \
--arg host "${ZABBIX_MONITORED_HOST}" \ --arg host "${ZABBIX_MONITORED_HOST}" \
--arg group_id "${group_id}" \ --arg group_id "${group_id}" \
--arg template_id "${template_id}" \ --arg template_id "${template_id}" \
'{jsonrpc:"2.0",method:"host.create",params:{host:$host,name:$host,status:0,groups:[{groupid:$group_id}],templates:[{templateid:$template_id}],tags:[{tag:"application",value:"vfire-monitor"}]},auth:$auth,id:1}')" | jq -r '.result.hostids[0]' '{jsonrpc:"2.0",method:"host.create",params:{host:$host,name:$host,status:0,groups:[{groupid:$group_id}],templates:[{templateid:$template_id}],tags:[{tag:"application",value:"vfire-monitor"}]},id:1}')" "${auth}" | jq -r '.result.hostids[0]'
} }
seed_vfire_runtime_config() { seed_vfire_runtime_config() {
@@ -554,7 +599,6 @@ provision_zabbix_objects() {
[[ -n "${group_id}" ]] || die "Falha ao criar ou localizar host group do Zabbix." [[ -n "${group_id}" ]] || die "Falha ao criar ou localizar host group do Zabbix."
host_id="$(ensure_zabbix_monitored_host "${auth}" "${group_id}")" host_id="$(ensure_zabbix_monitored_host "${auth}" "${group_id}")"
[[ -n "${host_id}" ]] || die "Falha ao criar ou localizar host monitorado do Zabbix." [[ -n "${host_id}" ]] || die "Falha ao criar ou localizar host monitorado do Zabbix."
zabbix_api_request "$(jq -cn --arg auth "${auth}" '{jsonrpc:"2.0",method:"user.logout",params:[],auth:$auth,id:1}')" >/dev/null || true
seed_vfire_runtime_config seed_vfire_runtime_config
} }
+3 -2
View File
@@ -18,9 +18,10 @@ ZABBIX_DB_NAME=zabbix
ZABBIX_DB_USER=zabbix ZABBIX_DB_USER=zabbix
ZABBIX_DB_PASSWORD= ZABBIX_DB_PASSWORD=
ZABBIX_ADMIN_USERNAME=Admin ZABBIX_ADMIN_USERNAME=Admin
ZABBIX_ADMIN_PASSWORD=zabbix # Evite usar "zabbix", "admin" ou "administrator" na senha do Admin do Zabbix.
ZABBIX_ADMIN_PASSWORD=
ZABBIX_TEMPLATE_FILE=/opt/vfire-monitor/zbx_export_templates.yaml ZABBIX_TEMPLATE_FILE=/opt/vfire-monitor/zbx_export_templates.yaml
ZABBIX_TEMPLATE_NAME=Notifier NFS320 ZABBIX_TEMPLATE_NAME="Notifier NFS320"
ZABBIX_HOST_GROUP=Notifier ZABBIX_HOST_GROUP=Notifier
ZABBIX_MONITORED_HOST=NFS-320 ZABBIX_MONITORED_HOST=NFS-320
+9 -8
View File
@@ -127,14 +127,15 @@ def normalize_config(data: dict, default_password: str) -> dict:
return config return config
def load_license_key(require_env: bool) -> bytes: def load_license_key(require_env: bool) -> bytes:
env_key = os.getenv("VFM_LICENSE_MASTER_KEY") env_key = os.getenv("VFM_LICENSE_MASTER_KEY")
if env_key: allow_legacy = os.getenv("VFM_ALLOW_LEGACY_LICENSE_KEY", os.getenv("ALLOW_LEGACY_LICENSE_KEY", "0")) == "1"
return env_key.encode("utf-8") if env_key:
if require_env: return env_key.encode("utf-8")
raise RuntimeError( if require_env and not allow_legacy:
"VFM_LICENSE_MASTER_KEY e obrigatoria em producao. Defina a variavel de ambiente antes de iniciar o sistema." raise RuntimeError(
) "VFM_LICENSE_MASTER_KEY e obrigatoria em producao. Defina a variavel de ambiente antes de iniciar o sistema."
)
LOGGER.warning( LOGGER.warning(
"VFM_LICENSE_MASTER_KEY nao definido. Usando chave legada embutida; mova a chave para variavel de ambiente." "VFM_LICENSE_MASTER_KEY nao definido. Usando chave legada embutida; mova a chave para variavel de ambiente."
) )