~tasdomas/amulet/actions

« back to all changes in this revision

Viewing changes to amulet/sentry.py

  • Committer: Marco Ceppi
  • Date: 2015-04-29 10:03:43 UTC
  • mfrom: (226.3.3)
  • Revision ID: git-v1:682be6c7216852967250155628474d9edc8c5c5d
Merge pull request #72 from juju/lp-1430488

Lp 1430488

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
import json
3
3
import os
4
4
import subprocess
 
5
import time
5
6
 
6
7
import pkg_resources
7
8
 
39
40
    def directory_listing(self, *args):
40
41
        raise NotImplemented()
41
42
 
42
 
    def juju_agent(self):
 
43
    def juju_agent(self, timeout):
43
44
        raise NotImplemented()
44
45
 
45
46
 
93
94
        output, code = self._run(command)
94
95
        return output.strip(), code
95
96
 
96
 
    def _run(self, command, unit=None):
 
97
    def _run(self, command, unit=None, timeout=300):
 
98
        """
 
99
        Run a command against an individual unit.
 
100
 
 
101
        The timeout defaults to 5m to match the `juju run` command, but can
 
102
        be increased to wait for other running hook contexts to complete.
 
103
        """
97
104
        unit = unit or self.info['unit_name']
98
 
        cmd = ['juju', 'run', '--unit', unit, command]
 
105
        cmd = [
 
106
            'juju', 'run',
 
107
            '--unit', unit,
 
108
            '--timeout', "%ds" % timeout,
 
109
            command
 
110
        ]
99
111
        p = subprocess.Popen(
100
112
            cmd,
101
113
            stdout=subprocess.PIPE,
105
117
        output = stdout if p.returncode == 0 else stderr
106
118
        return output.decode('utf8'), p.returncode
107
119
 
108
 
    def _run_unit_script(self, cmd):
 
120
    def _run_unit_script(self, cmd, timeout=300):
109
121
        cmd = "/tmp/amulet/{}".format(cmd)
110
 
        output, return_code = self._run(cmd)
 
122
        output, return_code = self._run(cmd, timeout=timeout)
111
123
        if return_code == 0:
112
124
            return json.loads(output)
113
125
        else:
114
126
            raise IOError(output)
115
127
 
116
 
    def juju_agent(self):
117
 
        return self._run_unit_script("juju_agent.py")
 
128
    def juju_agent(self, timeout=300):
 
129
        return self._run_unit_script("juju_agent.py", timeout)
118
130
 
119
131
    def relation(self, from_rel, to_rel):
120
132
        this_unit = '{service}/{unit}'.format(**self.info)
223
235
 
224
236
    def wait_for_status(self, juju_env, services, timeout=300):
225
237
        """Return env status, but only after all units have a
226
 
        public-address assigned.
 
238
        public-address assigned and are in a 'started' state.
 
239
 
 
240
        Some substrates (like Amazon) will return a public-address while the
 
241
        machine is still allocating, so it's necessary to also check the
 
242
        agent-state to see if the unit is ready.
227
243
 
228
244
        Raises if a unit reaches error state, or if public-address not
229
245
        available for all units before timeout expires.
235
251
                    ready = True
236
252
                    status = waiter.status(juju_env)
237
253
                    for service in services:
238
 
                        if not 'units' in status['services'][service]:
 
254
                        if 'units' not in status['services'][service]:
239
255
                            continue
240
256
                        for unit, unit_dict in \
241
257
                                status['services'][service]['units'].items():
244
260
                                    unit, unit_dict.get('agent-state-info')))
245
261
                            if 'public-address' not in unit_dict:
246
262
                                ready = False
 
263
                            if 'started' != unit_dict.get('agent-state'):
 
264
                                ready = False
247
265
                    if ready:
248
266
                        return status
249
267
        except helpers.TimeoutError:
254
272
            raise
255
273
 
256
274
    def wait(self, timeout=300):
257
 
        #for unit in self.unit:
 
275
        """
 
276
        wait_for_status, called by __init__, blocks until units are in a
 
277
        started state. Here we wait for a unit to finish any running hooks.
 
278
        When the unit is done, juju_agent will return {}. Otherwise, it returns
 
279
        a dict with the name of the running hook.
 
280
 
 
281
        Raises an error if the timeout is exceeded.
 
282
        """
258
283
        ready = False
259
284
        try:
260
285
            with helpers.timeout(timeout):
261
 
                # Make sure we're in a 'started' state across the board
262
 
                waiter.wait(timeout=timeout)
263
286
                while not ready:
264
287
                    for unit in self.unit.keys():
265
 
                        status = self.unit[unit].juju_agent()
 
288
                        status = self.unit[unit].juju_agent(timeout=timeout)
 
289
 
266
290
                        # Check if we have a hook key and it's not None
267
291
                        if status is None:
268
292
                            ready = False