New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabric 2 alpha/beta feedback meta-ticket! #1591

Closed
bitprophet opened this Issue Apr 21, 2017 · 28 comments

Comments

Projects
None yet
@bitprophet
Member

bitprophet commented Apr 21, 2017

Please make sure you've read this blog post and all its links first!: http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta


This is the place to leave feedback for issues not covered under any of the existing tickets; please search the below places first!!


Not finding anything relevant? Leave a comment below! I'm looking for feedback similar but not limited to:

  • "I refuse to use 2.0 until you put back in the magic, global, non object oriented mode!" (though I'll just link you to pyinvoke/invoke#186 and ask you to supply rationale there ;))
  • "I really like what you did with $feature but it's missing $sub-feature, which I really need! Is that planned?" (I'll either say 'yes', 'no' or 'no but you can now trivially implement it yourself! it doesn't need to be in core!')
  • "I really like what you did with $feature but the way it's set up right now, it's hard/impossible to do $sub-use-case!" (I'll probably ask you for details and possibly ask for an example PR of the API you'd like to see.)

@bitprophet bitprophet added this to the 2.0 milestone Apr 21, 2017

@bitprophet bitprophet changed the title from Fabric 2 alpha feedback meta-ticket! to Fabric 2 alpha/beta feedback meta-ticket! Apr 21, 2017

@UkuLoskit

This comment has been minimized.

Show comment
Hide comment
@UkuLoskit

UkuLoskit commented Apr 21, 2017

Small mistake in the URL, it should be http://bitprophet.org/blog/2017/04/17/fabric-2-alpha-beta/

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Apr 21, 2017

Member

Goes to show how well I remember my own website, eh? Thanks! I even ran a link checker on my post, but...not against this ticket ;)

Member

bitprophet commented Apr 21, 2017

Goes to show how well I remember my own website, eh? Thanks! I even ran a link checker on my post, but...not against this ticket ;)

@RedKrieg

This comment has been minimized.

Show comment
Hide comment
@RedKrieg

RedKrieg Apr 21, 2017

Contributor

I have a proposal for how fabric 1's roledefs system can be implemented in a way that I believe to be in line with fabric 2's philosophy. Each Collection of tasks can also have @group decorated functions in the same namespace that return populated Group objects against which tasks can be run. Namespaces would matter, so if fabfile.py contained a Collection called deploy who had @groups called web and db, one could use deploy.web.execute(mytask) or fab -G deploy.web mytask to execute mytask on each host in the web group. These decorated functions would be called lazily and memoized to prevent unnecessary API calls, should a host list lookup be a slow operation as implemented by the user.

Is this in line with the design philosophy for fabric 2? I'd love to take a swing at implementation if so.

Contributor

RedKrieg commented Apr 21, 2017

I have a proposal for how fabric 1's roledefs system can be implemented in a way that I believe to be in line with fabric 2's philosophy. Each Collection of tasks can also have @group decorated functions in the same namespace that return populated Group objects against which tasks can be run. Namespaces would matter, so if fabfile.py contained a Collection called deploy who had @groups called web and db, one could use deploy.web.execute(mytask) or fab -G deploy.web mytask to execute mytask on each host in the web group. These decorated functions would be called lazily and memoized to prevent unnecessary API calls, should a host list lookup be a slow operation as implemented by the user.

Is this in line with the design philosophy for fabric 2? I'd love to take a swing at implementation if so.

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Apr 22, 2017

Member

That's a neat idea, @RedKrieg! I've been deferring my own brainstorm for how "best" to generate Group objects and/or how to refer to them on the CLI, but offhand that sounds like a reasonable way to go. I just crapped out far too many words in #1594 and included your idea there (+ a link). Let's continue discussion there, but tl;dr yes I'd love to see a PoC PR.

Member

bitprophet commented Apr 22, 2017

That's a neat idea, @RedKrieg! I've been deferring my own brainstorm for how "best" to generate Group objects and/or how to refer to them on the CLI, but offhand that sounds like a reasonable way to go. I just crapped out far too many words in #1594 and included your idea there (+ a link). Let's continue discussion there, but tl;dr yes I'd love to see a PoC PR.

@max-arnold

This comment has been minimized.

Show comment
Hide comment
@max-arnold

max-arnold Apr 25, 2017

What is the best approach to run a command locally despite -H argument being present, for example if I want to combine local build and rsync to remote host into a single task?

max-arnold commented Apr 25, 2017

What is the best approach to run a command locally despite -H argument being present, for example if I want to combine local build and rsync to remote host into a single task?

@RedKrieg

This comment has been minimized.

Show comment
Hide comment
@RedKrieg

