์ด ๋ธ๋ก๊ทธ ๊ฒ์๋ฌผ๊ณผ ๋ชจ๋ ๋งํฌ๋ฅผ ๋จผ์ ์ฝ์๋์ง ํ์ธํ์ญ์์ค!: http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta
๊ธฐ์กด ํฐ์ผ์์ ๋ค๋ฃจ์ง ์๋ ๋ฌธ์ ์ ๋ํ ํผ๋๋ฐฑ์ ๋จ๊ธธ ์ ์๋ ๊ณณ์ ๋๋ค. ๋จผ์ ์๋ ์ฅ์๋ฅผ ๊ฒ์ํด์ฃผ์ธ์!!
๊ด๋ จ ํญ๋ชฉ์ ์ฐพ์ง ๋ชปํ์ จ์ต๋๊น? ์๋์ ์๊ฒฌ์ ๋จ๊ฒจ์ฃผ์ธ์! ํผ๋๋ฐฑ์ _๋น์ทํ์ง๋ง ์ด์ ๊ตญํ๋์ง ์๋_ ์ฐพ๊ณ ์์ต๋๋ค.
URL์ ์์ ์ค์, http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta/ ์ฌ์ผ ํฉ๋๋ค.
๋ด๊ฐ ๋ด ์น์ฌ์ดํธ๋ฅผ ์ผ๋ง๋ ์ ๊ธฐ์ตํ๋์ง ๋ณด์ฌ์ฃผ๋ ค๊ณ ์, ์? ๊ฐ์ฌ ํด์! ๋ด ๊ฒ์๋ฌผ์ ๋ํ ๋งํฌ ๊ฒ์ฌ๊ธฐ๋ฅผ ์คํํ์ง๋ง ...์ด ํฐ์ผ์๋ ๋ฐ๋ํ์ง ์์ต๋๋ค ;)
๋๋ fabric 1์ roledefs ์์คํ
์ด fabric 2์ ์ฒ ํ๊ณผ ์ผ์นํ๋ค๊ณ ๋ฏฟ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํ๋ ์ ์๋ ๋ฐฉ๋ฒ์ ๋ํ ์ ์์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์์
์ ๊ฐ Collection
์๋ ์์
์ ์คํํ ์ ์๋ ์ฑ์์ง Group
๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ ๋์ผํ ๋ค์์คํ์ด์ค์ @group
๋ฐ์ฝ๋ ์ดํ
๋ ํจ์๊ฐ ์์ ์๋ ์์ต๋๋ค. ๋ค์์คํ์ด์ค๊ฐ ์ค์ํ๋ฏ๋ก fabfile.py
์ deploy
Collection
$๊ฐ ํฌํจ๋์ด ์์ผ๋ฉด $ web
๋ฐ db
๋ผ๋ $#$ @group
#$๊ฐ ์์ต๋๋ค. , deploy.web.execute(mytask)
๋๋ fab -G deploy.web mytask
๋ฅผ ์ฌ์ฉํ์ฌ web
๊ทธ๋ฃน์ ๊ฐ ํธ์คํธ์์ mytask
$๋ฅผ ์คํํ ์ ์์ต๋๋ค. ์ด๋ฌํ ๋ฐ์ฝ๋ ์ดํ
๋ ํจ์๋ ์ง์ฐ ํธ์ถ๋๊ณ ๋ถํ์ํ API ํธ์ถ์ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ฉ๋ชจํ๋ฉ๋๋ค. ํธ์คํธ ๋ชฉ๋ก ์กฐํ๊ฐ ์ฌ์ฉ์๊ฐ ๊ตฌํํ ๋๋ก ๋๋ฆฐ ์์
์ธ ๊ฒฝ์ฐ์
๋๋ค.
์ด๊ฒ์ ํจ๋ธ๋ฆญ 2์ ๋์์ธ ์ฒ ํ๊ณผ ์ผ์นํฉ๋๊น? ๊ทธ๋ ๋ค๋ฉด ๊ตฌํ์ ์ค์์ ์ทจํ๊ณ ์ถ์ต๋๋ค.
๋ฉ์ง ์์ด๋์ด๋ค์, @RedKrieg! Group ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ "๊ฐ์ฅ ์ข์" ๋ฐฉ๋ฒ ๋ฐ/๋๋ CLI์์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๋ด ์์ ์ ๋ธ๋ ์ธ์คํ ๋ฐ์ ์ฐ๊ธฐํ์ง๋ง ํฉ๋ฆฌ์ ์ธ ๋ฐฉ๋ฒ์ฒ๋ผ ๋ค๋ฆฝ๋๋ค. ๋ฐฉ๊ธ #1594์์ ๋๋ฌด ๋ง์ ๋จ์ด๋ฅผ ๊ธ์ด๋ชจ์๊ณ ๊ฑฐ๊ธฐ์ ๋น์ ์ ์์ด๋์ด๋ฅผ ํฌํจ์์ผฐ์ต๋๋ค(+ ๋งํฌ). ๊ฑฐ๊ธฐ์์ ํ ๋ก ์ ๊ณ์ํฉ์๋ค. ํ์ง๋ง PoC PR์ ๋ณด๊ณ ์ถ์ต๋๋ค.
์๋ฅผ ๋ค์ด ๋ก์ปฌ ๋น๋์ ์๊ฒฉ ํธ์คํธ์ ๋ํ rsync๋ฅผ ๋จ์ผ ์์
์ผ๋ก ๊ฒฐํฉํ๋ ค๋ ๊ฒฝ์ฐ์ ๊ฐ์ด -H
์ธ์๊ฐ ์์์๋ ๋ถ๊ตฌํ๊ณ ๋ก์ปฌ์์ ๋ช
๋ น์ ์คํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๋ฌด์์
๋๊น?
@max-arnold ์ฐ๊ฒฐ ๊ฐ์ฒด์๋ ๋ก์ปฌ ์์คํ
์์ .run
์ฒ๋ผ ์๋ํ๋ .local
์์ฑ์ด ์์ต๋๋ค. http://docs.fabfile.org/en/v2/api/connection.html#fabric .connection.Connection.local
์ข์, ๋๋ ์๊ฐ ๋ง๋ณด๋ค ๋ซ๋ค๊ณ ์๊ฐํ๋ค.
<strong i="6">@task</strong>
def build(ctx):
# should always run locally
ctx.local('uname -a')
<strong i="7">@task</strong>
def deploy(ctx):
build(ctx)
# this one should run on remote host
ctx.run('uname -a')
๊ฒฐํฉ๋ ์์ ์ด ์ ์คํ๋ฉ๋๋ค.
fab -H host deploy
AttributeError์ ํจ๊ป ๋ก์ปฌ ์์ ๋จ๋ ์คํจ: 'local'์ ๋ํ ์์ฑ ๋๋ ๊ตฌ์ฑ ํค ์์:
fab build
๊ธฐ๋ณธ์ ์ผ๋ก ํธ์ถ๋ ๋ฐฉ๋ฒ( -H
ํฌํจ ๋๋ ์ ์ธ)์ ๊ด๊ณ์์ด ๋ก์ปฌ์์ ์์
์ ์ํํ๊ณ ์ถ์ต๋๋ค.
๋ฐ๋ฉด์ ์ผ๋ถ ๋ช
๋ น์ ์๊ฒฉ์ผ๋ก๋ง ์คํํ๊ธฐ ์ํ ๊ฒ์
๋๋ค. ํธ์คํธ๊ฐ ์์ผ๋ฉด ctx.run
์ด ํธ์คํธ๋ฅผ ๋ก์ปฌ์์ ์คํํ๋ ค๊ณ ์๋ํ๋ฏ๋ก ์๊ธฐ์น ์์ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
| ์ฌ์ฉ์๊ฐ ์์
์ ์คํํฉ๋๋ค | ๋ช
๋ น/์์
์์ฑ์๊ฐ ์คํ๋๊ธฐ๋ฅผ ์ํจ | ์ด๋ป๊ฒ ํ๋ํด์ผ ํฉ๋๊น? |
|------------------------|--------------------------- ---|----------------|
| ์ง์ญ์ ์ผ๋ก | ์ง์ญ์ ์ผ๋ก | run() ๋์์ ๊ด์ฐฎ์ต๋๋ค(๊ทธ๋ฌ๋ ์๊ฒฉ์ผ๋ก ์คํํ๋ฉด ์์ฑ์์ ์๋๋ฅผ ์๋ฐํจ) |
| ์ง์ญ์ ์ผ๋ก | ์๊ฒฉ์ผ๋ก | ์คํจํด์ผ ํฉ๋๋ค(๋๋ ์ด์ ํจ๋ธ๋ฆญ์ฒ๋ผ ํธ์คํธ ๋ฌธ์์ด์ ์์ฒญํด์ผ ํจ) |
|ํ์ง์์ | ๋ก์ปฌ ๋๋ ์๊ฒฉ | run() ๋์์ ๊ด์ฐฎ์ต๋๋ค |
| ์๊ฒฉ์ผ๋ก | ์ง์ญ์ ์ผ๋ก | ํญ์ ๋ก์ปฌ์์ ์คํ๋์ด์ผ ํ์ง๋ง Context์๋ ์ด๋ฅผ ๋ณด์ฅํ๋ local() ๋ฉ์๋๊ฐ ์์ต๋๋ค. |
| ์๊ฒฉ์ผ๋ก | ์๊ฒฉ์ผ๋ก | run() ๋์์ ๊ด์ฐฎ์ต๋๋ค(๊ทธ๋ฌ๋ ๋ก์ปฌ ํธ์ถ ์ค์ ๋ฌธ์ ๊ฐ ์์๋จ) |
| ์๊ฒฉ์ผ๋ก | ๋ก์ปฌ ๋๋ ์๊ฒฉ | run() ๋์์ ๊ด์ฐฎ์ต๋๋ค |
@max-arnold ์ ํํ #98์ ๋๋ค! ์์ง ์์ ํ ํด๊ฒฐํ์ง ๋ชปํ์ต๋๋ค. ๊ฑฐ๊ธฐ์ ๋ช ๊ฐ์ง ํ๋์ ์ธ ์๊ฐ์ ์ฃผ์์ผ๋ก ๋ฃ๊ธฐ... ํธ์ง: this one
sudo์ ์ผ์นํ์ง ์๋ ๊ฒ์ผ๋ก ๋ณด์ด๋ ๊ฒ์ ๋ฐ๊ฒฌํ์ต๋๋ค.
์ฌ๊ธฐ์ connection
๋ ๋ฃจํธ๋ก ์ธ์ฆ๋ ์๊ฒฉ ์๋ฒ์
๋๋ค.
๋ฃจํธ๊ฐ ์๋ ๋ค๋ฅธ ์ฌ์ฉ์๋ก ๋ฌผ๊ฒฐํ ํ์ฅ ์๋:
c.sudo("echo bar > ~/foo", user="builder")
์ด๊ฒ์ ์ฑ๊ณตํ์ง๋ง /home/builder/foo๋ฅผ ์์ฑํ๋ ๋์ /root/foo๋ฅผ ์์ฑํ์ต๋๋ค.
๋ฐ๋ฉด์ ๋ด๊ฐ lsํ๋ ค๊ณ ํ๋ฉด :
c.sudo("ls", user="builder")
Permission denied
๋ฐ์ต๋๋ค.
๋ญ๊ฐ ๊ธฐ๋ถ์ด ๋์ฉ๋๋ค.
Dustin์ด ์์ ๋์ญ ์ธ ๋ณด๊ณ ํ์ ๋ ๋ด ์ถ์ธก์ ์ด๊ฒ์ด sudo
(๋ฉ์๋๊ฐ ์๋ ๋ช
๋ น) ํน์ ์ฃผ๋ฆ์ด๋ผ๋ ๊ฒ์
๋๋ค. ๋ง์ง๋ง์ผ๋ก ์ฐ๋ฆฌ๋ -H
๋ฅผ ์ฌ์ฉํ๊ณ ์๊ณ ๋ถ๋ช
ํ ์์๋๋ก 100% ์๋ํ์ง ์์ต๋๋ค.
์๋
ํ์ธ์ ์ ํ,
์ด๋ฏธ python 3์์ ์์
ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ง๊ธ fabric3
(ํจ๋ธ๋ฆญ 1.x ์ด์)์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
ํจ๋ธ๋ฆญ 2๋ก์ ๋ง์ด๊ทธ๋ ์ด์
์ ์๋ํ๊ณ ์ถ์์ง๋ง ์ฆ์ ์ผ ์คํ ํผ์ ๋๋ฌํ์ต๋๋ค. fabric.contrib
ํจ์๋ฅผ ๊ด๋ฒ์ํ๊ฒ ์ฌ์ฉํ์ง๋ง ๋ง์ด๊ทธ๋ ์ด์
๋ฌธ์์ ๋ ์ด์ ์กด์ฌํ์ง ์๋๋ค๊ณ ๋์ ์์ต๋๋ค.
ํ์คํ ๋๋ ๋๋ฑํ ์๋ก ๋๋์๊ฐ๋ ์ฝ๋๋ฅผ ๋ถํ๋ฆฌ๊ณ ์ถ์ง ์์ผ๋ฉฐ, fabric 1.x์ contrib.*
์ ๋ํ ๋ฌธ์ ์ ์๋ก ํ๋จํ๋ฉด ๋ง์ด ์ฌ์ฉ๋๋ ๊ฒ์ฒ๋ผ ๋ณด์
๋๋ค. ์ ์๊ฐ์๋ ๋ถ์กฑ์ ๋ง์ ๋ค๋ฅธ ์ฌ๋๋ค์ ์ด์ฃผ์ ์ฌ๊ฐํ ๋ฐฉํด๊ฐ ๋ ์ ์์ต๋๋ค.
fabric.contrib
์ ํด๋นํ๋ ๊ฒ์ผ๋ก ๋ณด์ด๋ ํจ์น์ํฌ ํ๋ก์ ํธ๋ฅผ ์ฐพ์์ง๋ง ๋ช ๋
๋์ ์ฝ๋๊ฐ ์
๋ฐ์ดํธ๋์ง ์์์ต๋๋ค.
fabric.contrib
๋ฅผ ํจ๋ธ๋ฆญ 2๋ก ์ด์ํ ๊ณํ์ด ์์ต๋๊น?
๊ฐ์ฌ ํด์,
๊ฐ๋ธ๋ฆฌ์
@garu57 ๋ค, ํ์ฌ ๊ณํ์ patchwork
๋ฅผ ๊ธฐ๋ณธ์ ์ผ๋ก "2.0's contrib"๋ก ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค. ํ์ฌ Fabric 1 ๊ธฐ๋ฐ์ด์ง๋ง Fabric 2.0.0์ด ๋์ค๋ฉด ๋ณ๊ฒฝ๋ ๊ฒ์
๋๋ค. ๊ฐ์ฅ ์ผ๋ฐ์ ์ผ๋ก ์ฌ์ฉ๋๋ ๊ธฐ์ฌ ๋นํธ๊ฐ ๋นจ๋ฆฌ ํฌํ
๋๊ธฐ๋ฅผ ๊ธฐ๋ํฉ๋๋ค.
์๋ ํ์ธ์ ์ฌ๋ฌ๋ถ,
๋๋๋ก ๋ด ํ๋ก๊ทธ๋จ์ ์๊ฒฉ ๋ช ๋ น์ ์คํํฉ๋๋ค.
source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./00-update-kernel.sh'
์คํฌ๋ฆฝํธ๊ฐ ๋ค์๊ณผ ๊ฐ์ด ์คํ๋๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
033[0;32m[DONE]\033[0m'
+ return 0
+ alt_test_done_msg 'Prepare evironment'
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
+ exit 0
๋ด ๋๋ฒ๊ทธ ์ถ๋ ฅ "?"๋ ํ์๋์ด์ผ ํฉ๋๋ค. ๋ด ์ฝ๋์ ๋ฐ๋ฅด๋ฉด :
class GenericFabric(object):
def __init__(self, host, user, key_filename=None, port=22):
connection_string = "{u}@{h}:{p}".format(u=user, h=host, p=port)
self.connection = Connection(connection_string)
self.key_filename = key_filename
#<strong i="13">@with_settings</strong>
def generic_cmd(self, command_str, timeout, fabric_timeout, **kwargs):
"""
Creating remote container from template
<strong i="14">@type</strong> command_str: str
<strong i="15">@param</strong> command_str: command for execute with VM
<strong i="16">@type</strong> timeout int or float
<strong i="17">@param</strong> timeout number of seconds for pause
<strong i="18">@type</strong> fabric_timeout int or float
<strong i="19">@param</strong> fabric_timeout number of seconds for timeout fabric run
<strong i="20">@rtype</strong>: FabricResponse
<strong i="21">@return</strong>: Return remote status of operation VM
"""
if fabric_timeout > 0:
command = self.connection.run(command_str.format(**kwargs),
timeout=fabric_timeout,
warn=True, echo=True)
else:
command = self.connection.run(command_str.format(**kwargs),
warn=True, echo=True)
print("?")
if timeout > 0:
sleep(timeout)
return FabricResponse(command)
def simple_generic_cmd(self, command_str, **kwargs):
"""
<strong i="22">@type</strong> command_str: str
<strong i="23">@param</strong> command_str: command for execute with VM
<strong i="24">@rtype</strong>: FabricResponse
<strong i="25">@return</strong>: Return remote status of operation VM
"""
return self.generic_cmd(command_str, 0.1, 0, **kwargs)
๊ทธ๋ฌ๋ "?"๋ ์์ต๋๋ค. ๊ทธ๋์ ๋๋ run()์ ๋งค๋ฌ๋ ค ์๋ค๊ณ ์ ์ํฉ๋๋ค.
์ฌ์ค, ๋ด ํ๋ก๊ทธ๋จ์ ๊ฑฐ๋ํ๊ณ ๋ค์ค ํ๋ก์ธ์ค ํ๋ก๊ทธ๋๋ฐ์ด ์์ต๋๋ค. ๊ต์ํ์ ์ก๊ธฐ ์ํด ๋ค์ ์ฝ๋๋ก ์๊ฒฉ ๋ช ๋ น์ ์คํํ๊ณ ์์ต๋๋ค.
class TestingSystemVM(GenericFabric):
#######
<strong i="7">@signal_alarm_down</strong>
def run_rpm_test(self, command_test, package, type_of_test="base"):
"""
"""
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(self.__timeout)
returned_value = Queue()
start_time = datetime.utcnow()
directory, command_test = os.path.split(command_test)
try:
if command_test.endswith(".yml"):
directory = directory.replace("/opt/QA", self.ansible.git_qa_repo)
output = self.ansible.play_ansible(command_test,
package,
directory)
else:
vm_instance = (self.host,
self.user,
self.key_filename,
self.os_name,
self.platform,
self.arch)
running_test = Process(target=separate_process_running_test,
args=(vm_instance,
returned_value,
directory,
command_test,
package,
type_of_test))
running_test.start()
running_test.join(self.__timeout)
if running_test.is_alive():
running_test.terminate()
command_test_res = "FAIL: Timeout\n"
return command_test_res, work_time(start_time), 1
elif returned_value.empty():
command_test_res = "FAIL: Problem while getting result\n"
return command_test_res, work_time(start_time), 1
else:
output = returned_value.get()
except TimeOut:
command_test_res = "FAIL: Timeout\n"
return command_test_res, work_time(start_time), 1
if output.failed or (package.name in ("lve-utils", "lve-stats") and
"FAIL" in output.stdout):
res_output = "FAIL: " + output.stdout
else:
res_output = output.stdout
return res_output, work_time(start_time), 0 if output.succeeded else 1
def separate_process_running_test(vm_instance, return_value_queue,
directory, command_test, package,
type_of_test="base"):
"""
"""
sleep(0.5)
signal.signal(signal.SIGTERM, kill_fabric_runner)
signal.signal(signal.SIGINT, kill_fabric_runner)
(host,
user,
key_filename,
os_name,
platform,
arch) = vm_instance
child_vm_instance = TestingSystemVM(host,
user,
key_filename,
os_name,
platform,
arch,
FakeAnsible())
if command_test.endswith(".bats"):
command_test = "/usr/bin/bats --tap " + command_test
else:
command_test = os.path.join("./", command_test)
output = child_vm_instance.simple_generic_cmd(child_vm_instance._c_run_test,
envvars=child_vm_instance.env_vars,
exec_test=command_test,
dir=directory,
package=package.name,
pver=package.version,
prel=package.release,
type_test=type_of_test)
print("!")
return_value_queue.put(output)
fabric2๋ฅผ ์ฌ์ฉํ ๋ ์์ ํ๋ก์ธ์ค์์ ์์๋ ์ผ๋ถ ๋ช
๋ น์ด ๋๋๋ก ์ค๋จ๋ฉ๋๋ค.
์
๋ฐ์ดํธ ์ฌ์ค, ๊ทธ๊ฒ์ ์ฝ๋์์ ๋ด ์ค์์์ต๋๋ค. ๋ฐ๋ผ์ fabric2์๋ ๊ต์ํ์ด ํฌํจ๋์ง ์์ต๋๋ค.
๋ชจ๋๋ค ์๋
,
๋๋ ๋ช ๊ฐ์ง ๋ฐ์ฌ ์คํ์ํ๊ณ ๋ด ๊ฒฝํ์ ๊ณต์ ํ ์ ์์ต๋๋ค.
๋จผ์ ์ฝ์์์ ๋ช ๋ น์ ์คํํ์ต๋๋ค.
ssh [email protected] -t "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'"
exit=0์ผ๋ก ์๋ฒฝํ๊ณ ๋น ๋ฅด๊ฒ ๋๋ฌ์ต๋๋ค.
###
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
* Prepare evironment [DONE]
+ exit 0
Connection to 192.168.0.34 closed.
์ข์.
๊ทธ๋ฐ ๋ค์ ๋ค๋ฅธ ๋ช
๋ น์ ์คํํ์ต๋๋ค.
ssh [email protected] "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'"
exit=0์ผ๋ก ๋๋ฌด ๋นจ๋ฆฌ ์๋ฃ๋์์ต๋๋ค.
###
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
+ exit 0
๊ทธ๋ฌ๋ "192.168.0.36์ ๋ํ ์ฐ๊ฒฐ์ด ๋ซํ์ต๋๋ค."๋ ์์ต๋๋ค. ์ค์ํ์ง ์๋์ง ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.
๊ทธ ํ VM์ ๋ค์ ๋ง๋ค๊ณ fabric2(IPython์์)๋ก ๋ช ๋ น์ ์คํํ์ต๋๋ค.
In [1]: from fabric import Connection
In [2]: Connection('[email protected]').run("source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'", pty=True)
....
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
* Prepare evironment [DONE]
+ exit 0
Out[2]: <Result cmd="source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" exited=0>
๋ํ pty=False๋ก ์คํํ์ต๋๋ค.
In [1]: from fabric import Connection
In [2]: Connection('[email protected]').run("source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'", pty=False)
+ echo -e '* Prepare evironment \033[0;32m[DONE]\033[0m'
+ exit 0
Out[2]: <Result cmd="source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" exited=0>
"์ ๋ํ ์ฐ๊ฒฐ์ด ์์์ต๋๋ค.
๋์งธ, ์์ ํ๋ก์ธ์ค์์ ์์ํด์ผ ํ๊ธฐ ๋๋ฌธ์ ๋ด ์ ์ฅ์ ์ข์ ํ๊ฒฝ์ด ์๋๋ผ๊ณ ๊ฒฐ์ ํ์ต๋๋ค. ๊ทธ๋์ VM์ ๋ค์ ๋ง๋ค๊ณ ๋ค์ ์ฝ๋๋ก ์คํฌ๋ฆฝํธ๋ฅผ ์คํํ์ต๋๋ค.
In [1]: import subprocess
In [2]: t = subprocess.Popen(""" ssh [email protected] -t "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" """, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True); r = t.communicate()
์ด ์คํ์ ์ถ๋ ฅ์๋ "192.168.0.34์ ๋ํ ์ฐ๊ฒฐ์ด ๋ซํ์ต๋๋ค."๊ฐ ์์์ต๋๋ค.
๋ฐ๋ฉด์
In [1]: import subprocess
In [2]: t = subprocess.Popen(""" ssh [email protected] "source /opt/centos/vars && su - -c 'cd /opt/QA/rpm_tests/p_lvemanager && ALT_TEST=base ALT_PACKAGE_NAME=lvemanager ALT_PACKAGE_VERSION=3.0 ALT_PACKAGE_RELEASE=11.el6.cloudlinux.21100.1.1505113712 ./01-prepare-environment.sh'" """, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True); r = t.communicate()
๋ ๋ค ๊ต์ํ์ ์ฒํ์ง ์์์ต๋๋ค.
์ค๋ ๋ฐค ๋๋ ๋ถ๊ธฐ๋ ํ๋ก์ธ์ค์์ fabric2๋ฅผ ์ฌ์ฉํ์ฌ ์คํฌ๋ฆฝํธ๋ฅผ ์์ํ๊ณ ์์ฑํ ๊ฒ์
๋๋ค.
์
๋ฐ์ดํธ ์ฌ์ค, ๊ทธ๊ฒ์ ์ฝ๋์์ ๋ด ์ค์์์ต๋๋ค. ๋ฐ๋ผ์ fabric2์๋ ๊ต์ํ์ด ํฌํจ๋์ง ์์ต๋๋ค.
Transfer.put
use_sudo
์ง์์ ๋ฐ๋ ๊ฒ์ด ์ข์ต๋๋ค.
ํ์ฌ ๊ฐ์ฅ ๊ฐ๋จํ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๊ถํ์ด ์๋ ๊ณณ์์ put
๋ฅผ ์ํํ ๋ค์ sudo mv
?
@ned2 use_sudo
๊ฐ get
/ put
์์ ์ค์ ๋ก ํ ์ ์๋ ๋ชจ๋ ๊ฒ์
๋๋ค. ์๋ฅผ ๋ค์ด v1์ด ์ํํ๋ ๋ฐฉ์์
๋๋ค. ๋ด๊ฐ ์๋ ํ "sudo๋ก" ํ์ผ์ ์
๋ก๋ํ๋ ๊ฒ์ ์ค์ ๋ก ๋ถ๊ฐ๋ฅํฉ๋๋ค! (๋ฃจํธ๋ก ์ฐ๊ฒฐํ์ง ์๋ ๊ฒ์ ์ข์ง ์์ผ๋ฉฐ ์ด์์ ์ผ๋ก๋ ํ์ฉ๋์ง ์์ต๋๋ค.)
v2์์ ์ข ๋ ๊น๋ํ API๋ฅผ ์ฌ์ฉํ๋ ค๋ ์๋๋ฅผ ๊ฐ์ํ ๋ get
/ put
์์ฒด ๋ด๋ถ์ ํด๋น ๋์์ ๋ฒ๋ค๋ก ๋ฌถ๋ ๋์ ๋ํผ๋ฅผ ๊ตฌํํ ๊ฐ๋ฅ์ฑ์ด ๋ ํฝ๋๋ค. Transfer.sudo_put
( self.put
ํธ์ถ)์ ๊ฐ์ ๊ฒ์ผ ์ ์์ต๋๋ค. ๊ทธ๋ ๊ฒ ํ๋ฉด "์์ํ" put
๊ฐ ์ต์ํ๋ฉ๋๋ค.
@bitprophet Fabric1๊ณผ ํจ๊ป ๋งค์ฐ ์์ ์ ์ด๊ณ ์ ์ฉํ ์ํํธ์จ์ด์ Fabric2 ์ถ์์ ๋ํ ๊ทํ์ ์ ๊ทผ ๋ฐฉ์์ ๋ํด ๊ฐ์ฌ๋ฅผ ํํ๋ฉฐ ์์ํ๊ฒ ์ต๋๋ค.
v2๋ฅผ ๊ฐ์ง๊ณ ๋๊ธฐ ์์ํ์ง๋ง ์ฐ๊ฒฐ์ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. Fabric 1์ SSH ๊ตฌ์ฑ์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค. Fabric 1์ ์ฐ๊ฒฐ์ ์๋ํ ๋ ์ํธ๋ฅผ ๋ฌป๋ ๋ฉ์์ง๋ฅผ ํ์ํฉ๋๋ค. Fabric 2๋ ์ด ์์ ์ ์ํํ์ง ์์ผ๋ฉฐ ์ธ์ฆ์ ์คํจํ๋ค๊ณ ํ์ํ์ง ์์ต๋๋ค. Connection์ ๋ํ ์ธ์ฆ ๋ฉ์ปค๋์ฆ์ ์ธ๊ธํ๋ v2 ๋ฌธ์์ ์ด๋ ๊ณณ์์๋ ๋ณผ ์ ์์ต๋๋ค. sudo๋ฅผ ์ฌ์ฉํ ์ํธ์ ๋ํ ์ธ๊ธ์ด ์์ง๋ง ๋ด๊ฐ ์์งํ ์ ์๋ ๊ฒ์ ์ฐ๊ฒฐ์ด ์ฑ๊ณตํ ์ดํ์ ๊ฒ์ ๋๋ค.
๋ด ์ง๋ฌธ์ ๋ฌธ์์์ ๋ญ๊ฐ๋ฅผ ๋์น ๊ฒ์ธ์ง ๋๋ ์ด๊ฒ์ด ๋๋ฝ๋ ๊ธฐ๋ฅ ๋๋ ๋ฌธ์ ์ธ์ง ์ฌ๋ถ์ ๋๋ค.
์ฝ๋:
<strong i="10">@task</strong>
def testing(c):
with Connection('MyHostname') as cxn:
print("Connected")
cxn.run('ls -l')
์ค๋ฅ:
File /lib/python3.4/site-packages/paramiko/auth_handler.py", line 223, in wait_for_response
raise e
paramiko.ssh_exception.AuthenticationException: Authentication failed.
๋ด SSH ๊ตฌ์ฑ(์ฌ๊ธฐ์ ๊ฒ์ํ๊ธฐ ์ํด ๋์ฒด๋ ๊ฐ):
Host MyHostname
HostName replacedhostname.co.uk
Port 22
IdentityFile ~/.ssh/id_rsa
User replaceduser
์ ๋ ์ต์ v2 ๋ฒ์ ์ ์ฌ์ฉ ์ค์ ๋๋ค. https://github.com/fabric/fabric/commit/fec3a22ee89900500ae731913fd33f9b56e89f46
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉด ๊ฐ์ ๋ฌธ์ ๋ฅผ ๊ฐ์ง ๋ค๋ฅธ ์ฌ๋์๊ฒ ๋์์ด ๋ ๊ฒ์ ๋๋ค.
์๊ฐ ๋ด ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.
@ Aiky30 ์๋ง๋ ๋น์ ์ด ์๋ ๊ฒ์
๋๋ค. ์ธ์ฆ ์์
์ ์ฌ์ ํ โโ์์
์ด ํ์ํฉ๋๋ค (๋๋ถ๋ถ ์งํ ์ค์ธ Paramiko ์์
์ด ํ์ํ๊ธฐ ๋๋ฌธ์ ์ธ์ฆ ์์ธ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ํด์ํ๊ธฐ๊ฐ ๋์ฐํ๊ฒ ์ด๋ ต์ง ์์ต๋๋ค.) ์ด ๊ฒฝ์ฐ์๋ ๋จ์ํ Fab ์ผ ์ ์์ต๋๋ค. 2๋ IdentityFile
๋ฅผ ํด์ํ์ง ์์ต๋๋ค. ํธ์คํธ, ์ฌ์ฉ์, ํฌํธ ๋ฐ ๊ธฐํ ์ฌ๋ฌ ์ค์ ์ ํ์
ํ์ง๋ง IdentityFile์ ์ฌ์ ํ โโํ ์ผ์
๋๋ค.
๊ทธ๊ฒ์ ๋ถ๋ถ์ ์ผ๋ก ์ฐ๋ฆฌ๊ฐ ์ง๊ธ ์ํธ๊ตฌ๋ฅผ ๋ค๋ฃจ์ง ์๊ธฐ ๋๋ฌธ์ ๋๋ค(์ ์ฐธ์กฐ - ์ฃผ์ด์ง ์ธ์ฆ ์คํจ๊ฐ ์ํธ๋ ์ํธ๊ตฌ๊ฐ ํ์ํจ์ ์๋ฏธํ๋ ๊ฒฝ์ฐ ๊ณผ๊ฐํ ์ถ์ธก์ ํด์ผ ํ๋ ํฐ Fabric 1 kludge๋ฅผ ํผํ๊ณ ์ถ์ต๋๋ค). ๋ฐ๋ผ์ ๊ทธ ํ์ "์ด ํ์ผ์ ์ ๊ธ ํด์ ํ ์ ์์ต๋๋ค" ์ค๋ฅ๋ก ์ ํํ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ ๋ค ๋ด๊ฐ ๋๋ถ๋ถ์ ์๊ฐ์ ssh-agent๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด๋ ์ฆ๊ฐ์ ์ธ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ๋ํ ์ฒซ ๋ฒ์งธ ์ ์์ด ๋ ๊ฒ์ ๋๋ค.
์ฆ, ๋น ์์ด์ ํธ ํค๊ฐ ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์ธ์ฆ ์ค์ 1์์ผ ๊ฐ๋ฅ์ฑ์ด ๋๊ธฐ ๋๋ฌธ์ IdentityFile๊ณผ ๋ช ์์ ์ํธ ๊ตฌ์ฑ ์ง์ ๋ชจ๋์์ ํดํนํ ๊ฐ์น๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. . ์ค๋ ๋ด๊ฐ ๊ทธ๊ฒ์ ๊นฐ ์ ์๋์ง ๋ณผ ๊ฒ์ ๋๋ค.
์คํ์ 2.0a๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
1) ์ค์ ๋ก ํธ์คํธ๋ฅผ ์ ์ํ๊ณ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ์ฝ๊ฐ ํค๋งค๊ณ ์์ต๋๋ค. ๋๋ ๋ธ ์์์ด:
fab -H user<strong i="7">@host</strong>:22 some-task
ํ์ง๋ง ๋งค๋ฒ ํธ์คํธ ์ธ๋ถ ์ ๋ณด(์ฌ์ฉ์, ํธ์คํธ, ํฌํธ)๋ฅผ ์ ๋ฌํ๊ณ ์ถ์ง ์๋ค๋ฉด fabfile.py
( Connection
s ๋๋ Group
)์์ ํธ์คํธ๋ฅผ ๊ตฌ์ฑํ๋ ๋ฐฉ๋ฒ์ ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค. https://github.com/fabric/fabric/issues/1591#issuecomment -296343613์ ์ฌ๋ฐ๋ฅด๊ฒ ์ดํดํ๋ค๋ฉด ํ์ฌ ์ง์๋์ง ์์ต๋๋ค(https://github.com/fabric/fabric/issues/1594์์ ์ถ์ ). )?
2) ๋ํ SSH ํค( ~/.ssh/id_rsa
)๋ฅผ ์ํธํํ๊ณ $ ssh-add
๋ฅผ ssh-agent
ํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค. ssh-add -l
๋ฅผ ํตํด ํค๋ฅผ ๋์ดํ๋ฉด ๋ํ๋ฉ๋๋ค. ์ผ๋ถ ์์
์ ์คํํ ๋ ์ ์ ํ ์ฌ์ฉ์ ์ด๋ฆ์ ์ ๊ณตํฉ๋๋ค.
fab -H musttu<strong i="20">@host</strong> sometask
์ ์๋ํฉ๋๋ค. ๊ทธ๋ฌ๋ ์๋ชป๋ ์ฌ์ฉ์(์: fab -H bad_user<strong i="23">@host</strong> sometask
)๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋ํ๋ฉ๋๋ค.
Traceback (most recent call last):
...
File "/home/maximus/.virtualenvs/testenv/lib/python3.6/site-packages/paramiko/pkey.py", line 326, in _read_private_key
raise PasswordRequiredException('Private key file is encrypted')
paramiko.ssh_exception.PasswordRequiredException: Private key file is encrypted
๊ทธ๋ฌ๋ ๋๋ ๊ทธ๊ฒ์ด https://github.com/paramiko/paramiko/issues/387 ์ ์ํ๋ฉฐ ์ค์ ๋ก ํจ๋ธ๋ฆญ 2.0์ ๊ตญํ๋์ง ์๋๋ค๊ณ ๊ฐ์ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ค, ssh-agent๊ฐ ์ด๋ฏธ ๋ณตํธํ๋ ํค๋ฅผ ๊ฐ์ง๊ณ ์์ ๋ PasswordRequiredException: Private key file is encrypted
์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ ์ด์ํ๊ฒ ๋๊ปด์ง๋๋ค. ์ฌ๋ฐ๋ฅด๊ฒ ์ดํดํ๋ค๋ฉด ์๋ชป๋ ๋ก๊ทธ์ธ ํ paramiko
ํค๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ๋์ฒด๋๊ณ ์ ๊ณต๋ ์ํธ๊ฐ ์์ผ๋ฉด ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
3) ์ ํ ์ฃผ์ ์์ ๊ธฐ๋ฅ์ ํ์ฉํ๋ ๊ฒ์ด ์ข์ ๊ฒ์ ๋๋ค(IDE์์ ๋ ๋์ ์๋ ์์ฑ์ ์ํด). https://github.com/pyinvoke/invoke/pull/458 ์ ๊ณ ๋ คํ ์๊ฐ์ด ์์ต๋๊น?
4) ํจ์น์ํฌ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ผ๋ ์์ด๋์ด๊ฐ ๋ง์์ ๋ญ๋๋ค. Fabric 1.x์ ๊ฒฝ์ฐ ๋ง์ ์ถ๊ฐ ๊ธฐ๋ฅ์ ํฌํจํ๋ https://github.com/sebastien/cuisine (๊ทธ๊ฒ์ ๊ฝค ์ฃฝ์ ๊ฒ ๊ฐ์ต๋๋ค)์ด ์์ต๋๋ค(์ง์ ์ฌ์ฉํ์ง๋ ์์์ต๋๋ค). ํจ์น์ํฌ์ ๋ํ ์์ด๋์ด๊ฐ ์ ์ฌํ ๊ฒ์ ๊ตฌ์ถํ๋ ๊ฒ์ ๋๊น? ๋๋ ํญ์ ๋ค๋ฅธ ๋๊ตฌ๊ฐ ๋ฐ๋ฅด๋ ๋ค์ค ๋๋ ํ ๋ฆฌ/๋ค์ค ํ์ผ YAML/DSL ์ ๊ทผ ๋ฐฉ์์ ์ซ์ดํ์ผ๋ฉฐ ๋ ๋ง์ ์ ์ฐ์ฑ, ๋ ์ฅํฉํ ๊ตฌ๋ฌธ, IDE ์๋ ์์ฑ, ์ฌ์ด ๋๋ฒ๊น ๋ฑ์ ์ป๊ธฐ ์ํด ํ์ด์ฌ์ ๋จธ๋ฌผ๊ณ ์ถ์ต๋๋ค.
5) ํจ๋ธ๋ฆญ 2.0์ ๋ํ py 2.6 ๋ฐ 3.2-3.3 ์ง์์ ์ญ์ ํ์ญ์์ค. ์ฌ๋๋ค์ ๊ทธ๋ฅ ๋์ด๊ฐ์ผ ํ๋ ๊ฑฐ ์๋๋๊น?
@tuukkamustonen - ํผ๋๋ฐฑ ์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค! ์๋ต:
์ญํ ์ ์ค์ ๋ก #1594์์ ๋ค๋ฃจ๊ณ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ssh_config
์ง์์ด ์์ฒด ์์ค์์ ์ํํ๋ ๋ฐฉ์ ์ธ์ ํธ์คํธ๋ณ ๊ตฌ์ฑ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๋ ๊ฒ๊ณผ ๊ด๋ จ๋ ๋ฌธ์ ์ ๋ํ ๋ ๋ค๋ฅธ ํฐ์ผ์ด ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
ํจ๋ธ๋ฆญ ์์ค ๊ตฌ์ฑ์ ssh_config
๋ฐ ๊ทธ๋ฃน ๋๋ ๋ฐํ์ ๋ฐ์ดํฐ์ ๋ชจ๋ ๊ฒ๊ณผ ์ ํํ ์กฐ์ ํ๋ ๋ฐฉ๋ฒ์ ๊ฒฐ์ ํ๋ ๊ฒ์ ์ฌ์ด ์ผ์ด ์๋๋๋ค. ๋น๋ก ๊ทธ๊ฒ์ด ๊ณง ์ผ์ด๋์ผ ํ์ง๋ง; ๋๋ ์ฒซ ๋ฒ์งธ ์ด์ ๋์ ๋ฐ์ฏค ์๊ฐํ ์๋ฃจ์
์ ์ํฉ๋๋ค.
๋ค์ ๋งํ์ง๋ง, ์ด๊ฒ์ ๊ทํ๊ฐ ์ธ๊ธํ Paramiko ํฐ์ผ์ด๋ฉฐ ๊ทํ์ ์ถ์ธก์ด ์ ํํฉ๋๋ค. ์๋ชป๋ ์ฌ์ฉ์ ์ด๋ฆ ์ํฉ์ ํญ์ ๊ฒฐ๊ตญ ์คํจํฉ๋๋ค. Paramiko๋ ๋ฐ์ํ ๋ง์ง๋ง ์ค๋ฅ๋ง ์ถ์ ํ๊ธฐ ๋๋ฌธ์ ๋ง์ง๋ง์ผ๋ก ์๋ํ ๊ฒ์ ๋์คํฌ์ ์๋ ์ํธํ๋ ํค ์ฌ๋ณธ. (์๋ฅผ ๋ค์ด ํด๋น ํค๋ฅผ ๋ค๋ฅธ ๊ณณ์ผ๋ก ์ด๋ํ ๊ฒฝ์ฐ ๋ง์ง๋ง ์ค๋ฅ๋ ๋ค๋ฅธ ์ค๋ฅ๊ฐ ๋ฉ๋๋ค.)
๋ฐฉ๊ธ ํด๋น ํฐ์ผ์ ๋ํด ์ธ๊ธํ์ต๋๋ค. ๋์ผํ ์ ์ฒด ๊ธฐ๋ฅ์ ๋ํด ๊ธฐ์กด ํฐ์ผ์ ๋ณต์ ํ ์๋ ์๊ณ ๋ณต์ ํ์ง ์์ ์๋ ์์ต๋๋ค. ๋๋ ๊ทธ ์ค๋๋ ๊ฒ๋ค์ ๋ํด ์ธ๊ธํ๊ณ IIRC๋ "์, ํ์ด์ฌ 2๋ฅผ ๋๋ฝํ์ง ์๋ ํ ์ข์ ๊ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค."๋ผ๊ณ ๋งํ์ต๋๋ค. ๊ทธ๋ฌ๋ ๋๋ถ๋ถ์ ๋ ํฐ ๋๋ฝ ๊ธฐ๋ฅ๋งํผ ์ฐ์ ์์๊ฐ ๋์ง ์์ผ๋ฏ๋ก "๋จ์ง ๋ณํฉํ ์ ์๋ ๋ชจ๋ ์์๊ฐ PR์ ํ์ธํด์ผ ํจ" ๋ฒํท์ ์ํฉ๋๋ค. :)
์, ์์ฃผ ์ค๋๋์์ง๋ง ์ฌ์ ํ ๋ง์์์ ๋จ์ ์๋ #461์ ์ฐธ์กฐํ์ญ์์ค. ์์ฆ ํฐ ๋ฌธ์ ๋ ๊ทธ๋ฌํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ Invoke์ Fabric ๋ชจ๋์ ๊ฑธ์ณ ์์ฑ๋๋ ๋ฐฉ๋ฒ์ ๋๋ค. ๋ง์/๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๋ถํ ๋ ๋ก์ปฌ/์๊ฒฉ ์ปจํ ์คํธ๋ฅผ "๋ชจ๋ฅด๋" ์ผ๋ฐ Invoke ์์ ์ ๊ฐ๋จํ ์์ฑํ ์ ์์ต๋๋ค. ์ด ์์ ์ ์๊ฒฉ ์์คํ ์ ๋ํด ์คํํ๋ ค๊ณ ํ ๋ Fabric ์ฐ๊ฒฐ ์ปจํ ์คํธ๋ฅผ ์ ๋ฌํ ์ ์์ต๋๋ค.
์ด๋ฌํ "์ปจํ ์คํธ ๋ถ๊ฐ์ง๋ก " ์์ ์ 'ํธ์ถ' ๋ผ์ด๋ธ๋ฌ๋ฆฌ(๋๋ ์ฌ์ ํ ๋ค๋ฅธ Invoke ๊ด๋ จ ๋ผ์ด๋ธ๋ฌ๋ฆฌ)์ ์๊ธฐ๋ฅผ ์ํ ๊ฒ์ ๋๋ค. ๊ทธ๋ฌ๋ ์ผ๋ถ(์: ์ ๋ช ๋ น๋ฟ๋ง ์๋๋ผ ํ์ผ ์ ์ก๊ณผ ๊ด๋ จ๋ ๋ชจ๋ ๊ฒ)๋ "ํจ๋ธ๋ฆญ ์ธ์"์ด ํ์ํฉ๋๋ค. ๊ทธ ๊ฒฉ์ฐจ๋ฅผ ์ขํ ๋ฐฉ๋ฒ์ ์ฐพ๋ ๊ฒ์ด ๋ฌธ์ ์ ๋๋ค.
"ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํธ์ถ๋ง ํ์ํ๊ณ ํจ๋ธ๋ฆญ์ ํ์ํ์ง ์์ต๋๋ค. ํ์ง๋ง ํจ๋ธ๋ฆญ์ ์ค์นํ์ง ์๊ณ ์ฐ๊ฒฐ ์ปจํ ์คํธ๋ฅผ ์ ๋ฌํ์ง ์์ผ๋ฉด ์์ ์ ํ์ ์งํฉ์ด ๋ถํํ ๊ฒ์ ๋๋ค." ๋ ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ถํ ํ ์ ์์ต๋๋ค(Fabric ์งํฅ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ๋ณด๋ค ์ผ๋ฐ์ ์ธ Invoke ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํจ) ๋ฑ.
์ต๊ทผ์ ์ด๊ฒ์ ํ์คํ ์นด๋์ ์์ต๋๋ค. paramiko/paramiko#1070 ๋ฐ/๋๋ pyinvoke/invoke#364๋ฅผ ์ฐธ์กฐํ์ธ์. Invoke 1.0, Fabric 2.0 ๋ฐ Paramiko 3.0(๋๋ _์๋ง๋_, 2.4/2.5/๋ฌด์์ด๋ )์ ๋ชจ๋ Python 2.7/3.4 ์ด์์ ๋๋ค.
์ฝ (1):
์ด๋ฏธ ์๊ณ ๊ณ์๊ฒ ์ง๋ง Ansible์ ์ธ๋ฒคํ ๋ฆฌ ์์ ์์ด๋์ด๋ฅผ ์ป๊ณ ์ถ์ ์๋ ์์ต๋๋ค. ์๋๋ฉด ์๋ ์๋ ์์ต๋๋ค :).
์ฝ (4):
https://github.com/pyinvoke/invocations ๊ฐ ์ด์ ๋ํ ์๊ฒฌ์ด ์๋ ๋ฐฉ๋ฒ์ด๋ผ๊ณ ์๊ฐํฉ๋๋ค. Invocations๋ _conventions_์ ์ ๊ณตํ๊ณ ํจ์น์ํฌ/์๋ฆฌ ์คํ์ผ ํจํค์ง ์์ ๋น๋ํ ์ ์์ง๋ง ๊ท์น(๋ฆด๋ฆฌ์ค ๋๋ ๋ฌธ์ ํ ์คํธ)์ ์ ํธ๋ฆฌํฐ(ํ์ผ ๋ณต์ฌ ๋๋ ๊ถํ ๋ณ๊ฒฝ ๋ฐฉ๋ฒ)์ ํผํฉํ์ง ์์ ๊ฒ์ ๋๋ค.
๋ก์ปฌ ์ ์ฉ, ์๊ฒฉ ์ ์ฉ ๋ฐ ๋ก์ปฌ+์๊ฒฉ ์์ ์ ์ํ ์ ํธ๋ฆฌํฐ๋ฅผ ๋์ผํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(ํจ์น์ํฌ)์ ๋ฃ๋ ๋ฐ ๋ฌธ์ ๊ฐ ์์ต๋๋ค. ๋ฌธ์๋ก ์ฒ๋ฆฌํ ์ ์๋ ๋ชจ๋(๋ ์คํธ๋ง, ์ฃผ์์์ ์๋ ์์ฑ ๋ฑ)๋ฅผ ์ง์ํ๋ ์์ .
์ด๊ฒ์ ๋ก์ง์ 2๊ฐ ์ด์์ ํจํค์ง๋ก ๋๋๋ ๊ฒ๋ณด๋ค ๋ ๋์ ๊ฒ ๊ฐ์ต๋๋ค. "ํธ์ถ ์ ์ฉ" ํจํค์ง์ ์์ ์ ๋จผ์ ์ถ๊ฐํ๊ณ ("์๊ฒฉ ์ ์ฉ" ์์ ๋ ์์ ์ ์์) ๋์ค์ ์๊ฒฉ ์๋ฒ์์๋ ์๋ํ๋๋ก ์ง์์ ์ถ๊ฐํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น์? ์ฝ๋๋ฅผ ์ด๋, ๋ณต์ฌ ๋๋ ํ์ฅํ์๊ฒ ์ต๋๊น? ๋ ๊ฒฝ์ฐ ๋ชจ๋ ๋ ๋ง์ ์์ ์ด ํ์ํ๊ณ ์ฌ์ฉ์๋ ๋ค๋ฅธ ๊ฐ์ ธ์ค๊ธฐ ๋ฑ์ด ํ์ํ๋ฏ๋ก ๋ค์ ๋ฒ๊ฑฐ๋กญ๊ฒ ๋ค๋ฆฝ๋๋ค.
PyPi์์ ์ฌ์ฉํ ์ ์์ ๋งํผ ์ถฉ๋ถํ ์ฐ๋งํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํฉ๋๊น?
@haydenflinner ์์ผ๋ก 1~2์ฃผ์ ๊ฑธ์ณ ์งํ๋ฉ๋๋ค!! (๋ชฉํ๋ 5์ 10์ผ์ธ PyCon์ผ๋ก ๊ฐ๋ ๋นํ๊ธฐ๋ฅผ ํ๊ธฐ ์ ์ ๋ฆด๋ฆฌ์คํ๋ ๊ฒ์ ๋๋ค.)
์๋ฅผ ๋ค์ด ์ด๋ฒ ์ฃผ์ ์์ ํ ์ต๊ทผ ์ ๋ฐ์ดํธ๋ ์ ๊ทธ๋ ์ด๋ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ญ์์ค. http://docs.fabfile.org/en/v2/upgrading.html
์ฌ์ค 2.0.0 ์ด์ ๋ฒ์ ์ ์ค์ ํฐ์ผ์ ๊ณง ์๋ฝํ ์์ ์ด๋ฏ๋ก ์ง๊ธ ์ด ํฐ์ผ์ ๋ซ๋ ๊ฒ์ด ์ข์ต๋๋ค ๐
์ฐธ๊ณ ํ์ธ์. ์ํ์๋ฉด ์ฌ๊ธฐ์์ ๋๊ธ์ ๋ฌ ์ ์์ต๋๋ค. ๋ฆด๋ฆฌ์ค ์ ์ ๋ชจ๋ ํ๋ก์ ํธ ๊ด๋ฆฌ ์ค๋น์ ํจ๊ป ์ต์ํ ๋ช ๊ฐ์ง ๊ธฐ๋ฅ ์์ ์ ์๋ฃํ๊ธฐ๋ฅผ ํฌ๋งํฉ๋๋ค.
์ค๋ ํจ๋ธ๋ฆญ v2๋ฅผ ๋ณด์๋๋ฐ ์ฃ์กํฉ๋๋ค. ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ ์ ์ธ์๋ฅผ ์ทจํ์ง๋ง ๊ตฌ๋ฌธ์ด ๋ณ๊ฒฝ๋์์ต๋๋ค. http://docs.pyinvoke.org/en/1.1/concepts/invoking-tasks.html#task -command-line-arguments ์ฐธ์กฐ
@dgarstang ๋ฌด๋ฃ ๋ ธ๋๋ ฅ์ ์ ๊ณตํ๋ ์ฌ๋๋ค๊ณผ ์ข ๋ ์ค๋ฆฝ์ ์ด๊ฑฐ๋ ๊ณต๊ฐ์ ์ธ ์ด์กฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค! ๊ทธ๋ฅ ๐
@task(hosts=xxx)
๋ฅผ ์ฌ์ฉํ๋ ๊ธฐ๋ฅ์ ์ถ๊ฐํฉ๋๋ค.(re: 3: --hosts
๋ฐ ์น๊ตฌ๋ฅผ ์์
๋ณ ์ธ์์ธ ๊ฒ์ฒ๋ผ ์ ๊ณตํ๋ ์ธก๋ฉด์์, ์ธ์ ๊ฐ ์ถ๊ฐํ ์๋ ์๋ ํญ๋ชฉ์ด๋ฉฐ, ๊ทธ๋ด๋งํ ๊ฐ์น๊ฐ ์๋์ง ์ฌ๋ถ์ ๋ํด ์ฐข์ด์ก์ต๋๋ค. ์์
๋ณ --help
์ ์ ์ฌํฉ๋๋ค.
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
@haydenflinner ์์ผ๋ก 1~2์ฃผ์ ๊ฑธ์ณ ์งํ๋ฉ๋๋ค!! (๋ชฉํ๋ 5์ 10์ผ์ธ PyCon์ผ๋ก ๊ฐ๋ ๋นํ๊ธฐ๋ฅผ ํ๊ธฐ ์ ์ ๋ฆด๋ฆฌ์คํ๋ ๊ฒ์ ๋๋ค.)
์๋ฅผ ๋ค์ด ์ด๋ฒ ์ฃผ์ ์์ ํ ์ต๊ทผ ์ ๋ฐ์ดํธ๋ ์ ๊ทธ๋ ์ด๋ ๋ฌธ์๋ฅผ ์ฐธ์กฐํ์ญ์์ค. http://docs.fabfile.org/en/v2/upgrading.html
์ฌ์ค 2.0.0 ์ด์ ๋ฒ์ ์ ์ค์ ํฐ์ผ์ ๊ณง ์๋ฝํ ์์ ์ด๋ฏ๋ก ์ง๊ธ ์ด ํฐ์ผ์ ๋ซ๋ ๊ฒ์ด ์ข์ต๋๋ค ๐