xticks barplot python host fabric

python - barplot - Cómo establecer hosts de destino en el archivo Fabric



pandas plot (15)

Deseo utilizar Fabric para implementar mi código de aplicación web en servidores de desarrollo, producción y producción. Mi fabfile:

def deploy_2_dev(): deploy(''dev'') def deploy_2_staging(): deploy(''staging'') def deploy_2_prod(): deploy(''prod'') def deploy(server): print ''env.hosts:'', env.hosts env.hosts = [server] print ''env.hosts:'', env.hosts

Muestra de salida:

host:folder user$ fab deploy_2_dev env.hosts: [] env.hosts: [''dev''] No hosts found. Please specify (single) host string for connection:

Cuando creo una tarea set_hosts() como se muestra en los documentos Fabric , env.hosts se configura correctamente. Sin embargo, esta no es una opción viable, tampoco lo es un decorador. Pasar hosts en la línea de comando finalmente resultaría en algún tipo de script de shell que llame al fabfile, yo preferiría que una sola herramienta hiciera el trabajo correctamente.

Dice en los documentos Fabric que ''env.hosts es simplemente un objeto de lista de Python''. Según mis observaciones, esto simplemente no es cierto.

¿Alguien puede explicar lo que está pasando aquí? ¿Cómo puedo configurar el host para implementar?


Aquí hay otro patrón de "summersault" que habilita el fab my_env_1 my_command usage:

Con este patrón, solo tenemos que definir entornos una vez usando un diccionario. env_factory crea funciones basadas en los nombres clave de ENVS . Puse ENVS en su propio directorio y archivo secrets.config.py para separar la configuración del código de la tela.

El inconveniente es que, tal como está escrito, agregar el decorador @task lo romperá .

Notas: Utilizamos def func(k=k): lugar de def func(): en la fábrica debido a la vinculación tardía . Obtenemos el módulo en ejecución con esta solución y lo aplicamos para definir la función.

secrets.config.py

ENVS = { ''my_env_1'': { ''HOSTS'': [ ''host_1'', ''host_2'', ], ''MY_OTHER_SETTING'': ''value_1'', }, ''my_env_2'': { ''HOSTS'': [''host_3''], ''MY_OTHER_SETTING'': ''value_2'' } }

fabfile.py

import sys from fabric.api import env from secrets import config def _set_env(env_name): # can easily customize for various use cases selected_config = config.ENVS[env_name] for k, v in selected_config.items(): setattr(env, k, v) def _env_factory(env_dict): for k in env_dict: def func(k=k): _set_env(k) setattr(sys.modules[__name__], k, func) _env_factory(config.ENVS) def my_command(): # do work


Aquí hay una versión más simple de la respuesta de serverhorrors :

from fabric.api import settings def mystuff(): with settings(host_string=''12.34.56.78''): run("hostname -f")


Contrariamente a algunas otras respuestas, es posible modificar las variables de entorno env dentro de una tarea. Sin embargo, este env solo se usará para tareas posteriores ejecutadas con la función fabric.tasks.execute .

from fabric.api import task, roles, run, env from fabric.tasks import execute # Not a task, plain old Python to dynamically retrieve list of hosts def get_stressors(): hosts = [] # logic ... return hosts @task def stress_test(): # 1) Dynamically generate hosts/roles stressors = get_stressors() env.roledefs[''stressors''] = map(lambda x: x.public_ip, stressors) # 2) Wrap sub-tasks you want to execute on new env in execute(...) execute(stress) # 3) Note that sub-tasks not nested in execute(...) will use original env clean_up() @roles(''stressors'') def stress(): # this function will see any changes to env, as it was wrapped in execute(..) run(''echo "Running stress test..."'') # ... @task def clean_up(): # this task will NOT see any dynamic changes to env

Sin envolver subtareas en execute(...) , se env configuraciones env nivel de módulo o lo que sea que pase desde la CLI fab .


Desde fab 1.5, esta es una forma documentada de establecer hosts dinámicamente.

http://docs.fabfile.org/en/1.7/usage/execution.html#dynamic-hosts

Cita del documento a continuación.

Uso de ejecutar con listas de host establecidas dinámicamente

Un caso común de uso intermedio a avanzado para Fabric es parametrizar la búsqueda de la lista de host de destino en el tiempo de ejecución (cuando el uso de Roles no es suficiente). ejecutar puede hacer que esto sea extremadamente simple, así:

from fabric.api import run, execute, task # For example, code talking to an HTTP API, or a database, or ... from mylib import external_datastore # This is the actual algorithm involved. It does not care about host # lists at all. def do_work(): run("something interesting on a host") # This is the user-facing task invoked on the command line. @task def deploy(lookup_param): # This is the magic you don''t get with @hosts or @roles. # Even lazy-loading roles require you to declare available roles # beforehand. Here, the sky is the limit. host_list = external_datastore.query(lookup_param) # Put this dynamically generated host list together with the work to be # done. execute(do_work, hosts=host_list)


El uso de roles actualmente se considera la forma "correcta" y "correcta" de hacer esto y es lo que "debería" hacer.

Dicho eso, si eres como la mayoría de lo que "te gustaría" o "deseas" es la capacidad de realizar un "syster retorcido" o cambiar los sistemas de destino sobre la marcha.

Por lo tanto, solo para fines de entretenimiento (!) El siguiente ejemplo ilustra lo que muchos podrían considerar como una maniobra arriesgada, pero de alguna manera totalmente satisfactoria, que dice algo como esto:

