blob: 0a66033f738e0b4839d35e7499800810cb5417c5 [file] [log] [blame]
Dennis Dmitriev566db4b2017-07-18 18:13:07 +03001# Copyright 2013 - 2017 Mirantis, Inc.
2#
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.
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030014
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030015# import copy
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030016import os
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030017
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030018import yaml
19
Dennis Dmitrievde847d92017-06-26 18:58:05 +030020from reclass_tools import helpers
21
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030022
Dennis Dmitriev6bd44252017-06-22 17:33:40 +030023def walkfiles(topdir, verbose=False):
24 walker = os.walk(topdir)
25 opener = open
26 prefix = ''
27 isdir = os.path.isdir(topdir)
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030028
29 if isdir:
30 for dirName, subdirList, fileList in walker:
31 for filename in fileList:
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030032 filepath = os.path.join(dirName, filename)
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030033 if verbose:
34 print (prefix + filepath)
35 with OpenFile(filepath, opener) as log:
36 yield (log)
37 else:
38 if verbose:
39 print (topdir)
40 with OpenFile(topdir, opener) as log:
41 yield (log)
42
43
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030044# def yaml_read(yaml_file):
45# if os.path.isfile(yaml_file):
46# with open(yaml_file, 'r') as f:
47# return yaml.load(f)
48# else:
49# print("\'{}\' is not a file!".format(yaml_file))
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030050
51
52class OpenFile(object):
53
54 fname = None
55 opener = None
56 readlines = None
57 fobj = None
58
59 def __init__(self, fname, opener):
60 self.fname = fname
61 self.opener = opener
62
63 def get_parser(self):
64 parsers = {'/lastlog': self.fake_parser,
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030065 '/wtmp': self.fake_parser,
66 '/btmp': self.fake_parser,
67 '/atop.log': self.fake_parser,
68 '/atop_': self.fake_parser,
69 '/atop_current': self.fake_parser,
70 '/supervisord.log': self.docker_parser,
71 '.gz': self.gz_parser,
72 '.bz2': self.gz_parser,
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030073 }
74 for w in parsers.keys():
75 if w in self.fname:
76 self.readlines = parsers[w]
77 return
78 try:
79 self.fobj = self.opener(self.fname, 'r')
80 self.readlines = self.plaintext_parser
81 except IOError as e:
82 print("Error opening file {0}: {1}".format(self.fname, e))
83 if self.fobj:
84 self.fobj.close()
Dennis Dmitriev566db4b2017-07-18 18:13:07 +030085 self.fobj = None
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +030086 self.readlines = self.fake_parser
87
88 def plaintext_parser(self):
89 try:
90 for s in self.fobj.readlines():
91 yield s
92 except IOError as e:
93 print("Error reading file {0}: {1}".format(self.fname, e))
94
95 def fake_parser(self):
96 yield ''
97
98 def docker_parser(self):
99 yield ''
100
101 def gz_parser(self):
102 yield ''
103
104 def bz2_parser(self):
105 yield ''
106
107 def __enter__(self):
108 self.get_parser()
109 return self
110
111 def __exit__(self, x, y, z):
112 if self.fobj:
113 self.fobj.close()
114
115
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300116def get_all_reclass_params(paths, verbose=False):
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300117 """Return dict with all used values for each param"""
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300118 _params = dict()
119 for path in paths:
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300120 for log in walkfiles(path, verbose):
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300121 if log.fname.endswith('.yml'):
Dennis Dmitriev65a80ee2017-06-30 17:30:37 +0300122 model = helpers.yaml_read(log.fname)
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300123 if model is not None:
124 # Collect all params from the models
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300125 _param = helpers.get_nested_key(
126 model,
127 ['parameters', '_param'])
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300128 if _param:
129 for key, val in _param.items():
130 if key in _params:
Dennis Dmitrievefaa1352017-06-19 12:56:11 +0300131 # Keep list values sorted
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300132 _params[key].append(val)
Dennis Dmitrievefaa1352017-06-19 12:56:11 +0300133 _params[key] = sorted(_params[key])
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300134 else:
135 _params[key] = [val]
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300136 return _params
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300137
138
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300139def add_reclass_parameter(paths, key, value, verbose=False, merge=False):
140 """Add a value to the specified key to all the files in the paths
141
142 if merge=False (default):
143 - new value replaces previous key content completely.
144
145 if merge=True:
146 - if the specified key type is list, then value will be appended
147 to the list. Value examples:
148 '1000'
149 'new_lab_name'
150 'cluster.virtual_cluster_name.infra'
151 'http://archive.ubuntu.com'
152 '[a, b, c]' # a list in the list
153 '{a:1, b:2, c:3}' # a dict in the list
154 - if the specified key type is an existing dict, then the dict
155 will be extended with the dict in the value. Value example:
156 '{address: 192.168.1.1, netmask: 255.255.255.0}'
157
158 - If the specified key type is string/int/bool - it will replace previous
159 value
160 """
161 add_key = key.split('.')
162
163 for path in paths:
164 for fyml in walkfiles(path, verbose=verbose):
165 if fyml.fname.endswith('.yml'):
166 model = helpers.yaml_read(fyml.fname)
167 if model is not None:
168
169 nested_key = helpers.get_nested_key(model, add_key)
170 if nested_key:
171 if merge is False:
172 nested_key = value
173 else:
174 if type(nested_key) is list:
175 nested_key.append(value)
176 elif type(nested_key) is dict:
177 nested_key.update(value)
178 else:
179 helpers.create_nested_key(model, path=add_key,
180 value=value)
181 else:
182 helpers.create_nested_key(model, path=add_key,
183 value=value)
184
185 with open(fyml.fname, 'w') as f:
186 f.write(
187 yaml.dump(
188 model, default_flow_style=False
189 )
190 )
191
192
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300193def remove_reclass_parameter(paths, key,
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300194 verbose=False,
195 pretend=False):
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300196 """Removes specified key from parameters from all reclass models
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300197
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300198 :param key: string with point-separated nested objects, for
199 example: parameters.linux.network.interface
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300200 :rtype dict: { 'file path': {nested_key}, ...}
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300201 """
202 remove_key = key.split('.')
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300203 # found_keys = {}
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300204
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300205 for path in paths:
206 for fyml in walkfiles(path, verbose=verbose):
207 if fyml.fname.endswith('.yml'):
Dennis Dmitriev65a80ee2017-06-30 17:30:37 +0300208 model = helpers.yaml_read(fyml.fname)
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300209 if model is not None:
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300210
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300211 # Clear linux.network.interfaces
Dennis Dmitrievde847d92017-06-26 18:58:05 +0300212 nested_key = helpers.get_nested_key(model, remove_key)
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300213 if nested_key:
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300214 # found_keys[fyml.fname] = copy.deepcopy(nested_key)
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300215 if pretend:
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300216 print("\n---\n# Found {0} in {1}"
217 .format('.'.join(remove_key), fyml.fname))
218 print(yaml.dump(nested_key,
219 default_flow_style=False))
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300220 else:
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300221 print("\n---\n# Removing {0} from {1}"
222 .format('.'.join(remove_key), fyml.fname))
223 print(yaml.dump(nested_key,
224 default_flow_style=False))
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300225
Dennis Dmitrievde847d92017-06-26 18:58:05 +0300226 helpers.remove_nested_key(model, remove_key)
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300227
Dennis Dmitriev6bd44252017-06-22 17:33:40 +0300228 with open(fyml.fname, 'w') as f:
229 f.write(
230 yaml.dump(
231 model, default_flow_style=False
232 )
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300233 )
Dennis Dmitriev566db4b2017-07-18 18:13:07 +0300234 # return found_keys