blob: 86731926f14c89bd404d98a9f712c08a1418ae6c [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):
42 walk_models.add_reclass_parameter(
43 self.params.path,
44 self.params.key_name,
45 self.params.add_value,
46 verbose=self.params.verbose,
47 merge=self.params.merge)
48
Dennis Dmitriev86750962017-07-11 19:44:05 +030049 def do_del_key(self):
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030050 walk_models.remove_reclass_parameter(
Dennis Dmitriev86750962017-07-11 19:44:05 +030051 self.params.path,
52 self.params.key_name,
53 verbose=self.params.verbose,
54 pretend=False)
55
56 def do_list_params(self):
57 results = walk_models.get_all_reclass_params(
58 self.params.path,
59 verbose=self.params.verbose)
60 print(yaml.dump(results))
61
62 def do_list_domains(self):
63 try:
64 from reclass_tools import reclass_models
65 except ImportError:
66 sys.exit("Please run this tool on the salt-master node "
67 "with installed 'reclass'")
68 inventory = reclass_models.inventory_list()
69 reclass_storage = reclass_models.reclass_storage(inventory=inventory)
70 print('\n'.join(sorted(reclass_storage.keys())))
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030071
Dennis Dmitriev86750962017-07-11 19:44:05 +030072 def do_list_nodes(self):
73 try:
74 from reclass_tools import reclass_models
75 except ImportError:
76 sys.exit("Please run this tool on the salt-master node "
77 "with installed 'reclass'")
78
79 inventory = reclass_models.inventory_list(domain=self.params.domain)
80 vcp_nodes = reclass_models.vcp_list(domain=self.params.domain,
81 inventory=inventory)
82 vcp_node_names = ['{0}.{1}'.format(name, domain)
83 for name, domain in vcp_nodes]
84
85 if self.params.vcp_only:
86 print('\n'.join(sorted(vcp_node_names)))
87 elif self.params.non_vcp_only:
88 print('\n'.join(sorted((node_name for node_name in inventory.keys()
89 if node_name not in vcp_node_names))))
90 else:
91 print('\n'.join(sorted(inventory.keys())))
92
93 def do_show_context(self):
94 try:
95 from reclass_tools import create_inventory
96 except ImportError:
97 sys.exit("Please run this tool on the salt-master node "
98 "with installed 'reclass'")
99
100 current_underlay_context = create_inventory.create_inventory_context(
101 domain=self.params.domain, keys=self.params.keys)
102
103 print(yaml.dump(current_underlay_context, default_flow_style=False))
104
105 def do_render(self):
106 try:
107 from reclass_tools import create_inventory
108 except ImportError:
109 sys.exit("Please run this tool on the salt-master node "
110 "with installed 'reclass'")
111
112 if not self.params.template_dir or not self.params.output_dir \
113 or not self.params.contexts:
114 sys.exit("Missing parameters, see: reclass-tools render -h")
115
116 create_inventory.render_dir(template_dir=self.params.template_dir,
117 output_dir=self.params.output_dir,
Dennis Dmitriev0cea5702017-07-17 19:03:23 +0300118 contexts=self.params.contexts,
119 env_name=self.params.env_name)
Dennis Dmitriev86750962017-07-11 19:44:05 +0300120
121 def get_params(self):
122
123 verbose_parser = argparse.ArgumentParser(add_help=False)
124 verbose_parser.add_argument('--verbose', dest='verbose',
125 action='store_const', const=True,
126 help='Show verbosed output', default=False)
127
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300128 merge_parser = argparse.ArgumentParser(add_help=False)
Dennis Dmitriev6792f7e2017-07-18 19:11:22 +0300129 merge_parser.add_argument('--merge', dest='merge',
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300130 action='store_const', const=True,
Dennis Dmitriev6792f7e2017-07-18 19:11:22 +0300131 help='Merge value to list or dict',
132 default=False)
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300133
Dennis Dmitriev86750962017-07-11 19:44:05 +0300134 key_parser = argparse.ArgumentParser(add_help=False)
135 key_parser_help = (
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300136 'Key name to find in reclass model files, for example:'
137 ' parameters.linux.network.interface')
Dennis Dmitriev86750962017-07-11 19:44:05 +0300138 key_parser.add_argument('key_name', help=key_parser_help, default=None)
139
140 keys_parser = argparse.ArgumentParser(add_help=False)
141 keys_parser.add_argument(
142 'keys',
143 help='Key names to find in reclass model files', nargs='*')
144
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300145 add_value_parser = argparse.ArgumentParser(add_help=False)
146 add_value_parser.add_argument(
147 'add_value',
148 help=('Value to add to the reclass model files, can be in the '
149 'inline YAML format'))
150
Dennis Dmitriev86750962017-07-11 19:44:05 +0300151 path_parser = argparse.ArgumentParser(add_help=False)
152 path_parser.add_argument(
153 'path',
154 help='Path to search for *.yml files.', nargs='+')
155
156 domain_parser = argparse.ArgumentParser(add_help=False)
157 domain_parser.add_argument(
158 '--domain', '-d', dest='domain',
159 help=('Show only the nodes which names are ended with the '
160 'specified domain, for example: example.local'))
161
Dennis Dmitriev0cea5702017-07-17 19:03:23 +0300162 env_name_parser = argparse.ArgumentParser(add_help=False)
163 env_name_parser.add_argument(
164 '--env-name', '-e', dest='env_name',
Dennis Dmitriev55989022017-07-17 19:23:16 +0300165 help=("Name of the 'environment' to create or use"),
166 default=None)
Dennis Dmitriev0cea5702017-07-17 19:03:23 +0300167
Dennis Dmitriev86750962017-07-11 19:44:05 +0300168 vcp_only_parser = argparse.ArgumentParser(add_help=False)
169 vcp_only_parser.add_argument(
170 '--vcp-only', dest='vcp_only',
171 action='store_const', const=True,
172 help=('Show only VCP nodes (present in '
173 'parameters.salt.control.cluster.internal.node)'),
174 default=False)
175
176 non_vcp_only_parser = argparse.ArgumentParser(add_help=False)
177 non_vcp_only_parser.add_argument(
178 '--non-vcp-only', dest='non_vcp_only',
179 action='store_const', const=True, default=False,
180 help=('Show only non-VCP nodes (absent in '
181 'parameters.salt.control.cluster.internal.node)'))
182
183 render_parser = argparse.ArgumentParser(add_help=False)
184 render_parser.add_argument(
185 '--template-dir', '-t', dest='template_dir',
186 help=('Coockiecutter-based template directory'))
187 render_parser.add_argument(
188 '--output-dir', '-o', dest='output_dir',
189 help=('Path to the directory where the rendered '
190 'template will be placed'))
191 render_parser.add_argument(
192 '--context', '-c', dest='contexts', nargs='+',
193 help=('YAML/JSON files with context data to render '
194 'the template'))
195
Dennis Dmitriev86750962017-07-11 19:44:05 +0300196 parser = argparse.ArgumentParser(
197 description="Manage virtual environments. "
198 "For additional help, use with -h/--help option")
199 subparsers = parser.add_subparsers(title="Operation commands",
200 help='available commands',
201 dest='command')
202
Dennis Dmitriev86750962017-07-11 19:44:05 +0300203 subparsers.add_parser('get-key',
204 parents=[key_parser, path_parser,
205 verbose_parser],
206 help="Find a key in YAMLs found in <path>",
207 description=("Get a key collected from "
208 "different YAMLs"))
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300209 subparsers.add_parser('add-key',
210 parents=[key_parser, add_value_parser,
211 path_parser, verbose_parser,
212 merge_parser],
213 help="Find a key in YAMLs found in <path>",
214 description=("Get a key collected from "
215 "different YAMLs"))
Dennis Dmitriev86750962017-07-11 19:44:05 +0300216 subparsers.add_parser('del-key',
217 parents=[key_parser, path_parser,
218 verbose_parser],
219 help="Delete a key from YAMLs found in <path>",
220 description="Delete a key from different YAMLs")
221 subparsers.add_parser('list-params',
222 parents=[path_parser, verbose_parser],
223 help=("Collect all options for "
224 "'parameters._params' keys from YAMLs "
225 "found in <path>"))
226 subparsers.add_parser('list-nodes',
227 parents=[domain_parser, vcp_only_parser,
228 non_vcp_only_parser],
229 help=("List nodes that are available for "
230 "reclass. Use on salt-master node only!"))
231 subparsers.add_parser('list-domains',
232 help=("List domains that are available from "
233 "reclass models. Use on salt-master "
234 "node only!"))
235 subparsers.add_parser('show-context',
236 parents=[domain_parser, keys_parser],
237 help=("Show domain nodes with rendered content "
238 "for specified keys. Use on salt-master "
239 "node for already generated inventory "
240 "only!"))
241 subparsers.add_parser('render',
Dennis Dmitriev0cea5702017-07-17 19:03:23 +0300242 parents=[render_parser, env_name_parser],
Dennis Dmitriev86750962017-07-11 19:44:05 +0300243 help=("Render cookiecutter template using "
244 "multiple metadata sources"))
245
246 if len(self.args) == 0:
247 self.args = ['-h']
248 return parser.parse_args(self.args)
249
250
251def main(args=None):
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300252 if args is None:
253 args = sys.argv[1:]
254
Dennis Dmitriev86750962017-07-11 19:44:05 +0300255 shell = Shell(args)
256 shell.execute()