env.remote_hosts = env.hosts = [''10.0.1.6''] env.remote_user = env.user = ''bob'' env.remote_password = env.password = ''password1'' env.remote_host_string = env.host_string env.local_hosts = [''127.0.0.1''] env.local_user = ''mark'' env.local_password = ''password2'' def perform_sumersault(): env_local_host_string = env.host_string = env.local_user + ''@'' + env.local_hosts[0] env.password = env.local_password run("hostname -f") env.host_string = env.remote_host_string env.remote_password = env.password run("hostname -f")

Luego corriendo:

fab perform_sumersault


Es muy sencillo. Simplemente inicialice la variable env.host_string y todos los siguientes comandos se ejecutarán en este host.

from fabric.api import env, run env.host_string = ''[email protected]'' def foo: run("hostname -f")


Estaba atrapado en esto yo mismo, pero finalmente lo descubrí. Simplemente no puede establecer la configuración env.hosts desde dentro de una tarea. Cada tarea se ejecuta N veces, una por cada Host especificado, por lo que la configuración está fundamentalmente fuera del alcance de la tarea.

Mirando su código anterior, simplemente podría hacer esto:

@hosts(''dev'') def deploy_dev(): deploy() @hosts(''staging'') def deploy_staging(): deploy() def deploy(): # do stuff...

Que parece que haría lo que estás pensando.

O puede escribir algún código personalizado en el ámbito global que analiza los argumentos de forma manual y establece env.hosts antes de que se defina su función. Por algunas razones, así es como configuré la mía.


Lo hago al declarar una función real para cada entorno. Por ejemplo:

def test(): env.user = ''testuser'' env.hosts = [''test.server.com''] def prod(): env.user = ''produser'' env.hosts = [''prod.server.com''] def deploy(): ...

Usando las funciones anteriores, escribiría lo siguiente para implementar en mi entorno de prueba:

fab test deploy

... y lo siguiente para implementar en producción:

fab prod deploy

Lo bueno de hacerlo de esta manera es que las funciones de test y prod se pueden utilizar antes que cualquier función fab, no solo implementar. Es increíblemente útil.


Necesita establecer host_string un ejemplo sería:

from fabric.context_managers import settings as _settings def _get_hardware_node(virtualized): return "localhost" def mystuff(virtualized): real_host = _get_hardware_node(virtualized) with _settings( host_string=real_host): run("echo I run on the host %s :: `hostname -f`" % (real_host, ))


Necesita modificar env.hosts a nivel de módulo, no dentro de una función de tarea. Yo cometí el mismo error.

from fabric.api import * def _get_hosts(): hosts = [] ... populate ''hosts'' list ... return hosts env.hosts = _get_hosts() def your_task(): ... your task ...


Para explicar por qué es incluso un problema. El comando fab está aprovechando el tejido de la biblioteca para ejecutar las tareas en las listas de host. Si intenta cambiar la lista de host dentro de una tarea, está intentando esencialmente cambiar una lista mientras la itera. O en el caso de que no tenga hosts definidos, recorra una lista vacía donde nunca se ejecuta el código donde estableció la lista para que se repita.

El uso de env.host_string es una alternativa para este comportamiento solo porque especifica directamente las funciones con qué hosts conectarse. Esto ocasiona algunos problemas en el sentido de que estará rehaciendo el bucle de ejecución si desea tener varios hosts para ejecutar.

La forma más sencilla en que las personas tienen la capacidad de establecer hosts en tiempo de ejecución es mantener el env populatiing como una tarea distinta, que configura todas las cadenas de host, usuarios, etc. Luego ejecutan la tarea de implementación. Se parece a esto:

fab production deploy

o

fab staging deploy

Donde la puesta en escena y la producción son como las tareas que has dado, pero ellas mismas no convocan la siguiente tarea. La razón por la que tiene que funcionar así, es que la tarea tiene que terminar y salir del ciclo (de hosts, en el caso env Ninguno, pero es un ciclo de uno en ese punto), y luego tener el ciclo terminado los hosts (ahora definidos por la tarea anterior) de nuevo.


Por lo tanto, para configurar los hosts y ejecutar los comandos en todos los hosts, debe comenzar por:

def PROD(): env.hosts = [''10.0.0.1'', ''10.0.0.2''] def deploy(version=''0.0''): sudo(''deploy %s'' % version)

Una vez que se definen, ejecuta el comando en la línea de comando:

fab PROD deploy:1.5

Lo que ejecutará la tarea de implementación en todos los servidores enumerados en la función PROD, ya que establece los entornos env.antes antes de ejecutar la tarea.


Puede asignar a env.hoststring antes de ejecutar una subtarea. Asigne a esta variable global en un bucle si desea iterar en varios hosts.

Desafortunadamente para ti y para mí, la tela no está diseñada para este caso de uso. Consulte la función main en http://github.com/bitprophet/fabric/blob/master/fabric/main.py para ver cómo funciona.


Soy totalmente nuevo en el tejido, pero para hacer que Fabric ejecute los mismos comandos en varios hosts (por ejemplo, para implementar en varios servidores, en un solo comando), puede ejecutar:

fab -H staging-server,production-server deploy

donde staging-server y production-server son 2 servidores con los que desea ejecutar la acción de implementación. Aquí hay un fabfile.py simple que mostrará el nombre del sistema operativo. Tenga en cuenta que fabfile.py debe estar en el mismo directorio donde ejecuta el comando fab.

from fabric.api import * def deploy(): run(''uname -s'')

Esto funciona con fabric 1.8.1 al menos.


Usa roledefs

from fabric.api import env, run env.roledefs = { ''test'': [''localhost''], ''dev'': [''[email protected]''], ''staging'': [''[email protected]''], ''production'': [''[email protected]''] } def deploy(): run(''echo test'')

Elija el rol con -R:

$ fab -R test deploy [localhost] Executing task ''deploy'' ...