RedKrieg Apr 25, 2017

Contributor

@max-arnold Connection objects have a .local attribute that acts like .run on the local machine: http://docs.fabfile.org/en/v2/api/connection.html#fabric.connection.Connection.local

Contributor

RedKrieg commented Apr 25, 2017

@max-arnold Connection objects have a .local attribute that acts like .run on the local machine: http://docs.fabfile.org/en/v2/api/connection.html#fabric.connection.Connection.local

@max-arnold

This comment has been minimized.

Show comment
Hide comment
@max-arnold

max-arnold Apr 25, 2017

Ok, I guess an example is better than words:

@task
def build(ctx):
    # should always run locally
    ctx.local('uname -a')


@task
def deploy(ctx):
    build(ctx)
    # this one should run on remote host
    ctx.run('uname -a')

Combined task runs fine:

fab -H host deploy

Local task alone fails with AttributeError: No attribute or config key found for 'local':

fab build

Basically I want to have a task which does something locally, no matter how it was invoked (with or without -H).

max-arnold commented Apr 25, 2017

Ok, I guess an example is better than words:

@task
def build(ctx):
    # should always run locally
    ctx.local('uname -a')


@task
def deploy(ctx):
    build(ctx)
    # this one should run on remote host
    ctx.run('uname -a')

Combined task runs fine:

fab -H host deploy

Local task alone fails with AttributeError: No attribute or config key found for 'local':

fab build

Basically I want to have a task which does something locally, no matter how it was invoked (with or without -H).

@max-arnold

This comment has been minimized.

Show comment
Hide comment
@max-arnold

max-arnold Apr 25, 2017

From the other side, some commands are only intended to run remotely. If no host is present,ctx.run will attempt to run them locally, which can lead to unexpected consequences.

