Tag: Windows

Mover docker-desktop-data fuera de la Unidad del Sistema

Docker es una tecnología que con el devenir de los años ha ido cogiendo cada vez mayor relevancia. Sirve tanto como herramienta de desarrollo para trabajar de manera más ágil y eficiente con entornos y/o ciertas herramientas, a la vez que se consolida como pieza base en los despliegues de infraestructura orientada a servicio.

En su origen, inició su camino en sistemas GNU/Linux con el firme objetivo de facilitar los despliegues de software, automatizando y abstrayendo los mismos. Originalmente su primera implementación para sistemas Windows fue usando VirtualBox, para luego pasar a la virtualización de Hyper-V propietaria de Microsoft que supuso una mejora muy importante del rendimiento de Docker en Windows. El problema es que esta actualización supuso que al requerir de Hyper-V, obligaba a que se contara al menos con una versión Windows 10 Pro o superior. No fue hasta junio de 2019 cuando con la llegada de WSL2 (evolución de la primera versión de WSL de agosto de 2016) cuando se pudo contar con Docker en cualquier versión del sistema de Windows.

Pero aunque Docker es estupendo, ocupa bastante a nada que empiezas a trabajar con imágenes y pones en marcha contenedores...😅 Esto sumado a que la tónica habitual es instalar cualquier software en la unidad del sistema por defecto, o en el peor de los casos instalar en la unidad del sistema sin opción a elegir; hace que sea un fastidio que Docker se instale en la unidad del sistema C y además vaya aumentando el espacio que utiliza. Aunque realmente, lo que ocupa si estas usando WSL2 como backend de funcionamiento de Docker en Windows, son los datos de los contenedores que se guardan en docker-desktop-data.

Por defecto Docker Desktop para Windows creará la siguientes dos distros:

  • docker-desktop
  • docker-desktop-data

Si accedemos a la ruta "%LOCALAPPDATA%/Docker/wsl", veremos dos carpetas, y dentro de cada una de ellas hay un archivo vhdx. Para más detalle:

  • data/ext4.vhdx que es consumido por docker-desktop-data
  • distro/ext4.vhdx que es consumido por docker-desktop

En el que docker-desktop-data se usa para almacenar imágenes, etc. Por lo tanto, su tamaño aumentará en el futuro, y en consecuencia, nuestra unidad de sistema (C:) se quedará sin espacio. A continuación, se muestra paso a paso cómo sacar docker-desktop-data fuera de la unidad del sistema, por ejemplo, D:\desktop-docker\data.

🐋⚙️ Procedimiento

Paso1: Parar Docker

(Creo que esto ya te lo esperabas 😉)

Paso2: Exportar, desregistrar e importar la distro

1- Apagar todas las distros WSL

wsl --shutdown

2- Exportar docker-desktop-data a un fichero TAR

wsl --export docker-desktop-data E:\docker-desktop\docker-desktop-data.tar

3- Desregistrar la distro actual docker-desktop-data

wsl --unregister docker-desktop-data

4- Importar la distro docker-desktop-data desde el fichero TAR

wsl --import docker-desktop-data E:\docker-desktop\data E:\docker-desktop\docker-desktop-data.tar --version 2

👀 Nota: En este paso, podemos encontrarnos con el error de no poder crear una red específica. Simplemente vuelve a ejecutar el comando de importación.

Paso 3: Arrancar Docker

(Creo que esto TAMBIÉN te lo esperabas 😁)

Con este procedimiento ya tendremos Docker en una unidad que no es la del sistema, en la que el crecimiento de la distro docker-desktop-data no supondrá un problema, evitando degradar el rendimiento del sistema por llenar la unidad del sistema.

Comprobar permisos de Administrador en una ejecución (estilo 🐍 Python)

Habitualmente nos encontramos con la situación en la que debemos ejecutar ciertos programas o flujos de ejecución y necesitamos permisos de Administrador. Estas situaciones se nos presentan cuando tenemos que manejar carpetas y ficheros en acciones que impliquen lectura, escritura o ejecución en directorios protegidos del sistema. Para ello se requiere una elevación de permisos que deberemos comprobar si existe antes de lanzar nuestra ejecución.

Aprovechando que seguramente tengamos que hacer esto varias veces, creo que la mejor opción de hacerlo es con el mejor lenguaje pegamento que existe hasta la fecha, que no es ni más ni menos que Python. Por ello la solución final que vamos a plantear es excelente tanto para administradores de sistemas como para desarrolladores, siendo además multiplataforma GNU/Linux y Windows.

