Open filiperochalopes opened 1 month ago
Arquivo que manda as Exceptions
br.gov.saude.esus.installers.core.EsusValidator.java
// ...
public boolean validateEnviroment(EsusConfig config) {
this.errors = new ArrayList<String>();
if (!Environment.isElevated()) {
this.errors.add("Esta ferramenta necessita executar com privil\u00e9gios de administrador.");
return false;
}
if (EsusConfig.Action.UNINSTALL.equals((Object)config.getAction())) {
return true;
}
if (!Environment.isUnix() && !Environment.isWindows()) {
this.errors.add("Esta ferramenta suporta apenas sistemas operacionais das fam\u00edlias Windows e Linux.");
} else if (EsusConstants.IS_WINDOWS_CONTAINER && !Environment.isWindows()) {
this.errors.add("Esta ferramenta suporta apenas sistemas operacionais da fam\u00edlia Windows.");
} else if (!EsusConstants.IS_WINDOWS_CONTAINER && !Environment.isUnix()) {
this.errors.add("Esta ferramenta suporta apenas sistemas operacionais da fam\u00edlia Linux.");
}
if (Environment.isUnix() && !Environment.hasSystemd() && !Boolean.TRUE.equals(config.getCustomDatabase())) {
this.errors.add("Essa ferramenta suporta apenas distribui\u00e7\u00f5es Linux com sistema de inicializa\u00e7\u00e3o System D.");
}
if (!Environment.isX64()) {
this.errors.add("Esta ferramenta suporta apenas sistemas operacionais de arquitetura x64.");
}
return this.errors.isEmpty();
}
private boolean validateDatabaseMinimumVersion(DatabaseConfig databaseConfig) {
this.errors = new ArrayList<String>();
DatabaseTester database = new DatabaseTester(databaseConfig);
ResultSet result = database.query("SELECT DS_TEXTO FROM TB_CONFIG_SISTEMA WHERE CO_CONFIG_SISTEMA = 'VERSAOBANCODADOS'");
try {
if (result != null && result.next()) {
Version version = new Version(result.getString("DS_TEXTO"));
if (!version.isValid() || version.isValid() && version.compareTo(EsusConstants.PEC_MINIMUM_VERSION) < 0) {
this.errors.add(String.format("O Banco de dados deve estar pelo menos na vers\u00e3o %s do e-SUS APS PEC. Atualize ou execute o seu PEC e tente novamente.", EsusConstants.PEC_MINIMUM_VERSION));
}
} else {
this.errors.add("N\u00e3o foi poss\u00edvel obter a vers\u00e3o do Banco de Dados.");
}
}
catch (SQLException e) {
this.errors.add("Falha ao executar a query no Banco de Dados: " + e.getLocalizedMessage());
}
database.dispose();
return this.errors.isEmpty();
}
private boolean validateDatabaseConnection(DatabaseConfig databaseConfig) {
this.errors = new ArrayList<String>();
DatabaseTester database = new DatabaseTester(databaseConfig);
if (!database.testConnection()) {
this.errors.add("N\u00e3o foi poss\u00edvel conectar ao Banco de Dados: " + database.getLastErrorMessage());
} else if (this.isConnectionInsecure(databaseConfig)) {
this.errors.add("\u00c9 necess\u00e1rio configurar o seu Banco de Dados para exigir credenciais para a conex\u00e3o.");
}
database.dispose();
return this.errors.isEmpty();
}
private boolean isConnectionInsecure(DatabaseConfig databaseConfig) {
DatabaseConfig databaseConfigInsecure = new DatabaseConfig();
databaseConfigInsecure.setConnectionUrl(databaseConfig.getConnectionUrl());
databaseConfigInsecure.setUsername(databaseConfig.getUsername());
databaseConfigInsecure.setPassword(null);
DatabaseTester databaseTester = new DatabaseTester(databaseConfigInsecure);
return databaseTester.testConnection();
}
private boolean validatePostgresDefault(EsusConfig config) {
boolean hasCustomDatabase;
PostgresConfig pc = new PostgresConfig();
PecRegistry pecRegistry = PecRegistry.load();
boolean bl = hasCustomDatabase = pecRegistry != null && pecRegistry.isCustomDatabase();
if (EsusConfig.Action.UPDATE.equals((Object)config.getAction()) && !hasCustomDatabase) {
log.info("o PEC utiliza o PostgreSQL padr\u00e3o.");
if (!pc.autodetect()) {
this.errors.add("N\u00e3o foi encontrado o PostgreSQL padr\u00e3o.");
return false;
}
PostgresCommander commander = new PostgresCommander(pc);
if (!NetworkUtils.isTcpPortInUse(pc.getPort()) && !commander.start()) {
this.errors.add("Falha ao iniciar o PostgreSQL padr\u00e3o.");
return false;
}
log.info("O PostgreSQL padr\u00e3o est\u00e1 em execu\u00e7\u00e3o.");
}
return true;
}
public boolean validateDatabase(DatabaseConfig databaseConfig) {
if (!this.validateDatabaseConnection(databaseConfig)) {
return false;
}
this.errors = new ArrayList<String>();
DatabaseTester database = new DatabaseTester(databaseConfig);
if (Boolean.TRUE.equals(database.tableExists("TB_CONFIG_SISTEMA")) && this.validateDatabaseMinimumVersion(databaseConfig)) {
this.validatePendingProcessing(databaseConfig);
}
database.dispose();
return this.errors.isEmpty();
}
// ...
Arquivo de configuração do banco de dados
br.gov.saude.esus.installer.core.database.DatabaseConfig.java
public class DatabaseConfig {
private String connectionUrl;
private String username;
private String password;
private String readonlyUsername;
private String readonlyPassword;
private boolean training = false;
public static DatabaseConfig fromRegistry(PecRegistry registry) {
if (registry == null) {
return null;
}
DatabaseConfig databaseConfig = DatabaseConfig.createDefault(!registry.isProduction());
if (StringUtils.isNotEmpty(registry.getDatabasePassword())) {
databaseConfig.setPassword(registry.getDatabasePassword());
}
if (StringUtils.isNotEmpty(registry.getDatabaseReadonlyPassword())) {
databaseConfig.setReadonlyPassword(registry.getDatabaseReadonlyPassword());
}
if (registry.isCustomDatabase()) {
databaseConfig.setConnectionUrl(registry.getDatabaseUrl());
databaseConfig.setUsername(registry.getDatabaseUsername());
}
return databaseConfig;
}
public static DatabaseConfig createDefault(boolean training) {
DatabaseConfig databaseConfig = new DatabaseConfig();
databaseConfig.setConnectionUrl("jdbc:postgresql://localhost:5433/esus");
databaseConfig.setUsername("postgres");
databaseConfig.setPassword("esus");
databaseConfig.setReadonlyUsername("esus_leitura");
databaseConfig.setReadonlyPassword("esus");
databaseConfig.setTraining(training);
return databaseConfig;
}
// ...
br.gov.saude.esus.installers.core.database.DatabaseTester.java
// ...
public boolean testConnection() {
this.lastErrorMessage = "";
if (this.config.getType() == null) {
this.lastErrorMessage = "A URL de conex\u00e3o deve come\u00e7ar com 'jdbc:postgresql' ou 'jdbc:oracle'";
return false;
}
Connection connection = this.getConnection();
if (connection != null) {
this.dispose();
}
return StringUtils.isEmpty(this.lastErrorMessage);
}
private Connection getConnection() {
try {
Class.forName(this.getDriverName());
return DriverManager.getConnection(this.config.getConnectionUrl(), this.config.getUsername(), this.config.getPassword());
}
catch (Exception e) {
this.lastErrorMessage = e.getLocalizedMessage();
return null;
}
}
// ...
public static boolean isUnix() {
return SystemUtils.IS_OS_UNIX;
}
public static boolean isWindows() {
return SystemUtils.IS_OS_WINDOWS;
}
private static boolean isWindowsX64() {
String path = System.getenv("SystemRoot");
if (StringUtils.isEmpty(path)) {
return false;
}
return IO.dirExists(IO.combinePaths(path, "SysWOW64"));
}
private static boolean isUnixX64() {
String output = Shell.getInstance().run("file -L /sbin/init").getOutput();
return StringUtils.isNotEmpty(output) && output.trim().toLowerCase().contains("64-bit");
}
public static boolean isX64() {
boolean is64bits;
boolean bl = is64bits = !SystemUtils.OS_ARCH.endsWith("64");
if (!is64bits) {
if (Environment.isWindows()) {
is64bits = Environment.isWindowsX64();
} else if (Environment.isUnix()) {
is64bits = Environment.isUnixX64();
}
}
return is64bits;
}
public static Version getJvmVersion() {
return new Version(System.getProperty("java.version"));
}
public static boolean isSupported() {
return Environment.isX64() && (Environment.isUnix() || Environment.isWindows());
}
public static String getVariable(String key) {
return System.getenv(key);
}
public static Map<String, String> getVariables() {
return System.getenv();
}
public static boolean hasSystemd() {
String output = Shell.getInstance().run("ps --no-headers -o comm 1").getOutput();
return StringUtils.isNotEmpty(output) && output.trim().toLowerCase().equals("systemd");
}
Ambientes testados:
Versão da aplicação testada 5.2.38 (maior parte dos testes) e 5.2.28 (poucos testes, porém mesmos erros). Utilizar branch
feature/noharm
se quiser facilitar a replicação dos testes. Edite.env.external-db
, pode adicionar algo na url como argumentos no arquivobuild.sh
e depois rodarsh build.sh -e -c
.Sistema Operacional
Máquina Ubuntu 24.04 LTS (GNU/Linux 6.8.0-1012-aws x86_64) Container Docker Ubuntu 22.04 com systemd
Banco de dados
Foram utilizados para teste:
Impressão:
Aparentemente o driver JDBC está mal configurado e com retornos difíceis de debugar, aparentemente só podemos usar um usuário chamado postgres e temos limitações quanto a url e uso de SSL na conexão.
Foram realizados testes com diversos clientes
psql
,jdbc postgres
do dbeaver e de script java criado para teste (42.7.3) que retornaram conexões positivas, porém não pelo jdbc utilizado na aplicação.Também notamos que o driver no pacote parece só fazer requisições "no encryption" fazendo com que tenhamos que desativar o SSL do banco, o que é uma falha de segurança.
Passos para o erro:
Rodar comando de instalação do pacote com diferentes url
Foi feito teste com
-verbose
, sem verbose, com-continue
e sem, também utilizado parâmetros de configuração SSL e de Debug na url como:E combinações entre essas variávels
Evidências:
O printscreen enviado pelo suporte usa
psql
como host, que não é um ip nem um domínio, a utilização delocalhost
,127.0.0.1
e domínios AWS retornam alguns erros dependendo da url utilizada, porém nenhum com sucesso:Veja esse exemplo, no mesmo ambiente diz que temos uma falha de senha, mas não temos:
Output:
Porém no mesmo ambiente com
psql
pg_hba.conf do teste acima
postgresql.conf
Olha que bizarro esse outro erro:
Output:
Ele queixa de falha de autenticação do usuário
postgres
, porém estou usando um usuário chamadoesus_user
Algo interessante é que o ambiente executado por
sh build.sh -f eSUS-AB-PEC-5.2.38-Linux64.jar
funciona, pois usapsql
como host, que é um serviço no docker-compose. O que achei interessante é que, no exemplo funcional que o suporte me enviou ele também usapsql
como host. Existe alguma limitação no nome do host? algum filtro/parse? Segue imagem do suporte:Tem final bem sucedido com Java 8, Ubuntu 22.04.4 LTS, porém não mostra se o
psql
nesse caso foi um apelido criado em/etc/hosts
ou um serviço docker como meu exemplo que também funciona.Debugando
Sabemos que o driver está em
org.postgresql.Driver.class
, porém existem duas referências dessa no archive *.jar. Uma desde a pasta raiz e outra que seguebr.org.postgresql.Driver.class
, aqui temos alguns arquivos relevantes, assim como o script de conexão utilzando JDBC PostgreSQL que funcionou:br.org.postgresql.ds.common.BaseDataSource.java
Meu script utilizando JDBC postgres funcionou normal:
Perguntas:
Tickets abertos:
https://esusaps.freshdesk.com/support/tickets/58738 - Abril de 2024 https://esusaps.freshdesk.com/support/tickets/64098 - 3 de Agosto de 2024.