User runs task Command/task author wants it to be runned How it should behave?
locally locally run() behavior is fine (but will violate author's intention if run remotely)
locally remotely It should fail (or ask for host string like old fabric did)
locally locally or remotely run() behavior is fine
remotely locally It should always run locally, but Context has no local() method to ensure it
remotely remotely run() behavior is fine (but problems are expected during local invocation)
remotely locally or remotely run() behavior is fine

max-arnold commented Apr 25, 2017

From the other side, some commands are only intended to run remotely. If no host is present,ctx.run will attempt to run them locally, which can lead to unexpected consequences.

User runs task Command/task author wants it to be runned How it should behave?
locally locally run() behavior is fine (but will violate author's intention if run remotely)
locally remotely It should fail (or ask for host string like old fabric did)
locally locally or remotely run() behavior is fine
remotely locally It should always run locally, but Context has no local() method to ensure it
remotely remotely run() behavior is fine (but problems are expected during local invocation)
remotely locally or remotely run() behavior is fine
@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Apr 25, 2017

Member

@max-arnold that's exactly #98! which I haven't actually fully solved yet. Putting some modern thoughts in there as a comment...edit: this one

Member

bitprophet commented Apr 25, 2017

@max-arnold that's exactly #98! which I haven't actually fully solved yet. Putting some modern thoughts in there as a comment...edit: this one

@dustinfarris

This comment has been minimized.

Show comment
Hide comment
@dustinfarris

dustinfarris May 22, 2017

I've noticed what appears to be inconsistency with sudo.

Where connection is a remote server, authenticated as root.

Trying to expand tilde as another user other than root:

c.sudo("echo bar > ~/foo", user="builder")

This succeeds, but rather than writing /home/builder/foo, it instead wrote /root/foo.

On the other hand, if I just try to ls:

c.sudo("ls", user="builder")

I get Permission denied.

Something feels off.

dustinfarris commented May 22, 2017

I've noticed what appears to be inconsistency with sudo.

Where connection is a remote server, authenticated as root.

Trying to expand tilde as another user other than root:

c.sudo("echo bar > ~/foo", user="builder")

This succeeds, but rather than writing /home/builder/foo, it instead wrote /root/foo.

On the other hand, if I just try to ls:

c.sudo("ls", user="builder")

I get Permission denied.

Something feels off.

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet May 22, 2017

Member

My guess when Dustin reported the above out-of-band, was that this is a sudo (the command, not the method) specific wrinkle, since last I looked we are using -H and apparently it doesn't behave 100% like we're expecting.

Member

bitprophet commented May 22, 2017

My guess when Dustin reported the above out-of-band, was that this is a sudo (the command, not the method) specific wrinkle, since last I looked we are using -H and apparently it doesn't behave 100% like we're expecting.

@garu57

This comment has been minimized.

Show comment
Hide comment
@garu57

garu57 Aug 10, 2017

Hi Jeff,
since i'm already working in python 3, right now i'm using fabric3 (the porting of fabric 1.x).

I was tempted to try the migration to fabric 2, but i immediately hit a show stopper. I make extensive usage of fabric.contrib functions, but migration doc says it no longer exists.

For sure i don't want to bloat the code reverting to their shell equivalent, and since, judging from the number of issues on contrib.* of fabric 1.x, it looks it is used a lot, i think its lack could be a serious hindrance for migrating for many others.
I found patchwork project that apparently contains the equivalent of fabric.contrib, but it's code is not updated since years.
Do you have any plan to port fabric.contrib to fabric 2?

Thanks,
Gabriele

garu57 commented Aug 10, 2017

Hi Jeff,
since i'm already working in python 3, right now i'm using fabric3 (the porting of fabric 1.x).

I was tempted to try the migration to fabric 2, but i immediately hit a show stopper. I make extensive usage of fabric.contrib functions, but migration doc says it no longer exists.

For sure i don't want to bloat the code reverting to their shell equivalent, and since, judging from the number of issues on contrib.* of fabric 1.x, it looks it is used a lot, i think its lack could be a serious hindrance for migrating for many others.
I found patchwork project that apparently contains the equivalent of fabric.contrib, but it's code is not updated since years.
Do you have any plan to port fabric.contrib to fabric 2?

Thanks,
Gabriele

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Aug 10, 2017

Member

@garu57 Yes, the plan right now is to use patchwork as basically "2.0's contrib". At the moment it's Fabric 1 based but that'll change after Fabric 2.0.0 comes out. I expect the most commonly used contrib bits to get ported over quickly.

Member

bitprophet commented Aug 10, 2017

@garu57 Yes, the plan right now is to use patchwork as basically "2.0's contrib". At the moment it's Fabric 1 based but that'll change after Fabric 2.0.0 comes out. I expect the most commonly used contrib bits to get ported over quickly.

@rpisarev

This comment has been minimized.

Show comment
Hide comment
@rpisarev

rpisarev Sep 11, 2017

Hi everyone,

Sometimes my program runs a remote command e.g.

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'

I see that scripts is executed like that:

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

and I should see also my debug output "?" according to my code :

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

    #@with_settings
    def generic_cmd(self, command_str, timeout, fabric_timeout, **kwargs):
        """
        Creating remote container from template

        @type command_str:     str
        @param command_str:    command for execute with VM
        @type timeout          int or float
        @param timeout         number of seconds for pause
        @type fabric_timeout   int or float
        @param fabric_timeout  number of seconds for timeout fabric run

        @rtype:                FabricResponse
        @return:               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):
        """
        @type command_str:     str
        @param command_str:    command for execute with VM

        @rtype:                FabricResponse
        @return:               Return remote status of operation VM
        """
        return self.generic_cmd(command_str, 0.1, 0, **kwargs)

But there are no ones "?". So I suggest there were hanging in the run().

Actually, my program is huge and there is multi-process programming. To catch hanging I'm executing remote commands with the following code:

class TestingSystemVM(GenericFabric):
#######
    @signal_alarm_down
    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)

When I use fabric2, some commands launched from child processes are hanging from time to time.
Upd. Actually, it was my mistake in the code. So, fabric2 doesn't contain hanging

rpisarev commented Sep 11, 2017

Hi everyone,

Sometimes my program runs a remote command e.g.

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'

I see that scripts is executed like that:

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

and I should see also my debug output "?" according to my code :

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

    #@with_settings
    def generic_cmd(self, command_str, timeout, fabric_timeout, **kwargs):
        """
        Creating remote container from template

        @type command_str:     str
        @param command_str:    command for execute with VM
        @type timeout          int or float
        @param timeout         number of seconds for pause
        @type fabric_timeout   int or float
        @param fabric_timeout  number of seconds for timeout fabric run

        @rtype:                FabricResponse
        @return:               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):
        """
        @type command_str:     str
        @param command_str:    command for execute with VM

        @rtype:                FabricResponse
        @return:               Return remote status of operation VM
        """
        return self.generic_cmd(command_str, 0.1, 0, **kwargs)

But there are no ones "?". So I suggest there were hanging in the run().

Actually, my program is huge and there is multi-process programming. To catch hanging I'm executing remote commands with the following code:

class TestingSystemVM(GenericFabric):
#######
    @signal_alarm_down
    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)

When I use fabric2, some commands launched from child processes are hanging from time to time.
Upd. Actually, it was my mistake in the code. So, fabric2 doesn't contain hanging

@rpisarev

This comment has been minimized.

Show comment
Hide comment
@rpisarev

rpisarev Sep 13, 2017

