One place for hosting & domains

      Cómo configurar Jupyter Notebook con Python 3 en Ubuntu 20.04 y conectar a través de los túneles SSH


      Introducción

      Jupyter Notebook es una aplicación web de código abierto que le permite crear y compartir código interactivo, visualizaciones y mucho más. Esta herramienta puede utilizarse con varios lenguajes de programación, como Python, Julia, R, Haskell y Ruby. A menudo se utiliza para trabajar con datos, modelos estadísticos, y aprendizaje automático.

      Jupyter Notebooks (o simplemente “Notebooks”) es un conjunto de documentos producidos por la aplicación Jupyter Notebook, la cual contiene tanto elementos de código informático como de texto enriquecido (párrafos, ecuaciones, cifras y enlaces, entre otros) que ayudan a presentar y compartir la investigación que puede reproducirse. Por tanto, puede ser una herramienta excelente para las presentaciones basadas en datos o basadas en programación, o como herramienta de enseñanza.

      Este tutorial mostrará cómo configurar Jupyter Notebook para que se ejecute desde un servidor Ubuntu 20.04, y demostrará cómo conectar y usar Notebook desde un equipo local a través de la tunelación. Al final de esta guía, podrá ejecutar código de Python 3 usando un Jupyter Notebook en ejecución en un servidor remoto.

      Requisitos previos

      Para completar esta guía, debe disponer de una instancia de servidor de Ubuntu 20.04 nueva con un firewall básico y un usuario no root con privilegios sudo configurados. Puede aprender a configurar esto en nuestro tutorial de configuración inicial para servidores.

      Paso 1: Configurar Python

      Para iniciar el proceso, instalaremos las dependencias que necesitamos para nuestro entorno de programación de Python desde los repositorios de Ubuntu. Ubuntu 20.04 viene preinstalado con Python 3. Usaremos el pip del administrador de paquetes de Python para instalar componentes adicionales un poco más tarde.

      Necesitaremos primero actualizar el índice de paquetes local apt y luego descargaremos e instalaremos los paquetes:

      A continuación, instale pip y los archivos de encabezado de Python, utilizados por algunas dependencias de Jupyter:

      • sudo apt install python3-pip python3-dev

      Ahora podemos proceder a configurar un entorno virtual de Python en el que instalaremos Jupyter.

      Paso 2: Crear un entorno virtual de Python para Jupyter

      Ahora Python 3, sus archivos de encabezado y pip están listos para comenzar, podemos crear un entorno virtual de Python para administrar nuestros proyectos. Instalaremos Jupyter en este entorno virtual.

      Para ello, primero necesitaremos acceso al comando virtualenv, que podemos instalar con pip.

      Actualice pip e instale el paquete escribiendo lo siguiente:

      • sudo -H pip3 install --upgrade pip
      • sudo -H pip3 install virtualenv

      El indicador -H garantiza que la política de seguridad defina la variable de entorno home como el directorio de inicio del usuario de destino.

      Con virtualenv ya instalado, podemos comenzar a crear nuestro entorno. Cree un directorio en el que podamos guardar los archivos de nuestro proyecto y posiciónese en él: Daremos a este directorio el nombre my_project_dir, pero deberá usar un nombre que sea significativo para usted y para el trabajo que está desarrolle.

      • mkdir ~/my_project_dir
      • cd ~/my_project_dir

      En el directorio del proyecto, crearemos un entorno virtual de Python. A los efectos de este tutorial, le daremos el nombre my_project_env, pero debería asignarle uno que se relacione con su proyecto.

      • virtualenv my_project_env

      Con esto, se creará un directorio llamado my_project_env dentro de su directorio my_project_dir. Dentro de este, se instalarán una versión local de Python y una versión local de pip. Podemos usar esto para instalar y configurar un entorno aislado de Python para Jupyter.

      Antes de instalar Jupyter, debemos activar el entorno virtual. Puede hacerlo escribiendo lo siguiente:

      • source my_project_env/bin/activate

      Su línea de comandos cambiará para indicar que ahora realizará operaciones en un entorno virtual de Python. Su línea de comandos ahora leerá algo como esto: (my_project_env)user@host:~/my_project_dir$.

      En este momento, está listo para instalar Jupyter en este entorno virtual.

      Paso 3: Instalar Jupyter

      Una vez activado su entorno virtual, instale Jupyter con la instancia local de pip.

      Nota: Cuando se active el entorno virtual (cuando (my_project_env) se encuentre al inicio de su línea de comandos), use pip en lugar de pip3, incluso si emplea Python 3. La copia del entorno virtual de la herramienta siempre se llama pip, independientemente de la versión de Python.

      En este punto, habrá instalado con éxito todo el software necesario para ejecutar Jupyter. Ahora podremos iniciar el servidor de Notebook.

      Paso 4: Ejecutar Jupyter Notebook

      Ya dispone de todo lo que necesita para ejecutar Jupyter Notebook. Para ejecutarlo, introduzca el siguiente comando:

      Se mostrará un registro de las actividades de Jupyter Notebook en el terminal. Cuando se ejecuta Jupyter Notebook, este funciona en un número de puerto específico. Normalmente, el primer notebook que ejecute usará el puerto 8888. Para verificar el número de puerto específico en el que se ejecuta Jupyter Notebook, consulte el resultado del comando utilizado para iniciarlo:

      Output

      [I 21:23:21.198 NotebookApp] Writing notebook server cookie secret to /run/user/1001/jupyter/notebook_cookie_secret [I 21:23:21.361 NotebookApp] Serving notebooks from local directory: /home/sammy/my_project_dir [I 21:23:21.361 NotebookApp] The Jupyter Notebook is running at: [I 21:23:21.361 NotebookApp] http://localhost:8888/?token=1fefa6ab49a498a3f37c959404f7baf16b9a2eda3eaa6d72 [I 21:23:21.361 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation). [W 21:23:21.361 NotebookApp] No web browser found: could not locate runnable browser. [C 21:23:21.361 NotebookApp] Copy/paste this URL into your browser when you connect for the first time, to login with a token: http://localhost:8888/?token=1fefa6ab49a498a3f37c959404f7baf16b9a2eda3eaa6d72

      Si ejecuta Jupyter Notebook en una computadora local (no en un servidor), puede dirigirse a la URL que se muestra para conectarse a Jupyter Notebook. Si ejecuta Jupyter Notebook en un servidor, deberá establecer conexión con este usando túneles SSH como se indica en la siguiente sección.

      En este punto, podrá mantener la conexión SSH abierta y Jupyter Notebook en ejecución, o bien cerrar la aplicación y volver a ejecutarla una vez que configure los túneles SSH. Optaremos por detener el proceso de Jupyter Notebook. Lo ejecutaremos de nuevo una vez que configuremos los túneles SSH. Para detener el proceso de Jupyter Notebook, presione CTRL+C, escriba Y y luego presione ENTER para confirmar. Se mostrará el siguiente resultado:

      Output

      [C 21:28:28.512 NotebookApp] Shutdown confirmed [I 21:28:28.512 NotebookApp] Shutting down 0 kernels

      A continuación, configuraremos un túnel SSH para poder acceder al Notebook.

      Paso 5: Establecer conexión con el servidor usando túneles SSH

      En esta sección, mostraremos cómo establecer una conexión con la interfaz web de Jupyter Notebook usando túneles SSH. Debido a que Jupyter Notebook se ejecutará en un puerto específico en el servidor (como el :8888 y el :8889, entre otros), los túneles SSH le permiten establecer conexión con el puerto del servidor de forma segura.

      En los dos apartados siguientes, se describe la forma de crear un túnel SSH desde 1) un Mac o Linux y 2) Windows. Consulte el apartado que corresponda a su computadora local.

      Túeneles SSH con una Mac o Linux

      Si está usando un equipo local Mac o Linux, los pasos para crear el túnel SSH son similares a usar SSH para iniciar sesión en su servidor remoto, excepto que hay parámetros adicionales en el comando ssh. En este apartado, se describirán los parámetros adicionales necesarios en el comando ssh para implementar un túnel con éxito.

      Esta implementación es posible ejecutando el siguiente comando SSH en una nueva ventana del terminal local:

      • ssh -L 8888:localhost:8888 your_server_username@your_server_ip

      El comando ssh abre una conexión SSH, pero -L especifica que se debe reenviar el puerto determinado en el host local (cliente) al host y puerto determinados en el lado remoto (servidor). Esto significa que todo lo que está en ejecución en el segundo número de puerto (por ejemplo 8888) en el servidor aparecerá en el primer número de puerto (por ejemplo 8888) en su computadora local.

      Cambie de forma opcional el puerto 8888 por uno que elija para evitar usar un puerto ya utilizado por otro proceso.

      server_username es su nombre de usuario (por ejemplo sammy) en el servidor que creó y your_server_ip es la dirección IP de su servidor.

      Por ejemplo, para el nombre de usuario sammy y la dirección del servidor 203.0.113.0, el comando sería el siguiente:

      • ssh -L 8888:localhost:8888 sammy@203.0.113.0

      Si no se produce ningún error después de ejecutar el comando ssh -L, podrá desplazarse a su entorno de programación y ejecutar Jupyter Notebook:

      Verá un resultado con una URL. Desde un navegador web en su máquina local, abra la interfaz web de Jupyter Notebook con la URL que comienza con http://localhost:8888. Asegúrese de que el número de token esté incluido o ingrese la cadena de número de token cuando se solicite en http://localhost:8888.

      Túneles SSH con Windows y Putty

      Si usa Windows, puede crear un túnel SSH usando Putty.

      Primero, ingrese la dirección URL o IP del servidor como el nombre de host, como se muestra:

      Establecer el nombre de host para el túnel SSH

      A continuación, haga clic en SSH en la parte inferior del panel izquierdo, para expandir el menú, y luego en Tunnels. Introduzca el número del puerto local que quiera usar para acceder a Jupyter en su máquina local. Seleccione 8000, o un número mayor, para evitar los puertos utilizados por otros servicios y fije el destino en localhost:8888, donde :8888 sea el número del puerto en el que se ejecute Jupyter Notebook.

      Luego, haga clic en el botón Add. Deberían aparecer los puertos en la lista de Forwarded ports:

      Lista de Forwarded ports

      Por último, haga clic en el botón Open para establecer conexión con el servidor a través de SSH y crear un túnel entre los puertos deseados. Diríjase a http://localhost:8000 (o cualquier puerto que haya elegido) en un navegador web para conectarse al Jupyter Notebook que funciona en el servidor. Asegúrese de que el número de token esté incluido, o ingrese la cadena de número de token cuando se solicite en http://localhost:8000.

      Paso 6: Usar Jupyter Notebook

      Esta sección repasa el uso básico de Jupyter Notebook. Si Jupyter Notebook aún no está en ejecución, inícielo con el comando jupyter notebook.

      Con esto, debería establecer conexión con este usando un navegador web. Jupyter Notebook es una herramienta muy poderosa que dispone de muchas características. En esta sección se mostrarán algunas de las características básicas para que comience a usar Notebook. Jupyter Notebook mostrará todos los archivos y las carpetas en el directorio desde el que se ejecuta. Por ello, cuando trabaje en un proyecto asegúrese de iniciarlo desde el directorio del proyecto.

      Para crear un nuevo archivo de Notebook, seleccione New > Python 3 en el menú desplegable que se encuentra en la parte superior derecha:

      Crear un nuevo notebook de Python 3

      Con esto se abrirá un Notebook. Ahora podemos ejecutar el código de Python en la celda o cambiar la celda a lenguaje de marcado. Por ejemplo, cambie la primera celda para aceptar el lenguaje de marcado haciendo clic en Cell > Cell Type > Markdown en la barra de navegación de la parte superior. Con esto, podremos escribir notas usando el lenguaje de marcado e incluso incluir ecuaciones escritas en LaTeX disponiéndolas entre los símbolos de $$. Por ejemplo, escriba lo siguiente en la celda después del cambio a lenguaje de marcado:

      # First Equation
      
      Let us now implement the following equation:
      $$ y = x^2$$
      
      where $x = 2$
      

      Para convertir el marcado en texto con formato, pulse las teclas CTRL y ENTER. Debería obtener un resultado similar al siguiente:

      Resultados de lenguaje de marcado

      Puede utilizar las celdas de lenguaje de marcado para crear notas y documentar su código. Implementaremos esa ecuación e imprimiremos el resultado. Haga clic en la celda superior, luego pulse las teclas ALT y ENTER juntas para añadir una celda debajo. Introduzca el siguiente código en la nueva celda.

      x = 2
      y = x**2
      print(y)
      

      Para ejecutar el código, presione CTRL+ENTER. Obtendrá los siguientes resultados:

      Resultado de la primera ecuación

      Ahora podrá importar módulos y usar el Notebook como lo haría con cualquier otro entorno de desarrollo de Python.

      Conclusión

      ¡Felicitaciones! Ahora debería poder escribir código y notas de Python que puedan reproducirse en lenguaje de marcado usando Jupyter Notebook. Si desea acceder a una visita rápida de Jupyter Notebook desde la interfaz, seleccione Help > User Interface Tour en el menú de navegación superior para obtener más información.

      A partir de aquí, puede iniciar un proyecto de análisis y visualización de datos leyendo Análisis y visualización de datos con pandas y Jupyter Notebook en Python 3.



      Source link

      Comprender desestructurar, los parámetros Rest y propagar sintaxis en JavaSript


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

      Introducción

      Desde la Edición 2015 de la especificación ECMAScript, hay disponibles muchas nuevas funciones para el lenguaje JavaScript para trabajar con conjuntos y objetos. Algunas de las más notables que aprenderá en este artículo son desestructurar, parámetros rest y propagar sintaxis. Estas funciones ofrecen formas más directas de acceder a los miembros de una matriz o un objeto, y pueden hacer que trabajar con estas estructuras de datos sea más rápido y conciso.

      Muchos otros lenguajes no tienen la sintaxis correspondiente para desestructurar, los parámetros rest y propagar, de forma que estas funciones pueden tener una curva de aprendizaje para los nuevos desarrolladores de JavaScript y para aquellos que provienen de otro lenguaje. En este artículo, aprenderá cómo desestructurar objetos y conjuntos, cómo usar el operador de propagación para descomprimir objetos y conjuntos y cómo usar los parámetros rest en las invocaciones de funciones.

      Desestructurar

      La asignación de desestructurar es una sintaxis que le permite asignar propiedades de objetos o elementos de una matriz como variables. Esto puede reducir enormemente las líneas de código necesarias para manipular datos en estas estructuras. Existen dos tipos de desestructuración: desestructurar objetos y desestructurar conjuntos.

      Desestructurar objetos

      La desestructuración de objetos permite crear nuevas variables usando una propiedad de objeto como el valor.

      Considere este ejemplo, un objeto que representa una nota con id, title y date:

      const note = {
        id: 1,
        title: 'My first note',
        date: '01/01/1970',
      }
      

      Tradicionalmente, si quería crear una nueva variable para cada propiedad, tendría que asignar cada variable individualmente, con muchas repeticiones:

      // Create variables from the Object properties
      const id = note.id
      const title = note.title
      const date = note.date
      

      Con la desestructuración de objetos, esto puede hacerse en una línea. Al rodear cada variable entre corchetes {}, JavaScript creará nuevas variables desde cada propiedad con el mismo nombre:

      // Destructure properties into variables
      const { id, title, date } = note
      

      Ahora console.log() las nuevas variables:

      console.log(id)
      console.log(title)
      console.log(date)
      

      Obtendrá los valores originales de la propiedad como resultado:

      Output

      1 My first note 01/01/1970

      Nota: Desestructurar un objeto no modifica el objeto original. Aún podría invocar note original con todas sus entradas intactas.

      La asignación predeterminada para la desestructuración de objetos crea nuevas variables con el mismo nombre que la propiedad del objeto. Si no desea que la nueva variable tenga el mismo nombre que el nombre de la propiedad, tendrá la opción de cambiar el nombre de la nueva variable usando dos puntos (:) para decidir un nuevo nombre, como se puede ver con noteId a continuación:

      // Assign a custom name to a destructured value
      const { id: noteId, title, date } = note
      

      Registre la nueva variable noteId para la consola:

      console.log(noteId)
      

      Recibirá el siguiente resultado:

      Output

      1

      También puede desestructurar valores de objetos anidados. Por ejemplo, actualice el objeto note para tener un objeto author anidado:

      const note = {
        id: 1,
        title: 'My first note',
        date: '01/01/1970',
        author: {
          firstName: 'Sherlock',
          lastName: 'Holmes',
        },
      }
      

      Ahora puede desestructurar note, luego desestructurarla de nuevo para crear variables desde las propiedades author:

      // Destructure nested properties
      const {
        id,
        title,
        date,
        author: { firstName, lastName },
      } = note
      

      A continuación, registre las nuevas variables firstName y lastName usando los literales de plantilla:

      console.log(`${firstName} ${lastName}`)
      

      Esto generará el siguiente resultado:

      Output

      Sherlock Holmes

      Observe que en este ejemplo, aunque tiene acceso a los contenidos del objeto author, el objeto author en sí mismo no es accesible. Para acceder a un objeto y a sus valores anidados, tendría que declararlos por separado:

      // Access object and nested values
      const {
        author,
        author: { firstName, lastName },
      } = note
      
      console.log(author)
      

      Este código dará como resultado el objeto author:

      Output

      {firstName: "Sherlock", lastName: "Holmes"}

      Desestructurar un objeto no es solo útil para reducir la cantidad de código que tiene que escribir; también le permite orientar el acceso a las propiedades que necesita.

      Finalmente, la desestructuración puede usarse para acceder a las propiedades de los valores primitivos del objeto. Por ejemplo, String es un objeto global para cadenas, y tiene una propiedad length:

      const { length } = 'A string'
      

      Esto encontrará la propiedad de longitud inherente de una cadena y la establecerá igual a la variable length. Registre length para ver si funciona:

      console.log(length)
      

      Verá el siguiente resultado:

      Output

      8

      La cadena A string se convirtió específicamente en un objeto para recuperar la propiedad length.

      Desestructuración de conjuntos

      La desestructuración de conjuntos le permite crear nuevas variables usando un elemento de una matriz como valor. Considere este ejemplo, una matriz con las diferentes partes de una fecha:

      const date = ['1970', '12', '01']
      

      Se garantiza que los conjuntos en JavaScript conserven su orden, de forma que en este caso, el primer índice siempre será un año, el segundo será el mes y así sucesivamente. Sabiendo esto, puede crear variables a partir de los elementos de la matriz:

      // Create variables from the Array items
      const year = date[0]
      const month = date[1]
      const day = date[2]
      

      Pero hacer esto manualmente puede ocupar mucho espacio en su código. Con la desestructuración de matrices, puede descomprimir los valores de la matriz para ordenarlos y asignarlos a sus propias variables, de esta forma:

      // Destructure Array values into variables
      const [year, month, day] = date
      

      Ahora registre las nuevas variables:

      console.log(year)
      console.log(month)
      console.log(day)
      

      Verá el siguiente resultado:

      Output

      1970 12 01

      Los valores pueden omitirse dejando la sintaxis de desestructuración en blanco entre comas:

      // Skip the second item in the array
      const [year, , day] = date
      
      console.log(year)
      console.log(day)
      

      Al ejecutar esto obtendremos el valor de year y day:

      Output

      1970 01

      Los conjuntos anidados pueden ser desestructurados también. Primero cree una matriz anidada:

      // Create a nested array
      const nestedArray = [1, 2, [3, 4], 5]
      

      Luego, desestructure esa matriz y registre las nuevas variables:

      // Destructure nested items
      const [one, two, [three, four], five] = nestedArray
      
      console.log(one, two, three, four, five)
      

      Recibirá el siguiente resultado:

      Output

      1 2 3 4 5

      La sintaxis de desestructuración puede aplicarse para desestructurar los parámetros en una función. Para probar esto, desestructurará keys y values de Object.entries().

      Primero, declare el objeto note:

      const note = {
        id: 1,
        title: 'My first note',
        date: '01/01/1970',
      }
      

      Dado este objeto, podría listar los pares clave-valor desestructurando argumentos a medida que se pasan al método forEach():

      // Using forEach
      Object.entries(note).forEach(([key, value]) => {
        console.log(`${key}: ${value}`)
      })
      

      O podría conseguir lo mismo usando un bucle for:

      // Using a for loop
      for (let [key, value] of Object.entries(note)) {
        console.log(`${key}: ${value}`)
      }
      

      De cualquier forma, recibirá lo siguiente:

      Output

      id: 1 title: My first note date: 01/01/1970

      La desestructuración de objetos y la desestructuración de conjuntos pueden combinarse en una única asignación de desestructuración. También pueden usarse parámetros predeterminados con la desestructuración, como se ve en este ejemplo que establece la fecha predeterminada a new Date().

      Primero, declare el objeto note:

      const note = {
        title: 'My first note',
        author: {
          firstName: 'Sherlock',
          lastName: 'Holmes',
        },
        tags: ['personal', 'writing', 'investigations'],
      }
      

      Luego desestructure el objeto, a la vez que establece una nueva variable date con el predeterminado de new Date():

      const {
        title,
        date = new Date(),
        author: { firstName },
        tags: [personalTag, writingTag],
      } = note
      
      console.log(date)
      

      console.log(date) proporcionará un resultado similar al siguiente:

      Output

      Fri May 08 2020 23:53:49 GMT-0500 (Central Daylight Time)

      Como se muestra en esta sección, la sintaxis de asignación de desestructuración añade mucha flexibilidad a JavaScript y le permite escribir un código más conciso. En la siguiente sección, verá cómo propagar sintaxis puede usarse para expandir las estructuras de datos en sus entradas de datos constituyentes.

      Propagación

      Propagar sintaxis (...) es otra adición útil a JavaScript para trabajar con conjuntos, objetos e invocaciones de función. La propagación permite descomprimir o expandir objetos e iterables (como los conjuntos), lo que puede ser usado para realizar copias superficiales de estructura de datos para aumentar la facilidad de la manipulación de datos.

      Propagación con conjuntos

      La propagación puede simplificar las tareas comunes con los conjuntos. Por ejemplo, digamos que tiene dos conjuntos y quiere combinarlos:

      // Create an Array
      const tools = ['hammer', 'screwdriver']
      const otherTools = ['wrench', 'saw']
      

      Originalmente, usaría concat() para concatenar los dos conjuntos:

      // Concatenate tools and otherTools together
      const allTools = tools.concat(otherTools)
      

      Ahora también puede propagar para descomprimir las matrices en un nueva matriz:

      // Unpack the tools Array into the allTools Array
      const allTools = [...tools, ...otherTools]
      
      console.log(allTools)
      

      Al ejecutar esto obtendrá lo siguiente:

      Output

      ["hammer", "screwdriver", "wrench", "saw"]

      Esto puede ser particularmente útil con la inmutabilidad. Por ejemplo, es posible que esté trabajando con una aplicación que tiene users guardados en una matriz de objetos:

      // Array of users
      const users = [
        { id: 1, name: 'Ben' },
        { id: 2, name: 'Leslie' },
      ]
      

      Podría usar push para modificar la matriz existente y añadir un nuevo usuario, que será una opción mutable:

      // A new user to be added
      const newUser = { id: 3, name: 'Ron' }
      
      users.push(newUser)
      

      Pero esto cambia la matriz user, que quizá queramos conservar.

      La propagación le permite crear una nueva matriz partir de una existente y añadir un nuevo elemento al final:

      const updatedUsers = [...users, newUser]
      
      console.log(users)
      console.log(updatedUsers)
      

      Ahora, la nueva matriz updatedUsers tiene el nuevo usuario, pero la matriz original users permanece sin cambios:

      Output

      [{id: 1, name: "Ben"} {id: 2, name: "Leslie"}] [{id: 1, name: "Ben"} {id: 2, name: "Leslie"} {id: 3, name: "Ron"}]

      Crear copias de datos en vez de cambiar los datos existentes puede ayudar a prevenir cambios inesperados. En JavaScript, cuando crea un objeto o matriz y lo asigna a otra variable, no está creando realmente un nuevo objeto, está pasando una referencia.

      Tome este ejemplo, en el cual se crea una matriz y se asigna a otra variable:

      // Create an Array
      const originalArray = ['one', 'two', 'three']
      
      // Assign Array to another variable
      const secondArray = originalArray
      

      Eliminar el último elemento de la segunda matriz modificará el primero:

      // Remove the last item of the second Array
      secondArray.pop()
      
      console.log(originalArray)
      

      Esto generará el siguiente resultado:

      Output

      ["one", "two"]

      La propagación le permite realizar una copia superficial de una matriz u objeto, lo que significa que cualquier propiedad de nivel superior se clonará, pero los objetos anidados se pasarán por referencia. Para conjuntos u objetos simples, una copia superficial puede ser todo lo que necesita.

      Si escribe el mismo código de ejemplo pero copia la matriz con propagación, la matriz original no se modificará:

      // Create an Array
      const originalArray = ['one', 'two', 'three']
      
      // Use spread to make a shallow copy
      const secondArray = [...originalArray]
      
      // Remove the last item of the second Array
      secondArray.pop()
      
      console.log(originalArray)
      

      Lo siguiente se registrará en la consola:

      Output

      ["one", "two", "three"]

      La propagación también puede usarse para convertir un conjunto, o cualquier otro iterable, a una matriz.

      Crear un nuevo conjunto y añadir algunas entradas:

      // Create a set
      const set = new Set()
      
      set.add('octopus')
      set.add('starfish')
      set.add('whale')
      

      A continuación, utilice el operador de propagación con set y registre los resultados:

      // Convert Set to Array
      const seaCreatures = [...set]
      
      console.log(seaCreatures)
      

      Esto dará el siguiente resultado:

      Output

      ["octopus", "starfish", "whale"]

      Esto puede ser útil para crear un conjunto desde una cadena:

      const string = 'hello'
      
      const stringArray = [...string]
      
      console.log(stringArray)
      

      Esto proporcionará una matriz con cada carácter como un elemento en la matriz:

      Output

      ["h", "e", "l", "l", "o"]

      Propagación con objetos

      Cuando se trabaja con objetos, la propagación puede usarse para copiar y actualizar objetos.

      Originalmente, Object.assign() se usó para copiar un objeto:

      // Create an Object and a copied Object with Object.assign()
      const originalObject = { enabled: true, darkMode: false }
      const secondObject = Object.assign({}, originalObject)
      

      El secondObject ahora será un clon del originalObject.

      Esto se simplifica con la sintaxis de propagación; puede copiar superficialmente un objeto propagándolo a uno nuevo:

      // Create an object and a copied object with spread
      const originalObject = { enabled: true, darkMode: false }
      const secondObject = { ...originalObject }
      
      console.log(secondObject)
      

      Esto dará como resultado lo siguiente:

      Output

      {enabled: true, darkMode: false}

      Igual que con las matrices, esto solo creará una copia superficial y los objetos anidados seguirán pasándose por referencia.

      Añadir o modificar propiedades sobre un objeto existente de forma inmutable se simplifica con la propagación. En este ejemplo, la propiedad isLoggedIn se añade al objeto user:

      const user = {
        id: 3,
        name: 'Ron',
      }
      
      const updatedUser = { ...user, isLoggedIn: true }
      
      console.log(updatedUser)
      

      Esto dará el siguiente resultado:

      Output

      {id: 3, name: "Ron", isLoggedIn: true}

      Algo importante a tener en cuenta a la hora de actualizar objetos mediante la propagación es que cualquier objeto anidado también se propagará. Por ejemplo, digamos que en el objeto user hay un objeto anidado organization:

      const user = {
        id: 3,
        name: 'Ron',
        organization: {
          name: 'Parks & Recreation',
          city: 'Pawnee',
        },
      }
      

      Si intentase añadir un nuevo elemento a organization, sobrescribiría los campos existentes:

      const updatedUser = { ...user, organization: { position: 'Director' } }
      
      console.log(updatedUser)
      

      Esto resultará en lo siguiente:

      Output

      id: 3 name: "Ron" organization: {position: "Director"}

      Si la mutabilidad no es un problema, el campo podría actualizarse directamente:

      user.organization.position = 'Director'
      

      Pero ya que estamos buscando una solución inmutable, podemos propagar el objeto interno para que conserve las propiedades existentes:

      const updatedUser = {
        ...user,
        organization: {
          ...user.organization,
          position: 'Director',
        },
      }
      
      console.log(updatedUser)
      

      Esto dará el siguiente resultado:

      Output

      id: 3 name: "Ron" organization: {name: "Parks & Recreation", city: "Pawnee", position: "Director"}

      Propagación con invocaciones de función

      La propagación también puede usarse con argumentos en las invocaciones de funciones.

      Como ejemplo, aquí hay una función multiply que toma tres parámetros y los multiplica:

      // Create a function to multiply three items
      function multiply(a, b, c) {
        return a * b * c
      }
      

      Normalmente, pasaría tres valores individualmente como argumentos a la invocación de función, de esta forma:

      multiply(1, 2, 3)
      

      El resultado sería el siguiente:

      Output

      6

      Sin embargo, si todos los valores que desea pasar a la función ya existen en una matriz, la propagación de sintaxis le permite usar cada elemento en una matriz como argumento:

      const numbers = [1, 2, 3]
      
      multiply(...numbers)
      

      Esto dará el mismo resultado:

      Output

      6

      Nota: Sin propagación, esto puede conseguirse usando apply():

      multiply.apply(null, [1, 2, 3])
      

      Esto proporcionará lo siguiente:

      Output

      6

      Ahora que ha visto cómo la propagación puede acortar su código, puede echar un vistazo a un uso diferente de la sintaxis ...: parámetros rest.

      Parámetros rest

      La última función que aprenderá en este artículo es la sintaxis parámetro rest. La sintaxis parece igual a medida que se propaga (...), pero tiene el efecto contrario. En vez de descomprimir una matriz u objeto en valores individuales, la sintaxis rest creará una matriz de un número indefinido de argumentos.

      En la función restTest, por ejemplo, si queremos que args sea una matriz compuesta de un número indefinido de argumentos, podrías tener lo siguiente:

      function restTest(...args) {
        console.log(args)
      }
      
      restTest(1, 2, 3, 4, 5, 6)
      

      Todos los argumentos pasados a la función restTest están ahora disponibles en la matriz args:

      Output

      [1, 2, 3, 4, 5, 6]

      La sintaxis rest puede usarse como el único parámetro o como el último parámetro en la lista. Si se utiliza como el único parámetro, recopilará todos los argumentos, pero si está al final de una lista, recopilará todos los argumentos que quedan, como se ve en este ejemplo:

      function restTest(one, two, ...args) {
        console.log(one)
        console.log(two)
        console.log(args)
      }
      
      restTest(1, 2, 3, 4, 5, 6)
      

      Esto tomará los dos primeros argumentos individualmente, y luego agrupará el resto en una matriz:

      Output

      1 2 [3, 4, 5, 6]

      El código anterior, la variable arguments podría usarse para recopilar todos los argumentos pasados a través de una función:

      function testArguments() {
        console.log(arguments)
      }
      
      testArguments('how', 'many', 'arguments')
      

      Esto nos dará el siguiente resultado:

      Output

      1Arguments(3) ["how", "many", "arguments"]

      Sin embargo, esto tiene algunas desventajas. Primero, la variable arguments no puede usarse con las funciones de flecha.

      const testArguments = () => {
        console.log(arguments)
      }
      
      testArguments('how', 'many', 'arguments')
      

      Esto resultaría en un error:

      Output

      Uncaught ReferenceError: arguments is not defined

      Adicionalmente, arguments no es una matriz verdadera y no puede usar métodos como map y filter sin convertirse primero a una matriz. También recogerá todos los argumentos pasados de solo el resto de los argumentos, como se ve en el ejemplo restTest(one, two, ...args).

      Rest puede usarse cuando se desestructuran las matrices también:

      const [firstTool, ...rest] = ['hammer', 'screwdriver', 'wrench']
      
      console.log(firstTool)
      console.log(rest)
      

      Esto proporcionará lo siguiente:

      Output

      hammer ["screwdriver", "wrench"]

      Rest también puede usarse cuando se desestructuran objetos:

      const { isLoggedIn, ...rest } = { id: 1, name: 'Ben', isLoggedIn: true }
      
      console.log(isLoggedIn)
      console.log(rest)
      

      Proporcionar el siguiente resultado:

      Output

      true {id: 1, name: "Ben"}

      De esta forma, la sintaxis rest proporciona métodos eficientes para recopilar una cantidad indeterminada de elementos.

      Conclusión

      En este artículo, ha aprendido cómo desestructurar, propagar sintaxis y sobre los parámetros rest. En resumen:

      • Desestructurar se usa para crear variables a partir de los elementos de una matriz o de propiedades de objetos.
      • Propagar sintaxis se usa para descomprimir iterables como matrices, objetos e invocaciones de función.
      • La sintaxis del parámetro rest creará una matriz a partir de un número indefinido de valores.

      Desestructurar, parámetros rest y propagar sintaxis son funciones útiles en JavaScript que ayudan a mantener su código conciso y limpio.

      Si desea ver la desestructuración en acción, eche un vistazo a Cómo personalizar componentes React con Props, que utiliza esta sintaxis para desestructurar datos y pasarlos a componentes front-end personalizados. Si desea aprender más sobre JavaScript, vuelva a nuestra página de la serie Cómo codificar en JavaScript.



      Source link

      Cómo monitorear los anuncios y las rutas de BGP utilizando BGPalerter en Ubuntu 18.04


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

      Introducción

      BGP (Protocolo de puerta de enlace de borde) es uno de los protocolos principales responsable de redirigir paquetes a través de Internet; por lo tanto, si presenta errores, se pueden producir interrupciones importantes. Por ejemplo, en 2019, un pequeño proveedor de servicios de Internet hizo una mala configuración de BGP que, lamentablemente, se propagó de manera ascendente y dejó importantes partes de Cloudflare y AWS sin conexión durante más de una hora.  Además, hace un año, se realizó un ataque a BGP para interceptar el tráfico a un proveedor de monederos de criptomonedas y robar los fondos de clientes desprevenidos.

      BGPalerter es una herramienta de monitoreo de la red de BGP de código abierto que puede proporcionar alertas en tiempo real sobre la actividad de BGP, incluso la visibilidad de rutas y los anuncios de nuevas rutas, así como actividades potencialmente nefastas, como intercepciones o fugas en las rutas. BGPalerter ingiere automáticamente la información de redireccionamiento de la red disponible públicamente, lo que significa que no necesita tener ningún nivel de acceso con privilegios ni integración en las redes que quiere controlar.

      Nota: BGPalerter ingiere automáticamente la información de redireccionamiento de la red disponible públicamente, lo que significa que no necesita tener ningún nivel de acceso con privilegios ni integración en las redes que quiere controlar. Todo el monitoreo cumple plenamente con la Ley de Uso Indebido de Computadoras (Computer Misuse Act), la Ley de Fraude y Abuso de Computadoras (Computer Fraud and Abuse Act), y otras leyes similares.  Sin embargo, se recomienda revelar de forma responsable cualquier hallazgo relevante al operador de la red afectado.

      En este tutorial, instalará y configurará BGPalerter para monitorear sus redes importantes, a fin de detectar actividades potencialmente sospechosas.

      Requisitos previos

      Para completar este tutorial, necesitará lo siguiente:

      Para cada dispositivo o red, necesitará identificar la dirección IP individual, el intervalo de la dirección IP o el número de sistema autónomo del que es parte. Esto se abarca en el paso 1.

      Una vez que tenga todo esto listo, inicie sesión en su servidor como non-root user.

      Paso 1: Identificar las redes que se quieren monitorear

      En este paso, identificará los detalles pertinentes de las redes que quiere monitorear.

      BGPalerter puede monitorear sobre la base de direcciones IP individuales o prefijos de red. También puede monitorear redes enteras sobre la base de su número de sistema autónomo (AS), que es un identificador global único de una red propiedad de una entidad administrativa en particular.

      Para encontrar esta información, puede utilizar el servicio de búsqueda IP-to-ASN de WHOIS, proporcionado por el servicio de inteligencia de amenazas Team Cymru. Se trata de un servidor de WHOIS personalizado diseñado para buscar información de dirección IP y enrutamiento de red.

      Si no tiene whois instalado, puede instalarlo usando el siguiente comando:

      • sudo apt update
      • sudo apt install whois

      Una vez que haya confirmado que whois está instalado, comience por realizar una búsqueda de la dirección IP de su propio servidor, utilizando el argumento -h para especificar un servidor personalizado:

      • whois -h whois.cymru.com your-ip-address

      Esto generará un resultado similar al siguiente, que muestra el nombre y el número de AS del que su servidor es parte. Normalmente, será el AS de su proveedor de alojamiento del servidor, por ejemplo, DigitalOcean.

      Output

      AS | IP | AS Name 14061 | your-ip-address | DIGITALOCEAN-ASN, US

      A continuación, puede realizar una búsqueda para identificar el prefijo de la red o el intervalo del que su servidor es parte. Para hacerlo, agregue el argumento -p a su solicitud:

      • whois -h whois.cymru.com " -p your-ip-address"

      El resultado será muy similar al comando anterior, pero, ahora, mostrará el prefijo de dirección IP al que pertenece la dirección IP de su servidor:

      Output

      AS | IP | BGP Prefix | AS Name 14061 | your-ip-address | 157.230.80.0/20 | DIGITALOCEAN-ASN, US

      Por último, puede buscar más detalles del AS del que forma parte su servidor, incluyendo la región geográfica y la fecha de asignación.

      Sustituya el número de AS que identificó usando los comandos anteriores. Utiliza el argumento -v para habilitar el resultado detallado, lo que garantiza que se muestren todos los detalles relevantes:

      • whois -h whois.cymru.com " -v as14061"

      El resultado mostrará más información sobre el AS:

      Output

      AS | CC | Registry | Allocated | AS Name 14061 | US | arin | 2012-09-25 | DIGITALOCEAN-ASN, US

      identificó detalles clave sobre las redes que quiere monitorear. Tome nota de estos detalles en algún lugar, ya que los necesitará más adelante. A continuación, comenzará a configurar BGPalerter.

      Paso 2: Crear un usuario sin privilegios para BGPalerter

      En este paso, creará una nueva cuenta de usuario sin privilegios para BGPalerter, dado que el programa no necesita ejecutarse con privilegios sudo/root.

      Primero, cree un usuario nuevo con contraseña deshabilitada:

      • sudo adduser --disabled-password bgpalerter

      No necesita configurar una contraseña o una clave de SSH, dado que solo utilizará este usuario como una cuenta de servicio para ejecutar/mantener BGPalerter.

      Inicie sesión con el usuario nuevo utilizando su:

      Ahora, está conectado con su usuario nuevo:

      bgpalerter@droplet:/home/user$
      

      Utilice el comando cd para dirigirse al directorio de inicio de su usuario nuevo:

      bgpalerter@droplet:/home/user$ cd
      bgpalerter@droplet:~$
      

      Creó un usuario sin privilegios nuevo para BGPalerter. A continuación, instalará y configurará BGPalerter en su sistema.

      Paso 3: Instalar y configurar BGPalerter

      En este paso, instalará y configurará BGPalerter. Asegúrese de seguir conectado con su usuario sin privilegios nuevo.

      Primero, debe identificar la última versión de BGPalerter, a fin de asegurarse de descargar la más reciente. Diríjase a la página de Lanzamientos de BGPalerter y copie el enlace de descarga de la versión de Linux x64 más reciente.

      Ahora, puede descargar una copia de BGPalerter usando wget, asegurándose de sustituir el enlace de descarga correcto:

      • wget https://github.com/nttgin/BGPalerter/releases/download/v1.24.0/bgpalerter-linux-x64

      Una vez que el archivo haya terminado de descargarse, márquelo como ejecutable:

      • chmod +x bgpalerter-linux-x64

      A continuación, compruebe que BGPalerter se haya descargado e instalado correctamente comprobando el número de la versión:

      • ./bgpalerter-linux-x64 --version

      Esto dará como resultado el número de la versión actual:

      Output

      1.24.0

      Para poder ejecutar BGPalerter adecuadamente, deberá definir las redes que desea monitorear en un archivo de configuración. Cree y abra el archivo prefixes.yml en su editor de texto favorito:

      En este archivo de configuración, especificará cada una de las direcciones IP individuales, los intervalos de dirección IP y los números de AS que quiere monitorear.

      Añada el siguiente ejemplo y ajuste los valores de configuración según sea necesario usando la información de la red que identificó en el paso 1:

      ~/prefixes.yml

      your-ip-address/32:
        description: My Server
        asn:
          - 14061
        ignoreMorespecifics: false
      
      157.230.80.0/20:
        description: IP range for my Server
        asn:
          - 14061
        ignoreMorespecifics: false
      
      options:
        monitorASns:
          '14061':
            group: default
      

      Puede monitorear todos los intervalos de dirección IP o números de AS que quiera. Para monitorear direcciones IP individuales, represéntelas utilizando /32 para IPv4 y /128 para IPv6.

      El valor ignoreMorespecifics se utiliza para determinar si BGPalerter debe ignorar la actividad de las rutas más específicas (pequeñas) que la que está monitoreando. Por ejemplo, si está monitoreando /20 y se detecta un cambio de enrutamiento para /24 en su interior, se considera que es más específica. En la mayoría de los casos, no es recomendable ignorarlas si está monitoreando una red grande con varios prefijos de cliente delegados, sin embargo, puede ayudar a reducir interferencias de fondo.

      Ahora, puede ejecutar BGPalerter por primera vez para comenzar a monitorear sus redes:

      Si BGPalerter se inicia correctamente, verá un resultado similar al siguiente. Tenga en cuenta que, a veces, el monitoreo puede tardar unos minutos en iniciarse:

      Output

      Impossible to load config.yml. A default configuration file has been generated. BGPalerter, version: 1.24.0 environment: production Loaded config: /home/bgpalerter/config.yml Monitoring 157.230.80.0/20 Monitoring your-ip-address/32 Monitoring AS 14061

      BGPalerter se seguirá ejecutando hasta que lo detenga usando Ctrl+C.

      En el siguiente paso, interpretará algunas de las alertas que BGPalerter puede generar.

      Paso 4: Interpretar alertas de BGPalerter

      En este paso, revisará algunas alertas de BGPalerter de ejemplo. BGPalerter emitirá alertas en la fuente de salida principal, y también, de forma opcional, en cualquier otro extremo de información que pueda configurarse dentro de config.yml, como se describe en la documentación de BGPalerter.

      De manera predeterminada, BGPalerter monitorea y alerta sobre lo siguiente:

      • Intercepciones de ruta: se produce cuando un AS anuncia un prefijo que no está permitido, lo que provoca que el tráfico se enrute de forma errónea. Puede ser un ataque deliberado o un error de configuración accidental.

      • Pérdida de visibilidad de la ruta: una ruta se considera visible cuando la mayoría de los enrutadores de BGP de Internet pueden redirigir de forma fiable hacia ella. La pérdida de visibilidad significa que su red no está disponible, por ejemplo, si su emparejamiento de BGP ha dejado de funcionar.

      • Nuevos anuncios de subprefijos: sucede cuando un AS comienza a anunciar un prefijo que es más pequeño de lo que se espera. Esto puede indicar un cambio de configuración previsto, un error de configuración accidental o, en algunos casos, un ataque.

      • Actividad en su AS: normalmente, se refiere a anuncios de rutas nuevas. Una ruta se considera “nueva” si BGPalerter todavía no la conoce.

      A continuación, se presentan algunas alertas de ejemplo, junto con una descripción breve de su significado:

      Alert #1

      The prefix 203.0.113.0/24 is announced by AS64496 instead of AS65540
      

      Esta alerta muestra pruebas de una intercepción de la ruta, donde AS64496 anunció 203.0.113.0/24 cuando se esperaba que se anuncie AS65540. Esto es un claro indicio de un error de configuración que conduce a una fuga de la ruta o a una intercepción deliberada de un atacante.

      Alert #2

      The prefix 203.0.113.0/24 has been withdrawn. It is no longer visible from 6 peers
      

      Esta alerta indica que la red 203.0.113.0/24 ya no está visible. Esto puede deberse a un problema de enrutamiento previo o a un fallo de energía en un enrutador.

      Alert #3

      A new prefix 203.0.113.0/25 is announced by AS64496. It should be instead 203.0.113.0/24 announced by AS64496
      

      Esta alerta indica que se anunció un prefijo más específico en un caso en el que no estaba previsto, por ejemplo, si se anunció /25 cuando se esperaba /24. Es muy probable que esto sea un error de configuración, sin embargo, en algunos casos, puede indicar la intercepción de la ruta.

      Alert #4

      AS64496 is announcing 192.0.2.0/24 but this prefix is not in the configured list of announced prefixes
      

      Por último, esta alerta indica que AS64496 anunció un prefijo que BGPalerter todavía no conoce. Esto podría deberse a que usted está anunciando legítimamente un nuevo prefijo o podría ser un indicio de un error de configuración que haya provocado que anunciara accidentalmente un prefijo propiedad de otra persona.

      En este paso, revisó algunas alertas de BGPalerter de ejemplo. A continuación, configurará BGPalerter para que se ejecute de forma automática en el arranque.

      Paso 5: Iniciar BGPalerter en el arranque

      En este último paso, configurará BGPalerter para que se ejecute en el arranque.

      Asegúrese de seguir conectado con su usuario sin privilegios nuevo y, luego, abra el editor de crontab:

      Luego, añada la siguiente línea a la parte inferior del archivo de crontab:

      crontab

      @reboot sleep 10; screen -dmS bgpalerter "./bgpalerter-linux-x64"
      

      Cada vez que su sistema se arranque, esto creará una sesión screen separada denominada ‘bgpalerter’ en la que se iniciará BGPalerter.

      Guarde y salga del editor de crontab. Ahora, es conveniente que reinicie su sistema para asegurarse de que BGPalerter se inicie correctamente en el arranque.

      Primero, cierre la sesión de su usuario de BGPalerter:

      Luego, proceda con un reinicio normal del sistema:

      Una vez que su sistema se haya reiniciado, vuelva a iniciar sesión en su servidor y utilice su para volver a acceder a su usuario de BGPalerter:

      Luego, puede unirse a la sesión en cualquier momento para ver el resultado de BGPalerter:

      En este último paso, configuró BGPalerter para que se ejecute en el arranque.

      Conclusión

      En este artículo, configuró BGPalerter y lo utilizó para monitorear cambios de enrutamiento de BGP en las redes.

      Si quiere hacer que BGPalerter sea más fácil de usar, puede configurarlo para que envíe alertas a un canal de slack a través de un webhook:

      Si quiere obtener más información sobre BGP, pero no tiene acceso a un entorno de producción de BGP, puede utilizar DN42 para realizar pruebas con BGP en un entorno seguro y aislado:



      Source link