Fabric: Secara opsional hindari menggunakan ssh jika pergi ke localhost

Dibuat pada 19 Agu 2011  ·  59Komentar  ·  Sumber: fabric/fabric

Keterangan

run()/Sudo() akan dengan cerdas melihat bahwa Anda akan pergi ke localhost dan hanya menjalankan local() sebagai gantinya. Ini mungkin akan menjadi hal opsional.

Komentar dari Jeff di IRC:

dan ya, maksud saya akan selalu ada overhead dengan ssh vs pipa lurus begitu saja Saya tidak berpikir akan sangat sulit untuk memperbarui run/Sudo (terutama di master sekarang karena mereka telah di-refactored) untuk memanggil/mengembalikan local( ) secara cerdas saya tidak yakin bahwa saya ingin perilaku semi magis itu di inti (bahkan dengan itu dimatikan secara default dengan optin untuk mengaktifkannya, itu akan membantu) tetapi meskipun demikian, itu akan menjadi eksperimen yang menarik. dan jika sesederhana yang saya pikirkan, sejujurnya saya tidak dapat menemukan alasan yang baik untuk tidak melakukannya (sekali lagi asalkan itu bukan perilaku default)

Awalnya disampaikan oleh Nick Welch ( mackstann ) pada 2009/11/11 di 01:39 EST

Hubungan

  • Digandakan oleh #364: Memungkinkan operasi lokal untuk melewati lapisan SSH
  • Terkait dengan #26: Menerapkan fitur "dry run"
Feature Network

Komentar yang paling membantu

Jika ada yang bertanya-tanya "mengapa ada orang yang melakukan ini?", Jawabannya adalah jika Anda memiliki pipa penyebaran, akan sangat membantu untuk menjalankan skrip penyebaran yang sama persis, tidak peduli lingkungan mana, daripada memiliki skrip pengaturan khusus untuk localhost vs segala sesuatu yang lain.

Semua 59 komentar

James Pearson (xiong.chiamiov) memposting:


Seperti yang juga disebutkan di irc, saya biasanya tidak menjalankan server ssh di mesin desktop, jadi saya sebenarnya tidak bisa ssh ke localhost.


pada 2009/11/11 at 3:13 EST

Travis Swicegood ( tswicegood ) memposting:


Saya baru saja mengimplementasikan sesuatu yang serupa malam ini dalam bentuk fungsi fabric.operations baru yang disebut do . Itu terlihat di env.run_as untuk melihat apakah itu sama dengan "lokal", dan dengan demikian beralih ke metode local alih-alih run (atau sudo jika sudo=True dilewatkan sebagai kwarg). Ini juga menangani awalan perintah lokal dengan sudo jika mereka menjalankan lokal.

Ini semacam cara berbeda untuk mengatasi masalah ini yang berfungsi tanpa mengubah perilaku run atau sudo . Perubahan ini tersedia di repositori saya .


pada 11-01-2010 pukul 12:22 EST

Morgan Goose ( goosemo ) memposting:


Saya benar-benar tidak melihat ini masuk akal. Apa gunanya menjalankan sebagai lokal. Salah satu persyaratan Fabric adalah sshd berjalan di mesin, jarak jauh atau loopback. Masalah lainnya adalah bahwa hanya mengubah lokal tidak memperhitungkan put, get, rsync_project, dan lainnya yang semuanya masih membutuhkan ssh. Mencoba mengimplementasikannya, hanya akan menyebabkan lebih banyak masalah, karena sekarang dalam ranah membuat fabfiles diterjemahkan ke bash.


pada 13-03-2011 pukul 23:14 EDT

Jeff Forcier ( bitprophet ) memposting:


Meskipun saya juga tidak 100% yakin bahwa ini adalah ide yang bagus, ini jelas merupakan sesuatu yang dibutuhkan oleh sejumlah pengguna -- permintaan lain telah diajukan sebagai #364 dengan penjelasan lain tentang kasus penggunaan.

Saya juga menambahkan tiket dry-run yang terkait dengan yang ini, karena (saya berasumsi - jika ada pengguna yang meminta dapat memverifikasi ini, itu bagus) kasus penggunaan utama untuk fitur ini adalah untuk pengujian/pengeringan- berlari.


pada 23-06-2011 pukul 11:26 EDT

Seperti disebutkan di #538, jika kita dapat sepenuhnya menormalkan ketiga runner sehingga dapat digunakan secara bergantian, kita harus memastikan bahwa pelepasan shell bekerja secara konsisten di ketiga runner tersebut. Saat ini kami tidak shell escape local , meskipun itu setidaknya sebagian karena tidak menggunakan pembungkus shell.

Jika ada yang bertanya-tanya "mengapa ada orang yang melakukan ini?", Jawabannya adalah jika Anda memiliki pipa penyebaran, akan sangat membantu untuk menjalankan skrip penyebaran yang sama persis, tidak peduli lingkungan mana, daripada memiliki skrip pengaturan khusus untuk localhost vs segala sesuatu yang lain.

+1 untuk fitur

+1

+10

+1

+1

Untuk menahan Anda, Anda bisa memastikan Anda menjalankan server OpenSSH. Pertama-tama lakukan sudo apt-get install ssh untuk memastikan Anda telah menginstalnya (bahkan jika Anda merasa sudah menginstalnya). Kemudian lakukan sudo service ssh start | stop | restart sesuai kebutuhan. Belajar dari thread ini .

+1

Kasus penggunaan saya sederhana: Saya ingin menggunakan skrip django-deploy yang sama untuk mengonfigurasi instans ec2 baik dengan cloud-init melalui CloudWatch (kasus untuk menjalankan perintah lokal) dan menggunakan fab deploy_django -H foo@bar .

+1

Ini akan sangat berguna. Satu kasus penggunaan yang saya miliki adalah menggunakan penyedia shell gelandangan untuk mengonfigurasi vm tertentu menggunakan fabric dan tanpa perlu ssh localhost.

+1

Saya terkejut tidak melihat ini di Fabric.

FYI: Implementasi fitur ini menjadi lebih kompleks ketika Anda memikirkan fungsi fabric seperti reboot() .

+1

Seharusnya sudah menjadi bagian dari inti !

+1

Sangat masuk akal: dari sudut pandang abstrak, local hanyalah kasus khusus dari run , di mana tidak ada mesin SSH yang terlibat.

Satu hal lagi untuk ditunjukkan (mungkin jelas): Fabric harus cukup pintar untuk memutuskan apakah run harus dikonversi ke local SETELAH membaca /etc/hosts.

Maksud saya: jika kita punya

env.host = [ 'mywebserver' ]

dan di /etc/hosts kita memiliki:

127.0.0.1 mywebserver

maka, setiap panggilan run sebenarnya adalah panggilan local .

Mengambil konsep ini selangkah lebih maju, kita juga harus memperlakukan run sebagai panggilan lokal ketika host jarak jauh memutuskan ke IP yang ditetapkan ke antarmuka jaringan mesin lokal.
Misalnya:
file bagus:

env.host = [ 'mywebserver' ]

/etc/hosts:

192.168.1.1 mywebserver

ip addr :

[...]
eth0:
  inet 192.168.1.1
[...]

+1

+1 :+1:

:+1:

+1

+1

Fabric 2 akan menggunakan pyinvoke/invoke jadi ini seharusnya cukup mudah dilakukan di sana. Saya akan menunggu Fabric 2 untuk cara non-retas untuk melakukan ini.

:+1:

+1

:+1:

:+1: Harap terapkan ini, terutama karena komputer mac tidak secara otomatis diatur untuk memiliki terowongan SSH yang dikonfigurasi untuk akses jarak jauh ke server localhost.

+1

+1 :)

+1 tolong

:+1:

:+1:

:+1:

Kami menggunakan Fab untuk membangun paket debian dan ini menambah kerumitan ekstra

teman-teman, halo semua
saya mencoba membuat tiruan kain dengan perbedaan:

  • run() fungsi bekerja dengan cara yang sama dengan subprocess.popen di bawah localhost seperti di bawah ssh terhubung ke remote host
  • Pabrik menggunakan openssh atau klien ssh lainnya (Anda harus memodifikasi konfigurasi untuk ini), sehingga Anda dapat menggunakan semua kekuatan soket ssh
  • Pabrik menggunakan pustaka gevent untuk eksekusi asinkron

Anda dapat melihat jika Anda membutuhkan fitur ini
https://github.com/Friz-zy/factory

Saya mungkin melewatkan sesuatu dalam diskusi ini, tetapi inilah yang saya lakukan untuk menggunakan kode yang sama dengan perintah fab run pada mesin localhost dan remote.

  1. Saya menetapkan env.use_ssh_config = True di fabfile.py saya
  2. ssh-copy-id localhost

Ini tidak menyelesaikan masalah Anda jika Anda tidak menjalankan server ssh di mesin lokal Anda

:+1:

+1

+1 Harap terapkan fitur ini :)

+1

Bisa sangat berguna untuk mem-bootstrap gambar Docker menggunakan skrip Fabric yang ada. Fitur ini akan menghindari untuk menginstal server SSH pada wadah, yang bertentangan dengan praktik terbaik Docker

+1

+1

+1

Selanjutnya untuk jawaban yang diberikan oleh @AntoniosHadji , berikut adalah instruksi lengkap untuk membuatnya berfungsi;

# Generate new SSH key for local usage
ssh-keygen -f ~/.ssh/id_rsa -N ''

# Add server keys to users known hosts (eliminates 'are you sure' messages);
ssh-keyscan -H localhost > ~/.ssh/known_hosts

# Allow user to ssh to itself
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

Sebenarnya, ini bisa dilakukan dengan menggunakan masakan . Anda perlu mengubah semua run eksekusi untuk referensi fungsi cuisine.run , yang dapat dilakukan dengan mudah dengan impor, dan mengubah mode ke lokal:

from cuisine import run, mode_local

mode_local()
print run("echo Hello")

Hebat @cgarciaarano

Untuk kasus penggunaan sederhana, ini berfungsi untuk saya:

from fabric.api import run, local
# ...
# in task:
  if env.host is None or env.host == 'localhost':
    run = local

:+1:

Saya ingin fabfile saya berjalan dari jarak jauh atau lokal ketika ssh bukan pilihan. Ini termasuk pembungkus lokal untuk get/put/exists dll.

:+1: Saya memiliki fabfiles yang berjalan baik secara lokal maupun jarak jauh dan saya akhirnya meretas fungsi pembungkus saya sendiri untuk menjalankan/lokal/menangani semua perbedaan halus seperti pengambilan keluaran dan penanganan kesalahan.

Bagaimana jika Anda memiliki koneksi ssh yang melakukan penerusan port dinamis dan pengikatan pada 127.0.0.2 (masih secara teknis localhost) pada port 2223. Saya dapat melihat bagaimana ini dapat menyebabkan masalah, untuk itu mencocokkan pada localhost dan menyelesaikan ke 127.0.0.1 daripada juga mendukung seluruh kelas 127.0.0.0/8 mungkin merupakan ide yang baik untuk ditangani.

@blade2005 Ya, seluruh rentang 127._._.* menunjuk ke localhost Anda (kecuali 127.0.0.0 dan 127.255.255.255) tetapi ketika Anda benar-benar menunjuk ke localhost Anda, Anda tidak akan menggunakan port kan?
Jadi saya percaya bahwa kita dapat dengan aman berasumsi bahwa 127.*.*.* == localhost dan ssh dapat dihindari tetapi 127.*.*.*:* menunjuk ke port yang diteruskan dan ssh diperlukan.

Sejujurnya, fitur ini mungkin lebih masuk akal sebagai plugin pihak ke-3 yang dibangun di atas kain, mirip dengan perpustakaan masakan. Kemudian kami hanya akan mengimpor fungsi yang dibungkus untuk run/get/put/etc, yang akan mengetahui apakah akan dijalankan secara lokal atau jarak jauh berdasarkan variabel env. Setidaknya dengan cara ini, seseorang dapat memulai ini untuk digunakan semua orang.

Saya mengimplementasikan sesuatu secara lokal, dan ini lebih banyak berfungsi daripada hanya beralih antara lokal/jalankan. Anda harus mempertimbangkan awalan, direktori yang diubah, pengguna sudo, dll.

