Levantar un contenedor de SQL Server en un NAS Synology

Después de varios intentos fallidos, por fin logre levantar un contenedor de SQL Server basado en Docker en mi NAS Synology.

Aquí les comento el paso a paso y los problemas que tuve al momento de levantar la instancia.

Primeramente, hay que verificar que nuestro NAS cumpla con los requerimientos mínimos, si es así, procedemos con la creación el contenedor dentro del Container Manager.

En la sección Contenedor, dar clic en el botón Crear.

En el campo Imagen, selecciona la opción Agregar Imagen.

En la configuración tendrás que agregar el registro de contenedores de Microsoft https://mcr.microsoft.com

Posteriormente, seleccionarlo como el contenedor de registro a utilizar

Después, buscar la imagen del contenedor de SQL Server mediante el buscador, ingresando el texto “mssql/server” en el buscador, y seleccionar la versión que se requiera.

Después, asignar un nombre y configurar los recursos a asignar a nuestro contenedor.

Para esto recomiendo utilizar prioridad de CPU media, ni alta ni baja ya que puede consumir todo nuestro CPU o puede no ser suficiente con configuración baja. Para el Limite de memoria asignar por lo menos un 30% mas de lo recomendado en los requerimientos mínimos, y muy importante, no habilitar el reinicio automático, ya que en caso de alguna falla puede entrar en un bucle de falla-reinicio infinito.

En la siguiente sección de configuración hay que asignar el puerto para nuestro contenedor, podría ser el puerto por defecto de SQL Server (1433) o algún otro.

Es importante configurar algún volumen físico de nuestro NAS a la ruta “/var/opt/mssql” del contenedor, para almacenar nuestras bases de datos fuera del contenedor y no se pierdan al apagar o reiniciar nuestro NAS.

Hay que agregar las siguientes variables de ambiente mínimas requeridas y asignar privilegios de ejecución al contenedor

Del resto de la configuración, pueden dejar las opciones por defecto y dar clic en Finalizar.

Con esto ya estaría listo nuestro contenedor de SQL Server, ya solo restaría crear alguna base de datos de ejemplo como la de AdventureWorks

Espero les sea de utilidad.

Referencias:

Prerequisites

Inicio rápido: Ejecución de imágenes de contenedor de SQL Server para Linux con Docker

Variables de ejecución del contenedor

Deploy and connect to SQL Server Linux containers

Montaje de un directorio host como volumen de datos

Restauración de una base de datos de SQL Server en un contenedor para Linux

AdventureWorks sample databases

Mover o respaldar archivos en un NAS Synology con script personalizado

En esta ocasión les comparto una opcion personalizada para mover o respaldar archivos en un NAS Synology mediante un script definido por el usuario, ejecutado de forma recursiva mediante el programador de tareas.

Esto puede ser util para ejecutar cualquier tipo de script, no solo para mover o respaldar archivos.

Lo primero que realice fue montar una carpeta remota, para esto abrir File Station

Ingrese al menú Herramientas / Montar carpeta remota / Carpeta compartida de CIFS e incluí las configuraciones de la carpeta remota

Posteriormente se tendría que crear el script a ejecutar y almacenarlo en algún directorio dentro del NAS

Para el script utilice comandos muy básicos de Linux, los comandos cp y rm

El script quedo de la siguiente forma:

