~bloodearnest/charms/trusty/rabbitmq-server/add-nagios-service-groups

« back to all changes in this revision

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

  • Committer: David Ames
  • Date: 2013-11-15 19:15:16 UTC
  • mto: This revision was merged to the branch mainline in revision 45.
  • Revision ID: david.ames@canonical.com-20131115191516-rrvszp2cgdi3hrqt
Enable nrpe-external-master-relation. Use charmhelpers (embedded for now)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Charm Helpers saltstack - declare the state of your machines.
 
2
 
 
3
This helper enables you to declare your machine state, rather than
 
4
program it procedurally (and have to test each change to your procedures).
 
5
Your install hook can be as simple as:
 
6
 
 
7
{{{
 
8
from charmhelpers.contrib.saltstack import (
 
9
    install_salt_support,
 
10
    update_machine_state,
 
11
)
 
12
 
 
13
 
 
14
def install():
 
15
    install_salt_support()
 
16
    update_machine_state('machine_states/dependencies.yaml')
 
17
    update_machine_state('machine_states/installed.yaml')
 
18
}}}
 
19
 
 
20
and won't need to change (nor will its tests) when you change the machine
 
21
state.
 
22
 
 
23
It's using a python package called salt-minion which allows various formats for
 
24
specifying resources, such as:
 
25
 
 
26
{{{
 
27
/srv/{{ basedir }}:
 
28
    file.directory:
 
29
        - group: ubunet
 
30
        - user: ubunet
 
31
        - require:
 
32
            - user: ubunet
 
33
        - recurse:
 
34
            - user
 
35
            - group
 
36
 
 
37
ubunet:
 
38
    group.present:
 
39
        - gid: 1500
 
40
    user.present:
 
41
        - uid: 1500
 
42
        - gid: 1500
 
43
        - createhome: False
 
44
        - require:
 
45
            - group: ubunet
 
46
}}}
 
47
 
 
48
The docs for all the different state definitions are at:
 
49
    http://docs.saltstack.com/ref/states/all/
 
50
 
 
51
 
 
52
TODO:
 
53
  * Add test helpers which will ensure that machine state definitions
 
54
    are functionally (but not necessarily logically) correct (ie. getting
 
55
    salt to parse all state defs.
 
56
  * Add a link to a public bootstrap charm example / blogpost.
 
57
  * Find a way to obviate the need to use the grains['charm_dir'] syntax
 
58
    in templates.
 
59
"""
 
60
# Copyright 2013 Canonical Ltd.
 
61
#
 
62
# Authors:
 
63
#  Charm Helpers Developers <juju@lists.ubuntu.com>
 
64
import os
 
65
import subprocess
 
66
import yaml
 
67
 
 
68
import charmhelpers.core.host
 
69
import charmhelpers.core.hookenv
 
70
 
 
71
 
 
72
charm_dir = os.environ.get('CHARM_DIR', '')
 
73
salt_grains_path = '/etc/salt/grains'
 
74
 
 
75
 
 
76
def install_salt_support(from_ppa=True):
 
77
    """Installs the salt-minion helper for machine state.
 
78
 
 
79
    By default the salt-minion package is installed from
 
80
    the saltstack PPA. If from_ppa is False you must ensure
 
81
    that the salt-minion package is available in the apt cache.
 
82
    """
 
83
    if from_ppa:
 
84
        subprocess.check_call([
 
85
            '/usr/bin/add-apt-repository',
 
86
            '--yes',
 
87
            'ppa:saltstack/salt',
 
88
        ])
 
89
        subprocess.check_call(['/usr/bin/apt-get', 'update'])
 
90
    # We install salt-common as salt-minion would run the salt-minion
 
91
    # daemon.
 
92
    charmhelpers.fetch.apt_install('salt-common')
 
93
 
 
94
 
 
95
def update_machine_state(state_path):
 
96
    """Update the machine state using the provided state declaration."""
 
97
    juju_state_to_yaml(salt_grains_path)
 
98
    subprocess.check_call([
 
99
        'salt-call',
 
100
        '--local',
 
101
        'state.template',
 
102
        state_path,
 
103
    ])
 
104
 
 
105
 
 
106
def juju_state_to_yaml(yaml_path, namespace_separator=':'):
 
107
    """Update the juju config and state in a yaml file.
 
108
 
 
109
    This includes any current relation-get data, and the charm
 
110
    directory.
 
111
    """
 
112
    config = charmhelpers.core.hookenv.config()
 
113
 
 
114
    # Add the charm_dir which we will need to refer to charm
 
115
    # file resources etc.
 
116
    config['charm_dir'] = charm_dir
 
117
    config['local_unit'] = charmhelpers.core.hookenv.local_unit()
 
118
 
 
119
    # Add any relation data prefixed with the relation type.
 
120
    relation_type = charmhelpers.core.hookenv.relation_type()
 
121
    if relation_type is not None:
 
122
        relation_data = charmhelpers.core.hookenv.relation_get()
 
123
        relation_data = dict(
 
124
            ("{relation_type}{namespace_separator}{key}".format(
 
125
                relation_type=relation_type.replace('-', '_'),
 
126
                key=key,
 
127
                namespace_separator=namespace_separator), val)
 
128
            for key, val in relation_data.items())
 
129
        config.update(relation_data)
 
130
 
 
131
    # Don't use non-standard tags for unicode which will not
 
132
    # work when salt uses yaml.load_safe.
 
133
    yaml.add_representer(unicode, lambda dumper,
 
134
                         value: dumper.represent_scalar(
 
135
                             u'tag:yaml.org,2002:str', value))
 
136
 
 
137
    yaml_dir = os.path.dirname(yaml_path)
 
138
    if not os.path.exists(yaml_dir):
 
139
        os.makedirs(yaml_dir)
 
140
 
 
141
    if os.path.exists(yaml_path):
 
142
        with open(yaml_path, "r") as existing_vars_file:
 
143
            existing_vars = yaml.load(existing_vars_file.read())
 
144
    else:
 
145
        existing_vars = {}
 
146
 
 
147
    existing_vars.update(config)
 
148
    with open(yaml_path, "w+") as fp:
 
149
        fp.write(yaml.dump(existing_vars))