Secara singkat memikirkan hal ini dalam konteks tiket terkait 2.0 lainnya, dan menyadari bahwa ada lebih banyak lagi yang muncul selain hanya " run menjadi rebinding dari local ":

  • Segala jenis tugas mode campuran yang benar-benar menggunakan local dan run , atau salah satu dari put / get , secara inheren menjadi bermasalah: operasi dengan definisi yang jelas 'lokal' dan 'jarak jauh' "berakhir" sekarang keduanya menunjuk secara lokal.

    • Saya berasumsi bahwa itu adalah kasus penggunaan minoritas (jika itu sama sekali) tetapi masih perlu diketahui, bahkan jika itu "memanggil operasi apa pun tetapi run atau sudo menaikkan DoesntMakeAnySenseError " atau apa pun.

    • put / get mungkin bisa berubah menjadi shutil.copy atau sejenisnya

    • local mungkin tidak akan diubah (walaupun saat mencetak apa yang terjadi, mungkin masih ingin dibedakan dari apa yang diawali dengan run-except-locally ...?)

    • Disinggung di atas, berbagai metode/contextmanagers manipulasi konteks seperti prefix , cd dll semuanya perlu dijawab pertanyaan serupa.

  • Selain itu, menjalankan perintah sudo secara lokal, berpotensi besar dan mungkin memerlukan pemeriksaan keamanan tambahan.

    • Kecuali jika itu juga menjadi pengikatan lain ke local , yang merupakan kemungkinan lain. Meskipun bukan perintah yang besar, perintah sudo yang bahkan bekerja secara lokal (yaitu yang di-deploy ke, dan di-deploy dari, Linux) mungkin perlu tetap diistimewakan secara lokal (mis. apt / yum dan teman-teman, mengutak-atik firewall, dll).

  • sudo juga (seperti yang disebutkan di atas oleh Jon) perlu meningkatkan kemungkinan untuk mengonfigurasi vektor konfigurasi lokal-vs-jarak jauh yang berbeda karena pengguna Sudo, kata sandi, dll cenderung berbeda antara kedua sisi.

    • Meskipun karena saya memikirkan semua ini dalam konteks Fab 2, penggantian konfigurasi per-Host yang diharapkan mungkin akan menyelesaikan bagian itu setidaknya - konteks localhost hanya akan diberikan nilai yang sesuai. (Plus, sebagai subkelas "untuk menjalankan hal-hal jarak jauh secara lokal" khusus, Context ia dapat melakukan hal-hal lain juga, jika diperlukan).

@max-arnold sedang mencoba ini di v2 alpha dan mengalami masalah yang membingungkan, yang diharapkan pada saat ini karena - saya belum sampai ke kasus penggunaan tiket khusus ini, selain memastikan run dan local memiliki API yang serupa mungkin.

Saat ini, masalah besar hanyalah sifat dan API objek yang terikat pada konteks tugas ( c atau ctx atau apa pun namanya) posarg. Saat ini, dan sekali lagi, ini tidak dimaksudkan untuk menjadi final, hanya bagaimana akhirnya sejauh ini:

  • secara default, ketika dijalankan oleh Invoke Executor , atau oleh Fab 2 FabExecutor ketika tidak ada host yang hadir, itu adalah invoke.Context , yang memiliki run yang berjalan secara lokal , dan tidak memiliki local ;
  • ketika Fab 2 memiliki Host untuk dijalankan, ia menciptakan fabric.Connection , yang run berjalan dari jarak jauh, dan yang local adalah rebinding dari run Invoke

Diperlukan pemikiran yang lebih spesifik, termasuk melihat kasus penggunaan di sini dan di tiket terkait. Brainstorming begitu saja:

  • Solusi yang berguna (atau setidaknya _dokumentasi_) untuk ini hampir pasti ada di inti (per obrolan sebelumnya tentang itu tinggal di luar inti) karena:

    • ini adalah kasus penggunaan yang cukup umum

    • mudah kacau

    • itu diperlukan untuk mengimplementasikan versi yang kompatibel dengan v2 dari patchwork (née contrib ) dan/atau invocations (Memanggil versi yang sama), terutama karena ini menginformasikan seberapa banyak mereka dapat berbagi kode melakukan. Banyak tugas dan/atau subrutin dalam basis kode semacam itu mungkin ingin dijalankan secara lokal atau jarak jauh.

  • Pada intinya ini tentang API apa yang diharapkan dari objek Konteks di mana tugas mungkin tidak tahu pasti "bagaimana" itu dipanggil
  • Bisa bergantung pada bagaimana tugas dihasilkan, yaitu versi berbeda dari @task dan/atau kwargs sama, di mana pengguna dapat menyatakan harapan mereka (yaitu "Saya benar-benar ingin diberikan konteks yang mampu jarak jauh", "tolong jangan pernah memberi saya konteks yang mampu jarak jauh", dll)

    • Kami mungkin ingin _memerlukan_ ini untuk menghindari ambiguitas ( ZoP #12 )

    • Semakin saya memikirkannya, semakin jelas bahwa kami ingin Fabric menumbuhkan pembungkus ringannya sendiri di sekitar @task / Task ; basis kode pure-Invoke hanya akan menggunakan @task yang akan selalu memicu diberi vanilla Context , sementara tugas yang dibuat melalui versi Fabric setidaknya memiliki opsi untuk diberikan Connection , jika tidak memerlukannya.

    • Kelemahannya adalah jenis tugas "Saya dapat berguna secara lokal XOR dari jarak jauh" yang disebutkan di atas; tugas yang hanya menginginkan satu opsi "jalankan perintah" dan tidak menggabungkan kedua mode secara bersamaan. Ini _tidak_ bekerja dengan baik dengan solusi "dekorator menyatakan jenis konteks" karena _perlu_ untuk 'mengalihkan' jenis konteks tergantung pada siapa yang memanggilnya dan bagaimana caranya.

    • Meskipun itu sebenarnya satu titik keseluruhan dari API saat ini; tugas-tugas itu _tidak peduli_ tentang subkelas konteks, _selama ctx.run() ada_.

    • Jadi mereka yang mungkin ingin didekorasi dengan versi "Saya hanya membutuhkan basis, konteks vanilla" dari @task , dengan pemahaman bahwa seseorang dari sudut pandang pemanggilan Fabric (atau seperti Fabric) memiliki opsi untuk memberikannya tugaskan Connection alih-alih Context .



      • Yang membawa kita kembali bertanya-tanya bagaimana tepatnya menjalankan tugas, alias pyinvoke/invoke#170



  • Terlepas dari penerapannya, kami harus memastikan bahwa kami meminimalkan potensi footgun re: pengguna melakukan hal-hal seperti:

    • Mengharapkan local ketika tidak ada (Kode yang mengharapkan Kain/Sambungan dijalankan melalui Invoke)

    • Mengharapkan run untuk berjalan secara lokal ketika seseorang malah diberi konteks dengan remote run (Panggilan/kode yang mengharapkan konteks dijalankan melalui Fabric)

    • Ada lagi dari komentar tambahan Max di sini

  • Seperti yang terlihat dalam komentar yang jauh lebih lama, sub-kasus penggunaan di sini adalah pengguna yang mengharapkan v2 yang setara dengan Connection('localhost').run('foo') untuk _tidak menggunakan SSH_ tetapi bertindak persis seperti Connection('localhost').local('foo') .

    • Saya _menebak_ kami sebenarnya tidak ingin melakukan ini karena rasanya seperti pistol jahat bagi siapa pun yang mencoba melakukan pemeriksaan kewarasan localhost. Itu hanya terasa terlalu ajaib bagi saya begitu saja. Tapi saya terbuka untuk argumen, mungkin berdasarkan keikutsertaan (mis., atur opsi konfigurasi seperti ssh.localhost_becomes_subprocess = True atau apa pun.)

Satu-satunya usecase saya di sini saat ini adalah upload_template() dapat merender template secara lokal.

Tentu saja orang bisa melakukannya seperti ini:

#http://matthiaseisen.com/pp/patterns/p0198/
import os
import jinja2


def render(tpl_path, context):
    path, filename = os.path.split(tpl_path)
    return jinja2.Environment(
        loader=jinja2.FileSystemLoader(path or './')
    ).get_template(filename).render(context)

Tetapi mengapa tidak memiliki opsi untuk merender secara lokal?

Penggunaan utama fitur ini, dalam kasus saya, adalah untuk menyebarkan konfigurasi aplikasi ke mesin lokal saya untuk pengujian lokal.

Pertimbangkan Anda memiliki settings.py.j2 yang dirender ke server tujuan setelah penerapan dan di sana bernama settings.py dan hanya berisi kode python, tanpa jinja.
Sekarang Anda ingin menguji secara lokal, tetapi secara lokal belum ada settings.py , karena perlu dirender dari settings.py.j2 .
Jadi aplikasi Anda tidak dapat memulai, dan Anda harus membuat settings.py secara manual untuk pengujian lokal Anda.

Ini sangat melelahkan, dan seharusnya lebih mudah.

Misalnya, di Ansible saya hanya akan memberi tahu tugas bahwa itu akan menggunakan "koneksi lokal", dan itu akan dirender pada Host lokal tanpa mencoba ssh ke dalamnya.

Sampai fitur ini tersedia di Fabric, saya akan menggunakan solusi yang ditempelkan di atas, tentu saja, karena ini hanya beberapa baris kode. Seharusnya lebih mudah meskipun imho. Saya merasa itu benar-benar jenis kain yang seharusnya memudahkan saya.

@fninja Saya belum mem-porting upload_template itu sendiri tapi saya sangat setuju bahwa itu termasuk dalam ruang masalah ini. Bisa dibilang orang bisa menangani ini hanya dengan memisahkan langkah render pembungkus Jinja dan langkah upload-beberapa-string upload, terutama karena yang terakhir sudah ada dalam bentuk "serahkan FLO ke put ". Misalnya:

from StringIO import StringIO # too lazy to remember the newer path offhand
from somewhere.jinja_wrapper import render
from invoke import task

<strong i="9">@task</strong>
def render_settings(c):
    rendered = render('settings.py.j2', {'template': 'params'})
    c.put(StringIO(rendered), 'remote/path/to/settings.py')

Tapi mungkin masih ada ruang untuk analog 1-stop yang lebih pendek lagi ke upload_template yang bisa berupa metode Connection atau subrutin yang mengambil argumen Connection .

Either way, itu menimbulkan lebih banyak pertanyaan tentang: bagaimana tepatnya memperlakukan hal semacam ini - misalnya, objek Context Invoke-only tidak memiliki put / get . Apakah layak menambahkannya? Sangat masuk akal bagi pengguna Fabric dalam konteks tiket ini (maka upload_template atau w/e cukup memanggil put dalam kedua kasus), tetapi untuk pengguna murni-Invoke, ini aneh dan bagian API yang tidak berguna.

+1 untuk menjadikan ini fitur inti

Pos silang dari #1637. Hanya sebuah ide:

from fabric import task, local

<strong i="6">@task</strong>
<strong i="7">@local</strong>
def build(ctx):
    with ctx.cd('/project/dir'):
        ctx.run('build > artifact.zip')

<strong i="8">@task</strong>
def deploy(conn):
    build(local(conn))

    with conn.cd('/remote/path'), local(conn).cd('/project/dir'):
        conn.put(remote_path='build.zip', local_path='artifact.zip')

Pada dasarnya local() dapat bertindak sebagai dekorator/pengelola konteks/fungsi dan mengubah Connection menjadi Context .

Kasus penggunaan lain yang menurut saya tidak disebutkan: Membangun perpustakaan fungsi yang dapat digunakan kembali. Dalam kasus saya, sebagian besar perintah git . Saya menulis dorun yang terlalu sederhana yang menyembunyikan perbedaan antara parameter fungsi run dan local (pada v1); fungsi mana yang dipilih dilewatkan sebagai parameter. Berikut adalah git checkout misalnya:

def git_checkout(branch, remote='origin', run=run):
    """Checkout a branch if necessary."""

    if branch == git_current_branch(run=run):
        return
    elif branch in git_local_branches(run=run):
        dorun('git checkout ' + branch, run=run)
    else:
        dorun('git checkout -t -b {0} {1}/{0}'.format(branch, remote), run=run)


def git_current_branch(run=run):
    """Get the current branch (aka HEAD)"""

    output = dorun('git name-rev --name-only HEAD', run=run)
    return output.strip()


def git_local_branches(run=run):
    """Get a list of local branches; assumes in repo directory."""

    output = dorun('git branch --no-color', run=run)
    branches = {l.strip().split(' ')[-1]
                for l in output.strip().split('\n')}
    return branches

Ini terlihat seperti ini:

from fabric.api import run as run_remote, local as run_local

def dorun(*args, **kwargs):
    """Work around the fact that "local" and "run" are very different."""
    kwargs.setdefault('run', run_remote)
    run = kwargs.pop('run')

    if run == run_local:
        kwargs.setdefault('capture', True)
    elif 'capture' in kwargs:
        del kwargs['capture']

    return run(*args, **kwargs)

Saya tidak tahu apa yang terjadi dengan sudo dan ada masalah yang tidak dapat saya tangani dengan mudah, seperti memperluas ~remoteuser untuk menghasilkan jalur.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

haydenflinner picture haydenflinner  ·  5Komentar

Grazfather picture Grazfather  ·  4Komentar

26huitailang picture 26huitailang  ·  3Komentar

yuvadm picture yuvadm  ·  5Komentar

bitprophet picture bitprophet  ·  6Komentar