0d1939a4cf6ca0e1d5b840e359112fb43b29b21c
[apex.git] / lib / python / apex / deploy_settings.py
1 ##############################################################################
2 # Copyright (c) 2016 Michael Chapman (michapma@redhat.com) and others.
3 #
4 # All rights reserved. This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
8 ##############################################################################
9
10
11 import yaml
12 import logging
13
14 from .common import utils
15
16 REQ_DEPLOY_SETTINGS = ['sdn_controller',
17                        'odl_version',
18                        'sdn_l3',
19                        'tacker',
20                        'congress',
21                        'dataplane',
22                        'sfc',
23                        'vpn',
24                        'vpp',
25                        'ceph',
26                        'gluon']
27
28 OPT_DEPLOY_SETTINGS = ['performance',
29                        'vsperf',
30                        'ceph_device',
31                        'yardstick',
32                        'dovetail']
33
34 VALID_ROLES = ['Controller', 'Compute', 'ObjectStorage']
35 VALID_PERF_OPTS = ['kernel', 'nova', 'vpp']
36 VALID_DATAPLANES = ['ovs', 'ovs_dpdk', 'fdio']
37
38
39 class DeploySettings(dict):
40     """
41     This class parses a APEX deploy settings yaml file into an object
42
43     Currently the parsed object is dumped into a bash global definition file
44     for deploy.sh consumption. This object will later be used directly as
45     deployment script move to python.
46     """
47     def __init__(self, filename):
48         init_dict = {}
49         if isinstance(filename, str):
50             with open(filename, 'r') as deploy_settings_file:
51                 init_dict = yaml.safe_load(deploy_settings_file)
52         else:
53             # assume input is a dict to build from
54             init_dict = filename
55
56         super().__init__(init_dict)
57         self._validate_settings()
58
59     def _validate_settings(self):
60         """
61         Validates the deploy settings file provided
62
63         DeploySettingsException will be raised if validation fails.
64         """
65
66         if 'deploy_options' not in self:
67             raise DeploySettingsException("No deploy options provided in"
68                                           " deploy settings file")
69         if 'global_params' not in self:
70             raise DeploySettingsException("No global options provided in"
71                                           " deploy settings file")
72
73         deploy_options = self['deploy_options']
74         if not isinstance(deploy_options, dict):
75             raise DeploySettingsException("deploy_options should be a list")
76
77         if ('gluon' in self['deploy_options'] and
78            'vpn' in self['deploy_options']):
79                 if (self['deploy_options']['gluon'] is True and
80                    self['deploy_options']['vpn'] is False):
81                         raise DeploySettingsException(
82                             "Invalid deployment configuration: "
83                             "If gluon is enabled, "
84                             "vpn also needs to be enabled")
85
86         for setting, value in deploy_options.items():
87             if setting not in REQ_DEPLOY_SETTINGS + OPT_DEPLOY_SETTINGS:
88                 raise DeploySettingsException("Invalid deploy_option {} "
89                                               "specified".format(setting))
90             if setting == 'dataplane':
91                 if value not in VALID_DATAPLANES:
92                     planes = ' '.join(VALID_DATAPLANES)
93                     raise DeploySettingsException(
94                         "Invalid dataplane {} specified. Valid dataplanes:"
95                         " {}".format(value, planes))
96
97         for req_set in REQ_DEPLOY_SETTINGS:
98             if req_set not in deploy_options:
99                 if req_set == 'dataplane':
100                     self['deploy_options'][req_set] = 'ovs'
101                 elif req_set == 'ceph':
102                     self['deploy_options'][req_set] = True
103                 else:
104                     self['deploy_options'][req_set] = False
105
106         if 'performance' in deploy_options:
107             if not isinstance(deploy_options['performance'], dict):
108                 raise DeploySettingsException("Performance deploy_option"
109                                               "must be a dictionary.")
110             for role, role_perf_sets in deploy_options['performance'].items():
111                 if role not in VALID_ROLES:
112                     raise DeploySettingsException("Performance role {}"
113                                                   "is not valid, choose"
114                                                   "from {}".format(
115                                                       role,
116                                                       " ".join(VALID_ROLES)
117                                                   ))
118
119                 for key in role_perf_sets:
120                     if key not in VALID_PERF_OPTS:
121                         raise DeploySettingsException("Performance option {} "
122                                                       "is not valid, choose"
123                                                       "from {}".format(
124                                                           key,
125                                                           " ".join(
126                                                               VALID_PERF_OPTS)
127                                                       ))
128
129     def _dump_performance(self):
130         """
131         Creates performance settings string for bash consumption.
132
133         Output will be in the form of a list that can be iterated over in
134         bash, with each string being the direct input to the performance
135         setting script in the form <role> <category> <key> <value> to
136         facilitate modification of the correct image.
137         """
138         bash_str = 'performance_options=(\n'
139         deploy_options = self['deploy_options']
140         for role, settings in deploy_options['performance'].items():
141             for category, options in settings.items():
142                 for key, value in options.items():
143                     bash_str += "\"{} {} {} {}\"\n".format(role,
144                                                            category,
145                                                            key,
146                                                            value)
147         bash_str += ')\n'
148         bash_str += '\n'
149         bash_str += 'performance_roles=(\n'
150         for role in self['deploy_options']['performance']:
151             bash_str += role + '\n'
152         bash_str += ')\n'
153         bash_str += '\n'
154
155         return bash_str
156
157     def _dump_deploy_options_array(self):
158         """
159         Creates deploy settings array in bash syntax.
160         """
161         bash_str = ''
162         for key, value in self['deploy_options'].items():
163             if not isinstance(value, bool):
164                 bash_str += "deploy_options_array[{}]=\"{}\"\n".format(key,
165                                                                        value)
166             else:
167                 bash_str += "deploy_options_array[{}]={}\n".format(key,
168                                                                    value)
169         return bash_str
170
171     def dump_bash(self, path=None):
172         """
173         Prints settings for bash consumption.
174
175         If optional path is provided, bash string will be written to the file
176         instead of stdout.
177         """
178         bash_str = ''
179         for key, value in self['global_params'].items():
180             bash_str += "{}={}\n".format(key, value)
181         if 'performance' in self['deploy_options']:
182             bash_str += self._dump_performance()
183         bash_str += self._dump_deploy_options_array()
184         utils.write_str(bash_str, path)
185
186
187 class DeploySettingsException(Exception):
188     def __init__(self, value):
189         self.value = value
190
191     def __str__(self):
192         return self.value