Fabric: 如果转到本地主机,可选择避免使用 ssh

创建于 2011-08-19  ·  59评论  ·  资料来源: fabric/fabric

描述

run()/sudo() 会智能地看到您将访问 localhost 并改为运行 local() 。 这可能是一个可选的事情。

Jeff 对 IRC 的评论:

是的,我的意思是 ssh 和直管总是会产生开销,我认为更新 run/sudo(尤其是在 master 中,因为它们已经被重构)来调用/返回本地( ) 聪明地,我并不肯定我希望在核心中具有这种半神奇的行为(即使默认情况下关闭它并选择启用它,这会有所帮助)但即便如此,这仍将是一个有趣的实验。 如果它像我想的那么简单,老实说,我想不出一个很好的理由不这样做(再次假设它不是默认行为)

最初由尼克·韦尔奇(提交mackstann )上2009-11-11下午1时39 EST

关系

  • 由 #364 复制:允许本地操作绕过 SSH 层
  • 与 #26 相关:实现“试运行”功能
Feature Network

最有用的评论

如果有人想知道“为什么会有人这样做?”,答案是,如果您有部署管道,那么运行完全相同的部署脚本会很有帮助,无论在哪种环境中,而不是为 localhost 使用特殊的安装脚本与其他一切。

所有59条评论

James Pearson (xiong.chiamiov) 发布:


正如在 irc 上提到的,我通常不会在台式机上运行 ssh 服务器,所以我实际上无法 ssh 到本地主机。


就在2009-11-11下午3时13 EST

Travis Swicegood ( tswicegood ) 发布:


我刚刚在今晚以一个名为do的新 fabric.operations 函数的形式实现了类似的东西。 它查看env.run_as以查看它是否等于“local”,然后切换到local方法而不是run (或sudo如果sudo=True作为 kwarg 传入)。 如果本地命令在本地运行,它还会处理带有sudo前缀的本地命令。

这是解决这个问题的一种不同方式,它可以在不改变runsudo 。 这些更改在我的存储库中可用。


2010-01-11 12:22

摩根鹅( goosemo ) 发布:


我真的不认为这是合理的。 以本地身份运行有什么意义。 Fabric 的要求之一是在机器上运行 sshd,远程或环回。 另一个问题是,仅更改 local 并没有考虑到 put、get、rsync_project 和其他仍然需要 ssh 的内容。 试图实现这些,只会导致更多的问题,因为它现在处于将 fabfiles 转换为 bash 的领域。


2011-03-13 11:14pm EDT

Jeff Forcier ( bitprophet ) 发布:


虽然我也不是 100% 相信这是一个好主意,但显然许多用户认为需要它 - 另一个请求已提交为 #364,并附有用例的另一个解释。

我还添加了与此相关的试运行票,因为(我假设 - 如果任何提出请求的用户可以验证这一点,那就太好了)此功能的主要用例是用于测试/试运行 -跑步。


2011-06-2311:26am EDT

如#538 中所述,如果我们能够完全标准化三个运行器,以便它们可以互换使用,我们需要确保外壳转义在它们之间一致地工作。 现在我们没有 shell 转义local ,尽管这至少部分是因为它没有使用 shell 包装器。

如果有人想知道“为什么会有人这样做?”,答案是,如果您有部署管道,那么运行完全相同的部署脚本会很有帮助,无论在哪种环境中,而不是为 localhost 使用特殊的安装脚本与其他一切。

+1 功能

+1

+10

+1

+1

为了阻止您,您只需确保 OpenSSH 服务器正在运行。 首先执行sudo apt-get install ssh以确保您已安装它(即使您认为已安装)。 然后做sudo service ssh start | stop | restart根据需要。 从这个线程中学到的

+1

我的用例很简单:我想使用相同的django-deploy 脚本通过 CloudWatch 使用cloud-init (运行本地命令的情况)和使用常规fab deploy_django -H foo@bar配置 ec2 实例。

+1

这将非常有用。 我的一个用例是使用 vagrant shell 配置器来配置特定的虚拟机,而无需 ssh localhost。

+1

我很惊讶没有在 Fabric 中看到这个。

仅供参考:当您考虑像reboot()这样的结构函数时,此功能的实现会变得更加复杂。

+1

应该已经是核心的一部分了!

+1

这完全有道理:从抽象的角度来看, local只是run一个特例,其中不涉及 SSH 机制。

还有一件事要指出(也许很明显):Fabric 应该足够聪明,可以决定是否在读取 /etc/hosts 后将run转换为local

我的意思是:如果我们有

env.host = [ 'mywebserver' ]

在 /etc/hosts 我们有:

127.0.0.1 mywebserver

那么,任何run调用实际上应该是local调用。

将这个概念更进一步,当远程主机解析为分配给本地机器的网络接口的 IP 时,我们还应该将run视为本地调用。
例如:
工厂文件:

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 将使用 pyinvoke/invoke,所以这应该很容易在那里完成。 我会等待 Fabric 2 以一种非黑客的方式来做到这一点。

:+1:

+1

:+1:

:+1: 请执行此操作,尤其是因为 mac 计算机不会自动设置为配置 SSH 隧道以远程访问本地主机服务器。

+1

+1 :)

+1 请

:+1:

:+1:

:+1:

我们正在使用 Fab 来构建 debian 包,这增加了额外的复杂性

伙计们,大家好
我尝试创建不同的织物克隆:

  • run() 函数的工作方式与 localhost 下的 subprocess.popen 与 ssh 连接到远程主机下的工作方式相同
  • 工厂使用 openssh 或任何其他 ssh 客户端(您应该为此修改配置),因此您可以使用 ssh 套接字的所有功能
  • 工厂使用 gevent 库进行异步执行

需要这个功能的可以看看
https://github.com/Friz-zy/factory

在这个讨论中我可能遗漏了一些东西,但这是我在本地主机和远程机器上使用相同的代码与 fab run命令所做的。

  1. 我在 fabfile.py 中设置了env.use_ssh_config = True
  2. ssh-copy-id 本地主机

如果您没有在本地机器上运行 ssh 服务器,这并不能解决您的问题

:+1:

+1

+1 请实现此功能:)

+1

使用现有的 Fabric 脚本引导 Docker 镜像可能非常有用。 此功能将避免在容器上安装 SSH 服务器,这违背了Docker 最佳实践

+1

+1

+1

除了@AntoniosHadji提供的答案

# 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

实际上,这可以使用food来完成。 您需要将所有run执行更改为引用cuisine.run函数,这可以通过导入轻松完成,并将模式更改为本地:

from cuisine import run, mode_local

mode_local()
print run("echo Hello")

伟大的@cgarciaarano

对于简单的用例,这对我有用:

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

:+1:

当 ssh 不是一个选项时,我希望我的 fabfile 远程或本地运行。 这包括用于 get/put/exists 等的本地包装器。

:+1: 我有在本地和远程运行的 fabfiles,我最终破解了我自己的 run/local/get 包装函数来处理所有细微的差异,例如输出捕获和错误处理。

如果您有一个 ssh 连接在 2223 端口上的 127.0.0.2(技术上仍然是本地主机)上执行动态端口转发和绑定怎么办。我可以看到这会如何导致问题,为此在本地主机上匹配并解析为 127.0.0.1 而不是同时支持整个 127.0.0.0/8 类可能是一个好主意。

@blade2005 是的,整个 127._._.* 范围都指向您的本地主机(127.0.0.0 和 127.255.255.255 除外),但是当您实际指向本地主机时,您不会使用端口,对吗?
所以我相信我们可以安全地假设127.*.*.* == localhost和 ssh 可以避免,但127.*.*.*:*指向转发端口并且需要 ssh。

老实说,这个功能可能更有意义,因为它是一个基于结构的 3rd 方插件,类似于美食库。 然后我们只需为 run/get/put/etc 导入包装函数,这些函数将根据环境变量知道是在本地还是远程运行。 至少这样,有人可以让每个人都开始使用它。

我在本地实现了一些东西,它比在本地/运行之间切换要多得多。 您必须考虑前缀、更改的目录、sudo 用户等。

在另一个与 2.0 相关的票证的上下文中简要地考虑了这一点,并意识到除了“ run成为local的重新绑定”之外还有更多:

  • 任何类型的同时使用localrunput / get任何一种的真正混合模式任务,都会变得固有问题:具有明确定义的操作'local' 和 'remote' “ends” 现在都指向本地。

    • 我认为这是一个少数用例(如果它是一个),但它仍然需要弄清楚,即使它“调用任何操作,但runsudo引发DoesntMakeAnySenseError " 或其他什么。

    • put / get大概可以变成shutil.copy或类似的

    • local大概不会改变(尽管在打印正在发生的事情时,可能仍然希望它与run-except-locally以...为前缀的内容区分开来?)

    • 上面提到,各种上下文操作方法/上下文管理器,如prefixcd等都需要回答类似的问题。

  • 除此之外,在本地运行sudo命令,是一个潜在的巨大的footgun,可能需要额外的安全检查。

    • 除非它也成为local另一个绑定,这是另一种可能性。 虽然不是很大,但任何在本地工作的sudo命令(即部署到 Linux 和从 Linux 部署)大概都需要在本地保持特权(例如apt / yum和朋友,防火墙修补等)。

  • sudo也(如 Jon 上面提到的)需要增加配置不同的 local-vs-remote 配置向量的可能性,因为 sudo 用户、密码等可能在双方之间有所不同。

    • 尽管我在 Fab 2 的上下文中考虑了所有这些,但预期的每主机配置覆盖可能至少可以解决这部分问题 - localhost上下文将简单地传递适当的值。 (另外,作为专用的“用于在本地运行远程事物”的Context子类,如果需要,它也可以做其他事情)。

@max-arnold 正在 v2 alpha 中尝试这个并遇到了令人困惑的问题,这是可以预料的,因为 - 除了确保run之外,我还没有了解这个特定票证的用例和local具有尽可能相似的 API。

目前,最大的问题只是绑定到任务上下文( cctx或任何名称)posarg 的对象的性质和 API。 目前,再一次,这不是最终的,它只是到目前为止的结果:

  • 默认情况下,当由 Invoke 的Executor或由 Fab 2 的FabExecutor在没有主机存在时执行时,它是invoke.Context ,它有一个run在本地运行, 并且缺少local
  • 当 Fab 2 有主机要运行时,它会创建一个fabric.Connection ,其run远程运行,其local是 Invoke 的run的重新绑定

需要更具体的思考,包括查看此处和链接票证中的用例。 临时头脑风暴:

  • 一个有用的解决方案(或至少是文档)应该几乎肯定存在于核心中(根据之前关于它生活在核心之外的讨论),因为:

    • 这是一个足够常见的用例

    • 很容易搞砸

    • 需要有效地实现patchwork (née contrib ) 和/或invocations (Invoke 的版本)的 v2 兼容版本,特别是因为它告知他们可以共享多少代码做。 这类代码库中的许多任务和/或子程序可能希望在本地或远程运行。

  • 本质上,它是关于从 Context 对象期望什么 API 的,其中任务可能不确定“如何”调用它
  • 可能取决于任务的生成方式,即不同版本的@task和/或 kwargs 相同,用户可以在其中声明他们的期望(即“我真的想获得一个远程上下文”, “请永远不要给我一个远程上下文”等)

    • 我们可能需要_require_这个以避免歧义( ZoP #12

    • 我越想越清楚,我们确实希望 Fabric 围绕@task / Task自己的轻量级包装器; pure-Invoke 代码库只会使用它的@task ,它总是会触发给一个 vanilla Context ,而通过 Fabric 版本创建的任务至少可以选择给一个Connection ,如果不需要的话。

    • 一个缺点是上面提到的“我可以在本地远程异或”类型的任务; 一个只需要一个“请运行命令”选项并且不会同时混合两种模式的任务。 这_不_适用于“装饰器声明上下文类型”解决方案,因为它_需要_根据谁调用它以及如何调用它来“切换”上下文类型。

    • 尽管这实际上是当前 API 的一个完整点; 这些任务_不关心_上下文子类,_只要ctx.run() _。

    • 因此,那些大概想要用@task的“我只需要一个基本的、普通的上下文”版本来装饰,并理解从 Fabric(或类似 Fabric)调用的角度来看,有人可以选择给那些任务Connection而不是Context



      • 这让我们重新思考如何执行任务,也就是 pyinvoke/invoke#170



  • 无论实施如何,我们都必须确保最大限度地减少潜在的footgun re:用户执行以下操作:

    • local不存在时期望它(通过 Invoke 运行的结构/连接期望代码)

    • 期望run在本地运行,而不是给一个带有远程run上下文(通过 Fabric 运行的调用/上下文预期代码)

    • Max在此处的附加评论中的其他任何内容

  • 正如在更老的评论中看到的那样,这里的一个子用例是用户期望 v2 等效于Connection('localhost').run('foo') _不使用 SSH_,而是完全像Connection('localhost').local('foo')

    • 我_猜测_我们实际上并不想这样做,因为对于任何试图进行本地主机健全性检查的人来说,这感觉就像一个讨厌的枪。 对我来说,这感觉太神奇了。 但我对争论持开放态度,可能是在选择加入的基础上(例如设置一个配置选项,如ssh.localhost_becomes_subprocess = True或其他。)

我目前唯一的用例是upload_template()能够在本地呈现模板。

当然可以这样做:

#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)

但是为什么没有在本地渲染的选项呢?

就我而言,此功能的主要用途是将应用程序配置部署到我的本地机器以进行本地测试。

考虑到您有一个settings.py.j2在部署时被渲染到目标服务器,它被命名为settings.py并且只包含 python 代码,没有 jinja。
现在你想在本地测试,但本地还没有settings.py ,因为它需要从settings.py.j2渲染。
因此您的应用程序无法启动,您必须手动创建一个单独的settings.py用于本地测试。

这很累人,应该更容易。

例如,在 Ansible 中,我只是告诉任务它将使用“本地连接”,它会在本地主机上呈现,而不会尝试通过 ssh 连接到它。

在 Fabric 中提供此功能之前,我将使用上面粘贴的解决方案,当然,因为它只是几行代码。 不过恕我直言,它应该更容易。 我觉得这真的是面料应该让我轻松的那种东西。

@fninja我还没有移植upload_template本身,但我绝对同意它属于这个问题空间。 可以说,可以通过将 Jinja 包装渲染步骤和上传一些字符串上传步骤分开来处理这个问题,尤其是因为后者已经以“将 FLO 交给put ”的形式存在。 例如:

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')

但是可能仍然有一个更短的 1-stop 模拟upload_template ,它可以是Connection方法或采用Connection参数的子程序。

无论哪种方式,它都会引发更多问题:究竟如何处理这类事情 - 例如,仅调用Context对象没有put / get 。 值得添加它们吗? 在这张票的上下文中,对于 Fabric 用户来说很有意义(然后upload_template或 w/e 在任何一种情况下都可以简单地调用put ),但对于纯 Invoke 用户来说,这很奇怪和 API 的无用部分。

+1 使其成为核心功能

来自 #1637 的交叉点。 只是一个想法:

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')

基本上local()可以充当装饰器/上下文管理器/函数并将ConnectionContext

我认为我没有看到提到的另一个用例:构建可重用函数库。 就我而言,它主要是git命令。 我写了一个过于简单的dorun隐藏了runlocal函数参数之间的差异(在 v1 上); 选择哪个函数作为参数传递。 例如,这是一个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

它看起来像这样:

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)

我不知道sudo会发生什么,并且有些问题我无法轻松处理,例如扩展~remoteuser以生成路径。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

haydenflinner picture haydenflinner  ·  5评论

supriyopaul picture supriyopaul  ·  4评论

shadyabhi picture shadyabhi  ·  5评论

bitprophet picture bitprophet  ·  6评论

peteruhnak picture peteruhnak  ·  6评论