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