Skip to content
Snippets Groups Projects
Commit 3444af8f authored by Fernando Alvez's avatar Fernando Alvez
Browse files

Merge branch 'release/v1.7.0'

parents 2609e932 445c88df
No related branches found
Tags v1.7.0
No related merge requests found
Showing
with 1574 additions and 12 deletions
......@@ -4,14 +4,21 @@
[CURRENT](/../compare/master...develop)
[v1.7.0](/../tree/v1.7.0) - 2019-08-20
* Nuevo argumento `--no-resguardar-config` al comando para reconfigurar, que evita realizar la exportación de la configuración actual
* Nuevo comando `docker:db-inicializar` y `docker:db-actualizar`que permite a partir de una instalación del proyecto existente en disco, recrear la base de negocios del proyecto como la de Toba
* Nuevo comando para sincronizar reportes `reportes:instalar` y `reportes:actualizar`
* Se hace opcional la configuración de RestHooks
* Mejoras al comando de reconfiguración para proyectos Toba
[v1.6.0](/../tree/v1.6.0) - 2019-06-10
* Se agrega configuración para validar los intentos de accesos en una instalación de proyecto sin la integración del login con SIU-Araí.
* Se reestructura los métodos que manejan comandos Toba.
* Se realizan mejoras al comando reconfigurar.
* Se corrige mensajes duplicados al cargar parámetros del instalador.
* Se corrige migración de configuración de SMTP al momento de la actualización.
* Se hace opcional la configuración de WS de AFIP.
* Se mejora como se muestran las advertencias generadas por los comandos toba durante la ejecución de procesos.
* Se agrega configuración para validar los intentos de accesos en una instalación de proyecto sin la integración del login con SIU-Araí
* Se reestructura los métodos que manejan comandos Toba
* Se realizan mejoras al comando reconfigurar
* Se corrige mensajes duplicados al cargar parámetros del instalador
* Se corrige migración de configuración de SMTP al momento de la actualización
* Se hace opcional la configuración de WS de AFIP
* Se mejora como se muestran las advertencias generadas por los comandos toba durante la ejecución de procesos
[v1.5.0](/../tree/v1.5.0) - 2019-04-03
* Soporte a Toba 3.2 (Dotenv conflictivo, ahora soportamos 2.x y 3.x)
......
......@@ -58,6 +58,20 @@ $worflowReconfigurar = new \SIU\Instalador\Toba\Workflow\Reconfiguracion($factor
$cmdReconfigurar = new \SIU\Instalador\Consola\ComandoReconfigurar();
$cmdReconfigurar->setWorkflow($worflowReconfigurar);
$worflowInstalacionDocker = new \SIU\Instalador\Toba\Workflow\InstalacionEnDocker($factory);
$cmdInicializarDB = new \SIU\Instalador\Consola\ComandoDockerDbInicializar();
$cmdInicializarDB->setWorkflow($worflowInstalacionDocker);
$cmdActualizarDB = new \SIU\Instalador\Consola\ComandoDockerDbActualizar();
$cmdActualizarDB->setWorkflow($worflowInstalacionDocker);
$worflowReportes = new \SIU\Instalador\Generico\Workflow\Reportes($factory);
$cmdReportesInst = new \SIU\Instalador\Consola\ComandoReportesInstalar();
$cmdReportesInst->setWorkflow($worflowReportes);
$cmdReportesAct = new \SIU\Instalador\Consola\ComandoReportesActualizar();
$cmdReportesAct->setWorkflow($worflowReportes);
$app = new \SIU\Instalador\Consola\Aplicacion($configuracion->getProyectoNombre(), $configuracion->getProyectoVersion());
......@@ -72,5 +86,9 @@ $app->add($cmdVarsEnv);
$app->add($cmdCrearBasePrueba);
$app->add($cmdExportarInstalacion);
$app->add($cmdReconfigurar);
$app->add($cmdInicializarDB);
$app->add($cmdActualizarDB);
$app->add($cmdReportesInst);
$app->add($cmdReportesAct);
$app->run();
......@@ -85,4 +85,12 @@ TOBA_ALIAS_PROYECTO="/proyecto"
##### CONFIG SEGURIDAD ####
SEGURIDAD_INTENTOS=3
SEGURIDAD_TIEMPO_BLOQUEO=5
SEGURIDAD_BLOQUEA_USUARIO=1
\ No newline at end of file
SEGURIDAD_BLOQUEA_USUARIO=1
##### CONFIG REPORTES ####
#ARAI_REPORTES_URL=http://localhost/reports/rest
#ARAI_REPORTES_PORT=80
#ARAI_REPORTES_USUARIO=deadmanwalking
#ARAI_REPORTES_PWD=youshouldenhancethis
#ARAI_REPORTES_DIR="/ruta/absoluta/al/directorio/de/reportes/en/el/proyecto"
\ No newline at end of file
<?php
namespace SIU\Instalador;
/**
* Clase que wrappea llamadas a la extension curl
*/
class ClienteCurl
{
protected $usr;
protected $port;
protected $url;
protected $pwd;
protected $auth;
protected $curlClient;
static protected $instancia;
protected function __construct()
{
$opciones = array(
CURLOPT_FAILONERROR => true,
CURLOPT_HEADER => false,
CURLOPT_HTTPGET => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_UNRESTRICTED_AUTH => true,
CURLOPT_SSL_VERIFYPEER => false, //TODO: REMOVER ESTO, SOLO PARA DEBUG
CURLOPT_VERBOSE => true);
$this->curlClient = curl_init();
curl_setopt_array($this->curlClient, $opciones);
}
function __destruct()
{
curl_close($this->curlClient);
unset($this->usr);
unset($this->port);
unset($this->url);
unset($this->pwd);
unset($this->auth);
self::$instancia = null;
}
static function instancia()
{
if (! isset(self::$instancia)) {
self::$instancia = new ClienteCurl();
}
return self::$instancia;
}
function setUsr($usr)
{
$this->usr = $usr;
}
function setPwd($pwd)
{
$this->pwd = $pwd;
if (! isset($this->usr)) {
throw \Exception(' Falta fijar el valor del parametro usuario' );
}
curl_setopt($this->curlClient, CURLOPT_USERPWD, "{$this->usr}:{$this->pwd}");
}
function setPort($port)
{
$this->port = $port;
curl_setopt($this->curlClient, CURLOPT_PORT, $this->port);
}
function setUrl($url)
{
$this->url = $url;
curl_setopt($this->curlClient, CURLOPT_URL, $this->url);
}
function setMethod($metodo)
{
curl_setopt($this->curlClient, CURLOPT_CUSTOMREQUEST, $metodo);
}
function setAuth($autenticacion)
{
switch ($autenticacion) {
case 'digest':
case 'ssl':
$this->auth = CURLAUTH_ANYSAFE;
break;
case 'basic':
default:
$this->auth = CURLAUTH_ANY;
break;
}
curl_setopt($this->curlClient, CURLOPT_HTTPAUTH, $this->auth);
}
function getStatus()
{
return curl_getinfo($this->curlClient, CURLINFO_RESPONSE_CODE);
}
function ejecutar($expected=array())
{
$esperados = (is_array($expected)) ? $expected : array($expected);
$respuesta = curl_exec($this->curlClient);
if (false === $respuesta) { //La quedo por algun motivo
$codigo = curl_getinfo($this->curlClient, CURLINFO_HTTP_CONNECTCODE);
throw new \Exception(" Codigo: $codigo " . curl_error($this->curlClient));
}
if (! empty($esperados) && !in_array(curl_getinfo($this->curlClient, CURLINFO_RESPONSE_CODE), $esperados)) { //Vino un status code distinto del esperado para exito
error_log(' Esperados: ' . var_export($esperados, true) . ' Actuales ' . curl_getinfo($this->curlClient, CURLINFO_RESPONSE_CODE));
throw new \Exception(' Error Code no esperado : ' . curl_error($this->curlClient));
}
return $respuesta;
}
function get($url, $expectedStatus=array())
{
$this->setUrl($url);
$this->setMethod('GET');
return $this->ejecutar($expectedStatus);
}
function post($url, $data, $expectedStatus=array())
{
$this->setUrl($url);
$this->setMethod('POST');
$this->setData($data);
return $this->ejecutar($expectedStatus);
}
function put($url, $data, $expectedStatus=array())
{
$this->setUrl($url);
$this->setMethod('PUT');
$this->setData($data);
return $this->ejecutar($expectedStatus);
}
function delete($url, $expectedStatus=array())
{
$this->setUrl($url);
$this->setMethod('DELETE');
return $this->ejecutar($expectedStatus);
}
function setData($data)
{
$data = (is_array($data)) ? http_build_query($data) : $data;
curl_setopt($this->curlClient, CURLOPT_POSTFIELDS, $data);
}
function setFile($filePath)
{
curl_setopt($this->curlClient, CURLOPT_FILE, $filePath);
}
}
......@@ -61,6 +61,7 @@ LOGO;
{
$controles = [
'php_version' => 'error|5.6.0',
'php_extension_curl' => 'error|',
];
return $controles;
......
<?php
namespace SIU\Instalador\Consola;
use Symfony\Component\Console\Input\InputOption;
/**
* Description of ComandoDockerDbActualizar.
*
* @author Sergio Fabian Vier <svier@siu.edu.ar>
*/
class ComandoDockerDbActualizar extends ComandoWorkflow
{
protected function configure()
{
$this
->setName('docker:db-actualizar')
->setDescription('Actualiza la estructura de la base de datos del proyecto')
->setHidden(true)
;
$this
->addOption(
'no-progress',
null,
InputOption::VALUE_NONE,
'No genera barras de progreso',
null
);
}
}
<?php
namespace SIU\Instalador\Consola;
use Symfony\Component\Console\Input\InputOption;
/**
* Description of ComandoDockerDbInicializar.
*
* @author Sergio Fabian Vier <svier@siu.edu.ar>
*/
class ComandoDockerDbInicializar extends ComandoWorkflow
{
protected function configure()
{
$this
->setName('docker:db-inicializar')
->setDescription('Inicializa la estructura de la base de datos del proyecto')
->setHidden(true)
;
$this
->addOption(
'crear-db',
null,
InputOption::VALUE_NONE,
'Crea una nueva base de negocio antes de instalar',
null
);
$this
->addOption(
'no-progress',
null,
InputOption::VALUE_NONE,
'No genera barras de progreso',
null
);
}
}
......@@ -60,6 +60,15 @@ class ComandoReconfigurar extends ComandoWorkflow
'No realiza la validación de servicios (SMTP, Registry, Redis)',
null
);
$this
->addOption(
'no-resguardar-config',
null,
InputOption::VALUE_NONE,
'No realiza una copia de seguridad local de la configuración existente',
null
);
}
protected function getMensajeAyuda()
......@@ -92,16 +101,29 @@ A continuación se especifica los argumentos disponibles para configurar:
|--------------------|----------------------------------------------------------------|----------------------------------------|
|afip | Las credenciales de conexión al web service de Afip | AFIP_WS_XXX |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|seguridad_acceso | Los datos configuración de seguridad de acceso | SEGURIDAD_XXX |
|seguridad-acceso | Los datos configuración de seguridad de acceso | SEGURIDAD_XXX |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|smtp | Los datos de conexión para SMTP | SMTP_XXX |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|db_negocio | Las credenciales de conexión a la base de datos del proyecto | PROYECTO_DB_XXX |
|db-negocio | Las credenciales de conexión a la base de datos del proyecto | PROYECTO_DB_XXX |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|db-toba | Las credenciales de conexión a la base de datos de Toba | TOBA_DB_XXX |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|api_rest | Los datos de conexión para API tipo REST | REST_XXX |
|api-rest | Los datos de conexión para API tipo REST | REST_XXX |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|sso | Los datos de conexión para SSO Saml (sin araí) | SSO_XXX |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|url | Las opciones de Toba | TOBA_ALIAS_NUCLEO |
| | | TOBA_ALIAS_PROYECTO |
| | | TOBA_URL_BASE |
| | | TOBA_URL_PORT |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|url-toba | Las opciones de Toba | TOBA_ALIAS_NUCLEO |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|url-proyecto | Las opciones de Toba | TOBA_ALIAS_PROYECTO |
| | | TOBA_URL_BASE |
| | | TOBA_URL_PORT |
|--------------------|----------------------------------------------------------------|----------------------------------------|
|toba | Las opciones de Toba | TOBA_URL_XXX, TOBA_PASSWORD, |
| | | TOBA_ID_DESARROLLADOR, |
| | | TOBA_SESSION_NAME, TOBA_FORZAR_HTTPS, |
......
<?php
namespace SIU\Instalador\Consola;
use Symfony\Component\Console\Input\InputOption;
/**
* Permite cambiar los permisos.
*
* @author Sergio Fabian Vier <svier@siu.edu.ar>
*/
class ComandoReportesActualizar extends ComandoWorkflow
{
protected function configure()
{
$this
->setName('reportes:actualizar')
->setDescription('Actualiza los reportes para la aplicación')
->setHelp($this->getMensajeAyuda())
// opciones
->addOption(
'no-progress',
null,
InputOption::VALUE_NONE,
'No genera barras de progreso',
null
);
}
protected function getMensajeAyuda()
{
$reemplazos = [
'%comando%' => $this->getExecutedCommand(),
];
$mensaje =
<<<'EOF'
Este comando permite actualizar los reportes del sistema, pensado para el acceso de un usuario y permitiendo al grupo que ejecuta el servidor web Apache acceder a los archivos necesarios.
<options=bold,underscore>Recuerde:</> no es una práctica segura que los archivos queden con permiso de superusuario o abierto con acceso para usuarios comunes.
Como ejecutar
=============
Supongamos que se trabaja en un sistema operativo Debian GNU/Linux y se quiere actualizar los reportes del proyecto en cuestion:
<info>%comando% reportes:actualizar </info>
Esto ejecutará las tareas necesarias para actualizar los reportes en el servidor correspondiente:
* accederá a la carpeta correspondiente para el proyecto y recuperara los reportes y recursos que contenga
* obtendra una lista de los recursos en el directorio indicado del proyecto y luego de calcular las diferencias llevará a cabo las acciones correspondientes
EOF;
$mensaje = strtr($mensaje, $reemplazos);
return $mensaje;
}
}
<?php
namespace SIU\Instalador\Consola;
use Symfony\Component\Console\Input\InputOption;
/**
* Permite cambiar los permisos.
*
* @author Sergio Fabian Vier <svier@siu.edu.ar>
*/
class ComandoReportesInstalar extends ComandoWorkflow
{
protected function configure()
{
$this
->setName('reportes:instalar')
->setDescription('Instala los reportes para la aplicación')
->setHelp($this->getMensajeAyuda())
// opciones
->addOption(
'no-progress',
null,
InputOption::VALUE_NONE,
'No genera barras de progreso',
null
);
}
protected function getMensajeAyuda()
{
$reemplazos = [
'%comando%' => $this->getExecutedCommand(),
];
$mensaje =
<<<'EOF'
Este comando permite instalar los reportes del sistema, pensado para el acceso de un usuario y permitiendo al grupo que ejecuta el servidor web Apache acceder a los archivos necesarios.
<options=bold,underscore>Recuerde:</> no es una práctica segura que los archivos queden con permiso de superusuario o abierto con acceso para usuarios comunes.
Como ejecutar
=============
Supongamos que se trabaja en un sistema operativo Debian GNU/Linux y se quiere instalar los reportes del proyecto en cuestion:
<info>%comando% reportes:instalar </info>
Esto ejecutará las tareas necesarias para instalar los reportes en el servidor correspondiente:
* generará una carpeta especifica para el proyecto dentro del servidor de reportes
* obtendra una lista de los recursos en el directorio indicado del proyecto y realizará las llamadas para convertir dichos recursos en elementos en el servidor de reportes
* finalmente agregará aquellos elementos que identifiquen a los reportes propiamente dichos
EOF;
$mensaje = strtr($mensaje, $reemplazos);
return $mensaje;
}
}
<?php
namespace SIU\Instalador\Generico\Paso;
use SIU\Instalador\Generico\Paso\SincronizarReportes;
use SIU\Instalador\ClienteCurl;
class ActualizarReportes extends SincronizarReportes
{
/**
* {@inheritdoc}
*/
protected function run()
{
$this->io()->msgSubtitulo('Actualizando Reportes:');
//Leer ambos extremos
try {
$this->listarArchivosProyecto(); //Recopilar info de los reportes en el directorio y sus recursos
$this->listarArchivosServer(); //Recopilar info de los reportes en el servidor y sus recursos
//Accion
$this->eliminarCarpetas();
$this->resetearRecursosServer();
$this->insertarRecursos(); //Inserta recursos que puede necesitar el reporte
$this->insertarReportes(); //Inserta los reportes para que al compilar este todo listo
} catch (\Exception $e) {
$this->errors[] = $e->getMessage();
}
}
/**
* Busca la carpeta base del proyecto, tira Excepcion si no la encuentra
* @param string $url URL de la API
* @throws \Exception
*/
protected function findCarpetaBase($url)
{
if (! isset($this->base_cliente)) {
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$url_get = $url . '/carpetas?proyecto=' . $this->config()->getProyectoId();
try {
$rsp = $curl->get($url_get);
$uri = json_decode($rsp, true);
$this->base_cliente = $uri[$this->config()->getProyectoId()];
} catch (\Exception $e) {
if (in_array($curl->getStatus(), [400, 404])) { //Crear la carpeta xq no existe
throw new \Exception('No se encuentra la carpeta base del proyecto, ejecute el comando reportes:instalar');
} else {
throw $e;
}
}
}
}
protected function eliminarCarpetas()
{
if (isset($this->base_cliente)) {
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$datos = ['proyecto' => $this->config()->getProyectoId(), 'uri' => $this->base_cliente];
$url_get = $this->getUrlDestino() . '/carpetas?' . http_build_query($datos);
$curl->delete($url_get, 204);
}
}
protected function resetearRecursosServer()
{
unset($this->recursos_server);
unset($this->reportes_server);
$this->reportes_server = $this->recursos_server = array();
}
}
......@@ -178,7 +178,7 @@ class CorregirPermisos extends Paso
private function permisosEscribiblePorApacheDirectorios()
{
$directorios = $this->getDirEscribiblePorApache();
$directorios = $this->soloDirectoriosExistentes($this->getDirEscribiblePorApache());
if (count($directorios) < 1) {
return;
......@@ -380,4 +380,27 @@ class CorregirPermisos extends Paso
{
return ['vendor'];
}
/**
* Filtra y retorna los directorios existentes
*
* @param $directorios array
*
* @return array
*/
protected function soloDirectoriosExistentes($directorios)
{
$existentes = [];
foreach ($directorios as $directorio) {
if (is_dir($directorio)) {
$existentes[] = $directorio;
} else {
$msg = "El directorio '$directorio' no existe";
$this->log($msg, LogLevel::ERROR);
$this->errors[] = $msg;
}
}
return $existentes;
}
}
<?php
namespace SIU\Instalador\Generico\Paso;
use SIU\Instalador\Generico\Paso\SincronizarReportes;
use SIU\Instalador\ClienteCurl;
class InstalarReportes extends SincronizarReportes
{
/**
* {@inheritdoc}
*/
protected function run()
{
$this->io()->msgSubtitulo('Instalando Reportes:');
//Leer ambos extremos
try {
$this->listarArchivosProyecto(); //Recopilar info de los reportes en el directorio y sus recursos
$this->listarArchivosServer(); //Recopilar info de los reportes en el servidor y sus recursos
if (empty($this->reportes_server) && empty($this->recursos_server)) {
//Accion
$this->insertarRecursos(); //Inserta recursos que puede necesitar el reporte
$this->insertarReportes(); //Inserta los reportes para que al compilar este todo listo
} else {
$this->errors[] = ' El servidor contiene reportes para el proyecto, ejecute el comando reportes:actualizar ';
}
} catch (\Exception $e) {
$this->errors[] = $e->getMessage();
}
}
/**
* Crea la carpeta de reportes del proyecto
* @return string La Uri de la carpeta inicial del proyecto en el servidor de reportes
*/
private function crearCarpetaReportes()
{
$url = $this->getUrlDestino() . '/carpetas';
//Pregunto el uri de la carpeta base para el proyecto
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
//Creo la carpeta
$data = ['carpeta' => ['proyecto' => $this->config()->getProyectoId(), 'uri' => '']];
$uri = $curl->post($url, json_encode($data, true));
return $uri;
}
/**
* Busca la carpeta base para el proyecto o la crea si no existe
* @param string $url URL de la API
* @throws \Exception
*/
protected function findCarpetaBase($url)
{
if (! isset($this->base_cliente)) {
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$url_get = $url . '/carpetas?proyecto='. $this->config()->getProyectoId();
try {
$rsp = $curl->get($url_get);
$uri = json_decode($rsp, true);
$this->base_cliente = $uri[$this->config()->getProyectoId()];
} catch (\Exception $e) {
if (in_array($curl->getStatus(), [400, 404])) { //Crear la carpeta xq no existe
$uri = json_decode($this->crearCarpetaReportes(), true);
$this->base_cliente = $uri['uri'];
} else {
throw $e;
}
}
}
}
}
<?php
namespace SIU\Instalador\Generico\Paso;
use SIU\Instalador\Paso;
/**
* Paso que realiza la creación de base de datos de negocio
*
* @author Sergio Fabian Vier <svier@siu.edu.ar>
*/
class MigrarBase extends Paso
{
public function configure()
{
$this->setNombre('Migración de base de negocio del proyecto');
$this->setDescripcion('Se realiza la creación/actualización de base de datos de negocio de un proyecto');
}
protected function preRun()
{
}
protected function run()
{
if ($this->io()->isCrearDb()) {
$this->io()->msgNote("Esta por crear la base de datos de negocio '".$this->parametros['db_proyecto']['dbname']."'");
$this->msgConfirmAsk('¿Desea continuar?');
$this->crearDbNegocio($this->parametros['db_proyecto']);
}
$this->migrarDB();
}
protected function postRun()
{
}
public function migrarDB()
{
throw new \Exception("Not implemented");
}
}
<?php
namespace SIU\Instalador\Generico\Paso;
use Symfony\Component\Filesystem\Filesystem;
use Psr\Log\LogLevel;
use SIU\Instalador\Paso;
class Parametrizar extends Paso
{
public function configure()
{
$this->setNombre('Parametrización del proyecto');
$this->setDescripcion("Se realiza la lectura del archivo del instalador 'instalador.env'");
}
protected function preRun()
{
$this->proyecto = $this->config()->getProyectoId();
}
protected function run()
{
$this->leerParametrosInstalador();
$this->cargarParametrosEntorno();
$this->cargarParametrosSMTP();
$this->cargarParametrosRestHooks();
$this->cargarParametrosReportes();
}
protected function postRun()
{
$comando_ejecutado = $this->io()->getCommandName();
// comandos habilitados para mostrar datos de instalacion
$comandos_habilitados = [
'proyecto:instalar',
'proyecto:actualizar',
];
if (in_array($comando_ejecutado, $comandos_habilitados)) {
$this->mostrarDatosInstalacion();
}
}
/**
* Carga en el contexto los parametros configurados en el archivo instalador.env.
*/
protected function cargarParametrosEntorno()
{
$this->parametros = [];
$this->getContexto()->set('parametros', $this->parametros);
}
/**
* Muestra en forma de tabla los parametros de configuracion y pide confirmacion
* para continuar con los pasos.
*/
protected function mostrarDatosInstalacion()
{
$parametros = $this->getContexto()->get('parametros');
if (empty($parametros)) {
return;
}
$headers = ['Parametro', 'Valor'];
$hay_config = false;
if (getenv('SMTP_ENTRADA') !== false) {
$rows = [];
$this->io()->msgSubtitulo('CONFIG DE SMTP');
$parametros_smtp = $this->getContexto()->get('parametros.smtp');
$parametros_smtp['smtp_clave'] = '***********';
foreach ($parametros_smtp as $key => $value) {
$rows[] = [$key, var_export($value, true)];
$this->log('[ PARAMETROS smtp ] '.$key.'=>'.var_export($value, true), LogLevel::INFO);
}
$this->io()->tableOutput($headers, $rows);
unset($rows);
$hay_config = true;
}
if (getenv('REST_HOOKS_REDIS_HOST') !== false) {
$rows = [];
$this->io()->msgSubtitulo('CONFIG DE REDIS');
$parametros_smtp = $this->getContexto()->get('parametros.resthooks');
foreach ($parametros_smtp as $key => $value) {
$rows[] = [$key, var_export($value, true)];
$this->log('[ PARAMETROS resthooks ] '.$key.'=>'.var_export($value, true), LogLevel::INFO);
}
$this->io()->tableOutput($headers, $rows);
unset($rows);
$hay_config = true;
}
if (\getenv('ARAI_REPORTES_URL')) {
$rows = [];
$this->io()->msgSubtitulo('CONFIG DE REPORTES');
$parametros_smtp = $this->getContexto()->get('parametros.reportes');
foreach ($parametros_smtp as $key => $value) {
$rows[] = [$key, var_export($value, true)];
$this->log('[ PARAMETROS reportes ] '.$key.'=>'.var_export($value, true), LogLevel::INFO);
}
$this->io()->tableOutput($headers, $rows);
unset($rows);
$hay_config = true;
}
if ($hay_config) {
$this->msgConfirmAsk('Verifique si los parámetros configuración son correctos. ¿Desea continuar?');
}
}
public function cargarParametrosSMTP()
{
if (getenv('SMTP_ENTRADA')) {
$smtp = [
'smtp_entrada' => getenv('SMTP_ENTRADA'),
'smtp_host' => $this->getEnv('SMTP_HOST', '127.0.0.1'),
'smtp_port' => $this->getEnv('SMTP_PORT', '465'),
'smtp_from' => getenv('SMTP_FROM'),
'smtp_auth' => $this->getEnv('SMTP_AUTH', '1'),
'smtp_usuario' => getenv('SMTP_USUARIO'),
'smtp_clave' => getenv('SMTP_CLAVE'),
'smtp_seguridad' => $this->getEnv('SMTP_SEGURIDAD', 'tls'),
'smtp_helo' => $this->getEnv('SMTP_HELO', '0'),
'smtp_nombre_from' => $this->getEnv('SMTP_NOMBRE_FROM', '')
];
$this->getContexto()->set('parametros.smtp', $smtp);
}
}
public function cargarParametrosRestHooks()
{
if (getenv('REST_HOOKS_REDIS_HOST')) {
$resthooks = [
'resthooks_activo' => true,
'resthooks_redis_host' => getenv('REST_HOOKS_REDIS_HOST'),
'resthooks_redis_port' => getenv('REST_HOOKS_REDIS_PORT')
];
$this->getContexto()->set('parametros.resthooks', $resthooks);
}
}
public function cargarParametrosReportes()
{
if (getenv('ARAI_REPORTES_URL')) {
$reportes = [
'reportes_host' => $this->getEnv('ARAI_REPORTES_URL'),
'reportes_port' => $this->getEnv('ARAI_REPORTES_PORT'),
'reportes_usuario' => $this->getEnv('ARAI_REPORTES_USUARIO'),
'reportes_pwd' => $this->getEnv('ARAI_REPORTES_PWD'),
'reportes_source_dir' => $this->getEnv('ARAI_REPORTES_DIR', $this->base_dir . '/reportes')
];
$this->getContexto()->set('parametros.reportes', $reportes);
}
}
protected function obtenerParametrosApiRest($parametros)
{
$cliente_datos = [];
$datos = explode(':', $parametros, 2);
if ($datos !== false && count($datos) == 2) {
$datos_aux = null;
if (strpos($datos[0], '%') !== false) {
$datos_aux = explode('%', $datos[0]);
$cliente_datos['auth'] = $datos_aux[0];
$cliente_datos['usuario'] = $datos_aux[1];
} else {
$cliente_datos['usuario'] = $datos[0];
}
if (strpos($datos[1], '@') !== false) {
$datos_aux = explode('@', $datos[1]);
$cliente_datos['clave'] = $datos_aux[0];
$cliente_datos['url'] = $datos_aux[1];
} else {
$cliente_datos['clave'] = $datos[1];
}
}
return $cliente_datos;
}
/**
* Verifica que el alias configurado en en env comience con "/" o si no lo agrega.
*/
protected function parseAlias($alias)
{
if ($alias == '') {
return $alias;
}
if (!preg_match("#^\/#", $alias, $matches)) {
$alias = '/'.$alias;
}
return $alias;
}
}
<?php
namespace SIU\Instalador\Generico\Paso;
use Psr\Log\LogLevel;
use SIU\Instalador\Paso;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Finder\Finder;
use SIU\Instalador\ClienteCurl;
abstract class SincronizarReportes extends Paso
{
protected $fs;
protected $dir_reportes;
protected $base_cliente;
protected $errors=array();
protected $reportes;
protected $recursos;
protected $reportes_server=array();
protected $recursos_server=array();
/**
* {@inheritdoc}
*/
public function configure()
{
$this->setNombre('Sincronizar los reportes del proyecto');
$this->setDescripcion('Se trasladan al servidor de reportes los ajustes sobre la estructura de reportes de un proyecto');
}
/**
* {@inheritdoc}
*/
protected function preRun()
{
$params = $this->getContexto()->get('parametros.reportes');
$this->dir_reportes = $params['reportes_source_dir'];
$this->url = $params['reportes_host'];
$this->usr = $params['reportes_usuario'];
$this->pwd = $params['reportes_pwd'];
$this->port = $params['reportes_port'];
$this->validarConexion();
$this->validarDirectorioReportes();
$this->fs = new Filesystem();
}
/**
* {@inheritdoc}
*/
protected function postRun()
{
if (count($this->errors) > 0) {
$this->io()->msgTitulo('Se han detectado los siguientes errores:');
foreach ($this->errors as $key => $error) {
$this->io()->msgError($error);
if ($key >= 19) { // cortamos el chorro a los 20 errores
$this->io()->msg('Se ha cortado la lista de errores. Existen '.count($this->errors).' errores.');
break;
}
}
}
}
/**
* Retorna los directorios excluidos para ignorar
*
* Nota: solo se utiliza con la opción --rapido
*/
protected function getDirectoriosExcluidos()
{
return [];
}
/**
* Retorna los nombres o extensiones de archivos a ignorar
* @return string
*
* Nota: solo se utiliza con la opción --rapido
*/
protected function getArchivosExcluidos()
{
return '*.jasper';
}
/**
* Devuelve un arreglo conteniendo la ruta de cada archivo considerado recurso
* @return array
*/
protected function getRecursosReportes()
{
return [];
}
/**
* Devuelve un arreglo conteniendo la ruta de cada archivo considerado reporte
* @return array
*/
protected function getReportes()
{
return [];
}
/**
* Devuelve la url donde se aloja la API siu-arai/reportes
* @return type
*/
protected function getUrlDestino()
{
return $this->url;
}
/**
* Devuelve la extension de un archivo especificado
* @param Symfony\Component\Finder\SplFileInfo $fileObj
* @return string
*/
protected function getMimeArchivo($fileObj)
{
return $fileObj->getExtension();
}
/**
* Intenta conectarse al servidor indicado por la configuracion para ver si esta disponible la api
*/
protected function validarConexion()
{
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$curl->get($this->getUrlDestino() . '/api-docs');
}
/**
* Intenta determinar la existencia del directorio indicado y su posibilidad de acceso para lectura
* @throws \Exception
*/
protected function validarDirectorioReportes()
{
if (! is_readable($this->dir_reportes)) {
throw new \Exception('Directorio indicado no accesible' ); //Die, die... you mf !!!
}
}
/**
* Recupera los archivos del directorio indicado por la config
* @return array
*/
protected function getArchivosProyecto()
{
$finder = new Finder();
$finder->ignoreDotFiles(false);
$finder->in($this->dir_reportes)
->exclude($this->ignorar())
->files()
->notName($this->ignorarArchivos());
$archivos = array();
if ($finder->hasResults()) {
$archivos = iterator_to_array($finder);
}
return $archivos;
}
/**
* Aplica permisos a nivel proyecto
*/
protected function listarArchivosProyecto()
{
$this->reportes = array(); //Actuales
$this->recursos = array();
$por_extension = array(); //Asignados por extension
$reportes = $this->getReportes();
$recursos = $this->getRecursosReportes();
$archivos = $this->getArchivosProyecto();
if (! empty($archivos)) {
//Separo en grupos segun lo que indique el proyecto
foreach($archivos as $file) {
$index = $file->getRelativePathName();
if (in_array($index, $reportes)) {
$this->reportes[$index] = $file;
} elseif (in_array($index, $recursos)) {
$this->recursos[$index] = $file;
} else {
$por_extension[$index] = $file;
}
}//fe
//Si hay mas archivos de los indicados, se separan por extension
if (! empty($por_extension)) {
foreach($por_extension as $lastChance) {
$index = $lastChance->getRelativePathName();
switch($this->getMimeArchivo($lastChance)) {
case 'jasper': //Los ignoro xq no es posible mandarlos al server
break;
case 'jrxml' :
if (empty($reportes)) { //Solo los considero reportes si no especificaron nada desde el proyecto
$this->reportes[$index] = $lastChance;
break;
}
default:
$this->recursos[$index] = $lastChance; //Cualquier cosa no evitada es un posible recurso para los reportes
} //sw
}//fe
unset($por_extension);
}
}
}
/**
* Recupera los archivos del servidor de reportes y los divide entre recursos y reportes en dos
* variables de clase
*/
protected function listarArchivosServer()
{
$this->reportes_server = array();
$this->recursos_server = array();
$url = $this->getUrlDestino();
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
//Leer la carpeta base del proyecto
$this->findCarpetaBase($url);
//Leer los reportes del server
$url_repo = $url . '/reportes?proyecto=' . $this->config()->getProyectoId();
try {
$resultado = json_decode($curl->get($url_repo), true);
foreach($resultado as $nombre => $ruta) {
if (false !== preg_match('|^([A-Za-z0-9_/]+\.jrxml)[_\d]*$|', $ruta, $matches) && ! empty($matches)) {
$ruta_final = str_replace($this->base_cliente. '/', '', $matches[1]);
$ruta = str_replace($this->base_cliente. '/', '', $ruta);
$this->reportes_server[$ruta_final] = $ruta;
}
}
} catch (\Exception $e) {
if ($curl->getStatus() != 404) {
throw $e;
}
}
unset($matches);
unset($resultado);
//Leer los archivos miscelaneos del server ( no jrxml)
$url_recu = $url . '/archivos?proyecto=' . $this->config()->getProyectoId();
try {
$resultado = json_decode($curl->get($url_recu), true);
foreach($resultado as $nombre => $ruta) {
if (false !== preg_match('|^([A-Za-z0-9_/]+\.(?!jrxml).+)[_\d]*$|', $ruta, $matches) && ! empty($matches)) {
$ruta_final = str_replace($this->base_cliente. '/', '', $matches[1]);
$ruta = str_replace($this->base_cliente. '/', '', $ruta);
$this->recursos_server[$ruta_final] = $ruta;
}
}
} catch (\Exception $e) {
if ($curl->getStatus() != 404) {
throw $e;
}
}
unset($curl);
unset($resultado);
}
//-------------------------------------------------------------------------------------------------------------------//
// RECURSOS VARIOS
//-------------------------------------------------------------------------------------------------------------------//
/**
* Determina que recursos deben ser eliminados y realiza la llamada al metodo que lo hace
*/
protected function eliminarRecursos()
{
$servidos = array_keys($this->recursos_server);
$actuales = array_keys($this->recursos);
$sobrantes = array_diff($servidos, $actuales);
if (! empty($sobrantes)) { //Hacer pelota los reportes y sus recursos
foreach($sobrantes as $ruta) {
if (isset($this->recursos_server[$ruta])) {
$this->_eliminarRecursos($this->recursos_server[$ruta]);
}
}
}
}
/**
* Determina que recursos deben incorporarse y realiza la llamada al metodo que lo hace
*/
protected function insertarRecursos()
{
$servidos = array_keys($this->recursos_server);
$actuales = array_keys($this->recursos);
$faltantes = array_diff($actuales, $servidos);
if (! empty($faltantes)) {
foreach($faltantes as $nuevos) {
if (isset($this->recursos[$nuevos])) {
$this->_insertarRecursos($this->recursos[$nuevos]); //Mete los recursos primero por si algun reporte tiene referencias a
}
}
}
}
/**
* Determina que recursos deben actualizarse y realiza la llamada al metodo que lo hace
*/
protected function modificarRecursos()
{
$servidos = array_keys($this->recursos_server);
$actuales = array_keys($this->recursos);
$modificables = array_intersect($actuales, $servidos);
if (! empty($modificables)) {
foreach($modificables as $mod) {
if (isset($this->recursos[$mod])) {
$this->_modificarRecursos($this->recursos[$mod]);
}
}
}
}
//-------------------------------------------------------------------------------------------------------------------//
// REPORTES
//-------------------------------------------------------------------------------------------------------------------//
/**
* Determina que reportes deben eliminarse y realiza la llamada al metodo que lo hace
*/
protected function eliminarReportes()
{
$servidos = array_keys($this->reportes_server);
$actuales = array_keys($this->reportes);
$sobrantes = array_diff($servidos, $actuales);
if (! empty($sobrantes)) {
foreach($sobrantes as $ruta) {
if (isset($this->reportes_server[$ruta])) {
$this->_eliminarReporteJrxml($this->reportes_server[$ruta]); //Elimina el informe primero
}
}
}
}
/**
* Determina que reportes deben agregarse y realiza la llamada al metodo que lo hace
*/
protected function insertarReportes()
{
$servidos = array_keys($this->reportes_server);
$actuales = array_keys($this->reportes);
$faltantes = array_diff($actuales, $servidos);
if (! empty($faltantes)) {
foreach($faltantes as $nuevos) {
if (isset($this->reportes[$nuevos])) {
$this->_insertarReportesJrxml($this->reportes[$nuevos]);
}
}
}
}
/**
* Determina que reportes deben actualizarse y realiza la llamada al metodo que lo hace
*/
protected function modificarReportes()
{
$servidos = array_keys($this->reportes_server);
$actuales = array_keys($this->reportes);
$modificables = array_intersect($actuales, $servidos);
if (! empty($modificables)) {
foreach($modificables as $mod) {
if (isset($this->reportes[$mod])) {
$this->_modificarReportesJrxml($this->reportes[$mod]);
}
}
}
}
//-------------------------------------------------------------------------------------------------------------------//
// AUXILIARES
//-------------------------------------------------------------------------------------------------------------------//
/**
* Dispara la eliminacion del recurso apuntado por la URI relativa indicada
* @param string $uri_recurso
*/
protected function _eliminarRecursos($uri_recurso)
{
$url = $this->getUrlDestino() . '/archivos';
$data = [ 'proyecto' => $this->config()->getProyectoId(), 'uri' => $this->base_cliente . '/' . $uri_recurso];
$url_del = $url . '?'.http_build_query($data);
//Instancio la conexion y ejecuto
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$curl->delete($url_del, 204);
unset($curl);
}
/**
* Dispara la insercion del recurso en el servidor de reportes
* @param mixed $datos
*/
protected function _insertarRecursos($datos)
{
if (! empty($datos)) {
$uri_archivo = $this->base_cliente . '/' . $datos->getRelativePathName();
$url = $this->getUrlDestino() . '/archivos';
//Prepara los parametros segun modelo
$data = [
'proyecto' => $this->config()->getProyectoId(),
'id' => $datos->getFileName(),
'uri' => $uri_archivo,
'archivo' => array( 'uri' => $uri_archivo,
'tipo' => $this->getMimeArchivo($datos),
'data' => base64_encode(file_get_contents($datos->getPathName())),
'temporal' => 0)
];
//Instancio la conexion y ejecuto
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$curl->post($url, json_encode($data, true), 201);
}
}
/**
* Dispara la actualizacion del recurso como (DEL + INS) para mantener siempre el mismo nro de version
* @param mixed $archivo
*/
protected function _modificarRecursos($archivo)
{
if (! empty($archivo)) {
$uri_archivo = $this->base_cliente . '/' . $archivo->getRelativePathName();
$url = $this->getUrlDestino() . '/archivos';
//Preparo parametros
$data = [ 'proyecto' => $this->config()->getProyectoId(), 'uri' => $uri_archivo];
$url_del = $url . '?'. http_build_query($data);
//Instancio la conexion y ejecuto el delete
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$curl->delete($url_del, 204);
//Vuelvo a generar el recurso
$this->_insertarRecursos($archivo);
}
}
/**
* Dispara la eliminacion del reporte indicado por la Uri relativa
* @param string $uri_reporte
*/
protected function _eliminarReporteJrxml($uri_reporte)
{
$data = [ 'proyecto' => $this->config()->getProyectoId(), 'uri' => $this->base_cliente . '/' .$uri_reporte];
$url = $this->getUrlDestino(). '/reportes';
$url = $url . '?' . http_build_query($data);
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$curl->delete($url, 204);
}
/**
* Dispara la insercion del reporte en el servidor
* @param mixed $archivo
*/
protected function _insertarReportesJrxml($archivo)
{
if (! empty($archivo)) {
$url = $this->getUrlDestino(). '/reportes';
$uri_archivo = $this->base_cliente . '/' . $archivo->getRelativePathName();
//Hay que agregarle la carpeta base
$data = ['recurso' => ['proyecto' => $this->config()->getProyectoId(),
'id' => $archivo->getFileName(),
'uri' => $uri_archivo,
'source' => array( 'uri' => $uri_archivo,
'temporal' => 0,
'data' => base64_encode(file_get_contents($archivo->getPathName()))
)
]
];
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$curl->post($url, json_encode($data, true), 201);
}
}
/**
* Dispara la modificacion de reportes como (DEL + INS) para mantener siempre una unica version
* @param mixed $archivo
*/
protected function _modificarReportesJrxml($archivo)
{
if (! empty($archivo)) {
$uri_archivo = $this->base_cliente . '/' . $archivo->getRelativePathName();
$url = $this->getUrlDestino(). '/reportes';
$data = [ 'proyecto' => $this->config()->getProyectoId(), 'uri' => $uri_archivo];
$url_del = $url .'?'. http_build_query($data);
$curl = ClienteCurl::instancia();
$this->configConexion($curl);
$curl->delete($url_del, 204);
$this->_insertarReportesJrxml($archivo);
}
}
/**
* Retorna directorios o patron de directorios a ignorar, solo si es --rapido
* @return array
*/
protected function ignorar()
{
if ($this->io()->isRapidoMode()) {
return $this->getDirectoriosExcluidos();
} else {
return null;
}
}
/**
* Retorna archivos o patron de archivos a ignorar, solo si es --rapido
* @return array
*/
protected function ignorarArchivos()
{
if ($this->io()->isRapidoMode()) {
return $this->getArchivosExcluidos();
} else {
return null;
}
}
/**
* Fija los parametros minimos al cliente de la conexion
* @param ClienteCurl $clienteCurl Referencia a instancia de la clase clienteCurl
*/
protected function configConexion(&$clienteCurl)
{
$clienteCurl->setPort($this->port);
$clienteCurl->setUsr($this->usr);
$clienteCurl->setPwd($this->pwd);
}
/**
* Obtiene la carpeta base para el proyecto
*/
abstract protected function findCarpetaBase($url);
}
<?php
namespace SIU\Instalador\Generico\Workflow;
use SIU\Instalador\Workflow;
class Reportes extends Workflow
{
/**
* {@inheritdoc}
*/
public function getDescripcionInicio()
{
$descripcion = <<<'DESCRIPCION'
Bienvenido al proceso de sincronización de reportes del proyecto %1$s.
Se le preguntará acerca de los cambios a realizar, específicamente
que directorio contiene los reportes del proyecto:
DESCRIPCION;
return sprintf($descripcion, $this->config()->getProyectoNombre());
}
/**
* {@inheritdoc}
*/
public function getDescripcionFin()
{
$descripcion = <<<'DESCRIPCION'
Se ha finalizado correctamente el proceso de sincronización de reportes del proyecto %1$s.
DESCRIPCION;
return sprintf($descripcion, $this->config()->getProyectoNombre());
}
/**
* {@inheritdoc}
*/
public function inicializarPasos()
{
$pasosInvolucrados = [
new \SIU\Instalador\Generico\Paso\Parametrizar(),
];
if ($this->command instanceof \SIU\Instalador\Consola\ComandoReportesActualizar) {
$pasosInvolucrados[] = new \SIU\Instalador\Generico\Paso\ActualizarReportes();
} elseif ($this->command instanceof \SIU\Instalador\Consola\ComandoReportesInstalar) {
$pasosInvolucrados[] = new \SIU\Instalador\Generico\Paso\InstalarReportes();
}
return $pasosInvolucrados;
}
}
......@@ -407,6 +407,15 @@ class InputOutput
return false;
}
public function isNoResguardarConfig()
{
if ($this->input->hasOption('no-resguardar-config')) {
return (bool) $this->input->getOption('no-resguardar-config');
}
return false;
}
public function isSobreescribirVariables()
{
if ($this->input->hasOption('sobreescribir-variables')) {
......
<?php
namespace SIU\Instalador\Toba\Paso\Docker;
use SIU\Instalador\Toba\Paso\TobaPaso;
/**
* Paso que realiza la migración de base de datos de negocio
*
* @author Sergio Fabian Vier <svier@siu.edu.ar>
*/
class ActualizarBaseProyectoToba extends TobaPaso
{
/**
* {@inheritdoc}
*/
public function configure()
{
$this->setNombre('Migración de base de negocio del proyecto');
$this->setDescripcion('Se realiza la actualización de base de datos de negocio de un proyecto');
}
/**
* {@inheritdoc}
*/
protected function preRun()
{
$this->msgConfirmAsk('Usted esta por actualizar la base de datos de negocio del proyecto ¿Desea continuar?');
}
/**
* {@inheritdoc}
*/
protected function run()
{
$parametros_cargar = $this->parametros['db_proyecto'];
$parametros_cargar['proyecto'] = $this->proyecto;
$this->tobaComando()->migrarProyecto($parametros_cargar);
}
/**
* {@inheritdoc}
*/
protected function postRun()
{
}
}
<?php
namespace SIU\Instalador\Toba\Paso\Docker;
use SIU\Instalador\Toba\Paso\TobaPaso;
/**
* Paso que realiza la migración de base de datos de Toba
*
* Ejecuta el comando "toba instancia regenerar" y:
* - requiere una DB de Toba existente
* - requiere un directorio instalación existente
* - exporta local (usuarios y perfiles)
* - carga metadatos del disco
*
* @author Sergio Fabian Vier <svier@siu.edu.ar>
*/
class ActualizarBaseToba extends TobaPaso
{
/**
* {@inheritdoc}
*/
public function configure()
{
$this->setNombre('Migración de base de datos de Toba');
$this->setDescripcion('Se realiza la actualización de base de datos Toba');
}
/**
* {@inheritdoc}
*/
protected function preRun()
{
$this->msgConfirmAsk('Usted esta por actualizar la base de datos de Toba ¿Desea continuar?');
}
/**
* {@inheritdoc}
*/
protected function run()
{
$this->tobaComando()->regenerarInstancia();
}
/**
* {@inheritdoc}
*/
protected function postRun()
{
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment