run()/sudo() würde intelligent erkennen, dass Sie zu localhost wechseln und stattdessen einfach local() ausführen. Dies wäre wahrscheinlich eine optionale Sache.
Kommentare von Jeff im IRC:
und ja, ich meine, es wird immer Overhead mit ssh vs. ) Ich bin mir nicht sicher, ob ich dieses halbmagische Verhalten im Kern haben möchte (auch wenn es standardmäßig deaktiviert ist und eine Option aktiviert ist, aber das würde helfen), aber trotzdem wäre es ein interessantes Experiment. und wenn es so einfach ist, wie ich denke, kann ich ehrlich gesagt keinen guten Grund dafür finden (wiederum vorausgesetzt, es ist nicht das Standardverhalten)
Ursprünglich eingereicht von Nick Welch ( mackstann ) am 11.11.2009 um 13:39 Uhr EST
James Pearson (xiong.chiamiov) schrieb:
Wie auch auf irc erwähnt, führe ich normalerweise keinen SSH-Server auf einem Desktop-Rechner aus, daher kann ich tatsächlich keine SSH-Verbindung zu localhost herstellen.
am 11.11.2009 um 15:13 Uhr EST
Travis Swicegood ( tswicegood ) hat gepostet:
Ich habe heute Abend etwas Ähnliches in Form einer neuen Fabric.operations-Funktion namens do
implementiert. Es prüft env.run_as
zu sehen, ob es gleich "lokal" ist, und wechselt dabei zur Methode local
anstelle der Methode run
(oder sudo
wenn sudo=True
als Kwarg übergeben wird). Es behandelt auch das Präfixieren lokaler Befehle mit sudo
falls sie lokal ausgeführt werden.
Dies ist eine andere Art, dieses Problem zu umgehen, das funktioniert, ohne das Verhalten von run
oder sudo
zu ändern. Diese Änderungen sind in meinem Repository verfügbar.
am 2010-01-11 um 12:22 Uhr EST
Morgan Goose ( goosemo ) hat gepostet:
Ich finde das wirklich nicht plausibel. Was bringt es, als lokal zu laufen. Eine der Anforderungen von Fabric ist, dass sshd auf dem Computer, Remote oder Loopback ausgeführt wird. Das andere Problem ist, dass nur das Ändern von local put, get, rsync_project und andere nicht berücksichtigt, die alle noch ssh benötigen. Der Versuch, diese zu implementieren, würde nur wirklich mehr Probleme verursachen, da es jetzt im Bereich der Übersetzung von Fabfiles in Bash liegt.
am 13.03.2011 um 23:14 Uhr EDT
Jeff Forcer ( Bitprophet ) schrieb:
Obwohl ich auch nicht 100% davon überzeugt bin, dass dies eine großartige Idee ist, ist es eindeutig etwas, das eine Reihe von Benutzern für notwendig halten – eine weitere Anfrage wurde als Nr. 364 mit einer anderen Erklärung des Anwendungsfalls eingereicht.
Ich habe auch das Probelauf-Ticket in Bezug auf dieses hinzugefügt, weil (ich nehme an - wenn einer der anfordernden Benutzer dies überprüfen kann, wäre das großartig) der Hauptanwendungsfall für diese Funktion ist das Testen / Trocken- Laufen.
am 23.06.2011 um 11:26 Uhr EDT
Wie in #538 erwähnt, müssen wir, wenn wir jemals in der Lage sind, die drei Runner vollständig zu normalisieren, damit sie austauschbar verwendet werden können, sicherstellen, dass die Shell-Escape-Funktion konsistent über sie hinweg funktioniert. Im Moment verwenden wir kein Shell-Escape local
, obwohl das zumindest teilweise daran liegt, dass es keinen Shell-Wrapper verwendet.
Wenn sich jemand fragt, "warum sollte das jemand tun?", lautet die Antwort, dass es bei einer Bereitstellungspipeline hilfreich sein kann, unabhängig von der Umgebung genau das gleiche Bereitstellungsskript auszuführen, anstatt ein spezielles Setup-Skript für localhost zu verwenden gegen alles andere.
+1 für die Funktion
+1
+10
+1
+1
Um Sie aufzuhalten, können Sie einfach sicherstellen, dass der OpenSSH-Server läuft. Führen Sie zuerst sudo apt-get install ssh
, um sicherzustellen, dass Sie es installiert haben (auch wenn Sie denken, dass Sie es tun). Dann mach sudo service ssh start
| stop
| restart
nach Bedarf. Aus diesem Thread gelernt .
+1
Mein Anwendungsfall ist einfach: Ich möchte dasselbe django-deploy-Skript verwenden, um ec2-Instanzen sowohl mit cloud-init über CloudWatch (der Fall für die Ausführung lokaler Befehle) als auch mit dem regulären fab deploy_django -H foo@bar
zu konfigurieren.
+1
Dies wäre wirklich nützlich. Ein Anwendungsfall, den ich habe, ist die Verwendung von vagrant Shell Provisioner, um eine bestimmte VM mit Fabric zu konfigurieren, ohne dass localhost ssh benötigt wird.
+1
Ich war überrascht, das nicht schon in Fabric zu sehen.
Zu Ihrer Information: Die Implementierung dieser Funktion wird komplexer, wenn Sie an Fabric-Funktionen wie reboot()
denken.
+1
Sollte schon Teil des Kerns sein!
+1
Es wäre durchaus sinnvoll: Aus abstrakter Sicht ist local
nur ein Sonderfall von run
, bei dem keine SSH-Maschinerie beteiligt ist.
Noch ein Hinweis (vielleicht offensichtlich): Fabric sollte schlau genug sein, um zu entscheiden, ob run
nach dem Lesen von /etc/hosts in local
umgewandelt werden soll.
Ich meine: wenn wir haben
env.host = [ 'mywebserver' ]
und in /etc/hosts haben wir:
127.0.0.1 mywebserver
dann sollten alle run
Aufrufe eigentlich local
Aufrufe sein.
Wenn wir dieses Konzept noch einen Schritt weiterführen, sollten wir run
als lokalen Anruf behandeln, wenn der Remote-Host eine IP auflöst, die einer Netzwerkschnittstelle des lokalen Computers zugewiesen ist.
Z.B:
Fabfile:
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 verwendet pyinvoke/invoke, daher sollte dies dort ziemlich einfach sein. Ich würde auf Fabric 2 warten, um dies zu tun.
:+1:
+1
:+1:
:+1: Bitte implementieren Sie dies, insbesondere da Mac-Computer nicht automatisch so eingerichtet sind, dass SSH-Tunnel für den Remote-Zugriff auf den localhost-Server konfiguriert sind.
+1
+1 :)
+1 bitte
:+1:
:+1:
:+1:
Wir verwenden Fab zum Erstellen von Debian-Paketen und dies erhöht die Komplexität
Leute, hallo zusammen
Ich versuche, einen Stoffklon mit Unterschied zu erstellen:
Sie können einen Blick darauf werfen, wenn Sie diese Funktion benötigen
https://github.com/Friz-zy/factory
Ich kann in dieser Diskussion etwas übersehen, aber hier ist, was ich getan habe, um denselben Code mit dem fabelhaften run
Befehl sowohl auf localhost als auch auf Remote-Rechnern zu verwenden.
env.use_ssh_config = True
in meiner fabfile.py eingestelltDies löst Ihr Problem nicht, wenn Sie keinen SSH-Server auf Ihrem lokalen Computer ausführen
:+1:
+1
+1 Bitte implementieren Sie diese Funktion :)
+1
Könnte sehr nützlich sein, um Docker-Images mithilfe vorhandener Fabric-Skripts zu booten. Diese Funktion würde die Installation eines SSH-Servers auf dem Container vermeiden, was gegen die Best Practices von Docker verstößt
+1
+1
+1
Neben der Antwort von
# 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
Tatsächlich kann dies mithilfe von Küche getan werden. Sie müssen alle run
Ausführungen so ändern, dass sie auf die cuisine.run
Funktion verweisen, was einfach mit einem Import durchgeführt werden kann, und den Modus auf lokal ändern:
from cuisine import run, mode_local
mode_local()
print run("echo Hello")
Großartig @cgarciaarano
Für einfache Anwendungsfälle funktioniert das bei mir:
from fabric.api import run, local
# ...
# in task:
if env.host is None or env.host == 'localhost':
run = local
:+1:
Ich möchte, dass meine Fabfile remote oder lokal ausgeführt wird, wenn ssh keine Option ist. Dazu gehören lokale Wrapper für get/put/exists usw.
:+1: Ich habe Fabfiles, die sowohl lokal als auch remote laufen, und ich habe meine eigenen Wrapper-Funktionen für run/local/get gehackt, um mit all den subtilen Unterschieden wie Ausgabeerfassung und Fehlerbehandlung umzugehen.
Was ist, wenn Sie eine ssh-Verbindung haben, die dynamische Portweiterleitung und Bindung auf 127.0.0.2 (technisch immer noch localhost) auf Port 2223 durchführt. Ich kann sehen, wie dies zu Problemen führen kann, zu diesem Zweck auf localhost abzugleichen und auf 127.0.0.1 anstatt auch aufzulösen? Es könnte eine gute Idee sein, die gesamte Klasse 127.0.0.0/8 zu unterstützen.
@blade2005 Ja , der gesamte 127._._.*-Bereich zeigt auf Ihren localhost (außer 127.0.0.0 und 127.255.255.255), aber wenn Sie tatsächlich auf Ihren localhost zeigen, verwenden Sie nicht den Port, oder?
Ich glaube also, dass wir mit Sicherheit davon ausgehen können, dass 127.*.*.* == localhost
und ssh vermieden werden können, aber 127.*.*.*:*
auf einen weitergeleiteten Port zeigt und ssh benötigt wird.
Ehrlich gesagt, würde diese Funktion wahrscheinlich mehr Sinn machen als ein auf Fabric basierendes Drittanbieter-Plugin, ähnlich wie die Küchenbibliothek. Dann würden wir einfach verpackte Funktionen für run/get/put/etc importieren, die wissen, ob sie lokal oder remote basierend auf einer env-Variablen ausgeführt werden sollen. Auf diese Weise könnte zumindest jemand damit beginnen, damit jeder es verwenden kann.
Ich habe etwas lokal implementiert, und es ist viel mehr Arbeit, als nur zwischen lokal/ausgeführt zu wechseln. Sie müssen Präfixe, geänderte Verzeichnisse, Sudo-Benutzer usw. berücksichtigen.
Habe kurz im Zusammenhang mit einem anderen 2.0-bezogenen Ticket darüber nachgedacht und festgestellt, dass noch mehr auftaucht als nur " run
wird zu einer erneuten Bindung von local
":
local
als auch run
oder eines von put
/ get
, wird von Natur aus problematisch: Operationen mit klar definierten 'local' und 'remote' "enden" jetzt beide lokal.run
oder sudo
erhöht DoesntMakeAnySenseError
" oder was auch immer.put
/ get
könnte sich vermutlich in shutil.copy
oder ähnliches verwandelnlocal
würde vermutlich nicht geändert werden (obwohl beim Drucken, was passiert, wahrscheinlich immer noch unterschieden werden soll von dem, was run-except-locally
vorangestellt ist...?)prefix
, cd
usw. müssen alle ähnliche Fragen beantworten.sudo
Befehlen eine potenziell enorme Waffe und erfordert wahrscheinlich zusätzliche Sicherheitsüberprüfungen.local
, was eine andere Möglichkeit ist. Obwohl es kein großes ist, müssen alle sudo
Befehle, die sogar lokal funktionieren (dh einer, der auf Linux verteilt und von Linux bereitgestellt wird), vermutlich lokal privilegiert bleiben (z. B. apt
/ yum
und Freunde, Firewall-Tüftelei usw.).sudo
auch (wie oben von Jon erwähnt) die Möglichkeit erweitern, unterschiedliche lokale vs. entfernte Konfigurationsvektoren zu konfigurieren, da sich der sudo-Benutzer, das Passwort usw. zwischen den beiden Seiten wahrscheinlich unterscheiden.localhost
würden einfach die entsprechenden Werte übergeben. (Außerdem könnte sie als dedizierte "zum lokalen Ausführen von Remote-Dings" Context
Unterklasse bei Bedarf auch andere Dinge tun).@max-arnold hat dies in der v2-Alpha ausprobiert und stieß auf verwirrende Probleme, was zu diesem Zeitpunkt zu erwarten ist, da ich den Anwendungsfall dieses speziellen Tickets noch nicht erreicht hatte, außer dass ich run
sicherstellte und local
haben so ähnliche APIs wie möglich.
Im Moment ist das große Problem einfach die Art und API des Objekts, das an den Kontext einer Aufgabe gebunden ist ( c
oder ctx
oder wie auch immer man es nennt) posarg. Dies soll derzeit noch nicht endgültig sein, es ist bisher nur so ausgegangen:
Executor
von Invoke oder von FabExecutor
von Fab 2 ausgeführt wird, wenn keine Hosts vorhanden sind, ist es invoke.Context
, das ein run
, das lokal ausgeführt wird , und es fehlt ein local
;fabric.Connection
, dessen run
remote ausgeführt wird und dessen local
eine Neubindung von run
von Invoke ist. Es sind spezifischere Überlegungen erforderlich, einschließlich der Betrachtung von Anwendungsfällen hier und in verknüpften Tickets. Brainstorming aus der Hand:
patchwork
(geb. contrib
) und/oder invocations
(Invokes Version davon) sinnvoll zu implementieren, insbesondere da es informiert, wie viel Code sie teilen können tun. Viele Tasks und/oder Subroutinen in diesen Arten von Codebasen möchten möglicherweise lokal oder remote ausgeführt werden.@task
und/oder Kwargs dazu, wo der Benutzer seine Erwartungen angeben kann (dh "Ich möchte wirklich einen remotefähigen Kontext erhalten", "Bitte geben Sie mir niemals einen remotefähigen Kontext" usw.)@task
/ Task
herum anbaut; pure-Invoke-Codebasen würden nur ihre @task
was immer dazu führen würde, dass eine Vanilla Context
, während Aufgaben, die über die Version von Fabric erstellt wurden, zumindest die Möglichkeit haben, eine Connection
, falls nicht erforderlich.ctx.run()
existiert_.@task
dekoriert werden, mit dem Verständnis, dass jemand von einem Fabric- (oder Fabric-ähnlichen) Aufruf-Standpunkt die Möglichkeit hat, diese zu geben Aufgaben a Connection
statt Context
.local
erwartet, wenn es nicht existiert (Fabric/Connection-erwartete Codeausführung über Invoke)run
lokal ausgeführt wird, wenn einem stattdessen ein Kontext mit einem entfernten run
zugewiesen wurde (Aufruf/Kontext-erwarteter Code wird über Fabric ausgeführt)Connection('localhost').run('foo')
_kein SSH verwendet_, sondern sich stattdessen genau wie Connection('localhost').local('foo')
verhält.ssh.localhost_becomes_subprocess = True
oder was auch immer.)Mein einziger Anwendungsfall hier im Moment wäre, dass upload_template()
eine Vorlage lokal rendern kann.
Natürlich könnte man es so machen:
#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)
Aber warum nicht eine Option zum lokalen Rendern haben?
Der Hauptzweck dieser Funktion besteht in meinem Fall darin, die Anwendungskonfiguration für lokale Tests auf meinem lokalen Computer bereitzustellen.
Stellen Sie sich vor, Sie haben ein settings.py.j2
, das bei der Bereitstellung auf dem Zielserver gerendert wird, und dort heißt es settings.py
und enthält nur Python-Code, kein Jinja.
Jetzt möchten Sie lokal testen, aber lokal gibt es noch kein settings.py
, da es von settings.py.j2
gerendert werden muss.
Ihre App kann also nicht gestartet werden und Sie müssen für Ihre lokalen Tests manuell ein separates settings.py
erstellen.
Das ist sehr anstrengend und sollte einfacher sein.
Zum Beispiel würde ich in Ansible der Aufgabe einfach mitteilen, dass sie "lokale Verbindung" verwenden wird, und sie würde auf dem lokalen Host rendern, ohne zu versuchen, per SSH darauf zuzugreifen.
Bis diese Funktion in Fabric verfügbar ist, verwende ich natürlich die oben eingefügte Lösung, da es sich nur um ein paar Codezeilen handelt. Es sollte aber imho einfacher sein. Ich glaube, das ist wirklich die Art von Stoff, die mir leicht gemacht werden sollte.
@fninja Ich habe upload_template
selbst noch nicht portiert, aber ich stimme definitiv zu, dass es in diesen Problembereich fällt. Man könnte dies wohl handhaben, indem man einfach den Jinja-Wrapping-Renderschritt und den Upload-some-String-Upload-Schritt aufteilt, zumal letzterer bereits in Form von "hand a FLO to put
" existiert. Z.B:
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')
Aber es gibt wahrscheinlich noch Platz für ein noch kürzeres 1-Stopp-Analogon zu upload_template
, das entweder eine Connection
Methode oder eine Subroutine mit einem Connection
Argument wäre.
In jedem Fall wirft es weitere Fragen auf, wie genau diese Art von Dingen zu behandeln ist - zum Beispiel haben Context
Objekte, die nur aufrufen, keine put
/ get
. Lohnt es sich, sie hinzuzufügen? Es macht für Fabric-Benutzer im Kontext dieses Tickets viel Sinn (dann können upload_template
oder wir können in beiden Fällen einfach put
aufrufen), aber für reine Invoke-Benutzer ist es bizarr und nutzloser Teil der API.
+1, um dies zu einer Kernfunktion zu machen
Crosspost von #1637. Nur eine Idee:
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')
Grundsätzlich kann local()
als Dekorateur/Kontextmanager/Funktion fungieren und Connection
in Context
umwandeln.
Ein weiterer Anwendungsfall, von dem ich glaube, dass er nicht erwähnt wurde: Erstellen einer Bibliothek mit wiederverwendbaren Funktionen. In meinem Fall sind es hauptsächlich git
Befehle. Ich habe ein zu einfaches dorun
, das die Unterschiede zwischen den Funktionsparametern run
und local
verbirgt (in Version 1); welche Funktion gewählt wird, wird als Parameter übergeben. Hier ist zum Beispiel ein git checkout
:
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
Es sieht aus wie das:
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)
Ich habe keine Ahnung, was mit sudo
passiert, und es gibt Probleme, mit denen ich nicht so einfach umgehen kann, wie das Erweitern von ~remoteuser
, um einen Pfad zu erzeugen.
Hilfreichster Kommentar
Wenn sich jemand fragt, "warum sollte das jemand tun?", lautet die Antwort, dass es bei einer Bereitstellungspipeline hilfreich sein kann, unabhängig von der Umgebung genau das gleiche Bereitstellungsskript auszuführen, anstatt ein spezielles Setup-Skript für localhost zu verwenden gegen alles andere.