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