Tenemos que tener en cuenta que GNU/Linux y Windows no funcionan igual para la gestión de permisos. En Windows preguntaremos desde la API disponible si el usuario es administrador, mientras que en GNU/Linux preguntaremos por si el usuario tiene permisos root.

import ctypes, os
from sys import exit


def is_admin():
    is_admin = False
    try:
        is_admin = os.getuid() == 0
    except AttributeError:
        is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0

    print ("Admin privileges: {}".format(is_admin))
    return is_admin

Para mirar los permisos en Windows usaremos la librería ctypes y para los permisos en GNU/Linux usaremos la librería os. Ambas están incluida en Python. Por una razón arbitraría se ha elegido comprobar primero GNU/Linux y después Windows.

Cuando se comprueba en GNU/Linux invocamos a la función os.getuid que nos devolverá 0 en el caso de ser root. Si llamamos a la función desde Windows con Python nos elevará una excepción del tipo AttributeError, que aprovecharemos a capturar para hacer la comprobación en Windows invocando a la función ctypes.windll.shell32.IsUserAnAdmin. En ambos casos guardaremos el booleano de la evaluación y lo devolveremos al final de la función.

Hasta aquí sencillo, pero esto es código Python y es necesario tener el interprete de Python, con el que obliga al sistema a tener instalado el intérprete de Python. Para solucionarlo, deberíamos convertir nuestro código en un programa añadiendo un punto de entrada y devolviendo un código de retorno tras la ejecución.

import ctypes, os
from sys import exit


def is_admin():
    is_admin = False
    is_win = False
    try:
        is_admin = os.getuid() == 0
    except AttributeError:
        is_admin = ctypes.windll.shell32.IsUserAnAdmin() != 0
        is_win = True

    print ("Admin privileges: {}".format(is_admin))
    return is_admin, is_win

Antes modificaremos un poco la función is_admin()añadiendo un valor is_win que usaremos para saber que estamos comprobando en GNU/Linux o Windows los permisos de administrador, devolviendo el valor como un segundo valor en el retorno de la función.

Recordad que Python es posible recoger múltiples valores de retorno en una variable como una tupla, en variables separadas o incluso tirar los valores que no nos interesen.

def my_function():
    a = 2
    b = 3
    return a, b

a = my_function()
print(a)  # out: (2, 3)

a, b = my_function()
print(a)  # out: 2
print(b)  # out: 3

a, _ = my_function()  #  b es ignorado
print(a)  # out: 2

Además añadimos un punto de entrada debajo de la función is_admin().

if __name__ == "__main__":
    is_admin, is_win = is_admin()
    # Converting boolean to integer 
    ret = int(is_admin == False)
    if is_win:
        exit(ret)
    else:
        exit(ret * -1)

Comprobar si __name__ es __main__, es una excelente forma de hacer que cada unidad de fichero Python sea ejecutable si se quiere. El nombre de __main__ sólo es dado al fichero Python que es dado al intérprete para ser ejecutado y en caso de no serlo, siempre puede ser importado en otro fichero Python, sin que el punto de entrada afecte.

Como vemos, ahora estamos recogiendo en el retorno is_admin e is_win. Necesitamos el segundo valor para decidir el valor de retorno, ya que los códigos de error en Windows son enteros positivos y en GNU/Linux son enteros negativos. El único punto en común es que devolver un 0 es señal de que la ejecución fue correcta. Sabiendo esto debemos adaptar el retorno de los errores dependiendo el sistema.

💾 Binarizando nuestra aplicación Python

Para convertirlo en un ejecutable usaremos PyInstaller, el cual podéis instalar con un simple pip install pyinstaller. Para binarizar nuestra aplicación en un ejecutable autocontenido con el interprete de Python ejecutaremos:

pyinstaller -F is_admin.py

De esta forma resultará, mucho mas sencilla la distribución de nuestra aplicación.

👔 Puesta en Producción

Ahora vamos a plantear los dos casos de uso para Windows y GNU/Linux. Como aclaración, decir que los ejemplos expuestos se pueden usar tanto con la versión binarizada o con la de código invocando al intérprete de Python.

Windows

@echo off

cd
cd /D "%~dp0"
cd

#REM python is_admin.py
is_admin.exe

