blob: 024b3cf065dae2313bbffeb0f77391502951da52 [file] [log] [blame]
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +03001#!/usr/bin/python
2# -*- coding: utf-8 -*-
3
4import hashlib
5import os
6import re
7import tarfile
8
9import urllib2
10import yaml
11
12from reclass_tools.helpers import ssh_client
13
14
15def walkfiles(topdir, identity_files=None, verbose=False):
16 if ":" in topdir:
17 host, path = topdir.split(":")
18 private_keys = ssh_client.get_private_keys(os.environ.get("HOME"), identity_files)
19 if "@" in host:
20 username, host = host.split("@")
21 else:
22 username = os.environ.get("USER")
23 remote = ssh_client.SSHClient(
24 host, username=username, private_keys=private_keys)
25
26 walker = remote.walk(path)
27 opener = remote.open
28 prefix = remote.host + ":"
29 isdir = remote.isdir(path, follow_symlink=True)
30 else:
31 walker = os.walk(topdir)
32 opener = open
33 prefix = ''
34 isdir = os.path.isdir(topdir)
35
36 if isdir:
37 for dirName, subdirList, fileList in walker:
38 for filename in fileList:
39 filepath = os.path.join(dirName,filename)
40 if verbose:
41 print (prefix + filepath)
42 with OpenFile(filepath, opener) as log:
43 yield (log)
44 else:
45 if verbose:
46 print (topdir)
47 with OpenFile(topdir, opener) as log:
48 yield (log)
49
50
51def yaml_read(yaml_file):
52 if os.path.isfile(yaml_file):
53 with open(yaml_file, 'r') as f:
54 return yaml.load(f)
55 else:
56 print("\'{}\' is not a file!".format(yaml_file))
57
58
59class OpenFile(object):
60
61 fname = None
62 opener = None
63 readlines = None
64 fobj = None
65
66 def __init__(self, fname, opener):
67 self.fname = fname
68 self.opener = opener
69
70 def get_parser(self):
71 parsers = {'/lastlog': self.fake_parser,
72 '/wtmp': self.fake_parser,
73 '/btmp': self.fake_parser,
74 '/atop.log': self.fake_parser,
75 '/atop_': self.fake_parser,
76 '/atop_current': self.fake_parser,
77 '/supervisord.log': self.docker_parser,
78 '.gz': self.gz_parser,
79 '.bz2': self.gz_parser,
80 }
81 for w in parsers.keys():
82 if w in self.fname:
83 self.readlines = parsers[w]
84 return
85 try:
86 self.fobj = self.opener(self.fname, 'r')
87 self.readlines = self.plaintext_parser
88 except IOError as e:
89 print("Error opening file {0}: {1}".format(self.fname, e))
90 if self.fobj:
91 self.fobj.close()
92 self.fobj = None
93 self.readlines = self.fake_parser
94
95 def plaintext_parser(self):
96 try:
97 for s in self.fobj.readlines():
98 yield s
99 except IOError as e:
100 print("Error reading file {0}: {1}".format(self.fname, e))
101
102 def fake_parser(self):
103 yield ''
104
105 def docker_parser(self):
106 yield ''
107
108 def gz_parser(self):
109 yield ''
110
111 def bz2_parser(self):
112 yield ''
113
114 def __enter__(self):
115 self.get_parser()
116 return self
117
118 def __exit__(self, x, y, z):
119 if self.fobj:
120 self.fobj.close()
121
122
123def get_nested_key(data, path=None):
124 if type(path) is not list:
125 raise("Use 'list' object with key names for 'path'")
126 for key in path:
127 value = data.get(key, None)
128 if value:
129 data = value
130 else:
131 return None
132 return data
133
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300134
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300135def remove_nested_key(data, path=None):
136 if type(path) is not list:
137 raise("Use 'list' object with key names for 'path'")
138
139 # Remove the value from the specified key
140 val = get_nested_key(data, path[:-1])
141 val[path[-1]] = None
142
143 # Clear parent keys if empty
144 while path:
145 val = get_nested_key(data, path)
146 if val:
147 # Non-empty value, nothing to do
148 return
149 else:
150 get_nested_key(data, path[:-1]).pop(path[-1])
151 path = path[:-1]
152
153
Dennis Dmitriev7d91b582017-06-16 02:01:39 +0300154def get_all_reclass_params(paths, identity_files=None, verbose=False):
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300155 """Return dict with all used values for each param"""
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300156 _params = dict()
157 for path in paths:
Dennis Dmitriev7d91b582017-06-16 02:01:39 +0300158 for log in walkfiles(path, identity_files, verbose):
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300159 if log.fname.endswith('.yml'):
160 model = yaml_read(log.fname)
161 if model is not None:
162 # Collect all params from the models
163 _param = get_nested_key(model, ['parameters', '_param'])
164 if _param:
165 for key, val in _param.items():
166 if key in _params:
167 _params[key].append(val)
168 else:
169 _params[key] = [val]
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300170 return _params
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300171
172
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300173def remove_reclass_parameter(paths, key,
174 identity_files=None, verbose=False):
175 """Removes specified key from parameters from all reclass models
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300176
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300177 :param key: string with point-separated nested objects, for
178 example: parameters.linux.network.interface
179 """
180 remove_key = key.split('.')
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300181
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300182 for path in paths:
183 for fyml in walkfiles(path, verbose=verbose):
184 if fyml.fname.endswith('.yml'):
185 model = yaml_read(fyml.fname)
186 if model is not None:
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300187
Dennis Dmitriev672bd442017-06-16 18:13:54 +0300188 # Clear linux.network.interfaces
189 interfaces = get_nested_key(model, remove_key)
190 if interfaces:
191 print(fyml.fname)
192 print(interfaces.keys())
193
194 remove_nested_key(model, remove_key)
195
196 print(model)
197 with open(fyml.fname, 'w') as f:
198 f.write(
199 yaml.dump(
200 model, default_flow_style=False
201 )
Dennis Dmitrieve56c8b92017-06-16 01:53:16 +0300202 )