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