~jaywink/charms/trusty/jujubackup/trunk

« back to all changes in this revision

Viewing changes to lib/charmhelpers/contrib/ansible/__init__.py

  • Committer: vincenzo di somma
  • Date: 2014-02-12 10:50:10 UTC
  • Revision ID: vincenzo.di.somma@canonical.com-20140212105010-tn1it3seyzk4ld2g
Works with u1 and s3, few minor details still need to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2013 Canonical Ltd.
2
 
#
3
 
# Authors:
4
 
#  Charm Helpers Developers <juju@lists.ubuntu.com>
5
 
"""Charm Helpers ansible - declare the state of your machines.
6
 
 
7
 
This helper enables you to declare your machine state, rather than
8
 
program it procedurally (and have to test each change to your procedures).
9
 
Your install hook can be as simple as:
10
 
 
11
 
{{{
12
 
import charmhelpers.contrib.ansible
13
 
 
14
 
 
15
 
def install():
16
 
    charmhelpers.contrib.ansible.install_ansible_support()
17
 
    charmhelpers.contrib.ansible.apply_playbook('playbooks/install.yaml')
18
 
}}}
19
 
 
20
 
and won't need to change (nor will its tests) when you change the machine
21
 
state.
22
 
 
23
 
All of your juju config and relation-data are available as template
24
 
variables within your playbooks and templates. An install playbook looks
25
 
something like:
26
 
 
27
 
{{{
28
 
---
29
 
- hosts: localhost
30
 
  user: root
31
 
 
32
 
  tasks:
33
 
    - name: Add private repositories.
34
 
      template:
35
 
        src: ../templates/private-repositories.list.jinja2
36
 
        dest: /etc/apt/sources.list.d/private.list
37
 
 
38
 
    - name: Update the cache.
39
 
      apt: update_cache=yes
40
 
 
41
 
    - name: Install dependencies.
42
 
      apt: pkg={{ item }}
43
 
      with_items:
44
 
        - python-mimeparse
45
 
        - python-webob
46
 
        - sunburnt
47
 
 
48
 
    - name: Setup groups.
49
 
      group: name={{ item.name }} gid={{ item.gid }}
50
 
      with_items:
51
 
        - { name: 'deploy_user', gid: 1800 }
52
 
        - { name: 'service_user', gid: 1500 }
53
 
 
54
 
  ...
55
 
}}}
56
 
 
57
 
Read more online about playbooks[1] and standard ansible modules[2].
58
 
 
59
 
[1] http://www.ansibleworks.com/docs/playbooks.html
60
 
[2] http://www.ansibleworks.com/docs/modules.html
61
 
"""
62
 
import os
63
 
import subprocess
64
 
 
65
 
import charmhelpers.contrib.templating.contexts
66
 
import charmhelpers.core.host
67
 
import charmhelpers.core.hookenv
68
 
import charmhelpers.fetch
69
 
 
70
 
 
71
 
charm_dir = os.environ.get('CHARM_DIR', '')
72
 
ansible_hosts_path = '/etc/ansible/hosts'
73
 
# Ansible will automatically include any vars in the following
74
 
# file in its inventory when run locally.
75
 
ansible_vars_path = '/etc/ansible/host_vars/localhost'
76
 
 
77
 
 
78
 
def install_ansible_support(from_ppa=True):
79
 
    """Installs the ansible package.
80
 
 
81
 
    By default it is installed from the PPA [1] linked from
82
 
    the ansible website [2].
83
 
 
84
 
    [1] https://launchpad.net/~rquillo/+archive/ansible
85
 
    [2] http://www.ansibleworks.com/docs/gettingstarted.html#ubuntu-and-debian
86
 
 
87
 
    If from_ppa is false, you must ensure that the package is available
88
 
    from a configured repository.
89
 
    """
90
 
    if from_ppa:
91
 
        charmhelpers.fetch.add_source('ppa:rquillo/ansible')
92
 
        charmhelpers.fetch.apt_update(fatal=True)
93
 
    charmhelpers.fetch.apt_install('ansible')
94
 
    with open(ansible_hosts_path, 'w+') as hosts_file:
95
 
        hosts_file.write('localhost ansible_connection=local')
96
 
 
97
 
 
98
 
def apply_playbook(playbook, tags=None):
99
 
    tags = tags or []
100
 
    tags = ",".join(tags)
101
 
    charmhelpers.contrib.templating.contexts.juju_state_to_yaml(
102
 
        ansible_vars_path, namespace_separator='__',
103
 
        allow_hyphens_in_keys=False)
104
 
    call = [
105
 
        'ansible-playbook',
106
 
        '-c',
107
 
        'local',
108
 
        playbook,
109
 
    ]
110
 
    if tags:
111
 
        call.extend(['--tags', '{}'.format(tags)])
112
 
    subprocess.check_call(call)
113
 
 
114
 
 
115
 
class AnsibleHooks(charmhelpers.core.hookenv.Hooks):
116
 
    """Run a playbook with the hook-name as the tag.
117
 
 
118
 
    This helper builds on the standard hookenv.Hooks helper,
119
 
    but additionally runs the playbook with the hook-name specified
120
 
    using --tags (ie. running all the tasks tagged with the hook-name).
121
 
 
122
 
    Example:
123
 
        hooks = AnsibleHooks(playbook_path='playbooks/my_machine_state.yaml')
124
 
 
125
 
        # All the tasks within my_machine_state.yaml tagged with 'install'
126
 
        # will be run automatically after do_custom_work()
127
 
        @hooks.hook()
128
 
        def install():
129
 
            do_custom_work()
130
 
 
131
 
        # For most of your hooks, you won't need to do anything other
132
 
        # than run the tagged tasks for the hook:
133
 
        @hooks.hook('config-changed', 'start', 'stop')
134
 
        def just_use_playbook():
135
 
            pass
136
 
 
137
 
        # As a convenience, you can avoid the above noop function by specifying
138
 
        # the hooks which are handled by ansible-only and they'll be registered
139
 
        # for you:
140
 
        # hooks = AnsibleHooks(
141
 
        #     'playbooks/my_machine_state.yaml',
142
 
        #     default_hooks=['config-changed', 'start', 'stop'])
143
 
 
144
 
        if __name__ == "__main__":
145
 
            # execute a hook based on the name the program is called by
146
 
            hooks.execute(sys.argv)
147
 
    """
148
 
 
149
 
    def __init__(self, playbook_path, default_hooks=None):
150
 
        """Register any hooks handled by ansible."""
151
 
        super(AnsibleHooks, self).__init__()
152
 
 
153
 
        self.playbook_path = playbook_path
154
 
 
155
 
        default_hooks = default_hooks or []
156
 
        noop = lambda *args, **kwargs: None
157
 
        for hook in default_hooks:
158
 
            self.register(hook, noop)
159
 
 
160
 
    def execute(self, args):
161
 
        """Execute the hook followed by the playbook using the hook as tag."""
162
 
        super(AnsibleHooks, self).execute(args)
163
 
        hook_name = os.path.basename(args[0])
164
 
        charmhelpers.contrib.ansible.apply_playbook(
165
 
            self.playbook_path, tags=[hook_name])