~barryprice/juju-deployer/LP1892423

« back to all changes in this revision

Viewing changes to deployer/config.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
from os.path import abspath, isabs, join, dirname
 
2
import logging
 
3
import tempfile
 
4
import shutil
 
5
import urllib
 
6
import urlparse
 
7
 
 
8
 
 
9
from .deployment import Deployment
 
10
from .utils import ErrorExit, yaml_load, path_exists, dict_merge
 
11
 
 
12
 
 
13
class ConfigStack(object):
 
14
 
 
15
    log = logging.getLogger("deployer.config")
 
16
 
 
17
    def __init__(self, config_files):
 
18
        self.config_files = config_files
 
19
        self.data = {}
 
20
        self.yaml = {}
 
21
        self.include_dirs = []
 
22
        self.urlopen = urllib.urlopen
 
23
        self.load()
 
24
 
 
25
    def _yaml_load(self, config_file):
 
26
        if config_file in self.yaml:
 
27
            return self.yaml[config_file]
 
28
 
 
29
        if urlparse.urlparse(config_file).scheme:
 
30
            response = self.urlopen(config_file)
 
31
            if response.getcode() == 200:
 
32
                temp = tempfile.NamedTemporaryFile(delete=True)
 
33
                shutil.copyfileobj(response, temp)
 
34
                temp.flush()
 
35
                config_file = temp.name
 
36
            else:
 
37
                self.log.warning("Could not retrieve %s", config_file)
 
38
                raise ErrorExit()
 
39
 
 
40
        with open(config_file) as fh:
 
41
            try:
 
42
                self.yaml[config_file] = yaml_load(fh.read())
 
43
            except Exception, e:
 
44
                self.log.warning(
 
45
                    "Couldn't load config file @ %r, error: %s:%s",
 
46
                    config_file, type(e), e)
 
47
                raise
 
48
 
 
49
        return self.yaml[config_file]
 
50
 
 
51
    def keys(self):
 
52
        return sorted(self.data)
 
53
 
 
54
    def get(self, key):
 
55
        if not key in self.data:
 
56
            self.log.warning("Deployment %r not found. Available %s",
 
57
                             key, ", ".join(self.keys()))
 
58
            raise ErrorExit()
 
59
        deploy_data = self.data[key]
 
60
        deploy_data = self._resolve_inherited(deploy_data)
 
61
        return Deployment(key, deploy_data, self.include_dirs)
 
62
 
 
63
    def load(self):
 
64
        data = {}
 
65
        include_dirs = []
 
66
        for fp in self._resolve_included():
 
67
            if path_exists(fp):
 
68
                include_dirs.append(dirname(abspath(fp)))
 
69
            d = self._yaml_load(fp)
 
70
            data = dict_merge(data, d)
 
71
        self.data = data
 
72
        if 'include-config' in self.data:
 
73
            self.data.pop('include-config')
 
74
        self.include_dirs = include_dirs
 
75
 
 
76
    def _inherits(self, d):
 
77
        parents = d.get('inherits', ())
 
78
        if isinstance(parents, basestring):
 
79
            parents = [parents]
 
80
        return parents
 
81
 
 
82
    def _resolve_inherited(self, deploy_data):
 
83
        if not 'inherits' in deploy_data:
 
84
            return deploy_data
 
85
        inherits = parents = self._inherits(deploy_data)
 
86
        for parent_name in parents:
 
87
            parent = self.get(parent_name)
 
88
            inherits.extend(self._inherits(parent.data))
 
89
            deploy_data = dict_merge(parent.data, deploy_data)
 
90
 
 
91
        deploy_data['inherits'] = inherits
 
92
        return deploy_data
 
93
 
 
94
    def _includes(self, config_file):
 
95
        files = [config_file]
 
96
        d = self._yaml_load(config_file)
 
97
        if 'include-config' in d:
 
98
            inc_f = d['include-config']
 
99
            if not isabs(inc_f):
 
100
                inc_f = join(dirname(config_file), inc_f)
 
101
            files.extend(self._includes(inc_f))
 
102
        return files
 
103
 
 
104
    def _resolve_included(self):
 
105
        files = []
 
106
        [files.extend(self._includes(cf)) for cf in self.config_files]
 
107
        return files