software - ¿El tejido python es compatible con el conjunto dinámico env.hosts?
pip install fabric (3)
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 ir dinámico 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:</path/to/config.cfg>
''''''
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
########################################
# B-O-F 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 <whatever> related hosts
#
#
[main]
aws_key = <key>
aws_sec = <secret>
fabric_ssh_user = <your_user>
fabric_ssh_key_filename = /path/to/your/.ssh/<whatever>.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-[d-s]01
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?
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 instancia que acaba de crearse por 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í). execute 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.
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...
Usaría esto para encadenar las tareas como la fab staging deploy
fab production deploy
o la fab production deploy
.