Hello everybody,
I did some launch experiments and can share my experience.

Firstly, I ran command from my console

ssh root@192.168.0.34 -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'"

and that ended perfectly and fast with exit=0:

###
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
* Prepare evironment    [DONE]
+ exit 0
Connection to 192.168.0.34 closed.

Good.
Then I executed another command:

ssh root@192.168.0.36 "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'"

That was finished so fast with exit=0 too:

###
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
+ exit 0

But there isn't "Connection to 192.168.0.36 closed." I don't know it is important or not.

After that I recreated VMs and launched command by fabric2 (from IPython):

In [1]: from fabric import Connection
In [2]: Connection('root@192.168.0.52').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>

Also, I ran with pty=False:

In [1]: from fabric import Connection

In [2]: Connection('root@192.168.0.55').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>

There wasn't "Connection to closed." on both tests. Again I don't know it is important or not.

Secondly, I decided that is not a good environment for my stand, because I need launch from child process. So, I recreated VMs again and ran the script with next code:

In [1]: import subprocess

In [2]: t = subprocess.Popen(""" ssh root@192.168.0.34 -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()

In the output of this running there was "Connection to 192.168.0.34 closed."

On the other hand

In [1]: import subprocess

In [2]: t = subprocess.Popen(""" ssh root@192.168.0.36 "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()

Both of them haven't hanged.

Tonight I'll launch my scripts with fabric2 on the process that was forked and I'll write.
Upd. Actually, it was my mistake in the code. So, fabric2 doesn't contain hanging.

rpisarev commented Sep 13, 2017

Hello everybody,
I did some launch experiments and can share my experience.

Firstly, I ran command from my console

ssh root@192.168.0.34 -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'"

and that ended perfectly and fast with exit=0:

###
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
* Prepare evironment    [DONE]
+ exit 0
Connection to 192.168.0.34 closed.

Good.
Then I executed another command:

ssh root@192.168.0.36 "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'"

That was finished so fast with exit=0 too:

###
+ echo -e '* Prepare evironment    \033[0;32m[DONE]\033[0m'
+ exit 0

But there isn't "Connection to 192.168.0.36 closed." I don't know it is important or not.

After that I recreated VMs and launched command by fabric2 (from IPython):

In [1]: from fabric import Connection
In [2]: Connection('root@192.168.0.52').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>

Also, I ran with pty=False:

In [1]: from fabric import Connection

In [2]: Connection('root@192.168.0.55').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>

There wasn't "Connection to closed." on both tests. Again I don't know it is important or not.

Secondly, I decided that is not a good environment for my stand, because I need launch from child process. So, I recreated VMs again and ran the script with next code:

In [1]: import subprocess

In [2]: t = subprocess.Popen(""" ssh root@192.168.0.34 -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()

In the output of this running there was "Connection to 192.168.0.34 closed."

On the other hand

In [1]: import subprocess

In [2]: t = subprocess.Popen(""" ssh root@192.168.0.36 "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()

Both of them haven't hanged.

Tonight I'll launch my scripts with fabric2 on the process that was forked and I'll write.
Upd. Actually, it was my mistake in the code. So, fabric2 doesn't contain hanging.

@ned2

This comment has been minimized.

Show comment
Hide comment
@ned2

ned2 Sep 18, 2017

Would be good to get use_sudo support for Transfer.put.

I guess the simplest workaround for now is just to do a put somewhere I do have permissions then a sudo mv?

ned2 commented Sep 18, 2017

Would be good to get use_sudo support for Transfer.put.

I guess the simplest workaround for now is just to do a put somewhere I do have permissions then a sudo mv?

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Sep 18, 2017

Member

@ned2 that's all use_sudo can really do in get/put anyways, eg it's how v1 does it. Not actually possible to upload a file "with sudo" as far as I'm aware! (Not without connecting as root, which is a bad idea and ideally is not even allowed.)

Given the attempt to have a somewhat cleaner API in v2, I'm almost more likely to implement a wrapper instead of bundling that behavior inside get/put themselves. Maybe just something like Transfer.sudo_put (which would call self.put). That way the "pure" put is kept minimal.

Member

bitprophet commented Sep 18, 2017

@ned2 that's all use_sudo can really do in get/put anyways, eg it's how v1 does it. Not actually possible to upload a file "with sudo" as far as I'm aware! (Not without connecting as root, which is a bad idea and ideally is not even allowed.)

Given the attempt to have a somewhat cleaner API in v2, I'm almost more likely to implement a wrapper instead of bundling that behavior inside get/put themselves. Maybe just something like Transfer.sudo_put (which would call self.put). That way the "pure" put is kept minimal.

@Aiky30

This comment has been minimized.

Show comment
Hide comment
@Aiky30

Aiky30 Sep 22, 2017

@bitprophet I would like to start off by thanking you for some pretty stable and useful software with Fabric1 and your approach to releasing Fabric2.

I've started to play around with v2 but I've hit an issue with Connection. I'm using my SSH config from Fabric 1, Fabric 1 would prompt me for a password when attempting to connect. Fabric 2 is not doing this and fails stating that Authentication has failed. I cannot see anywhere in the v2 docs that mentions the authentication mechanism for Connection. There is a mention of passwords with sudo but from what I can gather this is after the connection has been successful anyway..

My question is whether I've missed something in the docs or whether this is a missing feature or an issue.

The code:

@task
def testing(c):
    with Connection('MyHostname') as cxn:
        print("Connected")

        cxn.run('ls -l')

The error:

  File /lib/python3.4/site-packages/paramiko/auth_handler.py", line 223, in wait_for_response
    raise e 
paramiko.ssh_exception.AuthenticationException: Authentication failed.

My SSH config (Replaced values to post here):

Host MyHostname
  HostName replacedhostname.co.uk
  Port 22
  IdentityFile ~/.ssh/id_rsa
  User replaceduser

I'm on the latest v2 version: fec3a22

Hopefully solving this will aid anyone else with the same issue.

Thank you for your time.

Aiky30 commented Sep 22, 2017

@bitprophet I would like to start off by thanking you for some pretty stable and useful software with Fabric1 and your approach to releasing Fabric2.

I've started to play around with v2 but I've hit an issue with Connection. I'm using my SSH config from Fabric 1, Fabric 1 would prompt me for a password when attempting to connect. Fabric 2 is not doing this and fails stating that Authentication has failed. I cannot see anywhere in the v2 docs that mentions the authentication mechanism for Connection. There is a mention of passwords with sudo but from what I can gather this is after the connection has been successful anyway..

My question is whether I've missed something in the docs or whether this is a missing feature or an issue.

The code:

@task
def testing(c):
    with Connection('MyHostname') as cxn:
        print("Connected")

        cxn.run('ls -l')

The error:

  File /lib/python3.4/site-packages/paramiko/auth_handler.py", line 223, in wait_for_response
    raise e 
paramiko.ssh_exception.AuthenticationException: Authentication failed.

My SSH config (Replaced values to post here):

Host MyHostname
  HostName replacedhostname.co.uk
  Port 22
  IdentityFile ~/.ssh/id_rsa
  User replaceduser

I'm on the latest v2 version: fec3a22

Hopefully solving this will aid anyone else with the same issue.

Thank you for your time.

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Sep 22, 2017

Member

@Aiky30 It's probably not you, the auth stuff still needs work (in large part due to needing some in-progress Paramiko work so auth exceptions aren't horribly hard to interpret correctly.) I think in this case it may simply be that Fab 2 isn't interpreting IdentityFile - we grab host, user, port and a bunch of other settings but IdentityFile is still a TODO.

That's partly because we also don't deal with passphrases right now (see above - want to avoid a big Fabric 1 kludge where we have to make wild guesses if a given auth fail means password or passphrase is needed). So you'd probably just transition to a "I can't unlock this file" error after that. And both of those are because I use an ssh-agent most of the time - which would be my 1st suggestion for an immediate workaround.

That said, I think it's probably worth me hacking in both IdentityFile and explicit passphrase config support, because non-agent keys are likely the number 1 most common auth setup out there so lacking it probably means most alpha/beta users are left in the lurch. Will see if I can bang that out today.

Member

bitprophet commented Sep 22, 2017

@Aiky30 It's probably not you, the auth stuff still needs work (in large part due to needing some in-progress Paramiko work so auth exceptions aren't horribly hard to interpret correctly.) I think in this case it may simply be that Fab 2 isn't interpreting IdentityFile - we grab host, user, port and a bunch of other settings but IdentityFile is still a TODO.