cd /volume1/directorioorigen/
cp -uvr /volume1/directorioorigen/ /volume1/directoriodestino/
rm -rv /volume1/directorioorigen/*

El comando cp sirve para copiar archivos y el rm sirve para eliminar archivos en el sistema operativo Linux, les incluyo una descripción de las opciones que maneje:

-u copia solo si el archivo es mas nuevo que el archivo destino o en el destino no existe
-v–verbose explain what is being done
-r–recursive copy directories recursively

Pienso en un futuro actualizar el script utilizando el comando rsync.

Por ultimo, para crear la tarea programada tienen que ingresar a Panel de Control / Programador de Tareas

Posteriormente, al menú Crear / Tareas Programadas / Script definido por el usuario

Ahí definirás el nombre de la tarea, periodicidad de ejecución y la ruta del script a ejecutar

También les recomiendo seguir las recomendaciones para guardar los resultados de la ejecución del script

Por el momento es todo, espero les sea de utilidad

Referencias:

Sugerencias para crear tareas y escribir scripts en el Programador de tareas

Montar carpetas remotas

Comandos linux que debes conocer

rsync: Delete Source File After Transfer

Configurar proxy http a Nuget

En alguna ocasión, en una empresa que trabajaba, tuve problemas para acceder a las librerías de Nuget, me marcaba algunos errores de autenticación como los siguientes:

C:\Program Files\dotnet\sdk\3.1.300\NuGet.targets(128,5): error : Unable to get repository signature information for source https://api.nuget.org/v3-index/re
pository-signatures/5.0.0/index.json.

C:\Users\MiUsuario\AppData\Local\Temp\fhlnaoru.gdt\restore.csproj]
C:\Program Files\dotnet\sdk\3.1.300\NuGet.targets(128,5): error : Response status code does not indicate success: 407 (authenticationrequired). [C:\Users\MiUsuario\AppData\Local\Temp\fhlnaoru.gdt\restore.csproj]

En esa empresa, el navegador tenia configurado un proxy http, por lo tanto me di a la tarea de buscar como configurar dicho proxy a el componente de Nuget.

Pude identificar que el componente Nuget tiene un archivo de configuración donde se puede indicar que se conecte a internet mediante un proxy, por el momento no recuerdo cual es esa ruta, sin embargo, no creo que sea difícil ubicarla preguntando le al señor Google o a alguna IA.

Es posible configurar manualmente el proxy, editando el archivo con cualquier editor de texto, o se puede usar la consola de comandos y utilizar los siguientes comandos:
nuget.exe config -set http_proxy=http://urlproxy:puerto
nuget.exe config -set http_proxy.user=dominioRed\Usuario
nuget.exe config -set http_proxy.password=contraseña


Posterior a esto solo es necesario cerrar y volver a abrir el Visual Studio y el componente Nuget ya tendrá acceso a los repositorios de Microsoft.

Espero les sea de utilidad.

Cambiar estéreo Jeep Cherokee 98-01 (XJ)

Hace algunos días me encontré unos apuntes de cuando cambie por primera vez el estéreo de mi Jeep Cherokee modelo 2000, y pues, para no perder esta información, la comparto aquí.

Son los códigos de colores de los arneses del estéreo de fabrica para una Jeep Cherokee modelo 98-01 y su correlación con los códigos de colores ISO estándar de cualquier estéreo comercial.

Les paso mas en limpio la información.

Terminal Negra (7 cables)

FuncionalidadCherokeeEstéreo
Right Rear (-)Azul-NaranjaMorado-Negro
Left Rear (-)Café-AzulVerde-Negro
Right Front (+)MoradoGris
Left Front (+)VerdeBlanco
Right Rear (+)Azul-BlancoMorado
Left Rear (+)Café-AmarilloVerde
Power AntenaVerde-RojoAzul

Terminal Gris (6 cables)

FuncionalidadCherokeeEstéreo
Volt Battery (12v +)RosaAmarillo
Switched (12v +)Rojo-BlancoRojo
DimmerNaranjaNaranja-Blanco
Ilumination / Dash LightNegro AmarilloNaranja
Right Front (-)VerdeGris-Negro
Left Front (-)Café-RojoBlanco-Negro

Terminal Negra (1 cable)

FuncionalidadCherokeeEstéreo
GroundNegroNegro

Les debo las fotos de las terminales, en una oportunidad que tenga les saco una foto.

Referencias:

https://mundotuerca.cl/factory-wiring-harness-stereo-hyundai-radio-wiring-color-codes/

ASP.Net y SignalR

SignalR es una componente de Microsoft para ASP.Net, su objetivo es agregar funcionalidad web en tiempo real a las aplicaciones, de tal forma que permite hacer que el código del servidor actualice o inserte contenido en los clientes conectados en tiempo real, similar a una consola de chat.

Es una abstracción de múltiples tecnologías PUSH, soporta diferentes protocolos de comunicación, los cuales negocia y utiliza en base a las características y/o limitaciones del servidor y el navegador web.

Soporta 4 protocolos de trasporte:

  • webSockets
  • foreverFrame
  • serverSentEvents
  • longPolling

Y maneja una arquitectura como la siguiente, donde HubsAPI y PersistentConnection API son 2 modelos diferentes de implementación del lado del Servidor.

Diagrama arquitectonico de SignalR

En general, simplifica mucho el proceso de realizar notificaciones Push en aplicaciones web y elimina la dependencia con servicios Push de terceros como IBM Bluemix o Google Firebase.

Para implementaciones en Azure, existe un componente llamado Azure SignalR el cual provee integración con componentes montados en Azure y resuelve algunos problemas de escalamiento horizontal que se generan al utilizar SignalR en Azure.

Para mayor información respecto a implementaciones dejo un ejemplo de implementación con .Net Framework y algunas referencias para .Net Core y .Net Framework.

Por el momento es todo, deja un comentario si te fue de utilidad.

Referencias:

.Net Core

https://learn.microsoft.com/es-mx/aspnet/core/signalr/introduction?view=aspnetcore-7.0&WT.mc_id=dotnet-35129-website

https://learn.microsoft.com/es-mx/aspnet/core/tutorials/signalr?view=aspnetcore-7.0&tabs=visual-studio

.Net Framework

https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/

Otros

https://en.wikipedia.org/wiki/Push_technology

Reproducir videos con audio EAC3, DTS o TrueHD en un NAS Synology

Actualización: Synology dejo de soportar la transcodificación de audio para el formato AAC a partir de la versión 7.1.1 del DSM (2022-09-27), el parche de AlexPresso plantea soportarlo, sin embargo aun no hay fecha de implementación.

Hace algún tiempo, después de comprar mi primer NAS Synology, me entere que la Video Station (la consola multimedia del NAS) no soporta la reproducción de videos que usen el formato de audio EAC3, DTS o TrueHD, así que me dí a la tarea de investigar la razón y una posible solución.

Encontré que la razón del porque no reproduce esos formatos de audio es muy simple, porque el NAS Synology no incluye los codecs para esos formatos, ya que son formatos propietarios y tendrían que pagar algo por incluirlos (por el precio del NAS creo que deberían incluirlos).

Así que buscando posibles soluciones y encontré 2 opciones, ambas instalando e utilizando el paquete FFmpeg de SynoCommunity.

La primera opción es transcodificar los archivos de video a otro formato de audio que si sea soportado por el NAS Synology, y la segunda opción, remplazar el transcodificador de audio de la Video Station para que transcodifique los video al vuelo sobre demanda.

Las ventajas de la primera opción es que la operación es muy sencilla, solo instalas el FFmpeg y ejecutas un comando.

El comando para convertir tus videos a formato AC3 seria algo similar a esto:

/path/to/ffmpeg -i "input.mkv" -map 0 -c:s copy -c:v copy -c:a ac3 -b:a 640k "output.mkv"

Es requerido utilizar la versión del FFmpeg de SynoCommunity. Aquí el proceso de instalación.

La desventaja de esta opción es que si tienes muchos archivos de video con formatos no soportados, la tarea de identificar y transcodificar cada archivo sera ardua.

Ahora, para la segunda opción, la ventaja es que es sobre demanda, y si tienes muchos archivos, para ti sera transparente, la Video Station hará el trabajo de transcodificar los videos al vuelo al momento de la reproducción, la desventaja es que la tarea de transcodificación consumirá recursos de tu NAS, principalmente uso de procesador, lo cual podrá tener efectos en el rendimiento de tu NAS.

El proceso consiste en remplazar la versión del paquete FFmpeg de la Video Station por la version 4 de SynoCommunity.

Primeramente, como se indico anteriormente, hay que instalar la versión 4 del paquete FFmpeg del repositorio de SynoCommunity.

Posteriormente sera necesario conectarnos via SSH al NAS. Se habilita desde el panel de control.

Una vez conectado, se utiliza el comando “sudo -i” para cambiar a usuario Root.

y por ultimo utilizas el siguiente comando para remplazar el paquete FFmpeg.

curl https://raw.githubusercontent.com/AlexPresso/VideoStation-FFMPEG-Patcher/main/patcher.sh | bash

si requieres quitar el parche y volver a la versión original del paquete FFmpeg

curl https://raw.githubusercontent.com/AlexPresso/VideoStation-FFMPEG-Patcher/main/patcher.sh | bash -s -- -a unpatch

Y ahora si, a disfrutar tu contenido multimedia.

Referencias:

synocommunity.com

VideoStation-FFMPEG-Patcher

converting eac3 to aac with ffmpeg

Operaciones con objetos DateTime y TimeSpan

En esta ocasión les comparto unos ejemplos muy básicos de comparación de fechas y horas.

Le mostrare una pequeña aplicación de consola que realice para unas pruebas.

El objetivo es comparar 2 horas con minutos, tipo 13:30, guardarlos en un TimeSpan y compararlos.

Console.WriteLine("Escribe una hora en formato HH:mm");
Console.WriteLine("Por ejemplo: 13:30");
TimeSpan time1 = TimeSpan.Parse(Console.ReadLine());
Console.WriteLine("Escribe otra hora en formato HH:mm");
TimeSpan time2 = TimeSpan.Parse(Console.ReadLine());

if (time1 > time2)
	Console.Write("La 1ra hora es mayor que la 2da");
else if (time1 < time2)
	Console.Write("La 2da hora es mayor que la 1ra");
else
	Console.Write("La 1ra hora es igual que la 2da");

Console.Read();

Entrega una salida como la siguiente:

Incluye una segunda opción donde obtiene la diferencia en horas entre dos fechas.

Console.WriteLine("Escribe un dia del mes:");
int dia1 = Convert.ToInt32(Console.ReadLine());
Console.WriteLine("Escribe otro dia del mes:");
int dia2 = Convert.ToInt32(Console.ReadLine());

DateTime date1 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, dia1);
DateTime date2 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, dia2); 

int total = Convert.ToInt32(date2.Subtract(date1).TotalHours);

Console.WriteLine("Horas de diferencia entre las 2 fechas: " + total.ToString());

Console.Read();

La segunda parte quedaría así:

Por el momento es todo, posteriormente iré agregando mas ejemplos a esta publicación.

Son unos ejemplos simples, espero a alguien le sean útiles.

Código de ejemplo:

https://pabloroman.mx/ejemplos/Test_DateTime&TimeSpan.zip

Recomendaciones al comprar un NAS Synology de gama baja

Les comparto algunos consejos a la hora de elegir un NAS marca Synology.

Cabe mencionar que esto es solo una recomendación de la gama baja de Synology, es totalmente basada en mi experiencia personal, les recomiendo encarecidamente buscar otras fuentes de información y formar su propio criterio.

Una vez dicho lo anterior, empezamos…

La gama baja de Synology se clasifica en DS J Series, DS Value Series y DS Plus Series.

DS J Series (DS120j, DS220j) – Es el equipo mas esencial, incluye procesadores de bajo desempeño y poca memoria RAM, su uso principal es el de un NAS Personal con algunas funciones de Cloud, como podría ser compartir archivos multimedia, sincronización de fotos.

DS Value Series (DS218, DS223) – Incluye lo mismo que el anterior con algunas mejoras en procesamiento, memoria y aplicaciones, algunas versiones incluyen opciones para ampliar la memoria RAM provista de fabrica. La biblioteca de aplicaciones es un poco mayor y permite activar mayores funcionalidades a nuestro NAS, como por ejemplo: funciona como DVR con la aplicación Survilance Station o como reproductor de contenido multimedia con la aplicación Video Station por decir algunas. Existe una versión DS Value Play que tiene un enfoque en transmisión de contenido multimedia e incluye un chip para decodificación de video, sin embargo, antes de adquirirlo, es importante informarse de que formatos de video admite cada versión.

DS Plus Series (DS218+, DS220+) – Es el mejor equipado de los 3 en cuestiones de memoria, procesamiento, incluye mejoras en puertos red y USB, permite la actualización de la memoria de fabrica e incluye un mayor numero de aplicaciones que brindan una funcionalidad muy completa para un Nube `Privada.

Como acceder al Disk Station Manager de Synology mediante un subdominio

En esta ocasión les comparto como configurar un subdominio para acceder al DSM de Synology.

El primer paso es ingresar al panel de control de su dispositivo Synology, a la opción “Portal de Inicio”.

En la sección Dominio, ingresa tu subdominio personalizado, por ejemplo: MiSubdominio.MiSitio.com

Posteriormente, en el panel de control dirígete a la opción “Seguridad / Certificado”.

Selecciona la opción “Agregar” para agregar o importar un certificado para el subdominio que configuraste a tu DSM.

Puedes crearlo con Let’s Encrypt o importarlo, en caso de que ya cuentes con un certificado para ese dominio.

También requerirás crear el subdominio con la herramienta de tu proveedor de DNS y esperar al menos 24 horas a que se propague por internet la dirección del nuevo subdominio.

Una configuración similar aplica para asignar un subdominio a la consola de alguna aplicación de nuestra DiskStation, por ejemplo: Download Station, Video Station, etc…

Espero les sea de utilidad.

Verificar la existencia de objetos en SQL Server

En esta ocasión les comparto un script para verificar la existencia de objetos en SQL Server, es muy útil para validar procesos de despliegue entre ambientes.

Solo necesitan agregar en la primera seccion los objetos a validar.

-----(Script to verify deploy DB objects...)-----

declare @TblResultset table 
(schema_name sysname null, 
ItemName sysname null, 
ParentName sysname null,	--apply for indexes and columns
ItemType int not null,		--1 for tables, 2 for udtt, 3 for stored procedures, 4 for functions, 5 for indexes & 6 for columns.
create_date datetime, 
modify_date datetime, 
StatusMsg nvarchar(256))

set nocount on 

--/* update here with the objects to search.... !!!! --*/
insert @TblResultset (schema_name, ItemName,ItemType,ParentName)
--tables (schema, TableName, 1, null)
select 'dbo', 'MyTable1' ,1,null union all
select 'dbo', 'MyTable2',1,null union all
--user defined table types (schema, UdtName, 2, null)
select 'dbo', 'udt_1',2,null union all
select 'dbo', 'udt_2',2,null union all
--stored procedures (schema, SpName, 3,null)
select 'dbo', 'MyProcedure1' ,3,null union all 
select 'dbo', 'MyProcedure2' ,3,null union all 
--functions (schema, FunctionName, 4,null)
select 'dbo', 'fn_MyFuntion1' ,4,null union all
--indexes (schema, idxName, 5, ParentTableName)
select 'MySchema', 'MyIndexName' ,5,'MyParentTable' union all
--columns  (schema, ColumnName, 6, ParentTableName)
select 'MySchema','MyColumnName',6,'MyParentTable'

