Cómo Ejecutar Vaultwarden En Podman Como Un Servicio Systemd

¿Qué es Vaultwarden?

Vaultwarden es una implementación alternativa de la API del servidor Bitwarden escrita en Rust. Es compatible con los clientes oficiales de Bitwarden y es una opción perfecta para una bóveda autohospedada. Al estar escrito en Rust, es liviano, a diferencia del Bitwarden original, que está escrito en C# y requiere muchos recursos.

¿Por qué Podman?

Docker no funciona correctamente como un servicio systemd. El problema es que systemd no monitorea un contenedor docker sino un cliente docker. Significa que si el contenedor falla pero el cliente se está ejecutando, systemd no reiniciará el contenedor. Es causado por la arquitectura cliente-servidor de Dockers. Hay una solución para esto, pero usar una solución nativa parece más razonable.

Podman es una herramienta nativa de Linux, de código abierto y sin demonios para ejecutar contenedores. Fue desarrollado bajo estándares OCI y funciona perfectamente con systemd. Debido a su naturaleza sin demonios, permite ejecutar contenedores bajo un usuario arbitrario.

Instalar podman

Mostraré cómo instalar podman en Ubuntu 20.10, para otras distribuciones consulte la guía oficial :

> sudo apt update
> sudo apt install podman

Ejecutar Vaultwarden

Mi configuración normal incluye el panel de administración habilitado y el registro de nuevos usuarios deshabilitado. Para habilitar el panel de administración, debemos pasar una ADMIN_TOKENvariable de entorno. Se recomienda utilizar una cadena aleatoria larga para este valor. Podemos generarlo usando el openssl randcomando:

> openssl rand -base64 48

Una cosa más que hacer antes de ejecutar nuestra bóveda es crear un directorio de datos. En este directorio, Vaultwarden almacena su configuración y base de datos:

> sudo mkdir /vaultwarden-data

Ahora todo está listo para ejecutar Vaultwarden:

> sudo podman pull vaultwarden/server:latest
> sudo podman run -d --name vaultwarden.pod -e ADMIN_TOKEN=YOUR_RANDOM_TOKEN_GOES_HERE -v /vaultwarden-data/:/data/ -p 8000:80 vaultwarden/server:latest

Crear servicio systemd

Cree un archivo de servicio en /etc/systemd/system/vaultwarden.pod.service:

> sudo touch /etc/systemd/system/vaultwarden.pod.service

Me gusta tener el .podsufijo para diferenciar los servicios nativos de los contenedores, pero puede omitirlo si lo desea.

Coloque el siguiente contenido en el archivo de servicio:

[Unit]
Description=Vaultwarden/Bitwarden Server (Rust Edition)
Documentation=https://github.com/dani-garcia/vaultwarden
Wants=syslog.service