That's partly because we also don't deal with passphrases right now (see above - want to avoid a big Fabric 1 kludge where we have to make wild guesses if a given auth fail means password or passphrase is needed). So you'd probably just transition to a "I can't unlock this file" error after that. And both of those are because I use an ssh-agent most of the time - which would be my 1st suggestion for an immediate workaround.

That said, I think it's probably worth me hacking in both IdentityFile and explicit passphrase config support, because non-agent keys are likely the number 1 most common auth setup out there so lacking it probably means most alpha/beta users are left in the lurch. Will see if I can bang that out today.

@tuukkamustonen

This comment has been minimized.

Show comment
Hide comment
@tuukkamustonen

tuukkamustonen Sep 27, 2017

Took 2.0a for a spin.

  1. I'm also a bit lost on how to actually define and use hosts. I can run:

    fab -H user@host:22 some-task
    

    But if I don't want to pass in host details (user, host, port) every time, I'm not sure how to configure hosts in fabfile.py (Connections or Group) and then just refer to them. If I understood #1591 (comment) correctly, it's just not supported at the moment (and tracked in #1594)?

  2. Also, I hit issue where I have encrypted SSH key (at ~/.ssh/id_rsa) and I have ssh-add'd that to ssh-agent. It shows up if I list the keys via ssh-add -l. When I run some task, giving out proper username:

    fab -H musttu@host sometask
    

    Things work ok. But if I use incorrect user, e.g. fab -H bad_user@host sometask, then I get:

    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
    

    But I assume that falls under paramiko/paramiko#387 and is not really specific to fabric 2.0. But yeah, it does feel weird to get PasswordRequiredException: Private key file is encrypted error, when the ssh-agent already has the decrypted key. If I understood correctly, after invalid login, paramiko will fall back to using key directly, and without passphrase provided will throw this error.

  3. Would be nice to allow type annotating task functions (for better auto-completion in IDE). Have you had time to consider pyinvoke/invoke#458 ?

  4. I like the idea of patchwork library. For fabric 1.x, there's https://github.com/sebastien/cuisine (that seems pretty dead) that contains lots of extra functions (haven't used it myself). Is the idea with patchwork to build something similar (so Chef/Ansible/SaltStack-style declarative functions, though with reduced scope)? I have always hated the multi-dir/multi-file YAML/DSL approach that other tools follow, and would just like to stay in python, to get more flexibility, less verbose syntax, IDE auto-completion, easy debugging, etc.

  5. Just drop py 2.6 and 3.2-3.3 support for fabric 2.0. Shouldn't people just move on?

tuukkamustonen commented Sep 27, 2017

Took 2.0a for a spin.

  1. I'm also a bit lost on how to actually define and use hosts. I can run:

    fab -H user@host:22 some-task
    

    But if I don't want to pass in host details (user, host, port) every time, I'm not sure how to configure hosts in fabfile.py (Connections or Group) and then just refer to them. If I understood #1591 (comment) correctly, it's just not supported at the moment (and tracked in #1594)?

  2. Also, I hit issue where I have encrypted SSH key (at ~/.ssh/id_rsa) and I have ssh-add'd that to ssh-agent. It shows up if I list the keys via ssh-add -l. When I run some task, giving out proper username:

    fab -H musttu@host sometask
    

    Things work ok. But if I use incorrect user, e.g. fab -H bad_user@host sometask, then I get:

    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
    

    But I assume that falls under paramiko/paramiko#387 and is not really specific to fabric 2.0. But yeah, it does feel weird to get PasswordRequiredException: Private key file is encrypted error, when the ssh-agent already has the decrypted key. If I understood correctly, after invalid login, paramiko will fall back to using key directly, and without passphrase provided will throw this error.

  3. Would be nice to allow type annotating task functions (for better auto-completion in IDE). Have you had time to consider pyinvoke/invoke#458 ?

  4. I like the idea of patchwork library. For fabric 1.x, there's https://github.com/sebastien/cuisine (that seems pretty dead) that contains lots of extra functions (haven't used it myself). Is the idea with patchwork to build something similar (so Chef/Ansible/SaltStack-style declarative functions, though with reduced scope)? I have always hated the multi-dir/multi-file YAML/DSL approach that other tools follow, and would just like to stay in python, to get more flexibility, less verbose syntax, IDE auto-completion, easy debugging, etc.

  5. Just drop py 2.6 and 3.2-3.3 support for fabric 2.0. Shouldn't people just move on?

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Oct 9, 2017

Member

@tuukkamustonen - thanks for the feedback! Responses:

  1. Roles are indeed covered under #1594 - and I think there's another ticket out there for the related issue of just having per-host config data, aside from how ssh_config support does so at its own level.

    Deciding how exactly to reconcile fabric-level config with ssh_config and then also with anything from Group or runtime data...isn't trivial. Though it definitely needs to happen soon; I just want to have a half-thought-out solution instead of a first-draft.

  2. Again, yes, this is the Paramiko ticket you mentioned, and your guess is accurate, the bad-username situation will always eventually fail, and since Paramiko only tracks the last error it encountered, it happens to be that the last thing it tried was the on-disk, encrypted copy of the key. (If you moved that key elsewhere, for example, the last error would be something else.)

  3. I just commented on that ticket, it may (or may not) duplicate existing tickets for the same overall feature. I've commented on those older ones and IIRC it's a "yea I think it'd be nice as long as it doesn't foul up Python 2." However it's not as high priority as most of the bigger missing features so it falls in the "needs a great, all boxes checked PR that I can just-merge" bucket :)

  4. Yes, see #461 which is very old but still on my mind. These days the big question is how such a lib would be written to span both Invoke and Fabric; in many/most cases one can simply write generic Invoke tasks that don't "know about" any split local/remote contexts, which can be handed a Fabric connection context when one wants to run them against a remote system.

    Such "context agnostic" tasks would want to live in the 'invocations' library (or some other still Invoke-specific lib); but some (e.g. anything involving file transfer and not just shell commands) would need to be "Fabric-aware". Figuring out how to bridge that gap is the problem.

    Could go the route of "that lib only requires invoke, does not hard-require fabric, but a subset of tasks will complain if you don't install fabric & hand them a Connection context." Could split up into two libs (with the Fabric-oriented one requiring the more generic Invoke one.) Etc.

  5. As of recently, this is definitely in the cards, see paramiko/paramiko#1070 and/or pyinvoke/invoke#364. Invoke 1.0, Fabric 2.0 and Paramiko 3.0 (or, maybe, a 2.4/2.5/whatever) will all be Python 2.7 / 3.4 and up.

Member

bitprophet commented Oct 9, 2017

@tuukkamustonen - thanks for the feedback! Responses:

  1. Roles are indeed covered under #1594 - and I think there's another ticket out there for the related issue of just having per-host config data, aside from how ssh_config support does so at its own level.

    Deciding how exactly to reconcile fabric-level config with ssh_config and then also with anything from Group or runtime data...isn't trivial. Though it definitely needs to happen soon; I just want to have a half-thought-out solution instead of a first-draft.

  2. Again, yes, this is the Paramiko ticket you mentioned, and your guess is accurate, the bad-username situation will always eventually fail, and since Paramiko only tracks the last error it encountered, it happens to be that the last thing it tried was the on-disk, encrypted copy of the key. (If you moved that key elsewhere, for example, the last error would be something else.)

  3. I just commented on that ticket, it may (or may not) duplicate existing tickets for the same overall feature. I've commented on those older ones and IIRC it's a "yea I think it'd be nice as long as it doesn't foul up Python 2." However it's not as high priority as most of the bigger missing features so it falls in the "needs a great, all boxes checked PR that I can just-merge" bucket :)

  4. Yes, see #461 which is very old but still on my mind. These days the big question is how such a lib would be written to span both Invoke and Fabric; in many/most cases one can simply write generic Invoke tasks that don't "know about" any split local/remote contexts, which can be handed a Fabric connection context when one wants to run them against a remote system.

    Such "context agnostic" tasks would want to live in the 'invocations' library (or some other still Invoke-specific lib); but some (e.g. anything involving file transfer and not just shell commands) would need to be "Fabric-aware". Figuring out how to bridge that gap is the problem.

    Could go the route of "that lib only requires invoke, does not hard-require fabric, but a subset of tasks will complain if you don't install fabric & hand them a Connection context." Could split up into two libs (with the Fabric-oriented one requiring the more generic Invoke one.) Etc.

  5. As of recently, this is definitely in the cards, see paramiko/paramiko#1070 and/or pyinvoke/invoke#364. Invoke 1.0, Fabric 2.0 and Paramiko 3.0 (or, maybe, a 2.4/2.5/whatever) will all be Python 2.7 / 3.4 and up.

@tuukkamustonen

This comment has been minimized.

Show comment
Hide comment
@tuukkamustonen

tuukkamustonen Oct 19, 2017

About (1):

I'm sure you know this already, but you may want to grab some ideas from Ansible's inventories. Or maybe not :).

About (4):

I think https://github.com/pyinvoke/invocations is way to opinionated for this. Invocations provides conventions and may build on top of patchwork/cuisine-style package, but I wouldn't mix conventions (how to release or doctest) with utilities (how to copy file or alter permissions).

I don't see problem in putting utils for local-only, remote-only and local+remote operations into the same library (patchwork). What operation supports which mode can be tackled as documentation (as docstring, auto-generated from annotation, etc.).

This feels better than splitting logic into 2+ packages. Because what if you first add an operation to your "invoke-only" package (and there might be even "remote-only" operations), and then later add support for it to work also on remote servers? Would you move, copy or extend the code? In either case, it's more work, and user needs different import, etc. so it sounds a bit cumbersome.

tuukkamustonen commented Oct 19, 2017

About (1):

I'm sure you know this already, but you may want to grab some ideas from Ansible's inventories. Or maybe not :).

About (4):

