<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Abele's Blog</title><link href="http://theabele.com/" rel="alternate"></link><link href="http://theabele.com/feeds/all.atom.xml" rel="self"></link><id>http://theabele.com/</id><updated>2015-09-20T00:00:00+03:00</updated><entry><title>How to create Abstract Test aka Contract Test using pytest fixtures</title><link href="http://theabele.com/dev/abstract-test-case-pytest" rel="alternate"></link><updated>2015-09-20T00:00:00+03:00</updated><author><name>Janis Abele</name></author><id>tag:theabele.com,2015-09-20:dev/abstract-test-case-pytest</id><summary type="html">&lt;p&gt;The solution I came up with:&lt;/p&gt;
&lt;div class="gist"&gt;
    &lt;script src='https://gist.github.com/ee049b1fdf7e4a1af71a.js?file=test_map_contract.py'&gt;&lt;/script&gt;
    &lt;noscript&gt;
        &lt;pre&gt;&lt;code&gt;import pytest


def square(num):
    return num * num


def recursive_map(f, _list):
    """Recusive map implementation."""
    if not _list:
        return []
    else:
        head, *tail = _list
        h = [f(head)]
        h.extend(recursive_map(f, tail))
        return h


class MapContract(object):
    @pytest.fixture
    def a_map(self):
        raise NotImplementedError('Not Implemented Yet')

    def test_can_handle_small_list(self, a_map):
        assert list(a_map(square, [1,3,4])) == [1, 9, 16]

    def test_can_handle_large_list(self, a_map):
        num = 10000
        assert len(list(a_map(square, range(num)))) == num


class TestSTDLibContract(MapContract):
    @pytest.fixture
    def a_map(self):
        return map


class TestRecursiveMap(MapContract):
    @pytest.fixture
    def a_map(self):
        return recursive_map
&lt;/code&gt;&lt;/pre&gt;
    &lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;Further reading:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.c2.com/cgi/wiki?AbstractTestCases"&gt;Abstract Test Case&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.thecodewhisperer.com/2005/03/02/in-brief-contract-tests/"&gt;Contract Test&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://pytest.org/latest/fixture.html"&gt;pytest fixtures&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</summary><category term="Python"></category><category term="pytest"></category><category term="test"></category></entry><entry><title>How to use Fabric with Salt-Stack</title><link href="http://theabele.com/dev/how-to-use-fabric-with-salt-stack" rel="alternate"></link><updated>2015-09-20T00:00:00+03:00</updated><author><name>Janis Abele</name></author><id>tag:theabele.com,2015-09-20:dev/how-to-use-fabric-with-salt-stack</id><summary type="html">&lt;p&gt;I like to use &lt;a class="reference external" href="http://www.fabfile.org/"&gt;Fabric&lt;/a&gt; in combination with &lt;a class="reference external" href="http://saltstack.com/"&gt;Salt-Stack&lt;/a&gt;. My current setup looks
like:&lt;/p&gt;
&lt;div class="gist"&gt;
    &lt;script src='https://gist.github.com/4ffbffe1871d47afa4c7.js?file=fabfile.py'&gt;&lt;/script&gt;
    &lt;noscript&gt;
        &lt;pre&gt;&lt;code&gt;from fabric.api import sudo, task, env, local, settings
from fabric.contrib.files import upload_template
from fabric.contrib.project import upload_project

import os


salt_task = hosts('@'.join([os.environ['AS_MASTER_USER'], os.environ['AS_MASTER_HOST']]))
"""Decorator to specify Salt-Stack master user and host."""


@task
def bootstrap_master():
    """Use insecure one-liner to install Salt-Stack master."""
    # XXX: Fails on Docker, see
    # https://github.com/saltstack/salt-bootstrap/issues/394
    with settings(warn_only=True):
        sudo('curl -L http://bootstrap.saltstack.org | sudo sh -s -- -M -N')

    upload_template(
        filename='master.template',
        destination='/etc/salt/master',
        template_dir='config',
        use_sudo=True,
        use_jinja=True,
    )
    sudo('service salt-master restart')