update RS
set RS.create_date = ST.create_date,
	RS.modify_date = ST.modify_date, 
	RS.StatusMsg = 
		case
			when ST.name is not null then 'Exists in database.'
			else 'Do not exists in database.'
		end
from @TblResultset RS 
	left outer join sys.tables ST 
		on RS.ItemName = ST.name
where RS.ItemType = 1 --tables

update RS
set RS.create_date = AO.create_date,
	RS.modify_date = null,
	RS.StatusMsg = 
	case
		when ST.name is not null then 'Exists in database.'
		else 'Do not exists in database.'
	end
from @TblResultset RS 
	left outer join  sys.table_types ST 
		on RS.ItemName = ST.name
	left outer join sys.all_objects AO 
		on ST.type_table_object_id = AO.object_id
where RS.ItemType = 2 --user defined table type


update RS
set RS.create_date = ST.created,
	RS.modify_date = ST.LAST_ALTERED,
	RS.StatusMsg = 
	case
		when ST.SPECIFIC_NAME is not null then 'Exists in database.'
		else 'Do not exists in database.'
	end
from @TblResultset RS 
	left outer join INFORMATION_SCHEMA.ROUTINES ST 
		on RS.ItemName = ST.SPECIFIC_NAME
where RS.ItemType in(3,4) --stored procedures & functions

