python फैब्रिक फ़ाइल में लक्ष्य होस्ट कैसे सेट करें




host fabric (12)

यह बहुत सरल है। बस env.host_string चर प्रारंभ करें और निम्न सभी आदेश इस होस्ट पर निष्पादित किए जाएंगे।

from fabric.api import env, run

env.host_string = '[email protected]'

def foo:
    run("hostname -f")

मैं अपने वेब ऐप कोड को विकास, स्टेजिंग और उत्पादन सर्वर पर तैनात करने के लिए फैब्रिक का उपयोग करना चाहता हूं। मेरा 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

नमूना उत्पादन:

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

जब मैं फैब्रिक डॉक्स में दिखाए गए set_hosts() कार्य को बनाता हूं, env.hosts ठीक से सेट होता है। हालांकि, यह एक व्यवहार्य विकल्प नहीं है, न ही एक सजावटी है। कमांड लाइन पर मेजबान पास करने के परिणामस्वरूप अंततः किसी प्रकार की शेल स्क्रिप्ट होती है जो fabfile को कॉल करती है, मैं एक एकल उपकरण को सही तरीके से काम करना पसंद करूंगा।

यह फैब्रिक डॉक्स में कहता है कि 'env.hosts बस एक पायथन सूची वस्तु है'। मेरे अवलोकन से, यह बस सच नहीं है।

क्या कोई यहां समझा सकता है कि क्या हो रहा है? मैं मेजबान को तैनात करने के लिए कैसे सेट कर सकता हूं?


यहां एक और "Summersault" पैटर्न है जो fab my_env_1 my_command उपयोग को सक्षम बनाता है:

इस पैटर्न के साथ, हमें केवल एक शब्दकोश का उपयोग करके वातावरण को परिभाषित करना होगा। env_factory ENVS के ENVS नामों के आधार पर कार्य बनाता है। मैं ENVS को अपनी निर्देशिका में ENVS हूं और ENVS कोड से कॉन्फ़िगर को अलग करने के लिए secrets.config.py फ़ाइल करता हूं।

दोष यह है कि, लिखित रूप में, @task सजावट जोड़ने से इसे तोड़ दिया जाएगा।

नोट्स: हम def func(k=k): def func(): कारखाने में देर से बाध्यकारी के कारण । हम इस समाधान के साथ चल रहे मॉड्यूल प्राप्त करते हैं और फ़ंक्शन को परिभाषित करने के लिए इसे पैच करते हैं।

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

सर्वरहोर्स उत्तर का एक सरल संस्करण यहां दिया गया है :

from fabric.api import settings

def mystuff():
    with settings(host_string='12.34.56.78'):
        run("hostname -f")

आप subtask निष्पादित करने से पहले env.hoststring को असाइन कर सकते हैं। यदि आप एकाधिक होस्टों पर पुन: प्रयास करना चाहते हैं तो इस ग्लोबल वैरिएबल को लूप में असाइन करें।

दुर्भाग्यवश आपके और मेरे लिए, कपड़े इस उपयोग के मामले के लिए डिज़ाइन नहीं किया गया है। यह कैसे काम करता है यह देखने के लिए http://github.com/bitprophet/fabric/blob/master/fabric/main.py पर main फ़ंक्शन देखें।


आपको host_string सेट करने की आवश्यकता है एक उदाहरण होगा:

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

यह बताने के लिए कि यह भी एक मुद्दा क्यों है। कमांड फैब मेजबान सूचियों पर कार्यों को चलाने के लिए पुस्तकालय को पुस्तकालय का लाभ उठा रहा है। यदि आप किसी कार्य के अंदर होस्ट सूची को आज़माकर बदलते हैं, तो आप इसे सक्रिय करते समय सूची बदलने की कोशिश कर रहे हैं। या उस स्थिति में जहां आपके पास कोई मेजबान परिभाषित नहीं है, एक खाली सूची पर लूप करें जहां कोड जहां आप लूप को सूची सेट करते हैं, कभी निष्पादित नहीं होता है।

Env.host_string का उपयोग केवल इस व्यवहार के लिए एक कार्य है जिसमें यह केवल उन कार्यों के लिए निर्दिष्ट है जो मेजबान से कनेक्ट होते हैं। इससे कुछ समस्याएं उत्पन्न होती हैं यदि आप निष्पादन लूप को रीमेक कर रहे हैं यदि आप कई होस्टों को निष्पादित करना चाहते हैं।

लोगों को रन टाइम पर मेजबान सेट करने की क्षमता का सबसे आसान तरीका है, env populatiing को एक अलग कार्य के रूप में रखना है, जो सभी होस्ट स्ट्रिंग्स, उपयोगकर्ता इत्यादि सेट करता है। फिर वे तैनाती कार्य चलाते हैं। यह इस तरह दिख रहा है:

fab production deploy

या

fab staging deploy

जहां स्टेजिंग और उत्पादन आपके द्वारा दिए गए कार्यों की तरह हैं, लेकिन वे अगले कार्य को स्वयं नहीं कहते हैं। इस तरह काम करने का कारण यह है कि कार्य को खत्म करना होगा, और लूप से बाहर होना होगा (मेजबानों में, एनवी मामले में कोई नहीं, लेकिन यह उस बिंदु पर एक का लूप है), और उसके बाद लूप खत्म हो गया है मेजबान (अब पिछले कार्य द्वारा परिभाषित) नया।


तो, मेजबान सेट करने के लिए, और आदेश सभी होस्टों में चलाए जाते हैं, आपको निम्न से शुरुआत करना होगा:

def PROD():
    env.hosts = ['10.0.0.1', '10.0.0.2']

def deploy(version='0.0'):
    sudo('deploy %s' % version)

एक बार परिभाषित हो जाने के बाद, कमांड लाइन पर कमांड चलाएं:

fab PROD deploy:1.5

PROD फ़ंक्शन में सूचीबद्ध सभी सर्वरों पर तैनाती कार्य चलाएगा, क्योंकि यह कार्य चलाने से पहले env.hosts सेट करता है।


मैं इसे प्रत्येक पर्यावरण के लिए एक वास्तविक कार्य घोषित करके करता हूं। उदाहरण के लिए:

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

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

def deploy():
    ...

उपर्युक्त कार्यों का उपयोग करके, मैं अपने परीक्षण वातावरण पर तैनात करने के लिए निम्न टाइप करूंगा:

fab test deploy

... और उत्पादन के लिए तैनात करने के लिए निम्नलिखित:

fab prod deploy

इस तरह से करने के बारे में अच्छी बात यह है कि test और prod फ़ंक्शंस का उपयोग किसी भी फैब फ़ंक्शन से पहले किया जा सकता है, न कि केवल तैनाती। यह अविश्वसनीय रूप से उपयोगी है।


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

-आर के साथ भूमिका चुनें:

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

इस पर अटक गया था, लेकिन आखिरकार इसे समझ लिया। आप बस एक कार्य के भीतर से env.hosts विन्यास सेट नहीं कर सकते हैं । प्रत्येक कार्य को प्रत्येक बार निर्दिष्ट किए जाने के लिए एन बार निष्पादित किया जाता है, इसलिए सेटिंग मूल रूप से कार्यक्षेत्र के बाहर होती है।

ऊपर अपना कोड देख रहे हैं, आप बस यह कर सकते हैं:

@hosts('dev')
def deploy_dev():
    deploy()

@hosts('staging')
def deploy_staging():
    deploy()

def deploy():
    # do stuff...

ऐसा लगता है कि यह वही करेगा जो आप चाहते हैं।

या आप वैश्विक स्कोप में कुछ कस्टम कोड लिख सकते हैं जो तर्कों को मैन्युअल रूप से विश्लेषण करता है, और आपके कार्य फ़ंक्शन को परिभाषित करने से पहले env.hosts सेट करता है। कुछ कारणों से, वास्तव में यह है कि मैंने अपना सेट कैसे सेट किया है।


आपको मॉड्यूल स्तर पर env.hosts को संशोधित करने की आवश्यकता है, कार्य कार्य के भीतर नहीं। मैंने भी यही गलती की।

from fabric.api import *

def _get_hosts():
    hosts = []
    ... populate 'hosts' list ...
    return hosts

env.hosts = _get_hosts()

def your_task():
    ... your task ...

चूंकि 1.5 1.5 यह गतिशील रूप से मेजबान सेट करने के लिए एक दस्तावेज तरीका है।

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

नीचे दस्तावेज़ से उद्धरण।

गतिशील रूप से सेट होस्ट सूचियों के साथ निष्पादन का उपयोग करना

फैब्रिक के लिए एक सामान्य इंटरमीडिएट-टू-एडवांस्ड यूज केस रनटाइम पर किसी की लक्षित होस्ट सूची के लुकअप को पैरामीटर करना है (जब भूमिकाओं का उपयोग पर्याप्त नहीं होता है)। निष्पादन इसे बेहद सरल बना सकता है, जैसे:

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)




fabric