@task
def bootstrap(master_hostname, hostname):
    """Setup salt minion.

    $ fab -H &lt;some_host&gt; bootstrap:&lt;master_hostname&gt;,&lt;some_host_readable_name&gt;
    """
    with settings(warn_only=True):
        sudo('curl -L http://bootstrap.saltstack.org | sudo sh')

    context = {
        'master_hostname': master_hostname,
        'id': hostname,
    }

    upload_template(
        filename='minion.template',
        destination='/etc/salt/minion',
        template_dir='config',
        context=context,
        use_sudo=True,
        use_jinja=True,
    )
    sudo('service salt-minion restart')


@task
def sync_states():
    """Sync Salt-Stack state files."""
    upload_project(local_dir='config/salt', remote_dir='/srv', use_sudo=True)
    upload_project(local_dir='config/pillar', remote_dir='/srv', use_sudo=True)


@task
def master():
    """Run in production."""
    env.user = os.environ['AS_MASTER_USER']
    env.hosts = os.environ['AS_MASTER_HOST']


@task
def vagrant():
    """Run tasks on vagrant instance."""
    env.user = 'vagrant'
    env.hosts = ['127.0.0.1:2222']
    result = local('vagrant ssh-config | grep IdentityFile', capture=True)
    env.key_filename = result.split()[1]


@salt_task
@task
def nginx_reload(*servername_seq):
    """Restart Nginx service."""
    salt('service.relaod nginx', *servername_seq)


def salt(cmd, *servername_seq):
    """Run salt command on given hosts."""
    args = '-L' if '*' not in servername_seq else ''
    cmd = cmd if cmd else 'cmd.run "uptime"'
    env.output_prefix = False

    sudo('salt {args} "{servername_csv}" {cmd}'.format(
        args=args,
        servername_csv=','.join(servername_seq),
        cmd=cmd,
    ))&lt;/code&gt;&lt;/pre&gt;
    &lt;/noscript&gt;
&lt;/div&gt;
&lt;p&gt;Bootstrap master:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;fab master bootstrap_master
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To add new minion run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;fab -H &amp;lt;minion_host&amp;gt; -u &amp;lt;minion_user&amp;gt; bootstrap:&amp;lt;master_ip&amp;gt;,&amp;lt;human_readable_minion_hostname&amp;gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Project layout:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;├── config
│   ├── master.template
│   ├── minion.template
│   ├── pillar
│   │   ├── base.sls
│   │   ├── homepage.sls
│   │   └── top.sls
│   └── salt
│       ├── _modules
│       ├── _states
│       ├── apps
│       ├── firewall
│       ├── nginx
│       ├── python
│       ├── supervisor
│       └── top.sls
├── env
│   ├── AS_MASTER_HOST
│   └── AS_MASTER_USER
├── fabfile.py
└── requirements.txt
&lt;/pre&gt;&lt;/div&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Keep configuration outside code with &lt;a class="reference external" href="https://pypi.python.org/pypi/envdir"&gt;envdir&lt;/a&gt;. &lt;cite&gt;$AS_MASTER_USER&lt;/cite&gt;,
&lt;cite&gt;$AS_MASTER_HOST&lt;/cite&gt; environment variables contains master host details.&lt;/li&gt;
&lt;li&gt;Explicitly copy state files to master. Allows to cheat and check states without
committing to configuration repository.&lt;/li&gt;
&lt;/ul&gt;
</summary><category term="Python"></category><category term="Fabric"></category><category term="Salt-Stack"></category><category term="envdir"></category></entry><entry><title>Alwas on USB connector</title><link href="http://theabele.com/misc/alwas-on-usb-connector" rel="alternate"></link><updated>2014-12-26T00:00:00+02:00</updated><author><name>Janis Abele</name></author><id>tag:theabele.com,2014-12-26:misc/alwas-on-usb-connector</id><summary type="html">&lt;p&gt;I'm fed up with RTFM. High-current or &lt;a class="reference external" href="http://bit.ly/1CMNiJP"&gt;sleep-and-charge&lt;/a&gt; USB connector is usually color coded yellow, orange or red. In ThinkPad manual it's called Always on USB connector.&lt;/p&gt;
</summary><category term="USB"></category><category term="RTFM"></category><category term="future self"></category></entry></feed>