[python] Fabric 파일에서 대상 호스트를 설정하는 방법

Fabric을 사용하여 웹 앱 코드를 개발, 스테이징 및 프로덕션 서버에 배포하고 싶습니다. 내 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:

Fabric 문서에set_hosts() 표시된대로 작업을 생성하면 env.hosts가 올바르게 설정됩니다. 그러나 이것은 실행 가능한 옵션이 아니며 데코레이터도 아닙니다. 명령 줄에서 호스트를 전달하면 궁극적으로 fabfile을 호출하는 일종의 셸 스크립트가 생성됩니다. 저는 하나의 도구가 작업을 제대로 수행하는 것을 선호합니다.

Fabric 문서에서 ‘env.hosts는 단순히 Python 목록 객체’라고 말합니다. 내 관찰에 따르면 이것은 사실이 아닙니다.

아무도 여기서 무슨 일이 일어나는지 설명 할 수 있습니까? 배포 할 호스트를 어떻게 설정할 수 있습니까?



답변

각 환경에 대한 실제 함수를 선언하여이를 수행합니다. 예를 들면 :

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

이 방법으로 그 일의 좋은 점은 것입니다 testprod기능 이전에 사용 할 수 있는 단지 배포하지, 팹 기능. 매우 유용합니다.


답변

roledef 사용

from fabric.api import env, run

env.roledefs = {
    'test': ['localhost'],
    'dev': ['user@dev.example.com'],
    'staging': ['user@staging.example.com'],
    'production': ['user@production.example.com']
} 

def deploy():
    run('echo test')

-R로 역할 선택 :

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


답변

다음은 serverhorror의 대답의 간단한 버전입니다 .

from fabric.api import settings

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


답변

이것에 스스로 붙어 있었지만 마침내 그것을 알아 냈습니다. 당신은 단순히 수 없습니다 에서 env.hosts 구성을 설정 내에서 작업. 각 작업은 지정된 각 호스트에 대해 한 번씩 N 번 실행되므로 설정은 기본적으로 작업 범위를 벗어납니다.

위의 코드를 보면 간단하게 다음과 같이 할 수 있습니다.

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

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

def deploy():
    # do stuff...

그것은 당신이 의도 한 것을 할 것 같습니다.

또는 인수를 수동으로 구문 분석하고 작업 함수가 정의되기 전에 env.hosts를 설정하는 전역 범위에 일부 사용자 지정 코드를 작성할 수 있습니다. 몇 가지 이유로, 이것이 제가 제 것을 설정 한 방법입니다.


답변

fab 1.5부터 이것은 호스트를 동적으로 설정하는 문서화 된 방법입니다.

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

아래 문서에서 인용하십시오.

동적으로 설정된 호스트 목록과 함께 실행 사용

Fabric의 일반적인 중상급 사용 사례는 런타임시 대상 호스트 목록 조회를 매개 변수화하는 것입니다 (역할 사용으로 충분하지 않은 경우). execute는 다음과 같이 매우 간단하게 만들 수 있습니다.

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)


답변

다른 답변과는 달리, 이다 수정하는 것이 가능 env작업 내에서 환경 변수를. 그러나 이것은 함수를 env사용하여 실행되는 후속 작업에만 사용됩니다 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

에서 하위 작업을 래핑하지 않으면 execute(...)모듈 수준 env설정 또는 fabCLI 에서 전달 된 모든 항목이 사용됩니다.


답변

다음과 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, ))