Fabric: ¡Meta-ticket de retroalimentación alfa/beta de Fabric 2!

Creado en 21 abr. 2017  ·  28Comentarios  ·  Fuente: fabric/fabric

¡Asegúrese primero de haber leído esta publicación de blog y todos sus enlaces!: http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta


Este es el lugar para dejar comentarios sobre problemas no cubiertos por ninguno de los tickets existentes; por favor busque los lugares a continuación primero!!


¿No encuentras nada relevante? ¡Deja un comentario a continuación! Estoy buscando comentarios _similares pero no limitados a_:

  • "¡Me niego a usar 2.0 hasta que vuelvas a ponerlo en el modo mágico, global, no orientado a objetos!" (aunque solo lo vincularé a pyinvoke/invoke#186 y le pediré que proporcione una justificación allí;))
  • "Me gusta mucho lo que hiciste con la $función, pero falta la $subfunción, ¡que realmente necesito! ¿Está planeado?" (Diré 'sí', 'no' o 'no, ¡pero ahora puede implementarlo trivialmente usted mismo! ¡No necesita estar en el núcleo!')
  • "Me gusta mucho lo que hiciste con $feature, pero por la forma en que está configurado ahora, ¡es difícil/imposible hacer $sub-caso de uso!" (Probablemente le pediré detalles y posiblemente le pida un PR de ejemplo de la API que le gustaría ver).

Comentario más útil

@haydenflinner ¡Estará sucediendo durante la próxima semana o dos! (El objetivo es publicar antes de subirme a mi avión a PyCon, que es el 10 de mayo).

Por ejemplo, consulte los documentos de actualización actualizados recientemente en los que estaba trabajando esta semana: http://docs.fabfile.org/en/v2/upgrading.html

De hecho, también puedo cerrar este ticket ahora, ya que pronto aceptaré los reales para 2.0.0 y superiores 👍

Todos 28 comentarios

Pequeño error en la URL, debería ser http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta/

Esto demuestra lo bien que recuerdo mi propio sitio web, ¿eh? ¡Gracias! Incluso ejecuté un verificador de enlaces en mi publicación, pero... no contra este ticket;)

Tengo una propuesta sobre cómo se puede implementar el sistema roledefs de fabric 1 de una manera que creo que está en línea con la filosofía de fabric 2. Cada Collection de tareas también puede tener @group funciones decoradas en el mismo espacio de nombres que devuelven Group objetos con los que se pueden ejecutar las tareas. Los espacios de nombres importarían, así que si fabfile.py contuviera un Collection llamado deploy que tuviera @group llamados web y db , se podría usar deploy.web.execute(mytask) o fab -G deploy.web mytask para ejecutar mytask en cada host del grupo web . Estas funciones decoradas se llamarían de forma perezosa y se memorizarían para evitar llamadas API innecesarias, en caso de que la búsqueda de una lista de host sea una operación lenta implementada por el usuario.

¿Está esto en consonancia con la filosofía de diseño del tejido 2? Me encantaría dar un giro a la implementación si es así.

¡Esa es una buena idea, @RedKrieg! He estado aplazando mi propia lluvia de ideas sobre cómo "mejor" generar objetos de grupo y/o cómo referirme a ellos en la CLI, pero de antemano suena como una forma razonable de hacerlo. Simplemente eliminé demasiadas palabras en el n.º 1594 e incluí tu idea allí (+ un enlace). Continuemos la discusión allí, pero tl;dr sí, me encantaría ver un PoC PR.

¿Cuál es el mejor enfoque para ejecutar un comando localmente a pesar de que el argumento -H está presente, por ejemplo, si quiero combinar la compilación local y rsync con el host remoto en una sola tarea?

Los objetos de @max-arnold Connection tienen un atributo .local que actúa como .run en la máquina local: http://docs.fabfile.org/en/v2/api/connection.html#fabric .conexión.Conexión.local

Ok, supongo que un ejemplo es mejor que las palabras:

<strong i="6">@task</strong>
def build(ctx):
    # should always run locally
    ctx.local('uname -a')