if errorlevel 1 (
   echo Exit Code is %errorlevel%
   echo.
   echo Admin privileges required
   echo Run it again as Administrator
   echo.
   pause
   exit /b %errorlevel%
)

#REM [your_executable].exe

pause

👀 Puedes descargar la versión binarizada de is_admin.exe

GNU/Linux

#!/bin/bash

pwd
cd `dirname $0`
SCRIPTDIR=`pwd`
pwd

#python is_admin.py
is_admin


if [ $? -eq 0 ]
then
  # [your_executable]
else
  echo Exit Code is $?
  echo.
  echo Admin privileges required
  echo Run it again as Administrator
  echo.
  read -rsp $'Press any key to continue...\n' -n 1 key
  exit $?
fi

read -rsp $'Press any key to continue...\n' -n 1 key

Si no estás tan familiarizado con el Bash te invito a que visites el proyecto ExplainShell para que puedas obtener la explicación de los diferentes comandos y argumentos.

🥅 Conclusiones

La solución presentada, sin ser seguramente perfecta, asegura tanto a administradores de sistemas como desarrolladores, comprobar si existen los permisos de administrador necesarios de manera sencilla; pudiendo hacerlo con una versión binarizada autocontenida que incluya el intérpretete Python, ejecutándolo usando el intérprete de Python del sistema gracias a ser todo dependencias internas, o llamando directamente a la función is_admin() si se quiere integrar en un desarrollo.

El código completo puedes encontrarlo en el siguiente gist de GitHub:

Espero que esta forma de trabajar te resulte útil y puedas extrapolarla y usar para otros casos Python como tu lenguaje pegamento generando código y aplicaciones altamente reutilizables.

Ocultar partición OEM tras actualización «Windows 10 April 2018 Update»

"Windows 10 April 2018 Update" (Actualización de características a Windows 10, versión 1803) es una actualización que ya lleva tiempo liberada, pero que hasta hace poco no me había atrevido a instalar por ciertos problemas que ocasionaba a los sistemas tras su instalación. La mayor parte de los problemas han sido solventados y actualmente el mayor problema que arrastra esta actualización es el de hacer visible desde el explorador de archivos la partición OEM (Original Equipment Manufacturer) que viene en tu equipo y que contiene:

  • Información de tu equipo
  • Herramientas para restaurar el sistema al estado de fábrica.

Dicha partición que ahora puedes ver y que te avisará constantemente de que hay falta de espacio siempre estuvo ahí, lo que pasa es que siempre estuvo oculta. Microsfot por alguna razón, introdujo este problema que a día de hoy sigue sin resolver de manera oficial con alguna actualización.

Si vas al "administrador de discos" de Windows verás dicha partición, pero no podrás hacer nada con ella para ocultarla.

La solución para ocultar la partición y evitar que el sistema nos avise constantemente de la falta de espacio en dicha partición, evitando también tener acceso desde el explorador de archivos a una partición a la cual NO deberíamos tener acceso directo, pasa por abrir la consola de comandos con privilegios de administrador y ejecutar los siguiente comandos:

diskpart
DISKPART> list volume

  Núm Volumen Ltr  Etiqueta     Fs     Tipo        Tamaño   Estado     Info
  ----------- ---  -----------  -----  ----------  -------  ---------  --------
  Volumen 0     E                      DVD-ROM         0 B  Sin medio
  Volumen 1     D   DATA        NTFS   Partición    931 GB  Correcto
  Volumen 2     C   OS          NTFS   Partición    237 GB  Correcto   Arranque
  Volumen 3     F               NTFS   Partición    499 MB  Correcto
  Volumen 4         SYSTEM      FAT32  Partición    260 MB  Correcto   Sistema

La herramienta "dispart" nos permite gestionar los volúmenes de nuestro sistema, escribimos "dispart" para activar la herramienta. Con el comando "list volume" listaremos todos los volúmenes disponibles en nuestro sistema. La partición OEM del fabricante suele rondar los 500 MB. Podremos identificarla fácilmente gracias a la letra con la que aparece en el explorador de ficheros. En mi caso tiene la letra F y es el volumen 3.

Ahora procedemos a ocultar la partición eliminando la letra de la partición y manteniendo la misma con los siguiente comandos:

DISKPART> select volume 3

El volumen 3 es el volumen seleccionado.

DISKPART> remove letter=F

