Example #1
0
def test_debug_print(monkeypatch, capsys):
    delimiter = '-' * 78 + '\n'
    import fabric.state
    monkeypatch.setitem(fabric.state.output, 'debug', False)
    debug_print("test")
    out, err = capsys.readouterr()
    assert out == ""
    assert err == ""
    monkeypatch.setitem(fabric.state.output, 'debug', True)
    debug_print("test")
    out, err = capsys.readouterr()
    assert out == "test\n" + delimiter
    assert err == ""
    monkeypatch.setitem(fabric.state.output, 'debug', True)
    debug_print("test\n")
    out, err = capsys.readouterr()
    assert out == "test\n" + delimiter
    assert err == ""
    monkeypatch.setitem(fabric.state.output, 'debug', True)
    debug_print(["foo", "bar"])
    out, err = capsys.readouterr()
    assert out == "['foo', 'bar']\n" + delimiter
    assert err == ""
Example #2
0
def read_config(config_filename=None):  # pylint: disable=too-many-locals,too-many-branches,too-many-statements
    r"""Read configuration from .yaml file.

    If ``config_filename`` is None - :func:`~read_config` will try to use
    ``config_filename`` constructed from ``env.real_fabfile`` by replacing ``.py`` file extension with ``.yaml`` one.
    If such config file exists it will be loaded and parsed by :func:`~read_config`.

    .. note::
        :func:`~read_config` with argument ``None`` is automatically executed during loading module ``fabrix.api``.

    Nevertheless, :func:`~read_config` can be called again from fabfile function to load specific configuration, for example,
    ``read_config('stage.yaml')`` or ``read_config('prod.yaml')`` - in this case files 'stage.yaml' and 'prod.yaml'
    will be looked for in the directory where ``env.real_fabfile`` is located.

    Configuration file has `yaml format <https://en.wikipedia.org/wiki/YAML#Syntax>`_ and can contains:

        - ``hosts:`` is list of hosts. Each host can be ip address or hostname.
          Also username and port can be mentioned. For example:

            * 10.10.10.10
            * example.com
            * root\@example.com
            * example.com:22
            * root\@example.com:22

        - ``roles:`` is dictionary with two possible keys, ``role`` and ``hosts``.

            * ``role`` is string, role name. It will be used as role name in Fabric ``env.roledefs`` dictionary.
            * ``hosts`` is list of hosts of this role, with syntax as it described above.

        - ``host_vars`` is dictionary with two possible keys, ``host`` and ``vars``.

            * ``host`` is existing host string from global ``hosts`` or ``roles`` ``hosts`` lists.
            * ``vars`` is dictionary, where keys is variable names and values can be any type.

        - ``role_vars`` is dictionary with two possible keys, ``role`` and ``vars``.

            * ``role`` is existing role name from global ``roles`` dictionary.
            * ``vars`` is dictionary, where keys is variable names and values can be any type.

        - ``defaults`` is dictionary where keys is variable names and values can be any type.

        - ``local_vars`` is dictionary where keys is variable names and values can be any type.

    Configuration file has additional restrictions:
        - ``hosts`` and ``roles`` can't be simultaneously defined in config, these two options are mutually exclusive.
        - one of ``hosts`` and ``roles`` must be defined in config, else config vill be considered invalid and rejected.
        - ``host_vars`` can be defined even in case when ``roles`` defined and global ``hosts`` is not defined.
        - ``role_vars`` can be defined in config only if ``roles`` defined.

    Variables from ``defaults`` dictionary has lowest priority and can be overriden via ``role_vars`` or ``host_vars``.

    If some variable defined in ``defaults`` and in ``role_vars`` - ``role_vars`` definition has higher priority for hosts with this specific role.

    Variable definition in ``host_vars`` has highest priority and override any variables defined in ``defaults`` and ``role_vars`` for this specific host.

    ``local_vars`` is variables intended to use as local configuration for host where fabfile functions is executed,
    these local variables are acessible via global :obj:`~fabrix.config.local_conf` dictionary
    after importing :obj:`~fabrix.config.local_conf` from ``fabrix.api``.

    ``defaults``/``role_vars``/``host_vars`` can be acessible via global :obj:`~fabrix.config.conf` dictionary
    after importing :obj:`~fabrix.config.conf` from ``fabrix.api``.

    Args:
        config_filename: full/relative configuration file name or None.

    Returns:
        After successful execution, :func:`~read_config` changes ``env.hosts`` list,
        ``env.roledefs`` dictionary and set global variables :obj:`~fabrix.config.conf` and :obj:`~fabrix.config.local_conf`.

    Raises:
        :class:`~exceptions.SystemExit`: When error occurred during parsing of configuration file.
    """

    argument_config_filename = config_filename
    if env.real_fabfile is None:
        return
    if argument_config_filename is None:
        dirname = os.path.dirname(env.real_fabfile)
        basename = os.path.basename(env.real_fabfile)
        name, dummy_ext = os.path.splitext(basename)
        config_filename = os.path.join(dirname, name + '.yaml')
    elif not os.path.isabs(argument_config_filename):
        dirname = os.path.dirname(env.real_fabfile)
        config_filename = os.path.join(dirname, argument_config_filename)
    else:
        config_filename = argument_config_filename
    if not os.path.isfile(config_filename):
        if argument_config_filename is None:
            return
        else:
            abort('read_config: config \'%s\' not exists' % config_filename)
    else:
        debug_print('fabrix: using config \'%s\'' % config_filename)
    try:
        with open(config_filename) as config_file:
            config = yaml.load(config_file)
    except yaml.parser.ParserError, ex:
        abort('read_config: error parsing config \'%s\':\n\n%s' % (config_filename, ex))
Example #3
0
     config_filename = argument_config_filename
 if not os.path.isfile(config_filename):
     if argument_config_filename is None:
         return
     else:
         abort('read_config: config \'%s\' not exists' % config_filename)
 else:
     debug_print('fabrix: using config \'%s\'' % config_filename)
 try:
     with open(config_filename) as config_file:
         config = yaml.load(config_file)
 except yaml.parser.ParserError, ex:
     abort('read_config: error parsing config \'%s\':\n\n%s' % (config_filename, ex))
 config_text = read_local_file(config_filename)
 config_yaml = yaml.dump(config)
 debug_print('config_text:', config_text, 'config_yaml:', config_yaml, 'config:', config)
 if 'hosts' in config and 'roles' in config:
     abort('read_config: hosts and roles can\'t be simultaneously defined in config')
 if 'hosts' not in config and 'roles' not in config:
     abort('read_config: hosts or roles must be defined in config')
 hosts = list()
 if 'hosts' in config:
     if not isinstance(config['hosts'], list):
         abort('read_config: hosts must be list type')
     if not config['hosts']:
         abort('read_config: hosts must not be empty')
     hosts_set = set()
     for host in config['hosts']:
         if host is None:
             abort('read_config: hosts host can\'t be empty string')
         if not isinstance(host, basestring):