วิธีดำเนินงานต่อเมื่อ Fabric ได้รับข้อผิดพลาด


94

เมื่อฉันกำหนดงานให้รันบนเซิร์ฟเวอร์ระยะไกลหลายตัวหากงานนั้นทำงานบนเซิร์ฟเวอร์หนึ่งและออกโดยมีข้อผิดพลาด Fabric จะหยุดและยกเลิกงานนั้น แต่ฉันต้องการทำให้ fabric ละเว้นข้อผิดพลาดและเรียกใช้งานบนเซิร์ฟเวอร์ถัดไป ฉันจะทำมันได้อย่างไร?

ตัวอย่างเช่น:

$ fab site1_service_gw
[site1rpt1] Executing task 'site1_service_gw'

[site1fep1] run: echo 'Nm123!@#' | sudo -S route
[site1fep1] err:
[site1fep1] err: We trust you have received the usual lecture from the local System
[site1fep1] err: Administrator. It usually boils down to these three things:
[site1fep1] err:
[site1fep1] err:     #1) Respect the privacy of others.
[site1fep1] err:     #2) Think before you type.
[site1fep1] err:     #3) With great power comes great responsibility.
[site1fep1] err: root's password:
[site1fep1] err: sudo: route: command not found

Fatal error: run() encountered an error (return code 1) while executing 'echo 'Nm123!@#' | sudo -S route '

Aborting.

คำตอบ:


147

จากเอกสาร :

... Fabric ตั้งค่าเริ่มต้นเป็นรูปแบบพฤติกรรม“ ล้มเหลวเร็ว”: หากมีสิ่งผิดปกติเกิดขึ้นเช่นโปรแกรมระยะไกลส่งคืนค่าที่ไม่เป็นศูนย์หรือโค้ด Python ของ fabfile พบข้อยกเว้นการดำเนินการจะหยุดทันที

โดยทั่วไปจะเป็นลักษณะการทำงานที่ต้องการ แต่มีข้อยกเว้นมากมายสำหรับกฎดังนั้น Fabric จึงจัดเตรียม env.warn_only ซึ่งเป็นการตั้งค่าแบบบูลีน ค่าเริ่มต้นเป็น False หมายความว่าเงื่อนไขข้อผิดพลาดจะส่งผลให้โปรแกรมยกเลิกทันที อย่างไรก็ตามหาก env.warn_only ถูกตั้งค่าเป็น True ในช่วงเวลาที่ล้มเหลว - ด้วยกล่าวว่าตัวจัดการบริบทการตั้งค่า - Fabric จะส่งข้อความเตือน แต่ดำเนินการต่อไป

ดูเหมือนว่าคุณสามารถใช้การควบคุมอย่างละเอียดในกรณีที่ข้อผิดพลาดถูกละเว้นโดยใช้ตัวsettingsจัดการบริบทได้ดังนี้:

from fabric.api import settings

sudo('mkdir tmp') # can't fail
with settings(warn_only=True):
    sudo('touch tmp/test') # can fail
sudo('rm tmp') # can't fail

13
อย่าลืมนำเข้าfrom fabric.api settings
cevaris

31

สำหรับ Fabric 1.5 มี ContextManager ที่ทำให้ง่ายขึ้น:

from fabric.api import sudo, warn_only

with warn_only():
    sudo('mkdir foo')

อัปเดต: ฉันยืนยันอีกครั้งว่าสิ่งนี้ใช้งานได้ใน ipython โดยใช้รหัสต่อไปนี้

from fabric.api import local, warn_only

#aborted with SystemExit after 'bad command'
local('bad command'); local('bad command 2')

#executes both commands, printing errors for each
with warn_only():
    local('bad command'); local('bad command 2')

คุณใช้ผ้ารุ่นไหน ฉันเพิ่งทดสอบใหม่ด้วย Fabric == 1.6.2 และใช้งานได้ดี
Chris Marinos

เป็นไปได้ว่าฉันใช้ Fabric == 1.9.0 และมันไม่ได้ผลสำหรับฉัน
cevaris

เพิ่งทดสอบเมื่อ 1.9.0 ด้วย ผลลัพธ์ของคุณเป็นอย่างไรเมื่อคุณลองใช้โค้ดตัวอย่างจากความคิดเห็นที่อัปเดตของฉัน
Chris Marinos

หากคุณไม่ต้องการพิมพ์คำเตือน / ข้อผิดพลาดคุณสามารถใช้ตัวจัดการการซ่อนบริบท:with hide('everything'):
np8

13

คุณยังสามารถตั้งค่าการตั้งค่าคำเตือนของสคริปต์ทั้งหมดให้เป็นจริงได้ด้วย

def local():
    env.warn_only = True

10

คุณควรตั้งค่าabort_exceptionตัวแปรสภาพแวดล้อมและตรวจจับข้อยกเว้น

ตัวอย่างเช่น:

from fabric.api        import env
from fabric.operations import sudo

class FabricException(Exception):
    pass

env.abort_exception = FabricException
# ... set up the rest of the environment...

try:
    sudo('reboot')
except FabricException:
    pass  # This is expected, we can continue.

คุณยังสามารถตั้งค่าเป็นบล็อกได้อีกด้วย โปรดดูเอกสารที่นี่


ขอบคุณสำหรับสิ่งนี้ แต่มีคำถามเดียว - เป็นไปได้หรือไม่ที่จะเข้าถึง / ส่งผ่านใน fabric env dict ปัจจุบันตามที่กำหนดไว้เมื่อเกิดข้อยกเว้น (ดังนั้นฉันสามารถพิมพ์การตั้งค่าเฉพาะบางอย่างได้โดยมีข้อยกเว้น)
Brian

@ ไบรอัน: คุณไม่สามารถตรวจสอบfabric.api.envภายในexceptบล็อกของคุณได้หรือไม่
ArtOfWarfare

@ArtOfWarefare อ่าโง่ฉันฉันพยายามหลีกเลี่ยงการห่องานทั้งหมดของฉันในการลอง / ยกเว้นและตั้งค่าแทนenv.abort_exception=MyExceptionเพื่อที่ฉันจะได้ทำงานล้มเหลวของตัวเอง มัน "ใช้ได้" ถ้าฉันใช้ฟังก์ชันแทนคลาส (ตรงตามข้อกำหนดที่เรียกได้สำหรับabort_exception) แต่ฉันยังคงแก้ไขปัญหาอื่น ๆ เกี่ยวกับแนวทางนั้น
Brian

@ ไบรอัน: ดังนั้นภายในร่างกายของฟังก์ชันนั้นตรวจสอบว่าfabric.api.envคืออะไร
ArtOfWarfare

8

ในผ้า 2.xคุณก็สามารถใช้วิงวอนของการทำงานกับเตือน = Trueโต้แย้ง อย่างไรก็ตามการเรียกใช้เป็นการพึ่งพาFabric 2.x :

from invoke import run
run('bad command', warn=True)

จากภายในงาน:

from invoke import task

@task
def my_task(c):
    c.run('bad command', warn=True)

7

ใน Fabric 1.3.2 เป็นอย่างน้อยคุณสามารถกู้คืนข้อยกเว้นได้โดยการจับSystemExitข้อยกเว้น ซึ่งจะมีประโยชน์หากคุณมีมากกว่าหนึ่งคำสั่งในการรันในชุดงาน (เช่นการปรับใช้) และต้องการล้างข้อมูลหากคำสั่งใดคำสั่งหนึ่งล้มเหลว


+1: ทดสอบแล้ว - ใช้งานได้กับ Fabric 1.9.0 ด้วย หลังจากจับสิ่งนี้คุณสามารถตรวจสอบSystemExitข้อความหรือรหัสของเพื่อดูรายละเอียดเพิ่มเติม
ArtOfWarfare

ดีกว่าการจับSystemExitตั้งabort_exceptionเป็นข้อยกเว้นอื่นเพื่อไม่ให้คุณจับข้อยกเว้นที่ไม่เกี่ยวข้องกับ Fabric โดยไม่ได้ตั้งใจ ดูคำตอบของฉันสำหรับตัวอย่าง: stackoverflow.com/a/27990242/901641
ArtOfWarfare

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.