paramsx 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of paramsx might be problematic. Click here for more details.
- paramsx-1.0.0/LICENSE +21 -0
- paramsx-1.0.0/PKG-INFO +9 -0
- paramsx-1.0.0/README.md +89 -0
- paramsx-1.0.0/paramsx/__init__.py +0 -0
- paramsx-1.0.0/paramsx/funcions.py +254 -0
- paramsx-1.0.0/paramsx/main.py +206 -0
- paramsx-1.0.0/paramsx/paramsx_config.py +12 -0
- paramsx-1.0.0/paramsx/text.py +12 -0
- paramsx-1.0.0/paramsx.egg-info/PKG-INFO +9 -0
- paramsx-1.0.0/paramsx.egg-info/SOURCES.txt +14 -0
- paramsx-1.0.0/paramsx.egg-info/dependency_links.txt +1 -0
- paramsx-1.0.0/paramsx.egg-info/entry_points.txt +2 -0
- paramsx-1.0.0/paramsx.egg-info/requires.txt +1 -0
- paramsx-1.0.0/paramsx.egg-info/top_level.txt +1 -0
- paramsx-1.0.0/setup.cfg +4 -0
- paramsx-1.0.0/setup.py +98 -0
paramsx-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Mario x
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
paramsx-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: paramsx
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Librería para gestionar y respaldar parámetros de AWS SSM de manera sencilla y eficiente.
|
|
5
|
+
Home-page: https://github.com/pistatxos/paramsx
|
|
6
|
+
Author: Mariox
|
|
7
|
+
Author-email: info@tomonota.net
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: boto3
|
paramsx-1.0.0/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# ParamsX
|
|
2
|
+
|
|
3
|
+
ParamsX es una librería diseñada para gestionar parámetros de AWS SSM de manera sencilla y eficiente. Con ella podrás:
|
|
4
|
+
- Leer parámetros almacenados en AWS SSM.
|
|
5
|
+
- Comparar y actualizar parámetros existentes.
|
|
6
|
+
- Eliminar parámetros que ya no estén presentes en los archivos de configuración.
|
|
7
|
+
- Crear respaldos para evitar pérdida de datos.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
#### Consejos varios para tener un orden en los parámetros
|
|
11
|
+
Para un uso óptimo, se recomienda organizar los parámetros de AWS SSM utilizando prefijos que sigan una estructura lógica. Por ejemplo:
|
|
12
|
+
- /APP/nombreApp/tipoEntorno/más datos...
|
|
13
|
+
|
|
14
|
+
Esta estructura permite identificar y gestionar los parámetros por su aplicación y entorno. En ParamsX, puedes configurar listas específicas para modificar y gestionar estos parámetros de manera eficiente.
|
|
15
|
+
|
|
16
|
+
## Instalación
|
|
17
|
+
|
|
18
|
+
pip install paramx
|
|
19
|
+
|
|
20
|
+
### Configuración inicial
|
|
21
|
+
Al instalar el paquete, se crea automáticamente una carpeta de configuración en tu directorio de usuario:
|
|
22
|
+
|
|
23
|
+
Windows: C:\Users\<tu_usuario>\.xsoft
|
|
24
|
+
Linux/MacOS: /home/<tu_usuario>/.xsoft
|
|
25
|
+
|
|
26
|
+
Dentro de esta carpeta encontrarás un archivo llamado paramsx_config.py.
|
|
27
|
+
Este archivo contiene la configuración inicial de la librería. Antes de usarla, debes asegurarte de editar este archivo para incluir el perfil de AWS y la región que utilizarás.
|
|
28
|
+
|
|
29
|
+
Contenido de paramsx_config.py:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
configuraciones = {
|
|
33
|
+
"profile_name": "default", # Cambiar por el nombre de tu perfil en ~/.aws/credentials
|
|
34
|
+
"region_name": "us-east-1", # Cambiar por tu región de AWS
|
|
35
|
+
"entornos": ["DEV", "PROD"], # Los entornos que manejarás
|
|
36
|
+
"parameter_list": [
|
|
37
|
+
"/params1/xx",
|
|
38
|
+
"/params2/xx",
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
Nota: Si el archivo paramsx_config.py ya existe, no será sobrescrito durante la instalación para proteger las configuraciones personalizadas.
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
## Modo de Uso
|
|
46
|
+
Ejecuta el comando principal desde la terminal:
|
|
47
|
+
|
|
48
|
+
```paramsx```
|
|
49
|
+
|
|
50
|
+
Navega por el menú interactivo:
|
|
51
|
+
|
|
52
|
+
El programa mostrará un menú donde Podrás:
|
|
53
|
+
- Leer parámetros desde AWS SSM.
|
|
54
|
+
- Cargar y actualizar parámetros.
|
|
55
|
+
- Backup de parámetros.
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Leer Parámetros:
|
|
59
|
+
1. Selecciona la opción "Leer parámetros" en el menú.
|
|
60
|
+
2. Elige el prefijo y el entorno que deseas consultar.
|
|
61
|
+
3. Los parámetros serán descargados y guardados en archivos como:
|
|
62
|
+
- parameters_DEV.py
|
|
63
|
+
- parameters_DEV_backup.py
|
|
64
|
+
```Importante: Los archivos se generarán en la misma ruta desde donde ejecutes el comando paramsx```
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
### Cargar Parámetros:
|
|
68
|
+
1. Modifica los archivos generados (parameters_DEV.py).
|
|
69
|
+
2. Usa la opción "Cargar parámetros desde archivo" para comparar los cambios.
|
|
70
|
+
3. El programa mostrará una lista con los siguientes estados:
|
|
71
|
+
- Nuevos: Parámetros que se agregarán.
|
|
72
|
+
- Modificados: Parámetros existentes que se actualizarán.
|
|
73
|
+
- Eliminados: Parámetros que se eliminarán automáticamente de AWS SSM.
|
|
74
|
+
* Revisa los cambios antes de confirmar.
|
|
75
|
+
```Importante: Una vez confirmados los cambios, los archivos parameters_DEV.py y parameters_DEV_backup.py se eliminarán automáticamente```
|
|
76
|
+
|
|
77
|
+
### Notas Adicionales
|
|
78
|
+
- Credenciales de AWS:
|
|
79
|
+
Asegúrate de que el perfil especificado en paramsx_config.py exista en tus archivos de configuración de AWS (~/.aws/credentials y ~/.aws/config).
|
|
80
|
+
|
|
81
|
+
- Seguridad:
|
|
82
|
+
Los parámetros se manejan como SecureString para garantizar que la información sensible esté cifrada
|
|
83
|
+
|
|
84
|
+
- Backup:
|
|
85
|
+
Antes de realizar cualquier cambio, ParamsX crea automáticamente un respaldo (parameters_DEV_backup.py). Este archivo se eliminará después de cargar los nuevos parámetro
|
|
86
|
+
|
|
87
|
+
## Licencia
|
|
88
|
+
ParamsX se distribuye bajo la licencia MIT. Puedes usarlo libremente, modificarlo y adaptarlo a tus necesidades. Recuerda siempre hacer un respaldo de tus configuraciones antes de realizar cambios.
|
|
89
|
+
```Nota: El creador de ParamsX no se hace responsable de posibles pérdidas de datos o configuraciones incorrectas.```
|
|
File without changes
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import os
|
|
3
|
+
from .text import HEADER_ASCII, FOOTER_TEXT
|
|
4
|
+
import curses
|
|
5
|
+
|
|
6
|
+
# Función para obtener parámetros con un entorno específico
|
|
7
|
+
def get_parameters_by_prefix(ssm, prefix):
|
|
8
|
+
parameters = []
|
|
9
|
+
next_token = None
|
|
10
|
+
|
|
11
|
+
while True:
|
|
12
|
+
request_args = {
|
|
13
|
+
"Path": prefix,
|
|
14
|
+
"WithDecryption": True,
|
|
15
|
+
"Recursive": True,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if next_token:
|
|
19
|
+
request_args["NextToken"] = next_token
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
response = ssm.get_parameters_by_path(**request_args)
|
|
23
|
+
except Exception as e:
|
|
24
|
+
raise RuntimeError(f"Error al obtener parámetros: {e}")
|
|
25
|
+
|
|
26
|
+
for param in response.get('Parameters', []):
|
|
27
|
+
parameters.append({
|
|
28
|
+
"parameter_name": param['Name'],
|
|
29
|
+
"parameter_value": param['Value']
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
next_token = response.get('NextToken')
|
|
33
|
+
if not next_token:
|
|
34
|
+
break
|
|
35
|
+
|
|
36
|
+
if not parameters:
|
|
37
|
+
raise ValueError(f"No se encontraron parámetros con el prefijo: {prefix}")
|
|
38
|
+
|
|
39
|
+
return parameters
|
|
40
|
+
|
|
41
|
+
# Función para borrar los parámetros
|
|
42
|
+
def delete_parameter(ssm_client, parameter_name):
|
|
43
|
+
try:
|
|
44
|
+
ssm_client.delete_parameter(Name=parameter_name)
|
|
45
|
+
print(f"Parámetro eliminado: {parameter_name}")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
print(f"Error al eliminar el parámetro {parameter_name}: {e}")
|
|
48
|
+
|
|
49
|
+
# Función para exportar parámetros a un archivo
|
|
50
|
+
def export_parameters_to_file(parameters, file_path):
|
|
51
|
+
with open(file_path, 'w') as f:
|
|
52
|
+
f.write("# PARAMS exportados\n")
|
|
53
|
+
f.write("parametros = [\n")
|
|
54
|
+
for param in parameters:
|
|
55
|
+
parameter_name = param['parameter_name']
|
|
56
|
+
parameter_value = param['parameter_value']
|
|
57
|
+
# Usar triple comillas para valores largos
|
|
58
|
+
f.write(f" {{'parameter_name': '{parameter_name}',\n")
|
|
59
|
+
f.write(f" 'parameter_value': \"\"\"{parameter_value}\"\"\"}},\n\n")
|
|
60
|
+
f.write("]\n")
|
|
61
|
+
|
|
62
|
+
# Función para comparar parámetros y mostrar las diferencias
|
|
63
|
+
def compare_parameters(file_path, backup_file_path, stdscr):
|
|
64
|
+
if not os.path.exists(file_path) or not os.path.exists(backup_file_path):
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
# Usar diccionarios específicos para cargar los archivos
|
|
68
|
+
current_scope = {}
|
|
69
|
+
backup_scope = {}
|
|
70
|
+
|
|
71
|
+
with open(file_path, 'r') as f:
|
|
72
|
+
exec(f.read(), current_scope)
|
|
73
|
+
|
|
74
|
+
with open(backup_file_path, 'r') as f:
|
|
75
|
+
exec(f.read(), backup_scope)
|
|
76
|
+
|
|
77
|
+
# Extraer los parámetros de cada archivo
|
|
78
|
+
current_params = current_scope.get('parametros', [])
|
|
79
|
+
backup_params = backup_scope.get('parametros', [])
|
|
80
|
+
|
|
81
|
+
# Comparar parámetros
|
|
82
|
+
changes = []
|
|
83
|
+
current_dict = {p['parameter_name']: p['parameter_value'] for p in current_params}
|
|
84
|
+
backup_dict = {p['parameter_name']: p['parameter_value'] for p in backup_params}
|
|
85
|
+
|
|
86
|
+
for key in current_dict:
|
|
87
|
+
if key not in backup_dict:
|
|
88
|
+
changes.append((key, "Nuevo", f"{key} - Nuevo"))
|
|
89
|
+
elif current_dict[key] != backup_dict[key]:
|
|
90
|
+
changes.append((key, "Modificado", f"{key} - Modificado"))
|
|
91
|
+
|
|
92
|
+
for key in backup_dict:
|
|
93
|
+
if key not in current_dict:
|
|
94
|
+
changes.append((key, "Eliminado", f"{key} - Eliminado"))
|
|
95
|
+
|
|
96
|
+
return changes
|
|
97
|
+
|
|
98
|
+
# Mostrar contenido comparado
|
|
99
|
+
def show_comparison_results(stdscr, changes):
|
|
100
|
+
stdscr.clear()
|
|
101
|
+
draw_header(stdscr)
|
|
102
|
+
|
|
103
|
+
max_y, max_x = stdscr.getmaxyx() # Tamaño del terminal
|
|
104
|
+
start_line = HEADER_ASCII.count("\n") + 1 # Reservar espacio para el header
|
|
105
|
+
visible_height = max_y - start_line - 3 # Espacio visible en el terminal (sin header/footer)
|
|
106
|
+
scroll_offset = 0 # Controlar desde qué línea se empieza a mostrar
|
|
107
|
+
buffer_lines = 2 # Número de líneas adicionales para mostrar al final
|
|
108
|
+
|
|
109
|
+
while True:
|
|
110
|
+
stdscr.clear()
|
|
111
|
+
draw_header(stdscr)
|
|
112
|
+
|
|
113
|
+
# Mostrar encabezado de la lista con cantidad y guía de navegación
|
|
114
|
+
title = f"Cambios detectados ({len(changes)}) - Usa ↑ y ↓ para navegar - Intro confirmar y Esc para salir"
|
|
115
|
+
stdscr.addstr(start_line, 0, title.center(max_x, "-"))
|
|
116
|
+
|
|
117
|
+
# Calcular el rango visible incluyendo el buffer
|
|
118
|
+
visible_changes = changes[scroll_offset:scroll_offset + visible_height]
|
|
119
|
+
|
|
120
|
+
for i, change in enumerate(visible_changes, start=1 + scroll_offset):
|
|
121
|
+
comment = f"{i}. {change[0]} - {change[1]}"
|
|
122
|
+
truncated_comment = comment[:max_x - 1] # Truncar si excede el ancho
|
|
123
|
+
stdscr.addstr(start_line + i - scroll_offset, 0, truncated_comment)
|
|
124
|
+
|
|
125
|
+
# Mostrar footer vacío o decorativo
|
|
126
|
+
draw_footer(stdscr)
|
|
127
|
+
|
|
128
|
+
# Actualizar pantalla
|
|
129
|
+
stdscr.refresh()
|
|
130
|
+
|
|
131
|
+
# Capturar entrada del usuario
|
|
132
|
+
key = stdscr.getkey()
|
|
133
|
+
|
|
134
|
+
# Manejar teclas de desplazamiento
|
|
135
|
+
if key == "KEY_UP" and scroll_offset > 0:
|
|
136
|
+
scroll_offset -= 1
|
|
137
|
+
elif key == "KEY_DOWN" and scroll_offset + visible_height < len(changes) + buffer_lines:
|
|
138
|
+
scroll_offset += 1
|
|
139
|
+
elif key == '\x1b': # Presionar Esc para salir
|
|
140
|
+
return False
|
|
141
|
+
elif key == '\n': # Presionar Enter para confirmar
|
|
142
|
+
return True
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# Función para mostrar el header personalizado
|
|
146
|
+
def draw_header(stdscr):
|
|
147
|
+
max_y, max_x = stdscr.getmaxyx()
|
|
148
|
+
separator = "=" * max_x
|
|
149
|
+
stdscr.addstr(0, 0, separator) # Línea superior del header
|
|
150
|
+
|
|
151
|
+
# Mostrar HEADER_ASCII línea por línea sin strip
|
|
152
|
+
header_lines = HEADER_ASCII.split("\n") # No eliminar espacios ni líneas vacías
|
|
153
|
+
last_line_index = 0 # Guardar el índice de la última línea válida
|
|
154
|
+
|
|
155
|
+
for i, line in enumerate(header_lines, start=1):
|
|
156
|
+
if line.strip(): # Solo imprimir líneas no vacías
|
|
157
|
+
stdscr.addstr(i, 0, line)
|
|
158
|
+
last_line_index = i # Actualizar la posición de la última línea visible
|
|
159
|
+
|
|
160
|
+
stdscr.addstr(last_line_index + 1, 0, separator) # Línea inferior después de la última línea del header
|
|
161
|
+
|
|
162
|
+
# Función para mostrar el footer personalizado
|
|
163
|
+
def draw_footer(stdscr):
|
|
164
|
+
rows, cols = stdscr.getmaxyx() # Tamaño del terminal
|
|
165
|
+
exit_text = "Pulsa 'Esc' para volver o salir" # Mensaje adicional
|
|
166
|
+
footer_text = FOOTER_TEXT[:cols - 1] # Recortar el texto si es más ancho que el terminal
|
|
167
|
+
separator = "-" * cols # Separador completo ajustado al ancho
|
|
168
|
+
|
|
169
|
+
# Asegurarse de que hay espacio suficiente para el footer
|
|
170
|
+
if rows > 2: # Verifica que haya espacio mínimo para el footer
|
|
171
|
+
try:
|
|
172
|
+
stdscr.addstr(rows - 3, 0, exit_text.center(cols, " ")) # Centrar el texto de salida
|
|
173
|
+
stdscr.addstr(rows - 2, 0, separator) # Línea separadora
|
|
174
|
+
stdscr.addstr(rows - 1, 0, footer_text.center(cols - 1, " ")) # Centrar el texto
|
|
175
|
+
except curses.error:
|
|
176
|
+
pass # Ignorar errores si no hay espacio suficiente
|
|
177
|
+
|
|
178
|
+
# Mostrar contenido principal del menú
|
|
179
|
+
def show_main_menu(stdscr):
|
|
180
|
+
start_line = HEADER_ASCII.count("\n") + 1 # Calcula dónde termina el header
|
|
181
|
+
stdscr.addstr(start_line, 0, "1. Leer parámetros".ljust(60))
|
|
182
|
+
stdscr.addstr(start_line + 1, 0, "2. Cargar parámetros desde archivo".ljust(60))
|
|
183
|
+
stdscr.addstr(start_line + 2, 0, "3. Crear Backup de parámetros".ljust(60))
|
|
184
|
+
stdscr.addstr(start_line + 3, 0, "Elija una opción (1/2): ")
|
|
185
|
+
|
|
186
|
+
# Mostrar selección de parámetros
|
|
187
|
+
def show_parameter_selection(stdscr, options):
|
|
188
|
+
stdscr.clear()
|
|
189
|
+
draw_header(stdscr)
|
|
190
|
+
start_line = HEADER_ASCII.count("\n") + 1 # Calcula el inicio después del header
|
|
191
|
+
stdscr.addstr(start_line, 0, "Seleccione un parámetro para leer:".center(60, "-"))
|
|
192
|
+
for idx, option in enumerate(options, start=1):
|
|
193
|
+
stdscr.addstr(start_line + idx, 0, f"{idx}. {option}")
|
|
194
|
+
draw_footer(stdscr)
|
|
195
|
+
stdscr.refresh()
|
|
196
|
+
|
|
197
|
+
while True:
|
|
198
|
+
key = stdscr.getkey()
|
|
199
|
+
if key == '\x1b': # Si se presiona Esc
|
|
200
|
+
return None # Cancelar selección
|
|
201
|
+
try:
|
|
202
|
+
choice = int(key) - 1
|
|
203
|
+
if 0 <= choice < len(options):
|
|
204
|
+
return choice
|
|
205
|
+
except ValueError:
|
|
206
|
+
pass # Ignorar entradas inválidas
|
|
207
|
+
|
|
208
|
+
# Mostrar selección de entorno
|
|
209
|
+
def show_environment_selection(stdscr, environments):
|
|
210
|
+
stdscr.clear()
|
|
211
|
+
draw_header(stdscr)
|
|
212
|
+
start_line = HEADER_ASCII.count("\n") + 1
|
|
213
|
+
stdscr.addstr(start_line, 0, "Seleccione el entorno:".center(60, "-"))
|
|
214
|
+
for idx, env in enumerate(environments, start=1):
|
|
215
|
+
stdscr.addstr(start_line + idx, 0, f"{idx}. {env}")
|
|
216
|
+
draw_footer(stdscr)
|
|
217
|
+
stdscr.refresh()
|
|
218
|
+
|
|
219
|
+
while True:
|
|
220
|
+
key = stdscr.getkey()
|
|
221
|
+
if key == '\x1b': # Si se presiona Esc
|
|
222
|
+
return None # Cancelar selección
|
|
223
|
+
try:
|
|
224
|
+
choice = int(key) - 1
|
|
225
|
+
if 0 <= choice < len(environments):
|
|
226
|
+
return choice
|
|
227
|
+
except ValueError:
|
|
228
|
+
pass # Ignorar entradas inválidas
|
|
229
|
+
|
|
230
|
+
# Pantalla de confirmación o resultados
|
|
231
|
+
def show_message(stdscr, message, color_pair=1):
|
|
232
|
+
stdscr.clear()
|
|
233
|
+
draw_header(stdscr)
|
|
234
|
+
start_line = HEADER_ASCII.count("\n") + 1
|
|
235
|
+
stdscr.addstr(start_line, 0, message.center(60, " "), curses.color_pair(color_pair))
|
|
236
|
+
draw_footer(stdscr)
|
|
237
|
+
stdscr.refresh()
|
|
238
|
+
time.sleep(3)
|
|
239
|
+
|
|
240
|
+
# Errores varios
|
|
241
|
+
def load_parameters(file_path):
|
|
242
|
+
if not os.path.exists(file_path):
|
|
243
|
+
raise FileNotFoundError(f"El archivo {file_path} no existe.")
|
|
244
|
+
|
|
245
|
+
param_scope = {}
|
|
246
|
+
try:
|
|
247
|
+
with open(file_path, 'r') as f:
|
|
248
|
+
exec(f.read(), param_scope) # Ejecuta el archivo en el contexto de param_scope
|
|
249
|
+
except SyntaxError as e:
|
|
250
|
+
raise SyntaxError(
|
|
251
|
+
f"Error de sintaxis en {file_path}.\nRevisa las comillas o el formato del archivo."
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
return param_scope.get('parametros', [])
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import boto3
|
|
3
|
+
import curses
|
|
4
|
+
import importlib.util
|
|
5
|
+
from .funcions import (
|
|
6
|
+
draw_header, draw_footer, show_main_menu, show_comparison_results,
|
|
7
|
+
show_environment_selection, show_message, show_parameter_selection,
|
|
8
|
+
get_parameters_by_prefix, delete_parameter, export_parameters_to_file,
|
|
9
|
+
compare_parameters, load_parameters
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# Ruta de la configuración personalizada
|
|
14
|
+
CONFIG_PATH = os.path.expanduser("~/.xsoft/paramsx_config.py")
|
|
15
|
+
|
|
16
|
+
# Cargar configuraciones desde el archivo de usuario
|
|
17
|
+
def load_config():
|
|
18
|
+
if not os.path.exists(CONFIG_PATH):
|
|
19
|
+
raise FileNotFoundError(f"No se encontró el archivo de configuración en {CONFIG_PATH}")
|
|
20
|
+
spec = importlib.util.spec_from_file_location("config", CONFIG_PATH)
|
|
21
|
+
config = importlib.util.module_from_spec(spec)
|
|
22
|
+
spec.loader.exec_module(config)
|
|
23
|
+
return config.configuraciones
|
|
24
|
+
|
|
25
|
+
# Función principal
|
|
26
|
+
def main(stdscr):
|
|
27
|
+
|
|
28
|
+
## Cargando configuración
|
|
29
|
+
config = load_config()
|
|
30
|
+
# Configurar boto3 con el perfil y región del usuario
|
|
31
|
+
boto3.setup_default_session(profile_name=config["profile_name"])
|
|
32
|
+
ssm = boto3.client("ssm", region_name=config["region_name"])
|
|
33
|
+
|
|
34
|
+
curses.start_color()
|
|
35
|
+
curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
|
|
36
|
+
curses.init_pair(2, curses.COLOR_RED, curses.COLOR_BLACK)
|
|
37
|
+
curses.init_pair(3, curses.COLOR_GREEN, curses.COLOR_BLACK)
|
|
38
|
+
|
|
39
|
+
environments = config['entornos']
|
|
40
|
+
PARAMETER_LIST = config['parameter_list']
|
|
41
|
+
|
|
42
|
+
while True:
|
|
43
|
+
stdscr.clear()
|
|
44
|
+
draw_header(stdscr)
|
|
45
|
+
show_main_menu(stdscr)
|
|
46
|
+
draw_footer(stdscr)
|
|
47
|
+
stdscr.refresh()
|
|
48
|
+
|
|
49
|
+
choice = stdscr.getkey()
|
|
50
|
+
|
|
51
|
+
if choice == '\x1b': # Código ASCII para 'Esc'
|
|
52
|
+
break # Salir del programa
|
|
53
|
+
|
|
54
|
+
elif choice == '1':
|
|
55
|
+
# Leer parámetros
|
|
56
|
+
param_choice = show_parameter_selection(stdscr, PARAMETER_LIST)
|
|
57
|
+
if param_choice is None: # Si se presionó Esc
|
|
58
|
+
continue # Regresar al menú principal
|
|
59
|
+
|
|
60
|
+
selected_param = PARAMETER_LIST[param_choice]
|
|
61
|
+
|
|
62
|
+
env_choice = show_environment_selection(stdscr, environments)
|
|
63
|
+
if env_choice is None: # Si se presionó Esc
|
|
64
|
+
continue # Regresar al menú principal
|
|
65
|
+
|
|
66
|
+
selected_env = environments[env_choice]
|
|
67
|
+
|
|
68
|
+
# Crear el prefijo completo
|
|
69
|
+
full_path = f"{selected_param}/{selected_env}"
|
|
70
|
+
show_message(stdscr, f"Buscando parámetros en: {full_path}...", 3) # Mensaje inicial
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
# Obtener parámetros desde AWS SSM
|
|
74
|
+
parameters = get_parameters_by_prefix(ssm, full_path)
|
|
75
|
+
except ValueError as e:
|
|
76
|
+
show_message(stdscr, f"ERROR: {e}", 2) # Error por prefijo vacío
|
|
77
|
+
continue # Regresar al menú principal
|
|
78
|
+
except Exception as e:
|
|
79
|
+
show_message(stdscr, f"Error inesperado: {e}", 2) # Error genérico
|
|
80
|
+
continue # Regresar al menú principal
|
|
81
|
+
|
|
82
|
+
# Validar si se encontraron parámetros antes de continuar
|
|
83
|
+
if not parameters:
|
|
84
|
+
show_message(stdscr, f"No se encontraron parámetros en: {full_path}.", 2)
|
|
85
|
+
continue # Regresar al menú principal
|
|
86
|
+
|
|
87
|
+
# Crear archivos si se encontraron parámetros
|
|
88
|
+
file_name = f"parameters_{selected_env}.py"
|
|
89
|
+
backup_file_name = f"parameters_{selected_env}_backup.py"
|
|
90
|
+
|
|
91
|
+
# Exportar parámetros al archivo principal
|
|
92
|
+
export_parameters_to_file(parameters, file_name)
|
|
93
|
+
|
|
94
|
+
# Crear un respaldo exacto del archivo principal
|
|
95
|
+
export_parameters_to_file(parameters, backup_file_name)
|
|
96
|
+
|
|
97
|
+
# Confirmación de archivos creados
|
|
98
|
+
show_message(stdscr, f"Archivos creados:\n- {file_name}\n- {backup_file_name}", 3)
|
|
99
|
+
|
|
100
|
+
elif choice == '2':
|
|
101
|
+
# Cargar parámetros desde archivo
|
|
102
|
+
env_choice = show_environment_selection(stdscr, environments)
|
|
103
|
+
if env_choice is None: # Si se presionó Esc
|
|
104
|
+
continue # Regresar al menú principal
|
|
105
|
+
|
|
106
|
+
selected_env = environments[env_choice]
|
|
107
|
+
file_name = f"parameters_{selected_env}.py"
|
|
108
|
+
backup_file_name = f"parameters_{selected_env}_backup.py"
|
|
109
|
+
|
|
110
|
+
if not os.path.exists(file_name) or not os.path.exists(backup_file_name):
|
|
111
|
+
show_message(stdscr, f"Archivos {file_name} o {backup_file_name} no encontrados.", 2)
|
|
112
|
+
continue
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
# Cargar parámetros del archivo principal
|
|
117
|
+
parametros = load_parameters(file_name)
|
|
118
|
+
except SyntaxError as e:
|
|
119
|
+
show_message(stdscr, f"ERROR: {e}", 2)
|
|
120
|
+
continue # Regresar al menú principal
|
|
121
|
+
except Exception as e:
|
|
122
|
+
show_message(stdscr, f"Error inesperado: {e}", 2)
|
|
123
|
+
continue # Regresar al menú principal
|
|
124
|
+
|
|
125
|
+
# Comparar los parámetros
|
|
126
|
+
changes = compare_parameters(file_name, backup_file_name, stdscr)
|
|
127
|
+
|
|
128
|
+
if changes:
|
|
129
|
+
# Mostrar resultados de la comparación
|
|
130
|
+
confirmed = show_comparison_results(stdscr, changes)
|
|
131
|
+
|
|
132
|
+
if not confirmed: # Si el usuario cancela
|
|
133
|
+
show_message(stdscr, "Operación cancelada volvemos a menú principal.", 2)
|
|
134
|
+
continue
|
|
135
|
+
|
|
136
|
+
# Subir parámetros si se confirman los cambios
|
|
137
|
+
with open(file_name, 'r') as f:
|
|
138
|
+
param_scope = {}
|
|
139
|
+
exec(f.read(), param_scope)
|
|
140
|
+
|
|
141
|
+
parametros = param_scope.get('parametros', [])
|
|
142
|
+
current_dict = {p['parameter_name']: p['parameter_value'] for p in parametros}
|
|
143
|
+
|
|
144
|
+
for change in changes:
|
|
145
|
+
param_name, change_type, _ = change
|
|
146
|
+
if change_type == "Nuevo" or change_type == "Modificado":
|
|
147
|
+
# Subir o actualizar parámetros
|
|
148
|
+
ssm.put_parameter(
|
|
149
|
+
Name=param_name,
|
|
150
|
+
Value=current_dict[param_name],
|
|
151
|
+
Type='SecureString',
|
|
152
|
+
Overwrite=True
|
|
153
|
+
)
|
|
154
|
+
elif change_type == "Eliminado":
|
|
155
|
+
# Borrar parámetros eliminados
|
|
156
|
+
delete_parameter(ssm, param_name)
|
|
157
|
+
|
|
158
|
+
# Eliminar los archivos una vez procesados
|
|
159
|
+
os.remove(file_name)
|
|
160
|
+
os.remove(backup_file_name)
|
|
161
|
+
show_message(stdscr, "¡Cambios aplicados y archivos eliminados!", 3)
|
|
162
|
+
else:
|
|
163
|
+
show_message(stdscr, "No se encontraron cambios entre los archivos.", 3)
|
|
164
|
+
|
|
165
|
+
elif choice == '3':
|
|
166
|
+
# Crear backup
|
|
167
|
+
param_choice = show_parameter_selection(stdscr, PARAMETER_LIST)
|
|
168
|
+
if param_choice is None: # Si se presionó Esc
|
|
169
|
+
continue # Regresar al menú principal
|
|
170
|
+
|
|
171
|
+
selected_param = PARAMETER_LIST[param_choice]
|
|
172
|
+
|
|
173
|
+
env_choice = show_environment_selection(stdscr, environments)
|
|
174
|
+
if env_choice is None: # Si se presionó Esc
|
|
175
|
+
continue # Regresar al menú principal
|
|
176
|
+
|
|
177
|
+
selected_env = environments[env_choice]
|
|
178
|
+
|
|
179
|
+
# Crear el prefijo completo
|
|
180
|
+
full_path = f"{selected_param}/{selected_env}"
|
|
181
|
+
try:
|
|
182
|
+
# Obtener parámetros desde AWS SSM
|
|
183
|
+
parameters = get_parameters_by_prefix(ssm, full_path)
|
|
184
|
+
except ValueError as e:
|
|
185
|
+
show_message(stdscr, f"ERROR: {e}", 2)
|
|
186
|
+
continue # Regresar al menú principal
|
|
187
|
+
except Exception as e:
|
|
188
|
+
show_message(stdscr, f"Error inesperado: {e}", 2)
|
|
189
|
+
continue # Regresar al menú principal
|
|
190
|
+
|
|
191
|
+
# Crear archivo de backup con nombre claro
|
|
192
|
+
backup_file_name = f"{selected_param.replace('/', '_')}_{selected_env}_backup.py"
|
|
193
|
+
export_parameters_to_file(parameters, backup_file_name)
|
|
194
|
+
|
|
195
|
+
# Confirmación de backup creado
|
|
196
|
+
show_message(stdscr, f"Backup creado:\n- {backup_file_name}", 3)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
else:
|
|
200
|
+
show_message(stdscr, "Opción inválida. Inténtalo de nuevo.", 2)
|
|
201
|
+
|
|
202
|
+
def entry_point():
|
|
203
|
+
curses.wrapper(main)
|
|
204
|
+
|
|
205
|
+
if __name__ == "__main__":
|
|
206
|
+
curses.wrapper(main)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
HEADER_ASCII = """
|
|
2
|
+
_____ __ __
|
|
3
|
+
| __ \ \ \ / /
|
|
4
|
+
| |__) |_ _ _ __ __ _ _ __ ___ ___ \ V /
|
|
5
|
+
| ___/ _` | '__/ _` | '_ ` _ \/ __| > <
|
|
6
|
+
| | | (_| | | | (_| | | | | | \__ \/ . \
|
|
7
|
+
|_| \__,_|_| \__,_|_| |_| |_|___/_/ \_\
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
FOOTER_TEXT = "By Mariox"
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: paramsx
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Librería para gestionar y respaldar parámetros de AWS SSM de manera sencilla y eficiente.
|
|
5
|
+
Home-page: https://github.com/pistatxos/paramsx
|
|
6
|
+
Author: Mariox
|
|
7
|
+
Author-email: info@tomonota.net
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: boto3
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
paramsx/__init__.py
|
|
5
|
+
paramsx/funcions.py
|
|
6
|
+
paramsx/main.py
|
|
7
|
+
paramsx/paramsx_config.py
|
|
8
|
+
paramsx/text.py
|
|
9
|
+
paramsx.egg-info/PKG-INFO
|
|
10
|
+
paramsx.egg-info/SOURCES.txt
|
|
11
|
+
paramsx.egg-info/dependency_links.txt
|
|
12
|
+
paramsx.egg-info/entry_points.txt
|
|
13
|
+
paramsx.egg-info/requires.txt
|
|
14
|
+
paramsx.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
boto3
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
paramsx
|
paramsx-1.0.0/setup.cfg
ADDED
paramsx-1.0.0/setup.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
from setuptools.command.install import install
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
import shutil
|
|
6
|
+
import platform
|
|
7
|
+
|
|
8
|
+
class CustomInstallCommand(install):
|
|
9
|
+
def run(self):
|
|
10
|
+
# Ejecutar instalación predeterminada
|
|
11
|
+
install.run(self)
|
|
12
|
+
|
|
13
|
+
# Detectar el sistema operativo
|
|
14
|
+
system = platform.system()
|
|
15
|
+
scripts_dir = None
|
|
16
|
+
|
|
17
|
+
if system == "Windows":
|
|
18
|
+
# Ruta del directorio de scripts para Windows
|
|
19
|
+
scripts_dir = os.path.join(
|
|
20
|
+
os.path.expanduser("~"),
|
|
21
|
+
"AppData",
|
|
22
|
+
"Roaming",
|
|
23
|
+
"Python",
|
|
24
|
+
f"Python{sys.version_info.major}{sys.version_info.minor}",
|
|
25
|
+
"Scripts",
|
|
26
|
+
)
|
|
27
|
+
elif system in ["Linux", "Darwin"]: # Linux o macOS
|
|
28
|
+
# Ruta del directorio de scripts para Linux/macOS
|
|
29
|
+
scripts_dir = os.path.join(os.path.dirname(sys.executable), "bin")
|
|
30
|
+
|
|
31
|
+
if scripts_dir:
|
|
32
|
+
# Verificar si el directorio ya está en el PATH
|
|
33
|
+
path_env = os.environ.get("PATH", "")
|
|
34
|
+
if scripts_dir not in path_env:
|
|
35
|
+
if system == "Windows":
|
|
36
|
+
# Agregar al PATH en Windows
|
|
37
|
+
os.system(f'setx PATH "{path_env};{scripts_dir}"')
|
|
38
|
+
print(f"Se agregó {scripts_dir} al PATH. Reinicia tu terminal para que los cambios surtan efecto.")
|
|
39
|
+
elif system == "Darwin":
|
|
40
|
+
# Usar .zshrc en macOS
|
|
41
|
+
zshrc_path = os.path.expanduser("~/.zshrc")
|
|
42
|
+
self._add_to_shell_config(zshrc_path, scripts_dir)
|
|
43
|
+
elif system == "Linux":
|
|
44
|
+
# Usar .bashrc en Linux
|
|
45
|
+
bashrc_path = os.path.expanduser("~/.bashrc")
|
|
46
|
+
self._add_to_shell_config(bashrc_path, scripts_dir)
|
|
47
|
+
|
|
48
|
+
# Crear el directorio de configuración de paramsx
|
|
49
|
+
config_dir = os.path.expanduser("~/.xsoft")
|
|
50
|
+
os.makedirs(config_dir, exist_ok=True)
|
|
51
|
+
|
|
52
|
+
# Archivo de configuración
|
|
53
|
+
config_file = "paramsx/paramsx_config.py"
|
|
54
|
+
target_file = os.path.join(config_dir, "paramsx_config.py")
|
|
55
|
+
|
|
56
|
+
if os.path.exists(target_file):
|
|
57
|
+
print(f"El archivo de configuración ya existe en {target_file}. No se sobrescribirá.")
|
|
58
|
+
else:
|
|
59
|
+
if os.path.exists(config_file):
|
|
60
|
+
shutil.copy(config_file, target_file)
|
|
61
|
+
print(f"Archivo de configuración copiado a {target_file}")
|
|
62
|
+
else:
|
|
63
|
+
print(f"Advertencia: No se encontró {config_file}. No se creó la configuración inicial.")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _add_to_shell_config(self, config_file, scripts_dir):
|
|
67
|
+
"""Añadir el directorio de scripts al archivo de configuración de shell."""
|
|
68
|
+
export_line = f'export PATH="{scripts_dir}:$PATH"'
|
|
69
|
+
if os.path.exists(config_file):
|
|
70
|
+
with open(config_file, "a") as f:
|
|
71
|
+
f.write(f"\n{export_line}\n")
|
|
72
|
+
print(f"Se agregó {scripts_dir} a {config_file}.")
|
|
73
|
+
else:
|
|
74
|
+
with open(config_file, "w") as f:
|
|
75
|
+
f.write(f"{export_line}\n")
|
|
76
|
+
print(f"Se creó {config_file} y se agregó {scripts_dir}.")
|
|
77
|
+
|
|
78
|
+
setup(
|
|
79
|
+
name="paramsx",
|
|
80
|
+
version="1.0.0",
|
|
81
|
+
packages=find_packages(),
|
|
82
|
+
include_package_data=True,
|
|
83
|
+
install_requires=[
|
|
84
|
+
"boto3",
|
|
85
|
+
],
|
|
86
|
+
entry_points={
|
|
87
|
+
"console_scripts": [
|
|
88
|
+
"paramsx=paramsx.main:entry_point",
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
cmdclass={
|
|
92
|
+
"install": CustomInstallCommand,
|
|
93
|
+
},
|
|
94
|
+
description="Librería para gestionar y respaldar parámetros de AWS SSM de manera sencilla y eficiente.",
|
|
95
|
+
author="Mariox",
|
|
96
|
+
author_email="info@tomonota.net",
|
|
97
|
+
url="https://github.com/pistatxos/paramsx",
|
|
98
|
+
)
|