Fabric: Fabric 2 ์•ŒํŒŒ/๋ฒ ํƒ€ ํ”ผ๋“œ๋ฐฑ ๋ฉ”ํƒ€ ํ‹ฐ์ผ“!

์— ๋งŒ๋“  2017๋…„ 04์›” 21์ผ  ยท  28์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: fabric/fabric

์ด ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ๊ณผ ๋ชจ๋“  ๋งํฌ๋ฅผ ๋จผ์ € ์ฝ์—ˆ๋Š”์ง€ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค!: http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta


๊ธฐ์กด ํ‹ฐ์ผ“์—์„œ ๋‹ค๋ฃจ์ง€ ์•Š๋Š” ๋ฌธ์ œ์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋‚จ๊ธธ ์ˆ˜ ์žˆ๋Š” ๊ณณ์ž…๋‹ˆ๋‹ค. ๋จผ์ € ์•„๋ž˜ ์žฅ์†Œ๋ฅผ ๊ฒ€์ƒ‰ํ•ด์ฃผ์„ธ์š”!!


๊ด€๋ จ ํ•ญ๋ชฉ์„ ์ฐพ์ง€ ๋ชปํ•˜์…จ์Šต๋‹ˆ๊นŒ? ์•„๋ž˜์— ์˜๊ฒฌ์„ ๋‚จ๊ฒจ์ฃผ์„ธ์š”! ํ”ผ๋“œ๋ฐฑ์„ _๋น„์Šทํ•˜์ง€๋งŒ ์ด์— ๊ตญํ•œ๋˜์ง€ ์•Š๋Š”_ ์ฐพ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • "๋‹น์‹ ์ด ๋งˆ๋ฒ•์˜ ๊ธ€๋กœ๋ฒŒ ๋น„๊ฐ์ฒด ์ง€ํ–ฅ ๋ชจ๋“œ๋กœ ๋Œ์•„๊ฐˆ ๋•Œ๊นŒ์ง€ 2.0 ์‚ฌ์šฉ์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค!" (ํ•˜์ง€๋งŒ ๋‚˜๋Š” ๋‹น์‹ ์„ pyinvoke/invoke#186์— ์—ฐ๊ฒฐํ•˜๊ณ  ๊ฑฐ๊ธฐ์— ๊ทผ๊ฑฐ๋ฅผ ์ œ๊ณตํ•˜๋„๋ก ์š”์ฒญํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค ;))
  • "$feature๋กœ ํ•œ ์ž‘์—…์ด ์ •๋ง ๋งˆ์Œ์— ๋“œ๋Š”๋ฐ ์ •๋ง ํ•„์š”ํ•œ $sub-feature๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค! ๊ณ„ํš๋œ ๊ฑด๊ฐ€์š”?" (๋‚˜๋Š” '์˜ˆ', '์•„๋‹ˆ์š”' ๋˜๋Š” '์•„๋‹ˆ์˜ค'๋ผ๊ณ  ๋งํ•  ๊ฒƒ์ด์ง€๋งŒ ์ด์ œ ์ง์ ‘ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค! ํ•ต์‹ฌ์— ์žˆ์„ ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค!')
  • "$feature๋กœ ํ•œ ์ž‘์—…์ด ์ •๋ง ๋งˆ์Œ์— ๋“ค์ง€๋งŒ ์ง€๊ธˆ ์„ค์ •๋œ ๋ฐฉ์‹์œผ๋กœ๋Š” $sub-use-case๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ต๊ฑฐ๋‚˜ ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค!" (์ž์„ธํ•œ ๋‚ด์šฉ์„ ๋ฌป๊ณ  ๋ณด๊ณ  ์‹ถ์€ API์˜ ์˜ˆ์ œ PR์„ ์š”์ฒญํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.)

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

@haydenflinner ์•ž์œผ๋กœ 1~2์ฃผ์— ๊ฑธ์ณ ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค!! (๋ชฉํ‘œ๋Š” 5์›” 10์ผ์ธ PyCon์œผ๋กœ ๊ฐ€๋Š” ๋น„ํ–‰๊ธฐ๋ฅผ ํƒ€๊ธฐ ์ „์— ๋ฆด๋ฆฌ์Šคํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

์˜ˆ๋ฅผ ๋“ค์–ด ์ด๋ฒˆ ์ฃผ์— ์ž‘์—…ํ•œ ์ตœ๊ทผ ์—…๋ฐ์ดํŠธ๋œ ์—…๊ทธ๋ ˆ์ด๋“œ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. http://docs.fabfile.org/en/v2/upgrading.html

์‚ฌ์‹ค 2.0.0 ์ด์ƒ ๋ฒ„์ „์˜ ์‹ค์ œ ํ‹ฐ์ผ“์„ ๊ณง ์ˆ˜๋ฝํ•  ์˜ˆ์ •์ด๋ฏ€๋กœ ์ง€๊ธˆ ์ด ํ‹ฐ์ผ“์„ ๋‹ซ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค ๐Ÿ‘

๋ชจ๋“  28 ๋Œ“๊ธ€

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 - ํ”ผ๋“œ๋ฐฑ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์‘๋‹ต:

  1. ์—ญํ• ์€ ์‹ค์ œ๋กœ #1594์—์„œ ๋‹ค๋ฃจ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ssh_config ์ง€์›์ด ์ž์ฒด ์ˆ˜์ค€์—์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ์‹ ์™ธ์— ํ˜ธ์ŠคํŠธ๋ณ„ ๊ตฌ์„ฑ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ–๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋˜ ๋‹ค๋ฅธ ํ‹ฐ์ผ“์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

    ํŒจ๋ธŒ๋ฆญ ์ˆ˜์ค€ ๊ตฌ์„ฑ์„ ssh_config ๋ฐ ๊ทธ๋ฃน ๋˜๋Š” ๋Ÿฐํƒ€์ž„ ๋ฐ์ดํ„ฐ์˜ ๋ชจ๋“  ๊ฒƒ๊ณผ ์ •ํ™•ํžˆ ์กฐ์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ ์‰ฌ์šด ์ผ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋น„๋ก ๊ทธ๊ฒƒ์ด ๊ณง ์ผ์–ด๋‚˜์•ผ ํ•˜์ง€๋งŒ; ๋‚˜๋Š” ์ฒซ ๋ฒˆ์งธ ์ดˆ์•ˆ ๋Œ€์‹  ๋ฐ˜์ฏค ์ƒ๊ฐํ•œ ์†”๋ฃจ์…˜์„ ์›ํ•ฉ๋‹ˆ๋‹ค.

  2. ๋‹ค์‹œ ๋งํ•˜์ง€๋งŒ, ์ด๊ฒƒ์€ ๊ท€ํ•˜๊ฐ€ ์–ธ๊ธ‰ํ•œ Paramiko ํ‹ฐ์ผ“์ด๋ฉฐ ๊ท€ํ•˜์˜ ์ถ”์ธก์ด ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค. ์ž˜๋ชป๋œ ์‚ฌ์šฉ์ž ์ด๋ฆ„ ์ƒํ™ฉ์€ ํ•ญ์ƒ ๊ฒฐ๊ตญ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค. Paramiko๋Š” ๋ฐœ์ƒํ•œ ๋งˆ์ง€๋ง‰ ์˜ค๋ฅ˜๋งŒ ์ถ”์ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์ง€๋ง‰์œผ๋กœ ์‹œ๋„ํ•œ ๊ฒƒ์€ ๋””์Šคํฌ์— ์žˆ๋Š” ์•”ํ˜ธํ™”๋œ ํ‚ค ์‚ฌ๋ณธ. (์˜ˆ๋ฅผ ๋“ค์–ด ํ•ด๋‹น ํ‚ค๋ฅผ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ์ด๋™ํ•œ ๊ฒฝ์šฐ ๋งˆ์ง€๋ง‰ ์˜ค๋ฅ˜๋Š” ๋‹ค๋ฅธ ์˜ค๋ฅ˜๊ฐ€ ๋ฉ๋‹ˆ๋‹ค.)

  3. ๋ฐฉ๊ธˆ ํ•ด๋‹น ํ‹ฐ์ผ“์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋™์ผํ•œ ์ „์ฒด ๊ธฐ๋Šฅ์— ๋Œ€ํ•ด ๊ธฐ์กด ํ‹ฐ์ผ“์„ ๋ณต์ œํ•  ์ˆ˜๋„ ์žˆ๊ณ  ๋ณต์ œํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๊ทธ ์˜ค๋ž˜๋œ ๊ฒƒ๋“ค์— ๋Œ€ํ•ด ์–ธ๊ธ‰ํ–ˆ๊ณ  IIRC๋Š” "์˜ˆ, ํŒŒ์ด์ฌ 2๋ฅผ ๋”๋Ÿฝํžˆ์ง€ ์•Š๋Š” ํ•œ ์ข‹์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค."๋ผ๊ณ  ๋งํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋Œ€๋ถ€๋ถ„์˜ ๋” ํฐ ๋ˆ„๋ฝ ๊ธฐ๋Šฅ๋งŒํผ ์šฐ์„  ์ˆœ์œ„๊ฐ€ ๋†’์ง€ ์•Š์œผ๋ฏ€๋กœ "๋‹จ์ง€ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ์ƒ์ž๊ฐ€ PR์„ ํ™•์ธํ•ด์•ผ ํ•จ" ๋ฒ„ํ‚ท์— ์†ํ•ฉ๋‹ˆ๋‹ค. :)

  4. ์˜ˆ, ์•„์ฃผ ์˜ค๋ž˜๋˜์—ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ ๋งˆ์Œ์†์— ๋‚จ์•„ ์žˆ๋Š” #461์„ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค. ์š”์ฆ˜ ํฐ ๋ฌธ์ œ๋Š” ๊ทธ๋Ÿฌํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ Invoke์™€ Fabric ๋ชจ๋‘์— ๊ฑธ์ณ ์ž‘์„ฑ๋˜๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค. ๋งŽ์€/๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๋ถ„ํ• ๋œ ๋กœ์ปฌ/์›๊ฒฉ ์ปจํ…์ŠคํŠธ๋ฅผ "๋ชจ๋ฅด๋Š”" ์ผ๋ฐ˜ Invoke ์ž‘์—…์„ ๊ฐ„๋‹จํžˆ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์€ ์›๊ฒฉ ์‹œ์Šคํ…œ์— ๋Œ€ํ•ด ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•  ๋•Œ Fabric ์—ฐ๊ฒฐ ์ปจํ…์ŠคํŠธ๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

    ์ด๋Ÿฌํ•œ "์ปจํ…์ŠคํŠธ ๋ถˆ๊ฐ€์ง€๋ก " ์ž‘์—…์€ 'ํ˜ธ์ถœ' ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(๋˜๋Š” ์—ฌ์ „ํžˆ ๋‹ค๋ฅธ Invoke ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ)์— ์žˆ๊ธฐ๋ฅผ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ผ๋ถ€(์˜ˆ: ์‰˜ ๋ช…๋ น๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŒŒ์ผ ์ „์†ก๊ณผ ๊ด€๋ จ๋œ ๋ชจ๋“  ๊ฒƒ)๋Š” "ํŒจ๋ธŒ๋ฆญ ์ธ์‹"์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๊ฒฉ์ฐจ๋ฅผ ์ขํž ๋ฐฉ๋ฒ•์„ ์ฐพ๋Š” ๊ฒƒ์ด ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

    "ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ํ˜ธ์ถœ๋งŒ ํ•„์š”ํ•˜๊ณ  ํŒจ๋ธŒ๋ฆญ์€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŒจ๋ธŒ๋ฆญ์„ ์„ค์น˜ํ•˜์ง€ ์•Š๊ณ  ์—ฐ๊ฒฐ ์ปจํ…์ŠคํŠธ๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ž‘์—…์˜ ํ•˜์œ„ ์ง‘ํ•ฉ์ด ๋ถˆํ‰ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค." ๋‘ ๊ฐœ์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ถ„ํ• ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(Fabric ์ง€ํ–ฅ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋Š” ๋ณด๋‹ค ์ผ๋ฐ˜์ ์ธ Invoke ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ํ•„์š”ํ•จ) ๋“ฑ.

  5. ์ตœ๊ทผ์— ์ด๊ฒƒ์€ ํ™•์‹คํžˆ ์นด๋“œ์— ์žˆ์Šต๋‹ˆ๋‹ค. 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๋ฅผ ๋ณด์•˜๋Š”๋ฐ ์ฃ„์†กํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

  1. ๋กค ๋ฐํ”„๋Š” ์–ด๋””๋กœ ๊ฐ”์Šต๋‹ˆ๊นŒ? ๋ช…๋ น์ค„์—์„œ ๋” ์ด์ƒ ์—ญํ•  ์ด๋ฆ„์„ ์ „๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด๊ฒƒ์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผํ•ฉ๋‹ˆ๊นŒ?
  2. ๋ช…๋ น์ค„์—์„œ ๋” ์ด์ƒ ์ž‘์—…์— ์ธ์ˆ˜๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด๊ฒƒ๋„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋‚˜์š”?
  3. -H ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ ์ž‘์—… ๋งค๊ฐœ๋ณ€์ˆ˜ ์•ž์— ์™€์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ๊ทธ ๋ฐ˜๋Œ€์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋„ˆ๋ฌด ๋”์ฐํ•ฉ๋‹ˆ๋‹ค.

์ž‘์—…์€ ์ธ์ˆ˜๋ฅผ ์ทจํ•˜์ง€๋งŒ ๊ตฌ๋ฌธ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. http://docs.pyinvoke.org/en/1.1/concepts/invoking-tasks.html#task -command-line-arguments ์ฐธ์กฐ

@dgarstang ๋ฌด๋ฃŒ ๋…ธ๋™๋ ฅ์„ ์ œ๊ณตํ•˜๋Š” ์‚ฌ๋žŒ๋“ค๊ณผ ์ข€ ๋” ์ค‘๋ฆฝ์ ์ด๊ฑฐ๋‚˜ ๊ณต๊ฐ์ ์ธ ์–ด์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค! ๊ทธ๋ƒฅ ๐Ÿ˜‰

  1. IIRC๊ฐ€ ์—…๊ทธ๋ ˆ์ด๋“œ ๋ฌธ์„œ์— ๋งํฌ๋˜์–ด ์žˆ๋Š” #1594๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.
  2. @ploxiln ์ด ์—ฌ๊ธฐ์— ๋Œ์•„์™”์Šต๋‹ˆ๋‹ค
  3. (๋ถ€๋ถ„์ ์œผ๋กœ) #1772๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”. ์ด๊ฒƒ์€ ๋งˆ์Šคํ„ฐ์— ๋ณ‘ํ•ฉ๋˜์–ด ๊ณง ๋‚˜์˜ฌ ๊ฒƒ์ž…๋‹ˆ๋‹ค. @task(hosts=xxx) ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

(re: 3: --hosts ๋ฐ ์นœ๊ตฌ๋ฅผ ์ž‘์—…๋ณ„ ์ธ์ˆ˜์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์ œ๊ณตํ•˜๋Š” ์ธก๋ฉด์—์„œ, ์–ธ์  ๊ฐ€ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋Š” ํ•ญ๋ชฉ์ด๋ฉฐ, ๊ทธ๋Ÿด๋งŒํ•œ ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š”์ง€ ์—ฌ๋ถ€์— ๋Œ€ํ•ด ์ฐข์–ด์กŒ์Šต๋‹ˆ๋‹ค. ์ž‘์—…๋ณ„ --help ์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