<strong i="7">@task</strong>
def deploy(ctx):
    build(ctx)
    # this one should run on remote host
    ctx.run('uname -a')

La tarea combinada funciona bien:

fab -H host deploy

La tarea local sola falla con AttributeError: No se encontró ningún atributo o clave de configuración para 'local':

fab build

Básicamente, quiero tener una tarea que haga algo localmente, sin importar cómo se haya invocado (con o sin -H ).

Por otro lado, algunos comandos solo están destinados a ejecutarse de forma remota. Si no hay ningún host presente, ctx.run intentará ejecutarlos localmente, lo que puede tener consecuencias inesperadas.

| El usuario ejecuta la tarea | El autor del comando/tarea quiere que se ejecute | ¿Cómo debe comportarse? |
|------------------------------------|------------------------------------ ---|----------------|
| localmente | localmente | el comportamiento de run() está bien (pero violará la intención del autor si se ejecuta de forma remota) |
| localmente | de forma remota | Debería fallar (o solicitar una cadena de host como lo hizo la tela anterior) |
|localmente | de forma local o remota | el comportamiento run() está bien |
| de forma remota | localmente | Siempre debe ejecutarse localmente, pero Context no tiene un método local() para garantizarlo |
| de forma remota | de forma remota | el comportamiento de run() está bien (pero se esperan problemas durante la invocación local) |
| de forma remota | de forma local o remota | el comportamiento run() está bien |

@max-arnold ¡ese es exactamente el número 98! que en realidad no he resuelto completamente todavía. Poniendo algunos pensamientos modernos allí como un comentario... editar: este

He notado lo que parece ser una inconsistencia con sudo.

Donde connection es un servidor remoto, autenticado como raíz.

Intentando expandir tilde como otro usuario que no sea root:

c.sudo("echo bar > ~/foo", user="builder")

Esto tiene éxito, pero en lugar de escribir /home/builder/foo, escribió /root/foo.

Por otro lado, si solo intento ls:

c.sudo("ls", user="builder")

Recibo Permission denied .

Algo se siente mal.

Supongo que cuando Dustin informó lo anterior fuera de banda, fue que se trata de una arruga específica sudo (el comando, no el método), desde la última vez que miré, estamos usando -H y aparentemente no se comporta al 100% como esperábamos.

Hola Jeff,
Como ya estoy trabajando en python 3, ahora mismo estoy usando fabric3 (la portabilidad de fabric 1.x).

Tuve la tentación de probar la migración a la estructura 2, pero de inmediato llegué a un punto muerto. Hago un uso extensivo de las funciones fabric.contrib , pero el documento de migración dice que ya no existe.

Por supuesto, no quiero inflar el código volviendo a su equivalente de shell, y dado que, a juzgar por la cantidad de problemas en contrib.* de fabric 1.x, parece que se usa mucho, creo que es la carencia podría ser un serio obstáculo para la migración de muchos otros.
Encontré un proyecto de mosaico que aparentemente contiene el equivalente de fabric.contrib , pero su código no se actualiza desde hace años.
¿Tiene algún plan para transferir fabric.contrib a la estructura 2?

Gracias,
gabriel

@ garu57 Sí, el plan en este momento es usar patchwork básicamente como "contribución de 2.0". Por el momento, está basado en Fabric 1, pero eso cambiará después de que salga Fabric 2.0.0. Espero que los bits de contribución más utilizados se transfieran rápidamente.

Hola a todos,

A veces mi programa ejecuta un comando remoto, por ejemplo

source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./00-update-kernel.sh'

Veo que los scripts se ejecutan así:

033[0;32m[DONE]\033[0m'
+ return 0
+ alt_test_done_msg 'Prepare evironment'
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
+ exit 0

y también debería ver mi salida de depuración "?" según mi código:

class GenericFabric(object):
    def __init__(self, host, user, key_filename=None, port=22):
        connection_string = "{u}@{h}:{p}".format(u=user, h=host, p=port)
        self.connection = Connection(connection_string)
        self.key_filename = key_filename

    #<strong i="13">@with_settings</strong>
    def generic_cmd(self, command_str, timeout, fabric_timeout, **kwargs):
        """
        Creating remote container from template

        <strong i="14">@type</strong> command_str:     str
        <strong i="15">@param</strong> command_str:    command for execute with VM
        <strong i="16">@type</strong> timeout          int or float
        <strong i="17">@param</strong> timeout         number of seconds for pause
        <strong i="18">@type</strong> fabric_timeout   int or float
        <strong i="19">@param</strong> fabric_timeout  number of seconds for timeout fabric run

        <strong i="20">@rtype</strong>:                FabricResponse
        <strong i="21">@return</strong>:               Return remote status of operation VM
        """
        if fabric_timeout > 0:
            command = self.connection.run(command_str.format(**kwargs),
                                          timeout=fabric_timeout,
                                          warn=True, echo=True)
        else:
            command = self.connection.run(command_str.format(**kwargs),
                                          warn=True, echo=True)
        print("?")
        if timeout > 0:
            sleep(timeout)
        return FabricResponse(command)

    def simple_generic_cmd(self, command_str, **kwargs):
        """
        <strong i="22">@type</strong> command_str:     str
        <strong i="23">@param</strong> command_str:    command for execute with VM

        <strong i="24">@rtype</strong>:                FabricResponse
        <strong i="25">@return</strong>:               Return remote status of operation VM
        """
        return self.generic_cmd(command_str, 0.1, 0, **kwargs)

Pero no hay "?". Así que sugiero que estaban colgados en la ejecución ().

En realidad, mi programa es enorme y hay programación multiproceso. Para atrapar el ahorcamiento, estoy ejecutando comandos remotos con el siguiente código:

class TestingSystemVM(GenericFabric):
#######
    <strong i="7">@signal_alarm_down</strong>
    def run_rpm_test(self, command_test, package, type_of_test="base"):
        """

        """
        signal.signal(signal.SIGALRM, alarm_handler)
        signal.alarm(self.__timeout)
        returned_value = Queue()
        start_time = datetime.utcnow()
        directory, command_test = os.path.split(command_test)
        try:
            if command_test.endswith(".yml"):
                directory = directory.replace("/opt/QA", self.ansible.git_qa_repo)
                output = self.ansible.play_ansible(command_test,
                                                   package,
                                                   directory)
            else:
                vm_instance = (self.host,
                               self.user,
                               self.key_filename,
                               self.os_name,
                               self.platform,
                               self.arch)
                running_test = Process(target=separate_process_running_test,
                                       args=(vm_instance,
                                             returned_value,
                                             directory,
                                             command_test,
                                             package,
                                             type_of_test))
                running_test.start()
                running_test.join(self.__timeout)
                if running_test.is_alive():
                    running_test.terminate()
                    command_test_res = "FAIL: Timeout\n"
                    return command_test_res, work_time(start_time), 1
                elif returned_value.empty():
                    command_test_res = "FAIL: Problem while getting result\n"
                    return command_test_res, work_time(start_time), 1
                else:
                    output = returned_value.get()
        except TimeOut:
            command_test_res = "FAIL: Timeout\n"
            return command_test_res, work_time(start_time), 1
        if output.failed or (package.name in ("lve-utils", "lve-stats") and
                                     "FAIL" in output.stdout):
            res_output = "FAIL: " + output.stdout
        else:
            res_output = output.stdout
        return res_output, work_time(start_time), 0 if output.succeeded else 1

def separate_process_running_test(vm_instance, return_value_queue,
                                  directory, command_test, package,
                                  type_of_test="base"):
    """

    """
    sleep(0.5)

    signal.signal(signal.SIGTERM, kill_fabric_runner)
    signal.signal(signal.SIGINT, kill_fabric_runner)
    (host,
     user,
     key_filename,
     os_name,
     platform,
     arch) = vm_instance
    child_vm_instance = TestingSystemVM(host,
                                        user,
                                        key_filename,
                                        os_name,
                                        platform,
                                        arch,
                                        FakeAnsible())
    if command_test.endswith(".bats"):
        command_test = "/usr/bin/bats --tap " + command_test
    else:
        command_test = os.path.join("./", command_test)

    output = child_vm_instance.simple_generic_cmd(child_vm_instance._c_run_test,
                                                  envvars=child_vm_instance.env_vars,
                                                  exec_test=command_test,
                                                  dir=directory,
                                                  package=package.name,
                                                  pver=package.version,
                                                  prel=package.release,
                                                  type_test=type_of_test)
    print("!")
    return_value_queue.put(output)

Cuando uso fabric2, algunos comandos lanzados desde procesos secundarios se bloquean de vez en cuando.
actualización En realidad, fue mi error en el código. Entonces, fabric2 no contiene colgantes.

Hola todos,
Hice algunos experimentos de lanzamiento y puedo compartir mi experiencia.

En primer lugar, ejecuté el comando desde mi consola.

ssh [email protected] -t "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'"

y eso terminó perfecto y rápido con exit=0:

###
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
* Prepare evironment    [DONE]
+ exit 0
Connection to 192.168.0.34 closed.

Bien.
Luego ejecuté otro comando:

ssh [email protected] "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'"

Eso se terminó tan rápido con exit=0 también:

###
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
+ exit 0

Pero no hay "Conexión a 192.168.0.36 cerrada". No sé si es importante o no.

Después de eso, recreé las máquinas virtuales y lancé el comando fabric2 (desde IPython):

In [1]: from fabric import Connection
In [2]: Connection('[email protected]').run("source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'", pty=True)
....
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
* Prepare evironment    [DONE]
+ exit 0
Out[2]: <Result cmd="source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" exited=0>

Además, corrí con pty=False:

In [1]: from fabric import Connection

In [2]: Connection('[email protected]').run("source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'", pty=False)
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
+ exit 0
Out[2]: <Result cmd="source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" exited=0>

No había "Conexión acerrado." en ambas pruebas. Una vez más, no sé si es importante o no.

En segundo lugar, decidí que no es un buen entorno para mi stand, porque necesito un proceso de lanzamiento desde un niño. Entonces, volví a crear las máquinas virtuales y ejecuté el script con el siguiente código:

In [1]: import subprocess

In [2]: t = subprocess.Popen(""" ssh [email protected] -t "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" """, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True); r = t.communicate()

En el resultado de esta ejecución había "Conexión a 192.168.0.34 cerrada".

Por otro lado

In [1]: import subprocess

In [2]: t = subprocess.Popen(""" ssh [email protected] "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" """, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True); r = t.communicate()

Ambos no han sido ahorcados.

Esta noche lanzaré mis scripts con fabric2 sobre el proceso que se bifurcó y escribiré.
actualización En realidad, fue mi error en el código. Entonces, fabric2 no contiene colgantes.

Sería bueno obtener use_sudo soporte para Transfer.put .

Supongo que la solución más simple por ahora es simplemente hacer un put en algún lugar donde tenga permisos y luego un sudo mv .

@ned2 eso es todo lo que use_sudo realmente puede hacer en get / put todos modos, por ejemplo, así es como lo hace v1. ¡No es posible cargar un archivo "con sudo" hasta donde yo sé! (No sin conectarse como root, lo cual es una mala idea e idealmente ni siquiera está permitido).

Dado el intento de tener una API algo más limpia en v2, es casi más probable que implemente un contenedor en lugar de agrupar ese comportamiento dentro get / put ellos mismos. Tal vez solo algo como Transfer.sudo_put (que llamaría self.put ). De esa manera, el put "puro" se mantiene mínimo.

@bitprophet Me gustaría comenzar agradeciéndole por un software bastante estable y útil con Fabric1 y su enfoque para lanzar Fabric2.

Empecé a jugar con v2 pero tuve un problema con Connection. Estoy usando mi configuración SSH de Fabric 1, Fabric 1 me pedirá una contraseña cuando intente conectarme. Fabric 2 no está haciendo esto y falla indicando que la autenticación ha fallado. No puedo ver en ninguna parte de los documentos v2 que mencione el mecanismo de autenticación para la conexión. Hay una mención de contraseñas con sudo, pero por lo que puedo deducir, esto es después de que la conexión haya sido exitosa de todos modos.

Mi pregunta es si me he perdido algo en los documentos o si se trata de una característica faltante o de un problema.

El código:

<strong i="10">@task</strong>
def testing(c):
    with Connection('MyHostname') as cxn:
        print("Connected")

        cxn.run('ls -l')

El error:

  File /lib/python3.4/site-packages/paramiko/auth_handler.py", line 223, in wait_for_response
    raise e 
paramiko.ssh_exception.AuthenticationException: Authentication failed.

Mi configuración SSH (valores reemplazados para publicar aquí):

Host MyHostname
  HostName replacedhostname.co.uk
  Port 22
  IdentityFile ~/.ssh/id_rsa
  User replaceduser

Estoy en la última versión v2: https://github.com/fabric/fabric/commit/fec3a22ee89900500ae731913fd33f9b56e89f46

Con suerte, resolver esto ayudará a cualquier otra persona con el mismo problema.

Gracias por tu tiempo.

@ Aiky30 Probablemente no seas tú, las cosas de autenticación todavía necesitan trabajo (en gran parte debido a la necesidad de algún trabajo de Paramiko en progreso, por lo que las excepciones de autenticación no son terriblemente difíciles de interpretar correctamente). Creo que en este caso puede ser simplemente que Fab 2 no está interpretando IdentityFile : tomamos host, usuario, puerto y un montón de otras configuraciones, pero IdentityFile sigue siendo TODO.

Eso se debe en parte a que tampoco tratamos con frases de contraseña en este momento (ver arriba: queremos evitar un gran error de Fabric 1 en el que tenemos que hacer conjeturas descabelladas si una falla de autenticación determinada significa que se necesita contraseña o frase de contraseña). Por lo tanto, probablemente pase a un error de "No puedo desbloquear este archivo" después de eso. Y ambos se deben a que uso un agente ssh la mayor parte del tiempo, lo que sería mi primera sugerencia para una solución inmediata.

Dicho esto, creo que probablemente valga la pena piratear tanto IdentityFile como el soporte de configuración de frase de contraseña explícita, porque las claves que no son de agente son probablemente la configuración de autenticación más común número 1, por lo que su falta probablemente significa que la mayoría de los usuarios alfa / beta se quedan en la estacada. . A ver si lo puedo sacar hoy.

Tomó 2.0a para dar una vuelta.

1) También estoy un poco perdido sobre cómo definir y usar hosts. Puedo correr:

   fab -H user<strong i="7">@host</strong>:22 some-task

Pero si no quiero pasar los detalles del host (usuario, host, puerto) cada vez, no estoy seguro de cómo configurar los hosts en fabfile.py ( Connection s o Group ) y luego solo consúltelos. Si entendí https://github.com/fabric/fabric/issues/1591#issuecomment -296343613 correctamente, simplemente no es compatible en este momento (y rastreado en https://github.com/fabric/fabric/issues/1594 )?

2) Además, llegué al problema en el que tengo una clave SSH cifrada (en ~/.ssh/id_rsa ) y tengo ssh-add en ssh-agent . Aparece si enumero las claves a través ssh-add -l . Cuando ejecuto alguna tarea, doy el nombre de usuario adecuado:

   fab -H musttu<strong i="20">@host</strong> sometask

Las cosas funcionan bien. Pero si uso un usuario incorrecto, por ejemplo, fab -H bad_user<strong i="23">@host</strong> sometask , obtengo:

Traceback (most recent call last): ... File "/home/maximus/.virtualenvs/testenv/lib/python3.6/site-packages/paramiko/pkey.py", line 326, in _read_private_key raise PasswordRequiredException('Private key file is encrypted') paramiko.ssh_exception.PasswordRequiredException: Private key file is encrypted

Pero supongo que se incluye en https://github.com/paramiko/paramiko/issues/387 y no es realmente específico de fabric 2.0. Pero sí, se siente raro recibir un error PasswordRequiredException: Private key file is encrypted , cuando el ssh-agent ya tiene la clave descifrada. Si entendí correctamente, después de un inicio de sesión no válido, paramiko volverá a usar la clave directamente, y sin la frase de contraseña proporcionada arrojará este error.

3) Sería bueno permitir funciones de tarea de anotación de tipo (para una mejor finalización automática en IDE). ¿Ha tenido tiempo de considerar https://github.com/pyinvoke/invoke/pull/458 ?

4) Me gusta la idea de la biblioteca de retazos. Para fabric 1.x, hay https://github.com/sebastien/cuisine (que parece bastante muerto) que contiene muchas funciones adicionales (no lo he usado yo mismo). ¿La idea con patchwork es construir algo similar (funciones declarativas de estilo Chef/Ansible/SaltStack, aunque con un alcance reducido)? Siempre he odiado el enfoque YAML/DSL de varios directorios/archivos múltiples que siguen otras herramientas, y me gustaría quedarme en python, para obtener más flexibilidad, una sintaxis menos detallada, finalización automática de IDE, fácil depuración, etc.

