~openstack-charmers/charms/trusty/nova-cloud-controller/keystonev3

« back to all changes in this revision

Viewing changes to tests/charmhelpers/contrib/openstack/amulet/deployment.py

  • Committer: Liam Young
  • Date: 2016-01-29 08:59:12 UTC
  • Revision ID: liam.young@canonical.com-20160129085912-nt5qbn1zyet3b6sq
CH sync

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# You should have received a copy of the GNU Lesser General Public License
15
15
# along with charm-helpers.  If not, see <http://www.gnu.org/licenses/>.
16
16
 
 
17
import logging
 
18
import re
 
19
import sys
17
20
import six
18
21
from collections import OrderedDict
19
22
from charmhelpers.contrib.amulet.deployment import (
20
23
    AmuletDeployment
21
24
)
22
25
 
 
26
DEBUG = logging.DEBUG
 
27
ERROR = logging.ERROR
 
28
 
23
29
 
24
30
class OpenStackAmuletDeployment(AmuletDeployment):
25
31
    """OpenStack amulet deployment.
28
34
       that is specifically for use by OpenStack charms.
29
35
       """
30
36
 
31
 
    def __init__(self, series=None, openstack=None, source=None, stable=True):
 
37
    def __init__(self, series=None, openstack=None, source=None,
 
38
                 stable=True, log_level=DEBUG):
32
39
        """Initialize the deployment environment."""
33
40
        super(OpenStackAmuletDeployment, self).__init__(series)
 
41
        self.log = self.get_logger(level=log_level)
 
42
        self.log.info('OpenStackAmuletDeployment:  init')
34
43
        self.openstack = openstack
35
44
        self.source = source
36
45
        self.stable = stable
38
47
        # out.
39
48
        self.current_next = "trusty"
40
49
 
 
50
    def get_logger(self, name="deployment-logger", level=logging.DEBUG):
 
51
        """Get a logger object that will log to stdout."""
 
52
        log = logging
 
53
        logger = log.getLogger(name)
 
54
        fmt = log.Formatter("%(asctime)s %(funcName)s "
 
55
                            "%(levelname)s: %(message)s")
 
56
 
 
57
        handler = log.StreamHandler(stream=sys.stdout)
 
58
        handler.setLevel(level)
 
59
        handler.setFormatter(fmt)
 
60
 
 
61
        logger.addHandler(handler)
 
62
        logger.setLevel(level)
 
63
 
 
64
        return logger
 
65
 
41
66
    def _determine_branch_locations(self, other_services):
42
67
        """Determine the branch locations for the other services.
43
68
 
45
70
           stable or next (dev) branch, and based on this, use the corresonding
46
71
           stable or next branches for the other_services."""
47
72
 
 
73
        self.log.info('OpenStackAmuletDeployment:  determine branch locations')
 
74
 
48
75
        # Charms outside the lp:~openstack-charmers namespace
49
76
        base_charms = ['mysql', 'mongodb', 'nrpe']
50
77
 
82
109
 
83
110
    def _add_services(self, this_service, other_services):
84
111
        """Add services to the deployment and set openstack-origin/source."""
 
112
        self.log.info('OpenStackAmuletDeployment:  adding services')
 
113
 
85
114
        other_services = self._determine_branch_locations(other_services)
86
115
 
87
116
        super(OpenStackAmuletDeployment, self)._add_services(this_service,
92
121
 
93
122
        # Charms which should use the source config option
94
123
        use_source = ['mysql', 'mongodb', 'rabbitmq-server', 'ceph',
95
 
                      'ceph-osd', 'ceph-radosgw']
 
124
                      'ceph-osd', 'ceph-radosgw', 'ceph-mon']
96
125
 
97
126
        # Charms which can not use openstack-origin, ie. many subordinates
98
 
        no_origin = ['cinder-ceph', 'hacluster', 'neutron-openvswitch', 'nrpe']
 
127
        no_origin = ['cinder-ceph', 'hacluster', 'neutron-openvswitch', 'nrpe',
 
128
                     'openvswitch-odl', 'neutron-api-odl', 'odl-controller',
 
129
                     'cinder-backup']
99
130
 
100
131
        if self.openstack:
101
132
            for svc in services:
111
142
 
112
143
    def _configure_services(self, configs):
113
144
        """Configure all of the services."""
 
145
        self.log.info('OpenStackAmuletDeployment:  configure services')
114
146
        for service, config in six.iteritems(configs):
115
147
            self.d.configure(service, config)
116
148
 
 
149
    def _auto_wait_for_status(self, message=None, exclude_services=None,
 
150
                              include_only=None, timeout=1800):
 
