blob: cf718c85614affbd8acbf38b13a9cfb42d9c56d2 [file] [log] [blame]
Dennis Dmitriev86750962017-07-11 19:44:05 +03001# Copyright 2013 - 2017 Mirantis, Inc.
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +03002#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15from __future__ import print_function
16
17import argparse
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030018import sys
19import yaml
20
21from reclass_tools import walk_models
22
23
Dennis Dmitriev86750962017-07-11 19:44:05 +030024class Shell(object):
25 def __init__(self, args):
26 self.args = args
27 self.params = self.get_params()
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030028
Dennis Dmitriev86750962017-07-11 19:44:05 +030029 def execute(self):
30 command_name = 'do_{}'.format(self.params.command.replace('-', '_'))
31 command_method = getattr(self, command_name)
32 command_method()
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030033
Dennis Dmitriev86750962017-07-11 19:44:05 +030034 def do_get_key(self):
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030035 walk_models.remove_reclass_parameter(
Dennis Dmitriev86750962017-07-11 19:44:05 +030036 self.params.path,
37 self.params.key_name,
38 verbose=self.params.verbose,
39 pretend=True)
40
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030041 def do_add_key(self):
Sergeyb50d1f02017-12-25 18:07:15 +040042 # Try convert to digits
43 try:
44 add_val = int(self.params.add_value)
45 except ValueError:
46 try:
47 add_val = float(self.params.add_value)
48 except ValueError:
49 add_val = self.params.add_value
50
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030051 walk_models.add_reclass_parameter(
52 self.params.path,
53 self.params.key_name,
Sergeyb50d1f02017-12-25 18:07:15 +040054 add_val,
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030055 verbose=self.params.verbose,
56 merge=self.params.merge)
57
Dennis Dmitriev86750962017-07-11 19:44:05 +030058 def do_del_key(self):
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030059 walk_models.remove_reclass_parameter(
Dennis Dmitriev86750962017-07-11 19:44:05 +030060 self.params.path,
61 self.params.key_name,
62 verbose=self.params.verbose,
63 pretend=False)
64
65 def do_list_params(self):
66 results = walk_models.get_all_reclass_params(
67 self.params.path,
68 verbose=self.params.verbose)
Dennis Dmitrieva7de8b52018-08-08 23:14:03 +030069 print(yaml.dump(results, width=255))
Dennis Dmitriev86750962017-07-11 19:44:05 +030070
71 def do_list_domains(self):
72 try:
73 from reclass_tools import reclass_models
74 except ImportError:
75 sys.exit("Please run this tool on the salt-master node "
76 "with installed 'reclass'")
77 inventory = reclass_models.inventory_list()
78 reclass_storage = reclass_models.reclass_storage(inventory=inventory)
79 print('\n'.join(sorted(reclass_storage.keys())))
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030080
Dennis Dmitriev86750962017-07-11 19:44:05 +030081 def do_list_nodes(self):
82 try:
83 from reclass_tools import reclass_models
84 except ImportError:
85 sys.exit("Please run this tool on the salt-master node "
86 "with installed 'reclass'")
87
88 inventory = reclass_models.inventory_list(domain=self.params.domain)
89 vcp_nodes = reclass_models.vcp_list(domain=self.params.domain,
90 inventory=inventory)
91 vcp_node_names = ['{0}.{1}'.format(name, domain)
92 for name, domain in vcp_nodes]
93
94 if self.params.vcp_only:
95 print('\n'.join(sorted(vcp_node_names)))
96 elif self.params.non_vcp_only:
97 print('\n'.join(sorted((node_name for node_name in inventory.keys()
98 if node_name not in vcp_node_names))))
99 else:
100 print('\n'.join(sorted(inventory.keys())))
101
Dennis Dmitriev806706d2017-07-29 22:31:23 +0300102 def do_trace_key(self):
103 try:
104 from reclass_tools import reclass_models
105 except ImportError:
106 sys.exit("Please run this tool on the salt-master node "
107 "with installed 'reclass'")
108 reclass_models.trace_key(key=self.params.key_name,
109 domain=self.params.domain,
110 node=self.params.node)
111
Dennis Dmitriev86750962017-07-11 19:44:05 +0300112 def do_show_context(self):
113 try:
114 from reclass_tools import create_inventory
115 except ImportError:
116 sys.exit("Please run this tool on the salt-master node "
117 "with installed 'reclass'")
118
119 current_underlay_context = create_inventory.create_inventory_context(
120 domain=self.params.domain, keys=self.params.keys)
121
Dennis Dmitrieva7de8b52018-08-08 23:14:03 +0300122 print(yaml.dump(current_underlay_context, default_flow_style=False,
123 width=255))
Dennis Dmitriev86750962017-07-11 19:44:05 +0300124
125 def do_render(self):
Dennis Dmitrievf260d152017-08-15 00:59:24 +0300126 from reclass_tools import render
Dennis Dmitriev86750962017-07-11 19:44:05 +0300127
128 if not self.params.template_dir or not self.params.output_dir \
129 or not self.params.contexts:
130 sys.exit("Missing parameters, see: reclass-tools render -h")
131
Dennis Dmitrievf260d152017-08-15 00:59:24 +0300132 render.render_dir(template_dir=self.params.template_dir,
133 output_dir=self.params.output_dir,
134 contexts=self.params.contexts,
135 env_name=self.params.env_name)
Dennis Dmitriev86750962017-07-11 19:44:05 +0300136
137 def get_params(self):
138
139 verbose_parser = argparse.ArgumentParser(add_help=False)
140 verbose_parser.add_argument('--verbose', dest='verbose',
141 action='store_const', const=True,
142 help='Show verbosed output', default=False)
143
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300144 merge_parser = argparse.ArgumentParser(add_help=False)
Dennis Dmitriev6792f7e2017-07-18 19:11:22 +0300145 merge_parser.add_argument('--merge', dest='merge',
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300146 action='store_const', const=True,
Dennis Dmitriev6792f7e2017-07-18 19:11:22 +0300147 help='Merge value to list or dict',
148 default=False)
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300149
Dennis Dmitriev86750962017-07-11 19:44:05 +0300150 key_parser = argparse.ArgumentParser(add_help=False)
151 key_parser_help = (
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300152 'Key name to find in reclass model files, for example:'
153 ' parameters.linux.network.interface')
Dennis Dmitriev86750962017-07-11 19:44:05 +0300154 key_parser.add_argument('key_name', help=key_parser_help, default=None)
155
156 keys_parser = argparse.ArgumentParser(add_help=False)
157 keys_parser.add_argument(
158 'keys',
159 help='Key names to find in reclass model files', nargs='*')
160
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300161 add_value_parser = argparse.ArgumentParser(add_help=False)
162 add_value_parser.add_argument(
163 'add_value',
164 help=('Value to add to the reclass model files, can be in the '
165 'inline YAML format'))
166
Dennis Dmitriev86750962017-07-11 19:44:05 +0300167 path_parser = argparse.ArgumentParser(add_help=False)
168 path_parser.add_argument(
169 'path',
170 help='Path to search for *.yml files.', nargs='+')
171
172 domain_parser = argparse.ArgumentParser(add_help=False)
173 domain_parser.add_argument(
174 '--domain', '-d', dest='domain',
175 help=('Show only the nodes which names are ended with the '
176 'specified domain, for example: example.local'))
177
Dennis Dmitriev806706d2017-07-29 22:31:23 +0300178 node_parser = argparse.ArgumentParser(add_help=False)
179 node_parser.add_argument(
180 '--node', '-n', dest='node',
181 help=('Show only the specified node, for example: '
182 'ctl01.example.local'))
183
Dennis Dmitriev0cea5702017-07-17 19:03:23 +0300184 env_name_parser = argparse.ArgumentParser(add_help=False)
185 env_name_parser.add_argument(
186 '--env-name', '-e', dest='env_name',
Dennis Dmitriev55989022017-07-17 19:23:16 +0300187 help=("Name of the 'environment' to create or use"),
188 default=None)
Dennis Dmitriev0cea5702017-07-17 19:03:23 +0300189
Dennis Dmitriev86750962017-07-11 19:44:05 +0300190 vcp_only_parser = argparse.ArgumentParser(add_help=False)
191 vcp_only_parser.add_argument(
192 '--vcp-only', dest='vcp_only',
193 action='store_const', const=True,
194 help=('Show only VCP nodes (present in '
195 'parameters.salt.control.cluster.internal.node)'),
196 default=False)
197
198 non_vcp_only_parser = argparse.ArgumentParser(add_help=False)
199 non_vcp_only_parser.add_argument(
200 '--non-vcp-only', dest='non_vcp_only',
201 action='store_const', const=True, default=False,
202 help=('Show only non-VCP nodes (absent in '
203 'parameters.salt.control.cluster.internal.node)'))
204
205 render_parser = argparse.ArgumentParser(add_help=False)
206 render_parser.add_argument(
207 '--template-dir', '-t', dest='template_dir',
208 help=('Coockiecutter-based template directory'))
209 render_parser.add_argument(
210 '--output-dir', '-o', dest='output_dir',
211 help=('Path to the directory where the rendered '
212 'template will be placed'))
213 render_parser.add_argument(
Dennis Dmitrievc2534372017-10-09 15:36:21 +0300214 '--context', '-c', dest='contexts', action='append',
Dennis Dmitriev86750962017-07-11 19:44:05 +0300215 help=('YAML/JSON files with context data to render '
216 'the template'))
217
Dennis Dmitriev86750962017-07-11 19:44:05 +0300218 parser = argparse.ArgumentParser(
219 description="Manage virtual environments. "
220 "For additional help, use with -h/--help option")
221 subparsers = parser.add_subparsers(title="Operation commands",
222 help='available commands',
223 dest='command')
224
Dennis Dmitriev86750962017-07-11 19:44:05 +0300225 subparsers.add_parser('get-key',
226 parents=[key_parser, path_parser,
227 verbose_parser],
228 help="Find a key in YAMLs found in <path>",
229 description=("Get a key collected from "
230 "different YAMLs"))
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300231 subparsers.add_parser('add-key',
232 parents=[key_parser, add_value_parser,
233 path_parser, verbose_parser,
234 merge_parser],
235 help="Find a key in YAMLs found in <path>",
236 description=("Get a key collected from "
237 "different YAMLs"))
Dennis Dmitriev86750962017-07-11 19:44:05 +0300238 subparsers.add_parser('del-key',
239 parents=[key_parser, path_parser,
240 verbose_parser],
241 help="Delete a key from YAMLs found in <path>",
242 description="Delete a key from different YAMLs")
243 subparsers.add_parser('list-params',
244 parents=[path_parser, verbose_parser],
245 help=("Collect all options for "
246 "'parameters._params' keys from YAMLs "
247 "found in <path>"))
248 subparsers.add_parser('list-nodes',
249 parents=[domain_parser, vcp_only_parser,
250 non_vcp_only_parser],
251 help=("List nodes that are available for "
252 "reclass. Use on salt-master node only!"))
253 subparsers.add_parser('list-domains',
254 help=("List domains that are available from "
255 "reclass models. Use on salt-master "
256 "node only!"))
257 subparsers.add_parser('show-context',
258 parents=[domain_parser, keys_parser],
259 help=("Show domain nodes with rendered content "
260 "for specified keys. Use on salt-master "
261 "node for already generated inventory "
262 "only!"))
Dennis Dmitriev806706d2017-07-29 22:31:23 +0300263 subparsers.add_parser('trace-key',
264 parents=[domain_parser, node_parser, key_parser],
265 help=("Use 'reclass' to merge the model and "
266 "show all the classes where the "
267 "specified key is overwritten, and updated"
268 " values during merging and after "
269 "interpolation. "
270 "Use on salt-master node only!"))
Dennis Dmitriev86750962017-07-11 19:44:05 +0300271 subparsers.add_parser('render',
Dennis Dmitriev0cea5702017-07-17 19:03:23 +0300272 parents=[render_parser, env_name_parser],
Dennis Dmitriev86750962017-07-11 19:44:05 +0300273 help=("Render cookiecutter template using "
274 "multiple metadata sources"))
275
276 if len(self.args) == 0:
277 self.args = ['-h']
278 return parser.parse_args(self.args)
279
280
281def main(args=None):
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300282 if args is None:
283 args = sys.argv[1:]
284
Dennis Dmitriev86750962017-07-11 19:44:05 +0300285 shell = Shell(args)
286 shell.execute()