Come impostare gli host di destinazione in Tessuto file

Voglio usare il Tessuto per distribuire la mia applicazione web di codice di sviluppo, produzione e messa in scena server. Il mio 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

Esempio di output:

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

Quando creo un set_hosts() attività come mostrato nella Tessuto docs, env.padroni di casa è impostato correttamente. Tuttavia, questo non è un’opzione praticabile, né è un decoratore. Il passaggio di eserciti sulla riga di comando con il risultato finale di un qualche tipo di script di shell che chiama il fabfile, io preferirei avere un unico strumento per fare il lavoro correttamente.

Si dice in Tessuto documenti che ” env.padroni di casa è semplicemente una lista Python oggetto’. Dalle mie osservazioni, questo è semplicemente non vero.

Qualcuno può spiegare cosa sta succedendo qui ? Come posso impostare l’host da distribuire ?

  • Ho lo stesso problema, hai trovato qualche soluzione?
  • per eseguire la stessa operazione su più server, utilizzare “fab -H temporanea server di produzione del server di distribuire”… più in la mia risposta qui sotto: stackoverflow.com/a/21458231/26510
  • Prova questo: docs.fabfile.org/en/1.13/usage/env.html#passwords
  • Questa risposta non si applica al tessuto 2+. Se qualcuno più familiarità con Stackoverflow convenzioni potuto modificare la domanda o un titolo di riferimento per il tessuto 1 potrebbe essere utile.
InformationsquelleAutor ssc | 2010-02-24

 