5) Simplemente suelte la compatibilidad con py 2.6 y 3.2-3.3 para fabric 2.0. ¿No debería la gente seguir adelante?

@tuukkamustonen - ¡gracias por los comentarios! Respuestas:

  1. De hecho, los roles están cubiertos en el n. ° 1594, y creo que hay otro ticket para el problema relacionado de solo tener datos de configuración por host, además de cómo el soporte de ssh_config lo hace en su propio nivel.

    Decidir cómo conciliar exactamente la configuración a nivel de estructura con ssh_config y luego también con cualquier cosa, desde datos de tiempo de ejecución o de grupo... no es trivial. Aunque definitivamente tiene que suceder pronto; Solo quiero tener una solución a medio pensar en lugar de un primer borrador.

  2. Nuevamente, sí, este es el ticket de Paramiko que mencionó, y su suposición es precisa, la situación del nombre de usuario incorrecto siempre fallará, y dado que Paramiko solo rastrea el último error que encontró, resulta que lo último que intentó fue la copia cifrada en disco de la clave. (Si movió esa clave a otro lugar, por ejemplo, el último error sería otra cosa).

  3. Acabo de comentar sobre ese ticket, puede (o no) duplicar los tickets existentes para la misma característica general. He comentado sobre los más antiguos y IIRC es un "sí, creo que sería bueno siempre que no estropee Python 2". Sin embargo, no tiene una prioridad tan alta como la mayoría de las características más grandes que faltan, por lo que cae en el grupo "necesita un excelente PR con todas las casillas marcadas que pueda fusionar" :)

  4. Sí, vea el n.º 461, que es muy antiguo pero todavía lo tengo en mente. En estos días, la gran pregunta es cómo se escribiría tal biblioteca para abarcar tanto Invoke como Fabric; en muchos/la mayoría de los casos, uno puede simplemente escribir tareas de invocación genéricas que no "conocen" ningún contexto local/remoto dividido, que se puede entregar a un contexto de conexión Fabric cuando uno quiere ejecutarlas en un sistema remoto.

    Tales tareas "independientes del contexto" querrían vivir en la biblioteca de 'invocaciones' (o alguna otra biblioteca aún específica de Invoke); pero algunos (por ejemplo, cualquier cosa que involucre la transferencia de archivos y no solo los comandos de shell) deberían ser "conscientes de Fabric". Averiguar cómo cerrar esa brecha es el problema.

    Podría seguir la ruta de "que lib solo requiere invocar, no requiere tejido, _pero_ un subconjunto de tareas se quejará si no instala tejido y les entrega un contexto de conexión". Podría dividirse en dos bibliotecas (con la orientada a Fabric que requiere la Invocación más genérica), etc.

  5. Recientemente, esto definitivamente está en las cartas, vea paramiko/paramiko#1070 y/o pyinvoke/invoke#364. Invoke 1.0, Fabric 2.0 y Paramiko 3.0 (o, _tal vez_, un 2.4/2.5/lo que sea) serán todos Python 2.7/3.4 y posteriores.