update RS
set RS.create_date = AO.create_date,
	RS.modify_date = AO.modify_date,
	RS.StatusMsg = 
	case
		when ST.name is not null then 'Exists in database.'
		else 'Do not exists in database.'
	end
from @TblResultset RS 
	left outer join  sysindexes ST 
		on RS.ItemName = ST.name
	left outer join sys.all_objects AO 
		on ST.id = AO.object_id
where RS.ItemType = 5 --index

update RS
set RS.create_date =null,
	RS.modify_date = null,
	RS.StatusMsg = 
	case
		when ST.name is not null then 'Exists in database.'
		else 'Do not exists in database.'
	end
from @TblResultset RS 
	left outer join  syscolumns ST 
		on RS.ItemName = ST.name and object_name(ST.id) = RS.ParentName
where RS.ItemType = 6 --columns

-----(((Output resultset)))-----
select schema_name, ItemName as ObjectName, 
case
	when ItemType = 1 then 'Table'
	when ItemType = 2 then 'UDTT'
	when ItemType = 3 then 'Stored Procedure'
	when ItemType = 4 then 'Function'
	when ItemType = 5 then 'Index'
	when ItemType = 6 then 'Column'
	else 'UFO'
end as ObjectType,
isnull (cast(create_date as varchar),'NA') as CreateDate, 
isnull(cast(modify_date as varchar),'NA') as ModifyDate,
StatusMsg
from @TblResultset

set nocount off
go

La salida del script seria asi:

Espero les sea de utilidad…