15 Replies
  1. 128

    Faccio dichiarando di una funzione reale per ogni ambiente. Per esempio:

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

    Utilizzando le funzioni di cui sopra, vorrei digitare il seguente distribuzione per il mio ambiente di test:

    fab test deploy

    …e la seguente distribuzione di produzione:

    fab prod deploy

    La cosa bella di questo metodo è che il test e prod funzioni possono essere utilizzate prima di qualsiasi fab funzione, non solo la distribuzione. È incredibilmente utile.

    • A causa di un bug nel tessuto (code.fabfile.org/issues/show/138#change-1497) è meglio includere utente host string (come [email protected]) invece di impostare env.utente.
    • Ho avuto lo stesso problema, e questo mi sembra la soluzione migliore. Definire l’host, utente e un sacco di altre impostazioni in un file YAML che viene caricato dal dev() e prod() funzioni. (In modo che posso riutilizzare lo stesso Tessuto script per progetti simili.)
    • Quando ho seguito il tuo link, ho visto “Welcome to nginx!“. Tutte le richieste di code.fabfile.org dominio di avere risposte del genere.
    • Sì, sembra che tutti i bug sono stati migrati su github.
    • Purtroppo, sembra che questo non funziona più – tessuto non eseguire operazioni senza env.padroni di casa già definito, e non esegue le funzioni in fab A B C stile senza di loro, può essere definita attività.
    • docs.fabfile.org/en/1.10/usage/… rivendicazioni funziona ancora
    • Sto usando 1.11.1 e posso confermare questo approccio non funziona per me.

  2. 75

    Utilizzare 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')

    Scegliere di ruolo con -R:

    $ fab -R test deploy
    [localhost] Executing task 'deploy'
    ...
    • O se l’attività è sempre in esecuzione sullo stesso ruolo, è possibile utilizzare il @ruoli() decoratore sul compito.
    • Suona come roledefs è una soluzione migliore definizione, compiti separati.
    • E ‘ davvero funziona,grazie.
    • Qualcuno sa come posso includere una password per il nome utente in un roledef? Un’ulteriore voce di dizionario 'password': 'some_password' sembra essere ignorato e conduce a un prompt in fase di runtime.
    • è possibile utilizzare env.le password che è un dizionario contenente utente+host+porta chiavi e password come valore. E. g. env.password={‘[email protected]:22’ : ‘password’}
  3. 49

    Qui una versione più semplice di serverhorrors risposta:

    from fabric.api import settings
    
    def mystuff():
        with settings(host_string='192.0.2.78'):
            run("hostname -f")
    • Per documentazione, le impostazioni contesto manager per l’override env variabili, non per l’impostazione inizialmente. Credo che roledefs, come thomie suggerito, è la più appropriata per la definizione dei padroni di casa come fase di sviluppo e test.
  4. 21

    Stato bloccato su di me, ma alla fine ha capito. Semplicemente non impostare la env.configurazione degli host da entro un compito. Ogni operazione viene eseguita N volte, una per ogni Host specificato, in modo che l’impostazione è, fondamentalmente, al di fuori di attività ambito.

    Guardando il tuo codice di cui sopra, si potrebbe semplicemente fare così:

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

    Che sembra come avrebbe fatto, cosa hai intenzione.

    O è possibile scrivere codice personalizzato in ambito globale che analizza gli argomenti manualmente, e set di env.padroni di casa prima che il vostro compito, la funzione è definita. Per un paio di motivi, che in realtà come ho il mio set up.

    • Trovato un modo: from fabric.api import env; env.host_string = "dev"
  5. 18

    Dal fab 1.5 questo è un documentato modo per impostare dinamicamente padroni di casa.

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

    Citazione dal doc di seguito.

    Utilizzo di eseguire in modo dinamico-set host liste

    Un comune intermedio-avanzato caso di utilizzo di Tessuto è
    parametri di ricerca di host di destinazione elenco in fase di esecuzione (quando l’uso di
    Ruoli non è sufficiente). eseguire possono rendere estremamente semplice, come
    quindi:

    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)
    • +1. Un sacco di veramente buone risposte verso il fondo della pagina qui.
  6. 10

    Al contrario di alcune altre risposte, è possibile modificare il env variabili di ambiente all’interno di un task. Tuttavia, questo env saranno utilizzati solo per le successive operazioni eseguite utilizzando il fabric.tasks.execute funzione.

    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

    Senza avvolgere sub-compiti in execute(...), il vostro livello di modulo env impostazioni o tutto ciò che è passato dal fab CLI verrà utilizzato.

    • Questa è la risposta migliore se si desidera impostare dinamicamente env.padroni di casa.
  7. 9

    È necessario impostare host_string un esempio potrebbe essere:

    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, ))
    • Dolce. Ho postato una versione più semplice del codice in un’altra risposta qui.
  8. 9

    Per spiegare perché è anche un problema. Il comando fab sta sfruttando il tessuto libreria per eseguire i compiti sulla lista degli host. Se si prova a modificare l’elenco di host all’interno di una attività, si sta essenzialmente il tentativo di modificare un elenco a scorrere su di esso. O nel caso in cui si dispone di host definito, loop su una lista vuota dove il codice in cui è possibile impostare l’elenco per eseguire un ciclo non viene mai eseguito.

    L’uso di env.host_string è un aggirare questo comportamento solo a specificare direttamente alle funzioni quali host per connettersi con. Questo è causa di alcuni problemi che dovrai rifare il ciclo di esecuzione, se si desidera avere un numero di host per eseguire.

    Il modo più semplice per le persone a fare la possibilità di impostare i padroni di casa in fase di esecuzione, è quello di mantenere la env populatiing come una distinta operazione, che consente di impostare tutti gli host stringhe, utenti, etc. Poi si esegue la distribuzione di attività. Assomiglia a questo:

    fab production deploy

    o

    fab staging deploy

    Dove la produzione e messa in scena sono come le attività che avete dato, ma non chiamare la prossima attività. Il motivo per cui si dispone di un lavoro come questo, è che l’attività deve finire, e interrompere il ciclo (di eserciti, nella env caso Nessuno, ma è un loop di uno, a quel punto), e poi il ciclo su i padroni di casa (ora definita dal precedente attività) di nuovo.

  9. 3

    È necessario modificare env.padroni di casa al livello di modulo, non all’interno di un task funzione. Ho fatto lo stesso errore.

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

    È molto semplice. Basta inizializzare la env.host_string variabile e tutti i seguenti comandi saranno eseguiti su questo host.

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

    Sono totalmente nuovo di tessuto, ma per ottenere un tessuto per eseguire gli stessi comandi su più host (ad esempio, per distribuire su più server, in un unico comando) è possibile eseguire:

    fab -H staging-server,production-server deploy 

    dove temporanea server e produzione-server sono 2 server di cui si desidera eseguire il deploy di azione contro. Ecco un semplice fabfile.py in cui verrà visualizzato il nome OS. Si noti che il fabfile.py dovrebbe essere nella stessa directory in cui si esegue il fab comando.

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

    Questo funziona con tessuto 1.8.1 almeno.

  12. 3

    Così, per i padroni di casa, e hanno i comandi eseguiti in tutti i padroni di casa, si deve iniziare con:

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

    Una volta che questi sono definiti, quindi eseguire il comando sulla riga di comando:

    fab PROD deploy:1.5

    Ciò che verrà eseguito il compito di distribuire su tutti i server elencati nella PROD funzione, come si imposta il env.padroni di casa prima dell’esecuzione dell’attività.

    • Supponiamo che la distribuzione sul primo host ha funzionato, ma l’uno il secondo errore, come faccio a farlo di nuovo solo sul secondo?
  13. 2

    Ecco un altro “summersault” pattern che consente la fab my_env_1 my_command uso:

    Con questo modello, abbiamo solo da definire gli ambienti di una volta l’uso di un dizionario. env_factory crea funzioni di base i nomi delle chiavi di ENVS. Ho messo ENVS nella propria directory e file secrets.config.py di configurazione separati dal codice tessuto.

    Lo svantaggio è che, come scritto, aggiungendo il @task decoratore si rompere.

    Note: usiamo def func(k=k): invece di def func(): in fabbrica a causa di l’associazione tardiva. Otteniamo il modulo in esecuzione con questa soluzione e patch per definire la funzione.

    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
  14. 0

    Tramite ruoli è attualmente considerata la “corretta” e “corretto” modo di fare questo ed è quello che si “dovrebbe” fare.

    Detto questo, se siete come la maggior parte di quello che “vorrei” o “desiderio” è la possibilità di eseguire un “twisted syster” o di commutazione sistemi di destinazione al volo.

    Così solo per scopi di intrattenimento (!) il seguente esempio illustra ciò che molti potrebbero considerare a rischio, e ancora in qualche modo completamente soddisfacente, manovra che va qualcosa come questo:

    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")

    Poi eseguire:

    fab perform_sumersault

Lascia un commento