~juju-deployers/juju-deployer/darwin

« back to all changes in this revision

Viewing changes to deployer/action/importer.py

  • Committer: Adam Gandelman
  • Date: 2013-09-03 20:44:14 UTC
  • mfrom: (114 darwin)
  • mto: This revision was merged to the branch mainline in revision 119.
  • 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
import time
 
3
 
 
4
from .base import BaseAction
 
5
from ..errors import UnitErrors
 
6
from ..utils import ErrorExit
 
7
 
 
8
 
 
9
class Importer(BaseAction):
 
10
 
 
11
    log = logging.getLogger("deployer.import")
 
12
 
 
13
    def __init__(self, env, deployment, options):
 
14
        self.options = options
 
15
        self.env = env
 
16
        self.deployment = deployment
 
17
 
 
18
    def add_units(self):
 
19
        self.log.debug("Adding units...")
 
20
        # Add units to existing services that don't match count.
 
21
        env_status = self.env.status()
 
22
        added = set()
 
23
        for svc in self.deployment.get_services():
 
24
            delta = (svc.num_units -
 
25
                     len(env_status['services'][svc.name].get('units', ())))
 
26
            if delta > 0:
 
27
                charm = self.deployment.get_charm_for(svc.name)
 
28
                if charm.is_subordinate():
 
29
                    self.log.warning(
 
30
                        "Config specifies num units for subordinate: %s",
 
31
                        svc.name)
 
32
                    continue
 
33
                self.log.info(
 
34
                    "Adding %d more units to %s" % (abs(delta), svc.name))
 
35
                for u in self.env.add_units(svc.name, abs(delta)):
 
36
                    added.add(u)
 
37
            else:
 
38
                self.log.debug(
 
39
                    " Service %r does not need any more units added.",
 
40
                    svc.name)
 
41
 
 
42
    def get_charms(self):
 
43
        # Get Charms
 
44
        self.log.debug("Getting charms...")
 
45
        self.deployment.fetch_charms(
 
46
            update=self.options.update_charms,
 
47
            no_local_mods=self.options.no_local_mods)
 
48
 
 
49
        # Load config overrides/includes and verify rels after we can
 
50
        # validate them.
 
51
        self.deployment.resolve(self.options.overrides or ())
 
52
 
 
53
    def deploy_services(self):
 
54
        self.log.info("Deploying services...")
 
55
        env_status = self.env.status()
 
56
        for svc in self.deployment.get_services():
 
57
            if svc.name in env_status['services']:
 
58
                self.log.debug(
 
59
                    " Service %r already deployed. Skipping" % svc.name)
 
60
                continue
 
61
 
 
62
            charm = self.deployment.get_charm_for(svc.name)
 
63
            self.log.info(
 
64
                " Deploying service %s using %s", svc.name, charm.charm_url)
 
65
            self.env.deploy(
 
66
                svc.name,
 
67
                charm.charm_url,
 
68
                self.deployment.repo_path,
 
69
                svc.config,
 
70
                svc.constraints,
 
71
                svc.num_units,
 
72
                svc.force_machine)
 
73
 
 
74
            if svc.expose:
 
75
                self.env.expose(svc.name)
 
76
 
 
77
            if self.options.deploy_delay:
 
78
                self.log.debug(" Waiting for deploy delay")
 
79
                time.sleep(self.options.deploy_delay)
 
80
 
 
81
    def add_relations(self):
 
82
        self.log.info("Adding relations...")
 
83
 
 
84
        # Relations
 
85
        status = self.env.status()
 
86
        created = False
 
87
 
 
88
        for end_a, end_b in self.deployment.get_relations():
 
89
            if self._rel_exists(status, end_a, end_b):
 
90
                continue
 
91
            self.log.info(" Adding relation %s <-> %s", end_a, end_b)
 
92
            self.env.add_relation(end_a, end_b)
 
93
            created = True
 
94
            # per the original, not sure the use case.
 
95
            self.log.debug(" Waiting 5s before next relation")
 
96
            time.sleep(5)
 
97
        return created
 
98
 
 
99
    def _rel_exists(self, status, end_a, end_b):
 
100
        # Checks for a named relation on one side that matches the local
 
101
        # endpoint and remote service.
 
102
        (name_a, name_b, rem_a, rem_b) = (end_a, end_b, None, None)
 
103
 
 
104
        if ":" in end_a:
 
105
            name_a, rem_a = end_a.split(":", 1)
 
106
        if ":" in end_b:
 
107
            name_b, rem_b = end_b.split(":", 1)
 
108
 
 
109
        rels_svc_a = status['services'][name_a].get('relations', {})
 
110
 
 
111
        found = False
 
112
        for r, related in rels_svc_a.items():
 
113
            if name_b in related:
 
114
                if rem_a and not r in rem_a:
 
115
                    continue
 
116
                found = True
 
117
                break
 
118
        if found:
 
119
            return True
 
120
        return False
 
121
 
 
122
    def wait_for_units(self, ignore_error=False):
 
123
        timeout = self.options.timeout - (time.time() - self.start_time)
 
124
        if timeout < 0:
 
125
            self.log.error("Reached deployment timeout.. exiting")
 
126
            raise ErrorExit()
 
127
        try:
 
128
            self.env.wait_for_units(
 
129
                int(timeout), watch=self.options.watch, no_exit=ignore_error)
 
130
        except UnitErrors:
 
131
            if not ignore_error:
 
132
                raise
 
133
 
 
134
    def run(self):
 
135
        self.start_time = time.time()
 
136
        self.env.connect()
 
137
 
 
138
        # Get charms
 
139
        self.get_charms()
 
140
        if self.options.branch_only:
 
141
            return
 
142
 
 
143
        self.deploy_services()
 
144
 
 
145
        # Workaround api issue in juju-core, where any action takes 5s
 
146
        # to be consistent to subsequent watch api interactions, see
 
147
        # http://pad.lv/1203105 which will obviate this wait.
 
148
        time.sleep(5.1)
 
149
 
 
150
        self.wait_for_units()
 
151
        self.add_units()
 
152
 
 
153
        rels_created = self.add_relations()
 
154
 
 
155
        # Wait for the units to be up before waiting for rel stability.
 
156
        self.log.debug("Waiting for units to be started")
 
157
        self.wait_for_units(self.options.retry_count)
 
158
        if rels_created:
 
159
            self.log.debug("Waiting for relations %d", self.options.rel_wait)
 
160
            time.sleep(self.options.rel_wait)
 
161
            self.wait_for_units(self.options.retry_count)
 
162
 
 
163
        if self.options.retry_count:
 
164
            self.log.info("Looking for errors to auto-retry")
 
165
            self.env.resolve_errors(
 
166
                self.options.retry_count,
 
167
                self.options.timeout - time.time() - self.start_time)