ফ্যাব্রিক ফাইলে লক্ষ্য হোস্ট কীভাবে সেট করবেন set


107

আমি আমার ওয়েব অ্যাপ্লিকেশন কোডটি বিকাশ, মঞ্চায়ন এবং উত্পাদন সার্ভারগুলিতে স্থাপন করতে ফ্যাব্রিকটি ব্যবহার করতে চাই। আমার ফেবিল:

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 সঠিকভাবে সেট করা থাকে। তবে এটি কোনও কার্যকর বিকল্প নয়, উভয়ই কোনও সজ্জাকারী নয়। কমান্ড লাইনে হোস্টগুলি পাস করার ফলে চূড়ান্তভাবে এক ধরণের শেল স্ক্রিপ্ট আসবে যা ফ্যাবফিল বলে one

এটি ফ্যাব্রিক ডক্সে বলা হয়েছে যে 'env.hosts কেবল একটি পাইথন তালিকার অবজেক্ট'। আমার পর্যবেক্ষণগুলি থেকে, এটি কেবল সত্য নয়।

এখানে কি চলছে কেউ ব্যাখ্যা করতে পারেন? আমি কীভাবে হোস্টকে স্থাপন করতে পারি?


আমারও একই সমস্যা, আপনি কি এর কোন সমাধান খুঁজে পেয়েছেন?
মার্টিন এম

একাধিক সার্ভারের বিরুদ্ধে একই কাজটি চালানোর জন্য, "ফাব-এইচ স্টেজিং-সার্ভার, প্রোডাকশন-সার্ভার মোতায়েন" ব্যবহার করুন ... আরও নীচে আমার উত্তরে: stackoverflow.com/a/21458231/26510
ব্র্যাড পার্কস

এটি ব্যবহার করে দেখুন: ডকস.ফ্যাবফিল.আর.এইন
ধ্রুব আগরওয়াল

এই উত্তরটি ফ্যাব্রিক 2+ এ প্রযোজ্য নয়। স্ট্যাকওভারফ্লো কনভেনশনগুলির সাথে আরও পরিচিত কেউ যদি ফ্যাব্রিক 1 উল্লেখ করার জন্য প্রশ্ন বা প্রশ্নের শিরোনাম সম্পাদনা করতে পারে তবে এটি সহায়ক হতে পারে।
জোনাথন বার্গার

উত্তর:


128

আমি প্রতিটি পরিবেশের জন্য একটি আসল ফাংশন ঘোষণা করে এটি করি। উদাহরণ স্বরূপ:

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ফাংশন সামনে ব্যবহার করা যেতে পারে কোন , প্রভূত ফাংশন শুধু স্থাপন না। এটি অবিশ্বাস্যভাবে দরকারী।


10
ফ্যাব্রিক মধ্যে একটি বাগ দরুন ( code.fabfile.org/issues/show/138#change-1497 ) এটা ভাল পরিবর্তে env.user সেটিং হোস্ট স্ট্রিং (produser@prod.server.com মত) ব্যবহারকারী অন্তর্ভুক্ত করা হয়।
মিখাইল কোরোভভ

1
আমারও একই সমস্যা ছিল এবং এটি সেরা সমাধানের মতো বলে মনে হচ্ছে। আমি হোয়াইটস, ব্যবহারকারী এবং অনেকগুলি সেটিংস একটি ওয়াইএএমএল ফাইলে সংজ্ঞায়িত করি যা ডেভ () এবং প্রোড () ফাংশন দ্বারা লোড করা হয়। (যাতে আমি একই প্রকল্পগুলির জন্য একই ফ্যাব্রিক স্ক্রিপ্টটি পুনরায় ব্যবহার করতে পারি))
ক্রিশ্চিয়ান দাভন

@ মিখাইলকোরোবভ: আমি যখন আপনার লিঙ্কটি অনুসরণ করেছি, তখন আমি দেখেছি "এনগিনেক্সে স্বাগতম! " ! code.fabfile.orgডোমেনের সমস্ত অনুরোধগুলির মতো প্রতিক্রিয়া রয়েছে।
টেডেক

হ্যাঁ, মনে হচ্ছে সমস্ত বাগগুলি গিথুবে স্থানান্তরিত হয়েছিল।
মিখাইল কোরোভভ

2
দুর্ভাগ্যক্রমে, দেখে মনে হচ্ছে এটি আর কাজ করে না - ফ্যাব্রিক এনভোচোস্টগুলি ইতিমধ্যে সংজ্ঞায়িত করা ছাড়া কাজ করবে না এবং fab A B Cতাদের কাজ হিসাবে সংজ্ঞায়িত না করে স্টাইলে ফাংশন পরিচালনা করবে না ।
ডিএনলসন

77

রোলেডফ ব্যবহার করুন

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

-আর এর সাথে ভূমিকা চয়ন করুন:

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

7
বা যদি টাস্কটি সর্বদা একই ভূমিকাতে চালিত হয় তবে আপনি টাস্কে @roles () সজ্জা ব্যবহার করতে পারেন।
টম

2
রোলেডফের মতো শব্দগুলি আলাদা আলাদা কার্যে তাদের সংজ্ঞায়নের চেয়ে ভাল সমাধান।
এহতেশ চৌধুরী

কেউ কীভাবে জানে যে আমি কীভাবে সরবরাহকৃত ব্যবহারকারীর জন্য একটি পাসওয়ার্ড অন্তর্ভুক্ত করতে পারি roledef? আরও একটি অভিধান এন্ট্রি 'password': 'some_password'উপেক্ষা করা হবে বলে মনে হয় এবং রানটাইমে প্রম্প্টের দিকে নিয়ে যায়।
শির্ক

@ ডির্ক আপনি এনভ.পাসওয়ার্ডস ব্যবহার করতে পারেন যা ব্যবহারকারী + হোস্ট + পোর্ট কী এবং পাসওয়ার্ড হিসাবে মান হিসাবে একটি অভিধান রয়েছে। উদাহরণস্বরূপ env.passwords = {'ব্যবহারকারীর @ হোস্ট: 22': 'পাসওয়ার্ড'}
জোনাথন

49

এখানে সার্ভারহররের উত্তরের একটি সহজ সংস্করণ :

from fabric.api import settings

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

2
প্রতি ডক্স , সেটিংস প্রসঙ্গ ম্যানেজার অগ্রাহ্য জন্য envতাদের প্রাথমিকভাবে সেট করার জন্য ভেরিয়েবল না। আমি মনে করি থোলির পরামর্শ অনুসারে রোলিফ ব্যবহার করা মঞ্চ, দেব এবং পরীক্ষার মতো হোস্টকে সংজ্ঞায়িত করার জন্য আরও উপযুক্ত।
টনি

21

আমি নিজেই এটি আটকে ছিল, কিন্তু অবশেষে এটি আউট। আপনি কেবল ভিতরে থেকে env.hosts কনফিগারেশন সেট করতে পারবেন না কোনও কাজের । প্রতিটি টাস্ক N বার কার্যকর করা হয়, প্রতিটি হোস্টের জন্য একবার নির্দিষ্ট করে দেওয়া হয়, সুতরাং সেটিংটি মূলত কার্যক্ষেত্রের বাইরে নয়।

উপরে আপনার কোডটির দিকে তাকিয়ে আপনি কেবল এটি করতে পারেন:

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

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

def deploy():
    # do stuff...

যা মনে হচ্ছে এটি আপনি যা করতে চান তা করবে।

অথবা আপনি বিশ্বব্যাপী স্কোপগুলিতে এমন কিছু কাস্টম কোড লিখতে পারেন যা আর্গুমেন্টগুলিকে ম্যানুয়ালি পার্স করে এবং আপনার টাস্ক ফাংশনটি সংজ্ঞায়নের আগে env.hosts সেট করে। কয়েকটি কারণে, আসলে আমি কীভাবে আমার সেট আপ করেছি।


একটি উপায় খুঁজে পাওয়া যায় নি: from fabric.api import env; env.host_string = "dev"
রোমান

18

যেহেতু 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)

3
+1 টি। এখানে পৃষ্ঠার নীচে দিকে অনেক ভাল উত্তর।
ম্যাট মন্টাগ

10

কিছু অন্যান্য উত্তরের বিপরীতে, কোনও কার্যের মধ্যে পরিবেশের ভেরিয়েবলগুলি সংশোধন করা সম্ভব 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সেটিংস বা fabসিএলআই থেকে পাস করা যা ব্যবহার করা হবে তা ব্যবহার করা হবে।


আপনি যদি env.hosts গতিশীলভাবে সেট করতে চান তবে এটি সেরা উত্তর।
JahMyst

9

আপনার 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, ))

মিষ্টি। আমি এখানে অন্য উত্তরে কোডের একটি সহজ সংস্করণ পোস্ট করেছি।
tobych

9

এটি এমনকি কেন একটি সমস্যা তা ব্যাখ্যা করার জন্য। কমান্ড ফেবহোস্ট তালিকাগুলিতে টাস্কগুলি চালানোর জন্য লাইব্রেরি ফ্যাব্রিককে করছে। যদি আপনি কোনও কাজের ভিতরে হোস্টের তালিকাটি চেষ্টা করে ও পরিবর্তন করেন তবে আপনি এটির পুনরাবৃত্তি করার সময় কোনও তালিকা পরিবর্তন করার চেষ্টা করছেন। অথবা যেখানে আপনার কোনও হোস্ট সংজ্ঞায়িত নেই, সেই ক্ষেত্রে খালি তালিকার উপর লুপ করুন যেখানে আপনি লুপের উপরে তালিকাটি সেট করেছেন সেই কোডটি কখনই কার্যকর হয় না।

Env.host_string এর ব্যবহার কেবলমাত্র এই আচরণের জন্য কাজ যা এটি হোস্টের সাথে কী সংযোগ স্থাপন করবে তা সরাসরি নির্দিষ্ট করে। এর ফলে কিছু সমস্যা দেখা দেয় যে আপনি কার্যকর করার জন্য বেশ কয়েকটি হোস্ট রাখতে চাইলে আপনি এক্সিকিউশন লুপটি পুনরায় তৈরি করবেন।

লোকেরা রান সময় হোস্ট সেট করার দক্ষতা তৈরি করার সহজ উপায় হ'ল এনভিকে জনপ্রিয়তাকে একটি আলাদা টাস্ক হিসাবে জনপ্রিয় করে তোলা, যা সমস্ত হোস্টের স্ট্রিং, ব্যবহারকারী ইত্যাদি স্থাপন করে তারপরে তারা মোতায়েনের কাজটি চালায়। দেখে মনে হচ্ছে:

fab production deploy

অথবা

fab staging deploy

যেখানে মঞ্চায়ন এবং উত্পাদন আপনার দেওয়া কাজগুলির মতো হয় তবে তারা পরবর্তী কাজটিকে নিজেরাই ডাকে না। এটি এর মতো কাজ করার কারণটি হ'ল, টাস্কটি শেষ করতে হবে এবং লুপটি ভেঙে ফেলতে হবে (হোস্টগুলির মধ্যে, এনভির ক্ষেত্রে কিছুই নয়, তবে এটি সেই সময়ে একটির লুপ), এবং তারপরে লুপটি শেষ করতে হবে হোস্টগুলি (এখন পূর্ববর্তী টাস্ক দ্বারা সংজ্ঞায়িত) নতুনভাবে।


3

আপনাকে মডিউল স্তরে env.hosts সংশোধন করতে হবে, কোনও কার্য কার্যের মধ্যে নয়। আমি একই ভুল করে।

from fabric.api import *

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

env.hosts = _get_hosts()

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

3

এটা খুবই সাধারণ. কেবল env.host_string ভেরিয়েবলটি আরম্ভ করুন এবং নিম্নলিখিত হোস্টগুলির উপরের সমস্ত কমান্ড কার্যকর করা হবে।

from fabric.api import env, run

env.host_string = 'user@exmaple.com'

def foo:
    run("hostname -f")

3

আমি ফ্যাব্রিকের ক্ষেত্রে সম্পূর্ণ নতুন, তবে একাধিক হোস্টে একই কমান্ড চালানোর জন্য ফ্যাব্রিক পেতে (যেমন একাধিক সার্ভারে স্থাপন করা, এক কমান্ডে) আপনি চালাতে পারেন:

fab -H staging-server,production-server deploy 

যেখানে স্টেজিং-সার্ভার এবং প্রোডাকশন-সার্ভার হ'ল 2 সার্ভার যার বিরুদ্ধে আপনি ডিপ্লয়ে অ্যাকশন চালাতে চান। এখানে একটি সাধারণ ফ্যাবিল.পিপি যা ওএস নামটি প্রদর্শন করবে। মনে রাখবেন যে ফাইব কমান্ডটি চালান সেখানে ফ্যাবফিল.পিটি একই ডিরেক্টরিতে থাকা উচিত।

from fabric.api import *

def deploy():
    run('uname -s')

এটি কমপক্ষে 1.8.1 ফ্যাব্রিকের সাথে কাজ করে।


3

সুতরাং, হোস্টগুলি সেট করতে, এবং সমস্ত হোস্ট জুড়ে কমান্ডগুলি চালিত করতে, আপনাকে এগুলি শুরু করতে হবে:

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

পিআরডি ফাংশনে তালিকাভুক্ত সমস্ত সার্ভারগুলিতে ডিপ্লাই টাস্কটি কী চালাবে, কারণ এটি টাস্কটি চালানোর আগে env.hosts সেট করে।


ধরা যাক প্রথম হোস্টে মোতায়েন কাজ করেছিল কিন্তু দ্বিতীয়টিতে একটি ব্যর্থ হয়েছে, আমি কীভাবে এটি কেবল দ্বিতীয় দ্বিতীয়টিতে করব?
সংখ্যা

2

env.hoststringসাবটাস্ক চালানোর আগে আপনি নির্ধারণ করতে পারেন । আপনি যদি একাধিক হোস্টের মাধ্যমে পুনরাবৃত্তি করতে চান তবে একটি লুপে এই গ্লোবাল ভেরিয়েবলকে বরাদ্দ করুন।

দুর্ভাগ্যক্রমে আপনার এবং আমার জন্য, ফ্যাব্রিক এই ব্যবহারের ক্ষেত্রে তৈরি করা হয়নি। পরীক্ষা করে দেখুন mainএ ফাংশন http://github.com/bitprophet/fabric/blob/master/fabric/main.py দেখতে কিভাবে এটি কাজ করে।


2

এখানে আরও একটি "সামারসোল্ট" প্যাটার্ন যা সক্ষম করে fab my_env_1 my_command ব্যবহার :

এই নিদর্শন দিয়ে, আমাদের কেবল অভিধান ব্যবহার করে একসময় পরিবেশকে সংজ্ঞায়িত করতে হবে। env_factoryএর মূলনামের উপর ভিত্তি করে ফাংশন তৈরি করে ENVS। আমি ফ্যাব্রিক কোড থেকে আলাদা কনফিগার করতে ENVSনিজের ডিরেক্টরি এবং ফাইল রেখেছি insecrets.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

0

ভূমিকা ব্যবহার করা বর্তমানে এটি করার "যথাযথ" এবং "সঠিক" উপায় হিসাবে বিবেচিত হয় এবং এটি আপনার করা উচিত should

এটি বলেছিল, আপনি যদি পছন্দ করেন এমন বেশিরভাগের মতো হন তবে "ইচ্ছা" বা "আকাঙ্ক্ষা" হ'ল ফ্লাইতে "মোচড়িত সিস্ট" বা টার্গেট সিস্টেমগুলি স্যুইচ করার দক্ষতা।

সুতরাং বিনোদনমূলক কাজের জন্য কেবলমাত্র (!) নীচের উদাহরণটি বোঝায় যে অনেকে ঝুঁকিপূর্ণ হিসাবে কী বিবেচনা করতে পারে, এবং তবুও কিছুটা পুরোপুরি সন্তুষ্টিজনক, কৌশল যা এই জাতীয় কিছু রয়েছে:

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

তারপরে চলছে:

fab perform_sumersault
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.