DiskPart quitó correctamente la letra de unidad o el punto de montaje.

Ahora si vamos al explorador de archivos, veremos que ya no nos aparece la partición y por supuesto ya no nos lanza continuamente el mensaje de falta de espacio en la misma . Si vamos al administrador de discos o ejecutamos de nuevo el comando "list volume" de diskpart, veremos que la partición ya no tiene letra asignada pero sigue ahí.

Ya tenemos la partición de nuevo como siempre estuvo , oculta! 😉

 

Hidden Console Start (HCS) – Esconde la consola y lanza procesos/aplicaciones en segundo plano

Dicen que no te das cuenta de algo hasta que lo pierdes... Esto es lo que me ha pasado cuando recientemente mi orientación profesional ha cambiado y he tenido  que trabajar con sistemas Windows en vez de GNU-Linux.

Acostumbrado a tener corriendo servicios en distintas máquinas con GNU-Linux acabas echando de menos su shell y la bestialidad de herramientas que hay. Vale sí lo reconozco, al final trabajaba en una máquina Windows, pero porque sigo pensando que las herramientas de desarrollo siguen siendo mejor que las que hay disponibles en GNU-Linux. Hay que reconocer que un Windows lo uso sólo para desarrollar (eso sí multiplataforma) y para jugar, para lo demás GNU-Linux sin duda!!!

Una de las cosas que he echado en falta recientemente es la posibilidad de usar el operador & de background tan potente en GNU-Linux. Este operador permite lanzar un proceso que se sigue ejecutando sin bloquear la shell y si la cerramos, éste sigue en segundo plano. Pues esto tan chulo, no puedes hacerlo en un Windows, porque su comando start no lo permite y la opción /B del comando no impide que al cerrarse la consola de comandos el proceso que has lanzado muera. A no ser que el proceso que has lazando cree su propio hilo no dependiente del proceso de la consola. Y tampoco es posible lanzar un proceso de consola de comandos sin consola, a no ser que esté programado explícitamente que la consola se oculte o no aparezca. Windows en este aspecto se cubre mucho, porque la única forma de crear procesos en background es construyendo servicios de Windows que tienen sus propias reglas a cumplir y por consiguiente hace falta desarrollo específico para que algo corra en segundo plano.

Visto el panorama y teniendo cierto conocimiento e idea, me decidí a generar una herramienta similar que funcionase en Windows como el operador &, o por lo menos a intentarlo. Para ello lo primero pensé en que quizás lo más adecuado fuese hacerlo en multiplataforma y generar una solución que funcionase tanto en Windows como en GNU-Linux. Atendiendo a este requisito, enseguida a mi mente llegó Python, porque además su instalación de paquetes es sencilla y potente a partes iguales, por no decir que es posible generar binarios (por ejemplo un .exe en Windows) si hiciera falta gracias a herramientas como py2exe y PyInstaller.

Con el punto de partida claro y unas horas de desarrollo, consigo lo que bautizo como Hidden Console Start o HCS. El proyecto puedes encontrarlo en Github:

Y su instalación es sencilla si tienes ya Python en tu equipo. En caso de no tener Python, pásate por la web de Python y descárgate la última versión disponible. Una vez instalado Python, solo tienes que ejecutar el siguiente comando en el CMD o PowerShell para instalar HCS:

pip install hcs --upgrade

Una vez instalado puedes ejecutar el proceso o aplicación que se quiera ejecutando HCS de la siguiente forma:

hcs -e "P1" "P2" ... "Pn-1" "Pn"

Pongamos un ejemplo:

hcs -e "ping 127.0.0.1 > log1.txt" "ping 192.168.1.17 > log2.txt"

En el ejemplo se lanzan dos comandos ping a distintas direcciones que son guardados en log1.txt y log2.txt respectivamente. Como se puede ver la consola de comandos no queda bloqueada y la información de los comandos ejecutados se va guardando el los ficheros.

Si por alguna razón tus procesos o aplicaciones no mueren o acaban, puedes finalizarlos en el caso de Windows abriendo el administrador de tareas:

Y en el caso de GNU-Linux con htop:

De esta forma podemos lanzar procesos y aplicaciones en segundo plano en sistemas Windows de una forma más o menos equivalente a como lo haríamos en GNU-Linux. Y obviamente podríamos usar HCS en GNU-Linux porque también funciona, pudiendo usarlo de la misma manera que en Windows.