151
        """Wait for all units to have a specific extended status, except
 
152
        for any defined as excluded.  Unless specified via message, any
 
153
        status containing any case of 'ready' will be considered a match.
 
154
 
 
155
        Examples of message usage:
 
156
 
 
157
          Wait for all unit status to CONTAIN any case of 'ready' or 'ok':
 
158
              message = re.compile('.*ready.*|.*ok.*', re.IGNORECASE)
 
159
 
 
160
          Wait for all units to reach this status (exact match):
 
161
              message = re.compile('^Unit is ready and clustered$')
 
162
 
 
163
          Wait for all units to reach any one of these (exact match):
 
164
              message = re.compile('Unit is ready|OK|Ready')
 
165
 
 
166
          Wait for at least one unit to reach this status (exact match):
 
167
              message = {'ready'}
 
168
 
 
169
        See Amulet's sentry.wait_for_messages() for message usage detail.
 
170
        https://github.com/juju/amulet/blob/master/amulet/sentry.py
 
171
 
 
172
        :param message: Expected status match
 
173
        :param exclude_services: List of juju service names to ignore,
 
174
            not to be used in conjuction with include_only.
 
175
        :param include_only: List of juju service names to exclusively check,
 
176
            not to be used in conjuction with exclude_services.
 
177
        :param timeout: Maximum time in seconds to wait for status match
 
178
        :returns: None.  Raises if timeout is hit.
 
179
        """
 
180
        self.log.info('Waiting for extended status on units...')
 
181
 
 
182
        all_services = self.d.services.keys()
 
183
 
 
184
        if exclude_services and include_only:
 
185
            raise ValueError('exclude_services can not be used '
 
186
                             'with include_only')
 
187
 
 
188
        if message:
 
189
            if isinstance(message, re._pattern_type):
 
190
                match = message.pattern
 
191
            else:
 
192
                match = message
 
193
 
 
194
            self.log.debug('Custom extended status wait match: '
 
195
                           '{}'.format(match))
 
196
        else:
 
197
            self.log.debug('Default extended status wait match:  contains '
 
198
                           'READY (case-insensitive)')
 
199
            message = re.compile('.*ready.*', re.IGNORECASE)
 
200
 
 
201
        if exclude_services:
 
202
            self.log.debug('Excluding services from extended status match: '
 
203
                           '{}'.format(exclude_services))
 
204
        else:
 
205
            exclude_services = []
 
206
 
 
207
        if include_only:
 
208
            services = include_only
 
209
        else:
 
210
            services = list(set(all_services) - set(exclude_services))
 
211
 
 
212
        self.log.debug('Waiting up to {}s for extended status on services: '
 
213
                       '{}'.format(timeout, services))
 
214
        service_messages = {service: message for service in services}
 
215
        self.d.sentry.wait_for_messages(service_messages, timeout=timeout)
 
216
        self.log.info('OK')
 
217
 
117
218
    def _get_openstack_release(self):
118
219
        """Get openstack release.
119
220
 
125
226
         self.precise_havana, self.precise_icehouse,
126
227
         self.trusty_icehouse, self.trusty_juno, self.utopic_juno,
127
228
         self.trusty_kilo, self.vivid_kilo, self.trusty_liberty,
128
 
         self.wily_liberty) = range(12)
 
229
         self.wily_liberty, self.trusty_mitaka,
 
230
         self.xenial_mitaka) = range(14)
129
231
 
130
232
        releases = {
131
233
            ('precise', None): self.precise_essex,
137
239
            ('trusty', 'cloud:trusty-juno'): self.trusty_juno,
138
240
            ('trusty', 'cloud:trusty-kilo'): self.trusty_kilo,
139
241
            ('trusty', 'cloud:trusty-liberty'): self.trusty_liberty,
 
242
            ('trusty', 'cloud:trusty-mitaka'): self.trusty_mitaka,
140
243
            ('utopic', None): self.utopic_juno,
141
244
            ('vivid', None): self.vivid_kilo,
142
 
            ('wily', None): self.wily_liberty}
 
245
            ('wily', None): self.wily_liberty,
 
246
            ('xenial', None): self.xenial_mitaka}
143
247
        return releases[(self.series, self.openstack)]
144
248
 
145
249
    def _get_openstack_release_string(self):
156
260
            ('utopic', 'juno'),
157
261
            ('vivid', 'kilo'),
158
262
            ('wily', 'liberty'),
 
263
            ('xenial', 'mitaka'),
159
264
        ])
160
265
        if self.openstack:
161
266
            os_origin = self.openstack.split(':')[1]