Alrededor de 1):

Estoy seguro de que ya lo sabe, pero es posible que desee obtener algunas ideas de los inventarios de Ansible . O tal vez no :).

Acerca de (4):

Creo que https://github.com/pyinvoke/invocations es demasiado obstinado para esto. Las invocaciones proporcionan _convenciones_ y pueden construirse sobre un paquete de estilo cuisine/patchwork, pero yo no mezclaría convenciones (cómo liberar o doctest) con utilidades (cómo copiar archivos o modificar permisos).

No veo ningún problema en poner utilidades para operaciones solo locales, solo remotas y locales + remotas en la misma biblioteca (mosaico). Qué operación admite qué modo se puede abordar como documentación (como cadena de documentación, generada automáticamente a partir de anotaciones, etc.).

Esto se siente mejor que dividir la lógica en más de 2 paquetes. Porque, ¿qué sucede si primero agrega una operación a su paquete "solo de invocación" (y puede haber incluso operaciones "solo remotas") y luego agrega soporte para que funcione también en servidores remotos? ¿Moverías, copiarías o extenderías el código? En cualquier caso, es más trabajo y el usuario necesita una importación diferente, etc., por lo que suena un poco engorroso.

¿Qué puedo hacer para pulir esto lo suficiente como para usar PyPi?

@haydenflinner ¡Estará sucediendo durante la próxima semana o dos! (El objetivo es publicar antes de subirme a mi avión a PyCon, que es el 10 de mayo).

Por ejemplo, consulte los documentos de actualización actualizados recientemente en los que estaba trabajando esta semana: http://docs.fabfile.org/en/v2/upgrading.html

De hecho, también puedo cerrar este ticket ahora, ya que pronto aceptaré los reales para 2.0.0 y superiores 👍

Tenga en cuenta que todavía pueden comentar aquí si lo desean. Tenga en cuenta que espero realizar al menos algunas partes del trabajo de funciones antes del lanzamiento, junto con toda la preparación para la gestión de proyectos.

Miré fabric v2 hoy y lo siento, simplemente no me atrevo a usarlo.

  1. ¿Adónde fueron los roledefs? ¿Por qué ya no puedo pasar un nombre de rol en la línea de comando? ¿Se supone que debo implementar esto yo mismo?
  2. ¿Por qué ya no puedo pasar argumentos a tareas en la línea de comando? ¿Se supone que debo implementar esto yo mismo también?
  3. ¿Por qué el parámetro -H tiene que ir antes del parámetro de tarea? Debería ser de otra manera. Esto es tan horrible.

Las tareas aceptan argumentos, pero la sintaxis cambió. Consulte http://docs.pyinvoke.org/en/1.1/concepts/invoking-tasks.html#task-command-line-arguments

@dgarstang ¡Es posible que desee considerar adoptar un tono más neutral o empático con las personas que le brindan su trabajo gratis! Solo digo 😉

  1. Ver #1594, cuyo IIRC está vinculado en el documento de actualización
  2. @ploxiln te cubre las espaldas aquí
  3. (Parcialmente) ver #1772 que se fusionó con el maestro y saldrá pronto; agrega la capacidad de usar @task(hosts=xxx) .

(re: 3: En términos de dar --hosts y amigos como si fueran argumentos por tarea, eso es algo que podría agregar en algún momento, se han desgarrado sobre si vale la pena. Similar a por tarea --help , cuantas más exclusiones "mágicas" agreguemos, mayor será la probabilidad de que un usuario intente usar ese mismo nombre para sus propios argumentos de tarea y se confunda cuando se rompa).

¿Fue útil esta página
0 / 5 - 0 calificaciones