¿El tejido python es compatible con el conjunto dynamic env.hosts?

Quiero cambiar el env.hosts dinámicamente porque a veces quiero implementar primero en una máquina, verifique si está bien y luego implementar en muchas máquinas. Actualmente necesito configurar env.hosts primero, ¿cómo podría configurar env.hosts en un método y no en global al inicio del script?

Sí, puedes configurar env.hosts dinámicamente. Un patrón común que utilizamos es:

 from fabric.api import env def staging(): env.hosts = ['XXX.XXX.XXX.XXX', ] def production(): env.hosts = ['YYY.YYY.YYY.YYY', 'ZZZ.ZZZ.ZZZ.ZZZ', ] def deploy(): # Do something... 

Utilizaría esto para encadenar las tareas como la fab staging deploy fab production deploy o la fab production deploy .

Más o menos tarde en la fiesta, pero logré esto con ec2 así (nota en EC2, no sabes cuál puede ser el ip / nombre de host, en general, por lo que casi tienes que ser dynamic para tener en cuenta cómo funciona el entorno / los sistemas. podría surgir – otra opción sería usar dyndns, pero esto aún sería útil):

 from fabric.api import * import datetime import time import urllib2 import ConfigParser from platform_util import * config = ConfigParser.RawConfigParser() @task def load_config(configfile=None): ''' ***REQUIRED*** Pass in the configuration to use - usage load_config: ''' if configfile != None: # Load up our config file config.read(configfile) # Key/secret needed for aws interaction with boto # (anyone help figure out a better way to do this with sub modules, please don't say classes :-) ) global aws_key global aws_sec aws_key = config.get("main","aws_key") aws_sec = config.get("main","aws_sec") # Stuff for fabric env.user = config.get("main","fabric_ssh_user") env.key_filename = config.get("main","fabric_ssh_key_filename") env.parallel = config.get("main","fabric_default_parallel") # Load our role definitions for fabric for i in config.sections(): if i != "main": hostlist = [] if config.get(i,"use-regex") == 'yes': for x in get_running_instances_by_regex(aws_key,aws_sec,config.get(i,"security-group"),config.get(i,"pattern")): hostlist.append(x.private_ip_address) env.roledefs[i] = hostlist else: for x in get_running_instances(aws_key,aws_sec,config.get(i,"security-group")): hostlist.append(x.private_ip_address) env.roledefs[i] = hostlist if config.has_option(i,"base-group"): if config.get(i,"base-group") == 'yes': print "%s is a base group" % i print env.roledefs[i] # env["basegroups"][i] = True 

donde get_running_instances y get_running_instances_by_regex son funciones de utilidad que hacen uso de boto ( http://code.google.com/p/boto/ )

ex:

 import logging import re from boto.ec2.connection import EC2Connection from boto.ec2.securitygroup import SecurityGroup from boto.ec2.instance import Instance from boto.s3.key import Key ######################################## # BOF get_instances ######################################## def get_instances(access_key=None, secret_key=None, security_group=None): ''' Get all instances. Only within a security group if specified., doesnt' matter their state (running/stopped/etc) ''' logging.debug('get_instances()') conn = EC2Connection(aws_access_key_id=access_key, aws_secret_access_key=secret_key) if security_group: sg = SecurityGroup(connection=conn, name=security_group) instances = sg.instances() return instances else: instances = conn.get_all_instances() return instances 

Aquí hay una muestra de cómo se veía mi configuración:

 # Config file for fabric toolset # # This specific configuration is for  related hosts # # [main] aws_key =  aws_sec =  fabric_ssh_user =  fabric_ssh_key_filename = /path/to/your/.ssh/.pem fabric_default_parallel = 1 # # Groupings - Fabric knows them as roledefs (check env dict) # # Production groupings [app-prod] security-group = app-prod use-regex = no pattern = [db-prod] security-group = db-prod use-regex = no pattern = [db-prod-masters] security-group = db-prod use-regex = yes pattern = mysql-[ds]01 

Otra nueva respuesta a una vieja pregunta. 🙂 Pero recientemente me encontré intentando configurar hosts de forma dinámica, y realmente tengo que estar en desacuerdo con la respuesta principal. Mi idea de dinámica , o al menos lo que intentaba hacer, era tomar un nombre de DNS de la instancia que acababa de crear con boto y acceder a esa instancia con un comando fab. No pude realizar el fab staging deploy , porque la instancia no existe en el momento de la edición de archivos fab.

Afortunadamente, fabric admite una asignación de host verdaderamente dinámica con execute . (Es posible que esto no existiera cuando se hizo la pregunta por primera vez, por supuesto, pero ahora sí). Ejecutar le permite definir una función a la que llamar, y el env.hosts que debe usar para ese comando. Por ejemplo:

 def create_EC2_box(data=fab_base_data): conn = boto.ec2.connect_to_region(region) reservations = conn.run_instances(image_id=image_id, ...) ... return instance.public_dns_name def _ping_box(): run('uname -a') run('tail /var/log/cloud-init-output.log') def build_box(): box_name = create_EC2_box(fab_base_data) new_hosts = [box_name] # new_hosts = ['ec2-54-152-152-123.compute-1.amazonaws.com'] # testing execute(_ping_box, hosts=new_hosts) 

Ahora puedo hacer fab build_box , y se activará una llamada de boto que crea una instancia y otra llamada de fabric que se ejecuta en la nueva instancia, sin tener que definir el nombre de la instancia en el momento de la edición.