[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start -a vaultwarden.pod
ExecStop=/usr/bin/podman stop vaultwarden.pod

[Install]
WantedBy=multi-user.target

Aquí hay algunas cosas que vale la pena señalar:

  • Restart=on-failureestá instruyendo que solo reinicie el servicio cuando salga con un código distinto de cero. Nos permite detener el servicio usando el comando podman stopasí como el .systemctl
  • Para almacenar los registros del contenedor en syslog, tenemos podman start -a. La -aopción indica adjuntar STDOUT y STDERR del contenedor.
  • WantedByes necesario para iniciar nuestro contenedor en el arranque del sistema. La multi-user.targetopción básicamente significa que el servicio debe iniciarse cuando todos los servicios de red estén activos y el sistema esté listo para aceptar inicios de sesión. Si omite la WantedByopción, su servicio NO se iniciará al arrancar.
  • La Wants=syslog.serviceopción indica que syslog debe iniciarse cuando se inicia nuestro servicio. Sin embargo, es un requisito débil y el servicio aún se iniciará si syslog no se inicia. En otras palabras, nos gustaría tener registros, pero no es obligatorio para nuestro servicio.

Vuelva a cargar el demonio:

> sudo systemctl daemon-reload

Y verifique el estado de Vaultwarden:

> sudo systemctl status vaultwarden.pod
● vaultwarden.pod.service - Vaultwarden/Bitwarden Server (Rust Edition)
     Loaded: loaded (/etc/systemd/system/vaultwarden.pod.service; disabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-05-26 15:25:08 UTC; 1 day 20h ago
       Docs: https://github.com/dani-garcia/vaultwarden
   Main PID: 19461 (podman)
      Tasks: 11 (limit: 1112)
     Memory: 26.9M
     CGroup: /system.slice/vaultwarden.pod.service
             ├─19461 /usr/bin/podman start -a vaultwarden.pod
             └─19574 /usr/libexec/podman/conmon --api-version 1 -c e2a6a794ddf8bb74308a9f64b98871913f6a46a8370c921dcb353f5db721cea0 -u e2a6a794ddf8bb74308a9f64b98871913f6a46a8370c921dcb353f5db721cea0 -r /usr/bin/crun -b /var/lib/containers/storage/overlay-containers/e2a6a7>

Ahora puede detener/iniciar el servicio Vaultwarden:

> sudo systemctl stop vaultwarden.pod
> sudo systemctl start vaultwarden.pod

Esta historia se publicó originalmente en https://atabakoff.com/how-to-run-vaultwarden-in-podman-as-a-systemd-service/

#podman 

What is GEEK

Buddha Community

Cómo Ejecutar Vaultwarden En Podman Como Un Servicio Systemd

Cómo Ejecutar Vaultwarden En Podman Como Un Servicio Systemd

¿Qué es Vaultwarden?

Vaultwarden es una implementación alternativa de la API del servidor Bitwarden escrita en Rust. Es compatible con los clientes oficiales de Bitwarden y es una opción perfecta para una bóveda autohospedada. Al estar escrito en Rust, es liviano, a diferencia del Bitwarden original, que está escrito en C# y requiere muchos recursos.

¿Por qué Podman?

Docker no funciona correctamente como un servicio systemd. El problema es que systemd no monitorea un contenedor docker sino un cliente docker. Significa que si el contenedor falla pero el cliente se está ejecutando, systemd no reiniciará el contenedor. Es causado por la arquitectura cliente-servidor de Dockers. Hay una solución para esto, pero usar una solución nativa parece más razonable.

Podman es una herramienta nativa de Linux, de código abierto y sin demonios para ejecutar contenedores. Fue desarrollado bajo estándares OCI y funciona perfectamente con systemd. Debido a su naturaleza sin demonios, permite ejecutar contenedores bajo un usuario arbitrario.

Instalar podman

Mostraré cómo instalar podman en Ubuntu 20.10, para otras distribuciones consulte la guía oficial :

> sudo apt update
> sudo apt install podman

Ejecutar Vaultwarden

Mi configuración normal incluye el panel de administración habilitado y el registro de nuevos usuarios deshabilitado. Para habilitar el panel de administración, debemos pasar una ADMIN_TOKENvariable de entorno. Se recomienda utilizar una cadena aleatoria larga para este valor. Podemos generarlo usando el openssl randcomando:

> openssl rand -base64 48

Una cosa más que hacer antes de ejecutar nuestra bóveda es crear un directorio de datos. En este directorio, Vaultwarden almacena su configuración y base de datos:

> sudo mkdir /vaultwarden-data

Ahora todo está listo para ejecutar Vaultwarden:

> sudo podman pull vaultwarden/server:latest
> sudo podman run -d --name vaultwarden.pod -e ADMIN_TOKEN=YOUR_RANDOM_TOKEN_GOES_HERE -v /vaultwarden-data/:/data/ -p 8000:80 vaultwarden/server:latest

Crear servicio systemd

Cree un archivo de servicio en /etc/systemd/system/vaultwarden.pod.service:

> sudo touch /etc/systemd/system/vaultwarden.pod.service

Me gusta tener el .podsufijo para diferenciar los servicios nativos de los contenedores, pero puede omitirlo si lo desea.

Coloque el siguiente contenido en el archivo de servicio:

[Unit]
Description=Vaultwarden/Bitwarden Server (Rust Edition)
Documentation=https://github.com/dani-garcia/vaultwarden
Wants=syslog.service

[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start -a vaultwarden.pod
ExecStop=/usr/bin/podman stop vaultwarden.pod

[Install]
WantedBy=multi-user.target

Aquí hay algunas cosas que vale la pena señalar:

  • Restart=on-failureestá instruyendo que solo reinicie el servicio cuando salga con un código distinto de cero. Nos permite detener el servicio usando el comando podman stopasí como el .systemctl
  • Para almacenar los registros del contenedor en syslog, tenemos podman start -a. La -aopción indica adjuntar STDOUT y STDERR del contenedor.
  • WantedByes necesario para iniciar nuestro contenedor en el arranque del sistema. La multi-user.targetopción básicamente significa que el servicio debe iniciarse cuando todos los servicios de red estén activos y el sistema esté listo para aceptar inicios de sesión. Si omite la WantedByopción, su servicio NO se iniciará al arrancar.
  • La Wants=syslog.serviceopción indica que syslog debe iniciarse cuando se inicia nuestro servicio. Sin embargo, es un requisito débil y el servicio aún se iniciará si syslog no se inicia. En otras palabras, nos gustaría tener registros, pero no es obligatorio para nuestro servicio.

Vuelva a cargar el demonio:

> sudo systemctl daemon-reload

Y verifique el estado de Vaultwarden:

> sudo systemctl status vaultwarden.pod
● vaultwarden.pod.service - Vaultwarden/Bitwarden Server (Rust Edition)
     Loaded: loaded (/etc/systemd/system/vaultwarden.pod.service; disabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-05-26 15:25:08 UTC; 1 day 20h ago
       Docs: https://github.com/dani-garcia/vaultwarden
   Main PID: 19461 (podman)
      Tasks: 11 (limit: 1112)
     Memory: 26.9M
     CGroup: /system.slice/vaultwarden.pod.service
             ├─19461 /usr/bin/podman start -a vaultwarden.pod
             └─19574 /usr/libexec/podman/conmon --api-version 1 -c e2a6a794ddf8bb74308a9f64b98871913f6a46a8370c921dcb353f5db721cea0 -u e2a6a794ddf8bb74308a9f64b98871913f6a46a8370c921dcb353f5db721cea0 -r /usr/bin/crun -b /var/lib/containers/storage/overlay-containers/e2a6a7>

Ahora puede detener/iniciar el servicio Vaultwarden:

> sudo systemctl stop vaultwarden.pod
> sudo systemctl start vaultwarden.pod

Esta historia se publicó originalmente en https://atabakoff.com/how-to-run-vaultwarden-in-podman-as-a-systemd-service/

#podman 

Diego  Elizondo

Diego Elizondo

1652926080

Cómo Construir Un Analizador En Rust Por Diversión Y Ganancias

Un viernes por la mañana, holgazaneando, estás pensando en los nuevos programas de Netflix para ver. Su jefe viene y le pide que escriba un analizador para un archivo de unidad de Systemd .

Lo necesita para el lunes.

Cada vez que pensabas que el fin de semana estaba disponible

Estás nervioso.

La última vez que se le pidió que escribiera un analizador, se metió en la madriguera del conejo de la web, copiando y pegando fórmulas Regex hasta que funcionó™.

Básicamente lo que todos los desarrolladores habían hecho (sangre en la mano)

Tomas un sorbo de tu té de boba para calmarte. Buscas Systemd en Google y te gusta... no, no es tan simple como pensabas.

Ese sentimiento cuando estás tan desesperado porque te quitan el fin de semana

Tu buen truco de copiar y pegar expresiones regulares sale volando por la ventana. Las posibilidades de pasar un fin de semana sin interrupciones para atracones de programas se acercan rápidamente null.

#PEG al rescate

No pierdas la esperanza todavía. Permítame presentarle Parse Expression Grammer (PEG) , una manera fácil de familiarizarse con los analizadores y ahorrar su valioso fin de semana.

PEG es una forma legible de escribir reglas de sintaxis y es bastante similar a las expresiones regulares, que es diferente de una contraparte de gramática libre de contexto como Backus-Naur Form (BNF) en la que las expresiones deben reducirse a símbolos más pequeños. Lo siento, Noam Chomsky , quizás otros días de trabajo.

Usaré una biblioteca de análisis de Rust PEG llamada Pest , que es bastante impresionante. Si aún no lo has hecho, esperaré mientras instalas Rust .

En serio, ¿quién no se oxida en estos días?

#Empezando

Comencemos con una gramática simple para analizar una declaración de declaración de variable similar a JavaScript. Comenzaremos pensando en un conjunto de reglas para entradas válidas.

#Una declaración de declaración:

  • comienza con una palabra clave var, seguida de uno o más identificadores.
  • es insensible al espacio en blanco
  • termina con un punto y coma ( ;)

#Un grupo de identificadores:

  • está precedido por una varpalabra clave
  • está delimitado por comas
  • es insensible al espacio en blanco

#Un identificador:

  • puede contener cualquier número de dígitos, caracteres y guiones bajos en mayúsculas y minúsculas
  • no puede comenzar con un dígito
  • no puede contener ningún espacio

Un identificador es un término , lo que significa que es una pieza irrompible del token. También lo son las varpalabras clave y los puntos y comas.

Regresa un poco al lado BNF, usando Extended Backus-Naur Grammar (EBNF) , podrías definir formalmente la gramática anterior de esta manera:

<alpha>  := 'a' | 'b' | 'c' | 'd' | 'e' | /* ... */ 'z'
         |  'A' | 'B' | 'C' | 'D' | 'E' | /* ... */ 'Z'

<digit>  := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

<Decl>   := 'var' <Idents> '\n'? ';'
<Idents> := <Ident> ('\n'? ',' <Ident>)*
<Ident>  := <alpha>+ (<alpha> | <digit> | '_')*

El nombre de la regla en mayúsculas representa un símbolo que no termina (es decir, se puede dividir en términos más pequeños). El nombre en minúscula representa un término.

En aras de la brevedad, omitimos los espacios en blanco implícitos de las reglas. Básicamente, pueden existir uno o más espacios en blanco entre cada símbolo que ve.

¡Vamos a profundizar en ello! Las reglas <alpha>y <digit>se explican por sí mismas, por lo que dejaremos que lo adivines.

<Decl>es la regla más compleja para una instrucción de declaración, que presenta una varpalabra clave, un <Idents>símbolo, una nueva línea opcional y termina con un punto y coma. Básicamente, esta regla dice: "Cualquier entrada de cadena que comience con var, seguida de uno o más espacios, luego una subregla <Idents>, seguida de uno o más espacios y finalmente termine con un solo punto y coma es válida y felizmente la masticaré. "

<Idents>puede ser un solo <Ident>símbolo, seguido de cero o más pares de comas y <Ident>.

Finalmente, un <Ident>debe comenzar con uno o más caracteres, seguido de cero o más caracteres, dígitos o guiones bajos.

#Ok, código por favor

¡Espera, joven Anakin! Cabeza caliente, eres. He aquí que, con la gramática definida, podremos analizar estas declaraciones:

var foo, bar, baz;

var   foo_1, baRamYu,baz99;

var foo_x
  , baroo
  , bazoo
  ;

No, no me olvidé de formatear mi código. ¡Es JS válido, y también es para nuestro analizador! Aquí hay algo que nuestras reglas no soportarán:

var 99Problems

¿Alguien quiere adivinar qué está mal aquí? ✋ Deja tu respuesta en el comentario. (psss, si tu respuesta es correcta, te sigo + 3 me gusta en tu publicación 👍)

#Entra el óxido y las plagas

Ok, espero que ya tengas Rust instalado (En tu terminal, intenta escribir which cargoy ver si aparece). Comience creando un nuevo proyecto binario de Rust con

$ cargo new --bin maybe-js; cd maybe-js

Dentro de la carpeta del proyecto, abra el Cargo.tomlarchivo y agregue lo siguiente en dependencies, y ejecútelo cargo updatepara instalarlo.

[dependencies]
pest = "2.0"
pest_derive = "2.0"

Una vez hecho esto, cdingrese srcy cree un archivo llamado grammar.pesty pegue lo siguiente en él:

alpha = { 'a'..'z' | 'A'..'Z' }
digit = { '0'..'9' }
underscore = { "_" }
newline = _{ "\n" | "\r" }
WHITESPACE = _{ " " }

declaration = { "var" ~ !newline ~ idents ~ newline? ~ ";" }
idents = { ident ~ (newline? ~ "," ~ ident)* }
ident = @{ !digit ~ (alpha | digit | underscore)+ }

Ahora bien, si he tenido su atención durante los últimos minutos, no debería ser difícil adivinar lo que está sucediendo aquí. (Oh, ¿no lo he hecho? De todos modos... aquí vamos)

Los cinco primeros son todos términos. Son conjuntos de valores válidos. el | se llama Choice Operator , que es como "o-si no".

first | or_else

Al hacer coincidir una expresión de elección, firstse intenta. Si first coincide con éxito, la expresión completa se realiza correctamente de inmediato. Sin embargo, si firstfalla, or_elsese intenta a continuación.

La newlineregla tiene un peculiar _antes del corchete, que en Pest habla significa "silencioso": simplemente no lo queremos como parte de nuestros tokens analizados, pero de todos modos es parte de una sintaxis válida.

La WHITESPACEregla tiene un lugar especial en Pest. Si lo definió, Pest insertará automáticamente espacios en blanco opcionales implícitos (de acuerdo con la WHITESPACEregla que defina) entre cada símbolo. Nuevamente, _dice que queremos silenciarlo, ya que no queremos toneladas de espacios en blanco como parte de nuestro árbol de sintaxis.

La declarationregla es muy similar a la contraparte de EBNF que aprendimos antes. Las tildes ("~") simplemente significan "y luego". La regla comienza con una palabra clave "var", seguida de cualquier cosa que no sea un salto de línea (el "!" hace lo que hubiera adivinado intuitivamente: negar una regla), seguida de una subregla idents, un salto de línea opcional y finaliza con un punto y coma.

La identsregla es nuevamente similar al ejemplo EBNF. Es un solo ident, seguido de cero o más idents separados por comas.

La identregla es un poco especial. La "@", conocida como Atomic , delante del corchete está ahí para decir: "No quiero que se apliquen espacios en blanco implícitos a esta regla". Seguro que no queremos incluir ningún espacio en nuestro nombre de variable. Además, marcar una regla como atómica de esta manera trata la regla como un término, silenciando las reglas internas de coincidencia. Cualquier regla interna se descarta.

string_lit = { "\"" ~ inner ~ "\"" }
inner = { ASCII_ALPHANUMERIC* }

Tenga en cuenta que ASCII_ALPHANUMERICes una regla incorporada conveniente en Pest para cualquier carácter y dígito ASCII.

Si analizamos una cadena "hola" con esta regla, esto generará primero un string_litnodo, que a su vez tiene un innernodo que contiene la cadena "hola", sin comillas.

Árbol de regla no atómica

Agregar un sigilo "@" delante del string_litcorchete:

string_lit = @{ "\"" ~ inner ~ "\"" }
inner = { ASCII_ALPHANUMERIC* }

string_litTerminaremos con un nodo plano que contiene ""hola"".

Árbol de la regla atómica

Un sigilo similar "$" conocido como Compound Atomic , protege los espacios en blanco implícitos dentro de la regla. La diferencia es que permite que las reglas de coincidencia internas se analicen normalmente.

La !digitparte evita que la regla avance si comienza con un número. Si no es así, una o más combinaciones de caracteres, números y guiones bajos están bien.

#Pero espera, ¿dónde está el código?

¡Dang, mi inteligente explorador! Pareces arrinconarme en cada movimiento. Sí, eso no era código en absoluto, sino una definición de gramática de Pest. Ahora tenemos que escribir un código de Rust para analizar un texto. Inicie src/main.rsy agregue lo siguiente:

/// You need to do this to use macro
extern crate pest;                                                                                                                                                                                   
#[macro_use]                                                                                                                                                                                         
extern crate pest_derive;                                                                                                                                                                            

/// 1. Import modules                                                                                                                                                                                            
use std::fs;                                                                                                                                                                                         
use pest::Parser;                                                                                                                                                                                    
use pest::iterators::Pair;                                                                                                                                                                           

/// 2. Define a "marker" struct and add a path to our grammar file.                                                                                                                                                                                                 
#[derive(Parser)]                                                                                                                                                                                    
#[grammar = "grammar.pest"]                                                                                                                                                                            
struct IdentParser; 

/// 3. Print the detail of a current Pair and optional divider
fn print_pair(pair: &Pair<Rule>, hard_divider: bool) {
    println!("Rule: {:?}", pair.as_rule());
    println!("Span: {:?}", pair.as_span());
    println!("Text: {:?}", pair.as_str());
    if hard_divider {
        println!("{:=>60}", "");
    } else {
        println!("{:->60}", "");
    }
}

fn main() {
    /// 4. Parse a sample string input
    let pair = IdentParser::parse(Rule::declaration, "var foo1, bar_99, fooBar;")
        .expect("unsuccessful parse")
        .next().unwrap();

    print_pair(&pair, true);
    
    /// 5. Iterate over the "inner" Pairs
    for inner_pair in pair.into_inner() {
 
        print_pair(&inner_pair, true);

        match inner_pair.as_rule() {
            /// 6. If we match an idents rule...
            Rule::idents =>  {
                /// 7. Iterate over another inner Pairs
                for inner_inner_pair in inner_pair.into_inner() {
                    match inner_inner_pair.as_rule() {
                        /// 8. The term ident is the last level
                        Rule::ident => {
                            print_pair(&inner_inner_pair, false);
                        }
                        _ => unreachable!(),
                    }
                }
            }
            _ => unreachable!(),
        }
    }
}

Está bien si no entiendes la mayoría de las cosas aquí. Ejecutémoslo cargo runen el directorio de su proyecto y miremos la salida impresa.

Rule: declaration
Span: Span { str: "var foo1, bar_99, fooBar;", start: 0, end: 28 }
Text: "var foo1, bar_99, fooBarBaz;"
============================================================
Rule: idents
Span: Span { str: "foo1, bar_99, fooBar", start: 4, end: 27 }
Text: "foo1, bar_99, fooBarBaz"
============================================================
Rule: ident
Span: Span { str: "foo1", start: 4, end: 8 }
Text: "foo1"
------------------------------------------------------------
Rule: ident
Span: Span { str: "bar_99", start: 10, end: 16 }
Text: "bar_99"
------------------------------------------------------------
Rule: ident
Span: Span { str: "fooBar", start: 18, end: 27 }
Text: "fooBarBaz"
------------------------------------------------------------

El concepto más importante aquí es un Pair. Representa un par de tokens coincidentes o, de manera equivalente, el texto distribuido que una regla con nombre coincidió correctamente.

A menudo usamos Pairs para:

Determinar qué regla produjo elPair

Usar el Paircomo materia prima&str

Inspeccionar las sub-reglas internas nombradas que produjeron elPair

let pair = Parser::parse(Rule::enclosed, "(..6472..) and more text")
    .unwrap().next().unwrap();

assert_eq!(pair.as_rule(), Rule::enclosed);
assert_eq!(pair.as_str(), "(..6472..)");

let inner_rules = pair.into_inner();
println!("{}", inner_rules); // --> [number(3, 7)]

A Pairpuede tener cero, una o más reglas internas. Para máxima flexibilidad, Pair::into_inner()devuelve Pairs, que es un tipo de iterador sobre cada par.

💡 Pair::into_inner()es un idioma muy común cuando se trabaja con Pest. Asegúrate de entender qué Paires a.

#Vamos a analizar Systemd

Si has llegado hasta aquí, te mereces este gatito.

Ahora es el momento de poner el trabajo. Aquí hay un ejemplo de un archivo de unidad Systemd:

[Unit]
Description=Nginx
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/home/ec2-user/.local/bin
Environment=LD_LIBRARY_PATH=/usr/local/lib
Environment=PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
ExecStart=/usr/local/sbin/nginx-runner.sh
Restart=on-failure
RestartSec=0
KillMode=process

[Install]
WantedBy=multi-user.target

El archivo está agrupado en secciones, cada una con un nombre entre corchetes. Cada sección contiene cero o más pares de nombre y valor de propiedad, separados por un signo igual "=".

Tratemos de desarrollar un conjunto de reglas. Cree un nuevo proyecto de óxido con cargo new --bin systemd-parser, luego cree un archivo con el nombre src/grammar.pestcon las siguientes reglas:


/// Implicit white spaces are ok.
WHITESPACE = _{ " " }

/// Set of characters permited 
char = { ASCII_ALPHANUMERIC | "." | "_" | "/" | "-"  }

/// name is one or more chars. Note that white spaces are allowed.
name = { char+ }

// value can be zero or more char, plus = and : for path variables.
value = { (char | "=" | ":" )* }

/// section is a name, enclosed by square brackets.
section = { "[" ~ name ~ "]" }

/// property pair is a name and value, separated by an equal sign.
property = { name ~ "=" ~ value }

/// A Systemd unit file structure
file = {
    SOI ~
    ((section | property)? ~ NEWLINE)* ~
    EOI
}

En el main.rsarchivo, comience con lo siguiente

extern crate pest;
#[macro_use]
extern crate pest_derive;

use std::fs;
use std::env::current_dir;
use std::collections::HashMap;
use pest::Parser;

#[derive(Parser)]
#[grammar = "grammar.pest"]
struct SystemdParser;

/// Implement a simple AST representation
#[derive(Debug, Clone)]
pub enum SystemdValue {
    List(Vec<String>),
    Str(String),
}

// ...

Como primer paso, después de las importaciones y la configuración iniciales, definimos una SystemdValueenumeración como una representación simple del tipo de datos en un archivo Systemd. SystemdValue::Str(String)capturará un solo valor de propiedad y SystemdValue::List(Vec<String>)capturará varios valores de propiedad con un nombre de clave de propiedad duplicado. Por ejemplo, en el nginx.servicearchivo anterior hay varias Environmentpropiedades.

Aquí está la mainfunción:


fn main() {
    // Read and parse the unit file.
    let unparsed_file = fs::read_to_string("nginx.service")
        .expect("cannot read file");
    let file = SystemdParser::parse(Rule::file, &unparsed_file).expect("fail to parse")
        .next()
        .unwrap();

    // Create a fresh HashMap to store the data.
    let mut properties: HashMap<String, HashMap<String, SystemdValue>> = HashMap::new();

    // These two mutable variables will be used to store
    // section name and property key name.
    let mut current_section_name = String::new();
    let mut current_key_name = String::new();

    // Iterate over the file line-by-line.
    for line in file.into_inner() {
		match line.as_rule() {
			Rule::section => {
                // Update the current_section_name
                let mut inner_rules = line.into_inner();
                current_section_name = inner_rules.next().unwrap().as_str().to_string();
			}
			Rule::property => {
                let mut inner_rules = line.into_inner();
                // Get a sub map of properties with the current_section_name key, or create new.
                let section = properties.entry(current_section_name.clone()).or_default();

                // Get the current property name and value.
                let name = inner_rules.next().unwrap().as_str().to_string();
                let value = inner_rules.next().unwrap().as_str().to_string();

                // If the property name already exists...
                if name == current_key_name {
                    // Get the section of the map with the key name, or insert a new SytemdValue::List.
                    let entry = section.entry(current_key_name.clone()).or_insert(SystemdValue::List(vec![]));
                    // Push the value onto the inner vector of SystemdValue::List.
                    if let SystemdValue::List(ent) = entry {
                        ent.push(value);
                    }
                } else {
                    // Create a new SystemdValue::List and save it under name key.
                    let entry = section.entry(name.clone()).or_insert(SystemdValue::List(vec![]));
                    // Push the current value onto the vector, then set the
                    // current_key_name to the current name.
                    if let SystemdValue::List(ent) = entry {
                        ent.push(value);
                    }
                    current_key_name = name;
                }
			}
			Rule::EOI => (),
			_ => unreachable!(),
		}
    }
}

Todo esto está bien, pero no usamos SystemdValue::Strninguna parte del código. Para mantener limpio el código, decidimos tratar cada propiedad como HashMap<String, SystemdValue::List(Vec<String>), donde la clave del mapa es la clave de propiedad y el vector String almacena la lista de valores de propiedad. Si no hay valor, el vector está vacío. Si hay un valor, este vector contiene ese único valor, y así sucesivamente.

Para que la API sea un poco más fácil de usar, escribiremos una pequeña función auxiliar para procesar todos los correos electrónicos de un solo valor Systemd::List(Vec<String>)y convertirlos en archivos Systemd::Str(String).

// Iterate over the nested maps, and convert empty and 
// single-element `SystemdValue::List<Vec<String>>` to 
// `SystemdValue::Str(String)`.
fn pre_process_map(map: &mut HashMap<String, HashMap<String, SystemdValue>>) {
    for (_, value) in map.into_iter() {
		for (_, v) in value.into_iter() {
			if let SystemdValue::List(vs) = v {
				if vs.len() == 0 {
					let v_ = SystemdValue::Str(String::new());
					*v = v_.clone();
				} else if vs.len() == 1 {
					let v_ = SystemdValue::Str((vs[0]).clone());
					*v = v_.clone();
				}
			}
		}
    }
}

¡Ahora estamos listos para imprimirlo para que el mundo lo vea!

fn main() {

    // Our main code 

    pre_process_map(properties);

    println!("{:#?}", properties);
}

¡Auge! ¡Felicidades! Acaba de escribir un analizador de archivos Systemd, además de uno mini JS. 🤯 Ahora tendrás algo de tiempo libre para divertirte el viernes por la noche. Con otra tarde, es posible que incluso descubras cómo serializar el archivo de tu unidad Systemd en JSON para impresionar a tu jefe el lunes.

Puede consultar el código del analizador implementado como biblioteca en [este repositorio] (https://github.com/jochasinga/systemd-parser)

Fuente: https://hackernoon.com/how-to-build-a-parser-in-rust-for-fun-and-profit

#rust 

joe biden

1619242752

Convertisseur OST en PST - Gratuit OST en PST pour convertir un fichier OST à fichier PST

Les utilisateurs ont deux façons de convertir les fichiers OST au format Outlook PST manuellement ou à l’aide de l’application. La conversion manuelle des fichiers OST prend beaucoup de temps ainsi que les efforts des utilisateurs. Par conséquent, les utilisateurs doivent utiliser un outil de conversion OST en PST. Le Datavare convertisseur OST vers PST est la meilleure solution pour convertir les fichiers OST au format Outlook PST.

Pour effectuer la conversion des fichiers OST, les utilisateurs doivent télécharger cette application incroyable. Cette application effectue la tâche de manière efficace et sans effort. Les utilisateurs peuvent convertir des fichiers OST entiers à l’aide de cet outil étonnant et à une vitesse rapide. Des données entières, y compris des notes, des messages, des contacts et des calendriers, sont converties au format PST à l’aide de cet outil incroyable. De plus, les utilisateurs sont libres d’enregistrer le fichier converti n’importe où sur votre système local. Avec cette application hautement compatible, les utilisateurs peuvent facilement utiliser ce convertisseur OST vers PST dans n’importe quel système d’exploitation Windows. C’est une application hautement interactive que même un utilisateur novice peut utiliser. L’application est une plate-forme sûre et sécurisée pour tous les utilisateurs. Les étapes requises pour convertir le fichier OST au format PST sont simples à implémenter.
Les utilisateurs sont libres d’enregistrer le fichier n’importe où dans leur système local sans rencontrer aucune difficulté.

Étapes pour convertir les fichiers

Suivez les étapes ci-dessous pour convertir les fichiers OST au format PST:

Étape 1 - Téléchargez l’outil de conversion OST en PST dans votre système d’exploitation Windows
Étape 2 - Lancez l’application
Étape 3 - Ajoutez les fichiers OST
Étape 4 - Aperçu des fichiers OST sélectionnés
Étape 5 - Choisissez l’emplacement pour enregistrer les fichiers convertis
Étape 6 - Enfin, cliquez sur le bouton «Convertir maintenant». Par conséquent, voici quelques étapes simples avec lesquelles un utilisateur peut facilement convertir ses fichiers OST au format Outlook PST.

Fonctionnalités de l’application

Faites-nous maintenant part de certaines fonctionnalités intelligentes de l’application qu’un utilisateur doit voir:

Convertissez les fichiers OST
L’application convertit librement les fichiers OST au format Outlook PST facilement et de manière fiable sans aucune obligation. La conversion directe des fichiers OST est effectuée par cet outil étonnant. De plus, les utilisateurs peuvent utiliser l’application dans n’importe quelle version de Windows, de la dernière à la plus ancienne version de l’application. L’application convertit toutes les données après avoir prévisualisé et numérisé les données. La taille des fichiers OST n’a pas d’importance dans l’ensemble du processus de conversion.

Précision
Avec une précision totale, tout un processus de conversion est effectué par l’application. Peu importe qu’un utilisateur entre le nombre de fichiers qu’il saisit, les utilisateurs sont autorisés à convertir les fichiers de manière irréprochable. Tous les fichiers OST sont facilement exportés de manière sûre et sécurisée sans aucun type de perte de données ou de corruption de données.

Emplacement spécifié par l’utilisateur
Les fichiers OST convertis peuvent être enregistrés n’importe où selon le souhait de l’emplacement spécifique à l’utilisateur. Une flexibilité totale des fichiers est fournie par l’application afin que l’utilisateur ne soit confronté à aucun problème lors de l’enregistrement du fichier.

Application hautement compatible
C’est une application hautement compatible qui peut être utilisée dans n’importe quelle version de Windows. De la version la plus ancienne à la plus récente de Windows, l’application peut être facilement exploitée sans aucune difficulté. La compatibilité de l’application est inégalée par rapport à toute autre application. Le résultat souhaité est fourni par l’application.

Déclaration finale

Téléchargez cet incroyable convertisseur OST en PST pour convertir vos fichiers OST au format Outlook PST. L’intégrité des fichiers est maintenue par l’application et la qualité des fichiers est conservée par l’application. Avec cette application hautement compatible, les utilisateurs obtiennent le résultat souhaité par les utilisateurs. De plus, vous devriez essayer la version de démonstration de l’application pour en savoir plus sur l’application. La version de démonstration de l’application est gratuite pour tous les utilisateurs. Cette version de démonstration de l’application donne aux utilisateurs le droit de convertir quelques fichiers OST. Pour convertir les fichiers illimités, l’utilisateur doit acheter la version sous licence de l’application maintenant.

Plus d’informations:- https://www.datavare.com/fr/convertisseur-ost-à-pst.html

#convertisseur ost en pst #conversion ost en pst #ost à l'importateur pst #importer ost vers pst #convertir ost en pst #exporter ost vers pst

Amara  Reichel

Amara Reichel

1597975200

Cómo crear un Slackbot en Python en Ubuntu 20.04

Introducción

Slack es una plataforma de comunicación diseñada para la productividad en el lugar de trabajo. Incluye características tales como mensajes directos, canales públicos y privados, llamadas de voz y de video e integraciones bot. Un Slackbot es un programa automatizado que puede realizar múltiples funciones en Slack, desde el envío de mensajes hasta la activación de tareas de alerta en ciertos eventos.

En este tutorial, creará un Slackbot en el lenguaje de programación Python. Python es un lenguaje popular que se enorgullece de su simplicidad y legibilidad. Slack proporciona una Python Slack API amplia para integrarla con Slack y realizar tareas comunes como enviar mensajes, añadir emojis a los mensajes y mucho más. Slack también proporciona una Python Slack Events API para integrarla con eventos en Slack, lo que le permite realizar acciones en eventos como mensajes y menciones.

Como una divertida demostración conceptual para ver el poder de Python y sus API de Slack, creará un CoinBot, un Slackbot que supervisa un canal, y, cuando se active, le lanzará una moneda. A continuación, puede modificar su CoinBot para que cumpla con cualquier número de aplicaciones un poco más prácticas.

#python #ubuntu 20.04 #slackbot #cómo

How to run Vaultwarden in Podman as a systemd service

What is Vaultwarden?

Vaultwarden is an alternative implementation of Bitwarden server API written in Rust. It’s compatible with official Bitwarden clients and is a perfect choice for a self-hosted vault. Being written in Rust makes it lightweight, unlike the original Bitwarden which is written in C# and quite resource-heavy.

Why Podman?

Docker doesn’t work properly as a systemd service. The problem is that systemd doesn’t monitor a docker container but a docker client. It means if the container crashes but the client is running, the systemd will not restart the container. It’s caused by Dockers’ client-server architecture. There’s a workaround for it but using a native solution seems more reasonable.

Podman is an open-source, daemon-less, Linux-native tool to run containers. It was developed under OCI standards and it works perfectly with systemd. Because of its daemon-less nature, it allows running containers under an arbitrary user.

Install Podman

I will show how to install podman in Ubuntu 20.10, fo other distributions refer to the official guide :

> sudo apt update
> sudo apt install podman

Run Vaultwarden

My normal setup includes the admin panel enabled and registration of new users disabled. To enable the admin panel we have to pass an ADMIN_TOKEN environment variable. It is recommended to use a long random string for this value. We can generate it using the openssl rand command:

> openssl rand -base64 48

One more thing to do before we run our vault is to create a data directory. In this directory Vaultwarden stores its config and database:

> sudo mkdir /vaultwarden-data

Now everything is ready to run Vaultwarden:

> sudo podman pull vaultwarden/server:latest
> sudo podman run -d --name vaultwarden.pod -e ADMIN_TOKEN=YOUR_RANDOM_TOKEN_GOES_HERE -v /vaultwarden-data/:/data/ -p 8000:80 vaultwarden/server:latest

Create systemd service

Create a service file under /etc/systemd/system/vaultwarden.pod.service:

> sudo touch /etc/systemd/system/vaultwarden.pod.service

I like to have the .pod suffix to differentiate native services from containerized, but you can omit it if you like so.

Put the following content to the service file:

[Unit]
Description=Vaultwarden/Bitwarden Server (Rust Edition)
Documentation=https://github.com/dani-garcia/vaultwarden
Wants=syslog.service

[Service]
Restart=on-failure
ExecStart=/usr/bin/podman start -a vaultwarden.pod
ExecStop=/usr/bin/podman stop vaultwarden.pod

[Install]
WantedBy=multi-user.target

Here are a few things worth pointing out:

  • Restart=on-failure is instructing to only restart the service when it exits with non-zero code. It allows us to stop the service using the podman stop as well as the systemctl command.
  • To store the container’s logs to syslog we have podman start -a. The -a option instructs to attach the container’s STDOUT and STDERR.
  • WantedBy is needed to start our container on system boot. The multi-user.target option basically means that the service should be started when all network services are up and the system is ready to accept logins. If you omit the WantedBy option your service will NOT start on boot.
  • The Wants=syslog.service option tells that syslog should be started when our service is being started. However, it’s a weak requirement and the service will still start if syslog fails to start. In other words, we would like to have logs but it’s not mandatory for our service.

Reload the daemon:

> sudo systemctl daemon-reload

And check the Vaultwarden status:

> sudo systemctl status vaultwarden.pod
● vaultwarden.pod.service - Vaultwarden/Bitwarden Server (Rust Edition)
     Loaded: loaded (/etc/systemd/system/vaultwarden.pod.service; disabled; vendor preset: enabled)
     Active: active (running) since Thu 2022-05-26 15:25:08 UTC; 1 day 20h ago
       Docs: https://github.com/dani-garcia/vaultwarden
   Main PID: 19461 (podman)
      Tasks: 11 (limit: 1112)
     Memory: 26.9M
     CGroup: /system.slice/vaultwarden.pod.service
             ├─19461 /usr/bin/podman start -a vaultwarden.pod
             └─19574 /usr/libexec/podman/conmon --api-version 1 -c e2a6a794ddf8bb74308a9f64b98871913f6a46a8370c921dcb353f5db721cea0 -u e2a6a794ddf8bb74308a9f64b98871913f6a46a8370c921dcb353f5db721cea0 -r /usr/bin/crun -b /var/lib/containers/storage/overlay-containers/e2a6a7>

Now you can stop/start the Vaultwarden service:

> sudo systemctl stop vaultwarden.pod
> sudo systemctl start vaultwarden.pod

This story was originally published at https://atabakoff.com/how-to-run-vaultwarden-in-podman-as-a-systemd-service/

#podman