I think https://github.com/pyinvoke/invocations is way to opinionated for this. Invocations provides conventions and may build on top of patchwork/cuisine-style package, but I wouldn't mix conventions (how to release or doctest) with utilities (how to copy file or alter permissions).

I don't see problem in putting utils for local-only, remote-only and local+remote operations into the same library (patchwork). What operation supports which mode can be tackled as documentation (as docstring, auto-generated from annotation, etc.).

This feels better than splitting logic into 2+ packages. Because what if you first add an operation to your "invoke-only" package (and there might be even "remote-only" operations), and then later add support for it to work also on remote servers? Would you move, copy or extend the code? In either case, it's more work, and user needs different import, etc. so it sounds a bit cumbersome.

@haydenflinner

This comment has been minimized.

Show comment
Hide comment
@haydenflinner

haydenflinner Apr 20, 2018

What can I do to get this polished enough to go on PyPi?

haydenflinner commented Apr 20, 2018

What can I do to get this polished enough to go on PyPi?

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Apr 27, 2018

Member

@haydenflinner It's happening over the next week or two!! (Aim is to release before I get on my plane to PyCon, which is May 10.)

For example, please see the recently updated upgrade docs I was just working on this week: http://docs.fabfile.org/en/v2/upgrading.html

In fact, I may as well close this ticket now, since I'll be accepting actual real ones for 2.0.0 and above soon 👍

Member

bitprophet commented Apr 27, 2018

@haydenflinner It's happening over the next week or two!! (Aim is to release before I get on my plane to PyCon, which is May 10.)

For example, please see the recently updated upgrade docs I was just working on this week: http://docs.fabfile.org/en/v2/upgrading.html

In fact, I may as well close this ticket now, since I'll be accepting actual real ones for 2.0.0 and above soon 👍

@bitprophet bitprophet closed this Apr 27, 2018

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Apr 27, 2018

Member

Do note, y'all can still comment here if you like. Note that I'm hoping to get at least a few chunks of feature work done before release, alongside all of the project management prep.

Member

bitprophet commented Apr 27, 2018

Do note, y'all can still comment here if you like. Note that I'm hoping to get at least a few chunks of feature work done before release, alongside all of the project management prep.

@dgarstang

This comment has been minimized.

Show comment
Hide comment
@dgarstang

dgarstang Jul 12, 2018

I looked at fabric v2 today and I'm sorry, I just can't bring myself to use it.

  1. Where did roledefs go? Why can't I pass a role name on the command line anymore? Am I supposed to implement this myself?
  2. Why can't I pass arguments to tasks on the command line anymore? Am I supposed to implement this myself as well?
  3. Why does the -H parameter have to come before the task parameter? It should be the other way around. This is so awful.

dgarstang commented Jul 12, 2018

I looked at fabric v2 today and I'm sorry, I just can't bring myself to use it.

  1. Where did roledefs go? Why can't I pass a role name on the command line anymore? Am I supposed to implement this myself?
  2. Why can't I pass arguments to tasks on the command line anymore? Am I supposed to implement this myself as well?
  3. Why does the -H parameter have to come before the task parameter? It should be the other way around. This is so awful.
@ploxiln

This comment has been minimized.

Show comment
Hide comment
@ploxiln

ploxiln commented Jul 12, 2018

@bitprophet

This comment has been minimized.

Show comment
Hide comment
@bitprophet

bitprophet Jul 13, 2018

Member

@dgarstang You may want to consider taking a more neutral or empathetic tone with folks who give you their free labor! Just sayin 😉

  1. See #1594, which IIRC is linked in the upgrading doc
  2. @ploxiln got your back here
  3. (Partly) see #1772 which is merged to master and will be out soon; it adds ability to use @task(hosts=xxx).

(re: 3: In terms of giving --hosts and friends as if they were per-task arguments, that's something I might add sometime, have been torn on whether it's worth it. Similar to per-task --help, the more "magic" exclusions we add, the higher chance a user will try using that same name for their own task args and get confused when it breaks.)

Member

bitprophet commented Jul 13, 2018

@dgarstang You may want to consider taking a more neutral or empathetic tone with folks who give you their free labor! Just sayin 😉

  1. See #1594, which IIRC is linked in the upgrading doc
  2. @ploxiln got your back here
  3. (Partly) see #1772 which is merged to master and will be out soon; it adds ability to use @task(hosts=xxx).

(re: 3: In terms of giving --hosts and friends as if they were per-task arguments, that's something I might add sometime, have been torn on whether it's worth it. Similar to per-task --help, the more "magic" exclusions we add, the higher chance a user will try using that same name for their own task args and get confused when it breaks.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment