~barryprice/juju-deployer/LP1892423

« back to all changes in this revision

Viewing changes to deployer/env/base.py

  • Committer: Adam Gandelman
  • Date: 2013-09-03 20:44:14 UTC
  • mfrom: (69.3.45 darwin)
  • Revision ID: adamg@canonical.com-20130903204414-xsqqz2gp83dp5d2o
MergeĀ lp:juju-deployer/darwin.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import logging
 
2
 
 
3
from ..utils import (
 
4
    _get_juju_home, path_join, yaml_load, ErrorExit, yaml_dump, temp_file,
 
5
    _check_call)
 
6
 
 
7
 
 
8
class BaseEnvironment(object):
 
9
 
 
10
    log = logging.getLogger("deployer.env")
 
11
 
 
12
    @property
 
13
    def env_config_path(self):
 
14
        jhome = _get_juju_home()
 
15
        env_config_path = path_join(jhome, 'environments.yaml')
 
16
        return env_config_path
 
17
 
 
18
    def _check_call(self, *args, **kwargs):
 
19
        if self.options and self.options.retry_count:
 
20
            kwargs['max_retry'] = self.options.retry_count
 
21
        return _check_call(*args, **kwargs)
 
22
 
 
23
    def _named_env(self, params):
 
24
        if self.name:
 
25
            params.extend(["-e", self.name])
 
26
        return params
 
27
 
 
28
    def _get_env_config(self):
 
29
        with open(self.env_config_path) as fh:
 
30
            config = yaml_load(fh.read())
 
31
            if self.name:
 
32
                if self.name not in config['environments']:
 
33
                    self.log.error("Environment %r not found", self.name)
 
34
                    raise ErrorExit()
 
35
                return config['environments'][self.name]
 
36
            else:
 
37
                env_name = config.get('default')
 
38
                if env_name is None:
 
39
                    if len(config['environments'].keys()) == 1:
 
40
                        env_name = config['environments'].keys().pop()
 
41
                    else:
 
42
                        self.log.error("Ambigious operation environment")
 
43
                        raise ErrorExit()
 
44
                return config['environments'][env_name]
 
45
 
 
46
    def _write_config(self, svc_name, config, fh):
 
47
        fh.write(yaml_dump({svc_name: config}))
 
48
        fh.flush()
 
49
 
 
50
#    def _write_config(self, svc_name, config, fh):
 
51
#        fh.write(yaml_dump(config))
 
52
#        fh.flush()
 
53
 
 
54
    def _get_units_in_error(self, status=None):
 
55
        units = []
 
56
        if status is None:
 
57
            status = self.status()
 
58
        for s in status.get('services', {}).keys():
 
59
            for uid, u in status['services'][s].get('units', {}).items():
 
60
                if 'error' in u['agent-state']:
 
61
                    units.append(uid)
 
62
                for uid, u in u.get('subordinates', {}).items():
 
63
                    if 'error' in u['agent-state']:
 
64
                        units.append(uid)
 
65
        return units
 
66
 
 
67
    def deploy(self, name, charm_url,
 
68
               repo=None, config=None,
 
69
               constraints=None, num_units=1, force_machine=None):
 
70
        params = self._named_env(["juju", "deploy"])
 
71
        with temp_file() as fh:
 
72
            if config:
 
73
                fh.write(yaml_dump({name: config}))
 
74
                fh.flush()
 
75
                params.extend(["--config", fh.name])
 
76
            if constraints:
 
77
                params.extend(['--constraints', constraints])
 
78
            if num_units != 1:
 
79
                params.extend(["--num-units", str(num_units)])
 
80
            if charm_url.startswith('local'):
 
81
                if repo == "":
 
82
                    repo = "."
 
83
                params.extend(["--repository=%s" % repo])
 
84
            if force_machine is not None:
 
85
                params.extend["--force-machine=%d" % force_machine]
 
86
 
 
87
            params.extend([charm_url, name])
 
88
            self._check_call(
 
89
                params, self.log, "Error deploying service %r", name)
 
90
 
 
91
    def terminate_machine(self, mid, wait=False):
 
92
        """Terminate a machine.
 
93
 
 
94
        The machine can't have any running units, after removing the units or
 
95
        destroying the service, use wait_for_units to know when its safe to
 
96
        delete the machine (ie units have finished executing stop hooks and are
 
97
        removed)
 
98
        """
 
99
        if int(mid) == 0:
 
100
            raise RuntimeError("Can't terminate machine 0")
 
101
        params = self._named_env(["juju", "terminate-machine"])
 
102
        params.append(mid)
 
103
        try:
 
104
            self._check_call(
 
105
                params, self.log, "Error terminating machine %r" % mid)
 
106
        except ErrorExit, e:
 
107
            if ("machine %s does not exist" % mid) in e.error.output:
 
108
                return
 
109
            raise
 
110
 
 
111
    def get_service_address(self, svc_name):
 
112
        status = self.get_cli_status()
 
113
        if svc_name not in status['services']:
 
114
            self.log.warning("Service %s does not exist", svc_name)
 
115
            return None
 
116
        units = status['services'][svc_name].get('units', {})
 
117
        unit_keys = list(sorted(units.keys()))
 
118
        if unit_keys:
 
119
            return units[unit_keys[0]].get('public-address', '')
 
120
        self.log.warning("Service %s has no units")
 
121
 
 
122
    def get_cli_status(self):
 
123
        params = self._named_env(["juju", "status"])
 
124
        with open('/dev/null', 'w') as fh:
 
125
            output = self._check_call(
 
126
                params, self.log, "Error getting status, is it bootstrapped?",
 
127
                stderr=fh)
 
128
        status = yaml_load(output)
 
129
        return status