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