One place for hosting & domains

      Cómo configurar el acceso remoto para MongoDB en Ubuntu 20.04


      Melissa Anderson escribió una versión anterior de este tutorial.

      Introducción

      MongoDB, también conocido como Mongo, es una base de datos de documentos de código abierto usada comúnmente en las aplicaciones web modernas. Por defecto, solo permite conexiones que se originan en el mismo servidor donde está instalado. Si desea administrar MongoDB de forma remota o conectarlo a un servidor de aplicaciones independiente, existen algunos cambios que deberá realizar a la configuración predeterminada.

      En este tutorial, configurará una instalación de MongoDB para permitir el acceso de forma segura desde un equipo remoto de confianza. Para hacer esto, actualizará las reglas de su firewall para proporcionar acceso del equipo remoto al puerto sobre el cual MongoDB está escuchando las conexiones, y a continuación actualizará su archivo de configuración para cambiar su ajuste de vinculación de IP. Luego, como paso final, probará que su equipo remoto puede realizar la conexión a su base de datos correctamente.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      • Un servidor con Ubuntu 20.04. Este servidor debería tener un usuario administrativo y un firewall configurado con ufw. Puede establecerlo siguiendo nuestra Guía inicial de configuración del servidor para Ubuntu 20.04.
      • MongoDB instalado en su servidor. Este tutorial asume que tiene instalado MongoDB 4.4 o una versión más reciente. Puede instalar esta versión siguiendo nuestro tutorial en Cómo instalar MongoDB en Ubuntu 20.04.
      • Un segundo equipo desde el cual accederá a su instancia de MongDB. Para mayor simplicidad, este tutorial asume que este equipo es otro servidor Ubuntu 20.04 con un usuario administrativo no root y un firewall UFW configurado siguiendo nuestra guía de configuración inicial para servidores de Ubuntu 20.04. Sin embargo, los Pasos 1 y 2, que describen el procedimiento real para permitir la conectividad remota sobre el servidor de la base de datos, funcionarán independientemente de qué sistemas operativos esté ejecutando el equipo remoto.

      Finalmente, aunque no es necesario para completar este tutorial, recomendamos encarecidamente que proteja su instalación de MongoDB creando una cuenta de usuario administrativo para la base de datos y permitiendo la autenticación. Para hacer esto, siga nuestro tutorial sobre Cómo proteger MongoDB en Ubuntu 20.04.

      Paso 1: Ajuste del firewall

      Asumiendo que siguió el tutorial de requisitos previos de configuración inicial del servidor y habilitó un firewall UFW en su servidor, su instalación de MongoDB será inaccesible desde Internet. Si tiene intención de usar el servidor de MongoDB solo a nivel local con aplicaciones que se ejecuten en el mismo servidor, este es el ajuste recomendado y seguro. Sin embargo, si desea poder conectar con su servidor MongoDB desde una ubicación remota, tendrá que permitir las conexiones entrantes al puerto donde está escuchando la base de datos añadiendo una nueva regla UFW.

      Comience verificando en qué puerto está escuchando la instalación de MongoDB con el comando lsof. Este comando normalmente devuelve una lista con cada archivo abierto en un sistema, pero cuando se combina con la opción -i, lista solo los archivos o corrientes de datos relacionados con la red:

      El siguiente comando redirigirá el resultado producido por lsof -i a un comando grep que busca una cadena llamada mongo:

      • sudo lsof -i | grep mongo

      Este resultado de ejemplo muestra que MongoDB está escuchando las conexiones en su puerto predeterminado, 27017:

      Output

      mongod 82221 mongodb 11u IPv4 913411 0t0 TCP localhost:27017 (LISTEN)

      En la mayoría de los casos, solo se debe acceder a MongoDB desde determinadas ubicaciones de confianza, como otro servidor que aloje una aplicación. Una forma de configurar esto es ejecutar el siguiente comando en su servidor MongoDB, que abre el acceso en el puerto predeterminado de Mongo mientras que explícitamente solo permite la dirección IP del otro servidor de confianza.

      Ejecute el siguiente comando, asegurándose de cambiar trusted_server_ip a la dirección IP del equipo remoto de confianza que usará para acceder a su instancia de MongoDB:

      Nota: Si el resultado del comando anterior mostró que su instalación de MongoDB está escuchando sobre un puerto no predeterminado, utilice ese número de puerto en lugar de 27017 en este comando.

      • sudo ufw allow from trusted_server_ip to any port 27017

      En el futuro, si alguna vez quiere acceder a MongoDB desde otro equipo, ejecute este comando de nuevo con la dirección IP del nuevo equipo en lugar de trusted_server_ip.

      Puede verificar el cambio en los ajustes del firewall con ufw:

      El resultado mostrará que el tráfico al puerto 27017 desde el servidor remoto ahora está permitido:

      Output

      Status: active To Action From -- ------ ---- OpenSSH ALLOW Anywhere 27017 ALLOW trusted_server_ip OpenSSH (v6) ALLOW Anywhere (v6)

      Puede encontrar ajustes de firewall más avanzados para restringir el acceso a servicios en Aspectos básicos de UFW: Reglas y comandos comunes de firewall.

      A continuación, vinculará MongoDB a la dirección IP pública del servidor para que pueda acceder a él desde su equipo remoto.

      Paso 2: Configurar una bindIP pública

      En este momento, aunque el puerto está abierto, MongoDB está actualmente vinculado a 127.0.0.1, la interfaz de red loopback. Esto significa que MongoDB solo puede aceptar conexiones que se originen en el servidor donde está instalado.

      Para permitir conexiones remotas, debe editar el archivo de configuración de MongoDB (/etc/mongod.conf) para vincular adicionalmente MongoDB a la dirección IP públicamente dirigible de su servidor. De esta forma, su instalación de MongoDB podrá escuchar las conexiones realizadas a su servidor MongoDB desde equipos remotos.

      Abra el archivo de configuración de MongoDB en su editor de texto preferido: El siguiente ejemplo utiliza nano:

      • sudo nano /etc/mongod.conf

      Busque la sección network interfaces y, a continuación, el valor bindIp:

      /etc/mongod.conf

      . . .
      # network interfaces
      net:
        port: 27017
        bindIp: 127.0.0.1
      
      . . .
      

      Añada una coma a esta línea seguida de la dirección IP pública de su servidor MongoDB:

      /etc/mongod.conf

      . . .
      # network interfaces
      net:
        port: 27017
        bindIp: 127.0.0.1,mongodb_server_ip
      
      . . .
      

      Guarde y cierre el archivo. Si utiliza nano, podrá hacerlo presionando CTRL+X, Y y luego ENTER.

      A continuación, reinicie MongoDB para que este cambio surta efecto:

      • sudo systemctl restart mongod

      Tras eso, su instalación de MongoDB podrá aceptar conexiones remotas desde cualquier equipo al que haya permitido acceder al puerto 27017. Como paso final, puede probar si el servidor remoto de confianza que permitió a través del firewall en el Paso 1 puede llegar a la instancia de MongoDB que se ejecuta en su servidor.

      Paso 3: Probar la conectividad remota

      Ahora que ha configurado su instalación de MongoDB para que escuche las conexiones que se originan en su dirección IP dirigible públicamente y ha concedido a su equipo remoto acceso a través del firewall de su servidor al puerto predeterminado de Mongo, puede probar que el equipo remoto puede conectarse.

      Nota: Como se mencionó en la sección Requisitos previos, este tutorial asume que su equipo remoto es otro servidor con Ubuntu 20.04. El procedimiento para permitir las conexiones remotas descrito en los Pasos 1 y 2 debería funcionar independientemente de qué sistema operativo ejecute su equipo remoto, pero los métodos de prueba descritos en este Paso no funcionan universalmente entre sistemas operativos.

      Una forma de probar que su servidor remoto de confianza puede conectarse a la instancia de MongoDB es usar el comando nc. nc, abreviatura de netcat, es una utilidad usada para establecer conexiones de red con TCP o UDP. Es útil para probar en casos como este porque le permite especificar una dirección IP y un número de puerto.

      Primero, inicie sesión en su servidor de confianza usando SSH:

      • ssh sammy@trusted_server_ip

      A continuación, ejecute el siguiente comando nc, que incluye la opción -z. Esto limita a nc para que solo analice un daemon de escucha en el servidor de destino sin enviar datos. Recuerde del tutorial de instalación de requisitos previos que MongoDB está ejecutándose como un daemon de servicio, lo que hace que esta opción sea útil para probar la conectividad. También incluye la opción v que aumenta la verbosidad del comando, lo que hace que netcat devuelva un resultado que de otra forma no devolvería.

      Ejecute el siguiente comando nc desde su servidor remoto de confianza, asegurándose de sustituir mongodb_server_ip con la dirección IP del servidor sobre el cual instaló MongoDB:

      • nc -zv mongodb_server_ip 27017

      Si el servidor de confianza puede acceder al daemon de MongoDB, su resultado indicará que la conexión se realizó correctamente:

      Output

      Connection to mongodb_server_ip 27017 port [tcp/*] succeeded!

      Asumiendo que tenga una versión compatible del shell de mongo instalado en su servidor remoto, puede en este momento conectar directamente con la instancia de MongoDB instalada en el servidor host.

      Una forma de conectar es con una URI de cadena de conexión, como esta:

      • mongo "mongodb://mongo_server_ip:27017"

      Nota: Si siguió el tutorial recomendado Cómo proteger MongoDB en Ubuntu 20.04, habrá cerrado el acceso a su base de datos para los usuarios sin autenticar. En este caso, necesitará usar una URI que especifique un nombre de usuario válido, como esta:

      • mongo "mongodb://username@mongo_server_ip:27017"

      El shell le pedirá automáticamente que introduzca la contraseña del usuario.

      Con eso, ha confirmado que su servidor MongoDB puede aceptar conexiones desde el servidor de confianza.

      Conclusión

      Ahora puede acceder a su instalación de MongoDB desde un servidor remoto. En este momento, puede administrar su base de datos Mongo remotamente desde el servidor de confianza. Alternativamente, podría configurar una aplicación para que se ejecute en el servidor remoto y utilice la base de datos remotamente.

      Si no ha configurado un usuario administrativo y habilitado la autenticación, cualquiera que tenga acceso a su servidor remoto podrá acceder también a su instalación de MongoDB. Si aún no lo ha hecho, le recomendamos encarecidamente que siga nuestra guía sobre Cómo proteger MongoDB en Ubuntu 20.04 para añadir usuario administrativo y habilitar un bloqueo adicional.



      Source link

      Como instalar e configurar o Postfix como um servidor SMTP apenas para envio no Ubuntu 20.04


      O autor selecionou o Free and Open Source Fund para receber uma doação como parte do programa Write for DOnations.

      Introdução

      O Postfix é um agente de transferência de e-mail (MTA), uma aplicação utilizada para enviar e receber e-mails. Ele pode ser configurado para enviar e-mails apenas de uma aplicação local. Isso é útil em situações em que você precisa enviar regularmente notificações por e-mail de seus apps ou, simplesmente, tem um grande tráfego de saída que um provedor de serviço de e-mail de terceiros não permitiria. Ele também é uma alternativa mais leve do que executar um servidor SMTP completo, enquanto mantém a funcionalidade necessária.

      Neste tutorial, você instalará e configurará o Postfix como um servidor SMTP apenas para envio. Você também solicitará certificados TLS gratuitos do Let’s Encrypt para seu domínio e criptografará os e-mails de saída usando-os.

      Pré-requisitos

      • Um servidor Ubuntu 20.04 configurado de acordo com o tutorial Initial Server Setup with Ubuntu 20.04, incluindo a criação de um usuário sudo não root.
      • Um nome de domínio totalmente registrado. Este tutorial utilizará o your_domain durante todo o processo. Você pode comprar um nome de domínio em Namecheap, obter um gratuitamente em Freenom ou usar o registrador de domínios de sua escolha.
      • Um registro de DNS do tipo A com your_domain apontando para o endereço IP público do seu servidor. Você pode seguir esta introdução para DNS DigitalOcean para mais detalhes sobre como adicioná-los.

      Nota: o hostname do seu servidor e o nome do seu Droplet devem corresponder ao your_domain, pois a DigitalOcean define automaticamente os registros de PTR para o endereço IP do Droplet de acordo com o nome dele.

      Você pode verificar o hostname do servidor digitando hostname no prompt de comando. A saída deve corresponder ao nome que você deu ao Droplet quando ele foi criado.

      Passo 1 — Instalando o Postfix

      Neste passo, você instalará o Postfix. A maneira mais rápida é instalar o pacote mailutils, que inclui os pacotes do Postfix com alguns programas suplementares que você utilizará para testar o envio de e-mail.

      Primeiro, atualize o banco de dados de pacotes:

      Em seguida, instale o Postfix executando o seguinte comando:

      • sudo apt install mailutils

      Perto do final do processo de instalação, será mostrada a janela de configuração do Postfix:

      Selecione Internet Site no menu e pressione TAB para selecionar<Ok>, depois ENTER

      A opção padrão é Internet Site Essa é a opção recomendada para seu caso de uso. Então, pressione TAB e, depois, ENTER. Se você só vir o texto de descrição, pressione TAB para selecionar OK, depois ENTER.

      Se ele não aparecer automaticamente, execute o seguinte comando para iniciá-lo:

      • sudo dpkg-reconfigure postfix

      Após isso, você receberá outro prompt de configuração sobre o nome do sistema de e-mail:

      Digite seu nome de domínio e, depois, pressione TAB para selecionar<Ok>, ENTER

      O nome do sistema de e-mail deve ser o mesmo que você atribuiu ao seu servidor quando você o estava criando. Quando você terminar, pressione TAB, seguido de ENTER.

      Agora você instalou o Postfix e poderá iniciar a configuração dele.

      Passo 2 — Configurando o Postfix

      Neste passo, você configurará o Postfix para enviar e receber e-mails apenas do servidor no qual ele está em execução — ou seja do localhost.

      Para que isso aconteça, você precisa configurar o Postfix para ouvir apenas na interface de loopback, a interface de rede virtual que o servidor utiliza para se comunicar internamente. Para fazer as alterações, você precisará editar o arquivo de configuração principal do Postfix chamado main.cf, armazenado em etc/postfix.

      Abra-o para edição utilizando seu editor de texto favorito:

      • sudo nano /etc/postfix/main.cf

      Procure as seguintes linhas:

      /etc/postfix/main.cf

      . . .
      mailbox_size_limit = 0
      recipient_delimiter = +
      inet_interfaces = all
      . . .
      

      Defina o valor da configuração inet_interfaces para loopback-only:

      /etc/postfix/main.cf

      . . .
      mailbox_size_limit = 0
      recipient_delimiter = +
      inet_interfaces = loopback-only
      . . .
      

      Outra diretiva que você precisará modificar é mydestination, que especifica a lista de domínios que são entregues através do transporte de entrega de correio local_transport. Por padrão, os valores são semelhantes a estes:

      /etc/postfix/main.cf

      . . .
      mydestination = $myhostname, your_domain, localhost.com, , localhost
      . . .
      

      Altere a linha para que ela fique como esta:

      /etc/postfix/main.cf

      . . .
      mydestination = localhost.$mydomain, localhost, $myhostname
      . . .
      

      Se o domínio é na verdade um subdomínio, e você gostaria que as mensagens de e-mail parecessem ter sido enviadas do domínio principal, adicione a seguinte linha ao final de main.cf:

      /etc/postfix/main.cf

      ...
      masquerade_domains = your_main_domain
      

      A configuração opcional masquerade_domains especifica os domínios para os quais o subdomínio será removido do endereço de e-mail.

      Quando terminar, salve e feche o arquivo.

      Nota: se você está hospedando vários domínios em um único servidor, os outros domínios podem também ser passados para o Postfix utilizando a diretiva mydestination.

      Em seguida, reinicie o Postfix executando o seguinte comando:

      • sudo systemctl restart postfix

      Você configurou o Postfix para enviar e-mails apenas do seu servidor. Agora, você irá testá-lo enviando uma mensagem de exemplo para um endereço de e-mail.

      Passo 3 — Testando o Servidor SMTP

      Neste passo, você testará se o Postfix pode enviar e-mails para uma conta de e-mail externa usando o comando mail, que faz parte do pacote mailutils que você instalou no primeiro passo.

      Para enviar um e-mail de teste, execute o seguinte comando:

      • echo "This is the body of the email" | mail -s "This is the subject line" your_email_address

      Você pode alterar o corpo e o assunto do e-mail ao seu gosto. Lembre-se de substituir your_email_address por um endereço de e-mail válido que você possa acessar.

      Agora, verifique o endereço de e-mail para o qual você enviou esta mensagem. Você deve ver a mensagem em sua caixa de entrada. Se ele não estiver lá, verifique sua pasta de spam. Neste ponto, todos os e-mails que você envia não são criptografados, o que faz com que os prestadores de serviços pensem que ele é provavelmente spam. Você configurará a criptografia mais tarde, no passo 5.

      Se você receber um erro do comando mail, ou se não tiver recebido uma mensagem após um longo período de tempo, verifique se a configuração do Postfix que você editou é válida e que o nome e o hostname do seu servidor estão configurados para o seu domínio.

      Observe que com esta configuração, o endereço no campo From para os e-mails de teste que você envia estará na forma de your_user_name@your_domain, onde your_user_name é o nome de usuário do servidor com o qual você executou o comando.

      Agora, você enviou um e-mail do seu servidor e verificou se ele foi recebido com sucesso. No próximo passo, você configurará o encaminhamento de e-mail para o root.

      Passo 4 — Sistema de encaminhamento de e-mail

      Neste passo, você configurará o encaminhamento e-mail para o usuário root, para que as mensagens geradas pelo sistema enviadas a ele em seu servidor sejam encaminhadas para um endereço de e-mail externo.

      O arquivo /etc/aliases contém uma lista de nomes alternativos para os destinatários de e-mail. Abra-o para edição:

      No estado padrão, ele se parece com isto:

      /etc/aliases

      # See man 5 aliases for format
      postmaster:    root
      

      A única diretiva presente especifica que os e-mails gerados pelo sistema são enviados para o root.

      Adicione a linha seguinte ao final do arquivo:

      /etc/aliases

      ...
      root:          your_email_address
      

      Com esta linha, você especifica que e-mails enviados para o root acabam sendo encaminhados para um endereço de e-mail. Lembre-se de substituir your_email_address pelo seu endereço de e-mail pessoal. Quando terminar, salve e feche o arquivo.

      Para que a mudança entre em vigor, execute o seguinte comando:

      A execução do newaliases construirá um banco de dados de aliases que o comando mail utiliza, que são pegos do arquivo de configuração que você acabou de editar.

      Teste se o envio de e-mails para o root funciona executando:

      • echo "This is the body of the email" | mail -s "This is the subject line" root

      Você deve receber o e-mail em seu endereço e-mail. Se ele não estiver lá, verifique sua pasta de spam.

      Neste passo, você configurou o encaminhamento de mensagens geradas pelo sistema para seu endereço de e-mail. Agora, você habilitará a criptografia de mensagens para que todos os e-mails que seu servidor enviar sejam imunizados contra adulteração em trânsito e sejam vistos como mais legítimos.

      Passo 5 — Habilitando a criptografia SMTP

      Agora você habilitará a criptografia SMTP solicitando um certificado TLS gratuito da Let’s Encrypt para o seu domínio (usando Certbot) e configurando o Postfix para usá-lo ao enviar mensagens.

      O Ubuntu inclui o Certbot em seus repositórios de pacotes padrão, para que você possa instalá-lo executando o seguinte comando:

      Quando solicitada a confirmação, digite Y e pressione ENTER.

      Como parte da configuração inicial de servidor nos pré-requisitos, você instalou o ufw, o firewall descomplicado. Você precisará configurá-lo para permitir a porta HTTP 80, para que a verificação de domínios possa ser concluída. Execute o comando a seguir para habilitá-lo:

      O resultado ficará parecido com este:

      Output

      Rule added Rule added (v6)

      Agora que a porta está aberta, execute o Certbot para obter um certificado:

      • sudo certbot certonly --standalone --rsa-key-size 4096 --agree-tos --preferred-challenges http -d your_domain

      Este comando ordena que o Certbot emita certificados com um tamanho de chaves RSA de 4096 bits para executar um servidor web temporário (--standalone) para verificação, e para verificar através da porta 80 (--preferred-challenges http). Lembre-se de substituir your_domain pelo seu domínio antes de executar o comando e digite seu endereço de e-mail quando solicitado.

      O resultado será semelhante a este:

      Output

      Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator standalone, Installer None Obtaining a new certificate Performing the following challenges: http-01 challenge for `your_domain` Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/your_domain/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/your_domain/privkey.pem Your cert will expire on 2020-07-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le

      Como escrito nas notas, seu certificado e o arquivo de chave privada foram salvos em /etc/letsencrypt/live/your_domain.

      Agora que você tem seu certificado, abra o main.cf para edição:

      • sudo nano /etc/postfix/main.cf

      Procure a seguinte sessão:

      /etc/postfix/main.cf

      # TLS parameters
      smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
      smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
      smtpd_tls_security_level=may
      
      smtp_tls_CApath=/etc/ssl/certs
      smtp_tls_security_level=may
      smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
      

      Modifique isso para ficar assim, substituindo your_domain pelo seu domínio, onde necessário. Isso irá atualizar suas configurações TLS para o Postfix:

      /etc/postfix/main.cf

      # TLS parameters
      smtpd_tls_cert_file=/etc/letsencrypt/live/your_domain/fullchain.pem
      smtpd_tls_key_file=/etc/letsencrypt/live/your_domain/privkey.pem
      smtpd_tls_security_level=may
      
      smtp_tls_CApath=/etc/ssl/certs
      smtp_tls_security_level=may
      smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
      

      Quando terminar, salve e feche o arquivo.

      Aplique as alterações reiniciando o Postfix:

      • sudo systemctl restart postfix

      Agora, tente enviar um e-mail novamente:

      • echo "This is the body of an encrypted email" | mail -s "This is the subject line" your_email_address

      Em seguida, verifique o endereço de e-mail que você forneceu. É possível que você veja a mensagem em sua caixa de entrada imediatamente, pois os provedores de e-mail são muito mais propensos a marcar mensagens não criptografadas como spam.

      Você pode verificar as informações técnicas sobre a mensagem de e-mail em seu cliente para ver que a mensagem está de fato criptografada.

      Conclusão

      Agora, você tem um servidor de e-mail apenas para envio, equipado com o Postfix. Criptografar todas as mensagens de saída é um bom primeiro passo eficaz para os provedores de e-mail não marcarem suas mensagens como spam imediatamente. Se você estiver fazendo isso em um cenário de desenvolvimento, então, esta medida deve ser o suficiente.

      No entanto, se o seu caso de uso for enviar e-mails para usuários do site em potencial (como e-mails de confirmação para uma inscrição no quadro de mensagens), verifique a configuração de registros SPF, para que os e-mails do seu servidor tenham ainda mais probabilidade de serem considerados legítimos.



      Source link

      Cómo usar subprocess para ejecutar programas externos en Python


      El autor seleccionó el COVID-19 Relief Fund para que reciba una donación como parte del programa Write for DOnations.

      Introducción

      Python 3 incluye el módulo subprocess para ejecutar programas externos y leer sus resultados en su código Python.

      Encontrará subprocess útil si desea usar otro programa en su computadora desde su código Python. Por ejemplo, es posible que desee invocar git desde su código Python para recuperar archivos en su proyecto que tienen un seguimiento por parte del control de versiones de git. Ya que cualquier programa al que acceda en su computadora puede estar controlado por subprocess, los ejemplos mostrados aquí serán aplicables a cualquier programa externo que desee invocar desde su código Python.

      subprocess incluye varias clases y funciones, pero en este tutorial cubriremos una de las funciones más útiles de subprocess: subprocess.run. Revisaremos sus diferentes usos y principales argumentos de palabras clave.

      Requisitos previos

      Para sacar el máximo provecho de este tutorial, se recomienda tener cierta familiaridad con la programación en Python 3. Puede consultar estos tutoriales para obtener la información de fondo necesaria:

      Ejecutar un programa externo

      Puede usar la función subprocess.run para ejecutar un programa externo desde su código Python. Primero, sin embargo, necesitará importar los módulos subprocess y sys a su programa:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "print('ocean')"])
      

      Si ejecuta esto, recibirá un resultado similar al siguiente:

      Output

      ocean

      Vamos a revisar este ejemplo:

      • sys.executable es la ruta absoluta al ejecutable de Python con el que se invocó su programa en un principio. Por ejemplo, sys.executable podría ser una ruta como /usr/local/bin/python.
      • subprocess.run obtiene una lista de cadenas que consisten en los componentes del comando que estamos intentando ejecutar. Ya que la primera cadena que pasamos es sys.executable, indicamos a subprocess.run que ejecute un nuevo programa Python.
      • El componente -c es una opción de línea de comandos python que le permite pasar una cadena con un programa completo Python para ejecutar. En nuestro caso, pasamos un programa que imprime la cadena ocean.

      Puede pensar en cada entrada de la lista que pasamos a subprocess.run como si estuviese separada por un espacio. Por ejemplo, [sys.executable, "-c", "print('ocean')"] se traduce aproximadamente como /usr/local/bin/python -c "print('ocean')". Observe que subprocess automáticamente pone entre comillas los componentes del comando antes de intentar ejecutarlos sobre el sistema operativo subyacente de forma que, por ejemplo, puede pasar un nombre de archivo que tenga espacios.

      Advertencia: Nunca pase una entrada no confiable a subprocess.run. Ya que subprocess.run tiene la capacidad de realizar comandos arbitrarios en su computadora, los agentes maliciosos pueden usarlo para manipular su computadora de formas inesperadas.

      Capturar resultados desde un programa externo

      Ahora que podemos invocar un programa externo usando subprocess.run, vamos a ver cómo podemos capturar el resultado desde ese programa. Por ejemplo, este proceso podría ser útil si quisiéramos usar git ls-files para crear todos sus archivos guardados actualmente bajo control de versiones.

      Nota: Los ejemplos que se muestran en esta sección requieren Python 3.7 o posterior. En particular, los argumentos de palabra clave capture_output y text fueron añadidos en Python 3.7 cuando se lanzó en junio del 2018.

      Vamos a añadir nuestro ejemplo anterior:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "print('ocean')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si ejecutamos este código, obtendremos un resultado como el siguiente:

      Output

      stdout: ocean stderr:

      Este ejemplo es, en gran medida, el mismo que presentamos en la primera sección: aún estamos ejecutando un subproceso para imprimir ocean. Es sobre todo importante que pasemos los argumentos de palabra clave capture_output=True y text=True a subproecss.run.

      subprocess-run devuelve un objeto subprocess.CompletedProcess que está vinculado a result. El objeto subprocess.CompletedProcess incluye detalles sobre el código de salida del programa externo y su resultado. capture_output=True garantiza que result-stdout y result-stderr se completan con el resultado correspondiente del programa externo. De forma predeterminada, result.stdout y result.stderr están vinculados como bytes, pero el argumento de palabra clave text=True indica a Python que decodifique los bytes en cadenas.

      En la sección de resultado, stdout es ocean (además de la nueva línea final que print añade de forma implícita) y no tenemos stderr.

      Vamos a probar un ejemplo que produce un valor no vacío para stderr:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "raise ValueError('oops')"], capture_output=True, text=True
      )
      print("stdout:", result.stdout)
      print("stderr:", result.stderr)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      stdout: stderr: Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops

      Este código ejecuta un subproceso de Python que crea de inmediato un ValueError. Cuando inspeccionamos el resultado final, no vemos nada en stdout y un Traceback de nuestro ValueError en stderr. Esto es porque, por defecto, Python escribe el Traceback de la excepción sin administrar a stderr.

      Generar una excepción en un código de salida erróneo

      A veces, es útil generar una excepción si un programa que ejecutamos sale con un código de salida erróneo. Los programas que salen con un código cero se consideran correctos, pero se considera que los programas que salen con un código no cero encontraron un error. Como ejemplo, este patrón podría ser útil si quisiéramos generar una excepción en el caso de que ejecutemos git ls-files es un directorio que realmente no era un repositorio git.

      Podemos usar el argumento de palabra clave check=True para que subprocess.run genere una excepción si el programa externo devuelve un código de salida no cero:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"], check=True)
      

      Si ejecutamos este código, obtendremos un resultado similar al siguiente:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Este resultado muestra que ejecutamos un subproceso que generó un error, que se imprime en stderr en nuestro terminal. A continuación, subprocess.run planteó generó un subprocess.CalledProcessError en nuestro nombre en nuestro programa Python principal.

      Alternativamente, el módulo subprocess también incluye el método subprocess.CompletedProcess.check_returncode, que podemos invocar a efectos similares:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "raise ValueError('oops')"])
      result.check_returncode()
      

      Si ejecutamos este código, recibiremos:

      Output

      Traceback (most recent call last): File "<string>", line 1, in <module> ValueError: oops Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 444, in check_returncode raise CalledProcessError(self.returncode, self.args, self.stdout, subprocess.CalledProcessError: Command '['/usr/local/bin/python', '-c', "raise ValueError('oops')"]' returned non-zero exit status 1.

      Ya que no pasamos check=True a subprocess.run, vinculamos correctamente una instancia subprocess.CompletedProcess a result, a pesar de que nuestro programa salió con un código no cero. Al invocar result.check_returncode(), sin embargo, se genera un subprocess.CalledProcessError porque detecta que el proceso completado salió con un código erróneo.

      Usar timeout para salir de los programas de forma anticipada

      subprocess.run incluye el argumento timeout para permitirle detener un programa externo si tarda demasiado en ejecutarse:

      import subprocess
      import sys
      
      result = subprocess.run([sys.executable, "-c", "import time; time.sleep(2)"], timeout=1)
      

      Si ejecutamos este código, obtendremos un resultado como el siguiente:

      Output

      Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/local/lib/python3.8/subprocess.py", line 491, in run stdout, stderr = process.communicate(input, timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1024, in communicate stdout, stderr = self._communicate(input, endtime, timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1892, in _communicate self.wait(timeout=self._remaining_time(endtime)) File "/usr/local/lib/python3.8/subprocess.py", line 1079, in wait return self._wait(timeout=timeout) File "/usr/local/lib/python3.8/subprocess.py", line 1796, in _wait raise TimeoutExpired(self.args, timeout) subprocess.TimeoutExpired: Command '['/usr/local/bin/python', '-c', 'import time; time.sleep(2)']' timed out after 0.9997982999999522 seconds

      El subproceso que intentamos ejecutar usó la función time.sleep para hibernar durante 2 segundos. Sin embargo, pasamos el argumento de palabra clave timeout=1 a subprocess.run para desconectar nuestro subproceso tras 1 segundo. Esto explica por qué nuestra invocación a subprocess.run finalmente generó una excepción subprocess.TimeoutExpired.

      Tenga en cuenta que el argumento de palabra clave timeout para subprocess.run es aproximado. Python hará todo lo posible para anular el subproceso tras el número de segundos de timeout, pero no será necesariamente exacto.

      Pasar input a programas

      A veces, los programas esperan que se pase una entrada a través de stdin.

      El argumento de palabra clave input a subprocess.run le permite pasar datos al stdin del subproceso. Por ejemplo:

      import subprocess
      import sys
      
      result = subprocess.run(
          [sys.executable, "-c", "import sys; print(sys.stdin.read())"], input=b"underwater"
      )
      

      Obtendremos un resultado similar al siguiente tras ejecutar este código:

      Output

      underwater

      En este caso, pasamos los bytes underwater a input. Nuestro subproceso objetivo utilizó sys.stdin para leer lo pasado en stdin (underwater) e imprimió nuestro resultado.

      El argumento de palabra clave input puede ser útil si desea encadenar múltiples invocaciones subprocess.run juntas pasando el resultado de un programa como la entrada de otro.

      Conclusión

      El módulo subprocess es una parte potente de la biblioteca estándar de Python que le permite ejecutar programas externos e inspeccionar sus resultados fácilmente. En este tutorial, aprendió a usar subprocess.run para controlar programas externos, pasar entrada a ellos, analizar sus resultados y comprobar sus códigos de retorno.

      El módulo subprocess expone clases y utilidades adicionales que no abarcamos en este tutorial. Ahora que tiene una base, puede usar la documentación del módulo subprocess para obtener más información sobre otras clases y utilidades disponibles.



      Source link