Merge ~vultaire/charm-logrotated:black-20.08 into charm-logrotated:master
- Git
- lp:~vultaire/charm-logrotated
- black-20.08
- Merge into master
Proposed by
Paul Goins
Status: | Merged |
---|---|
Approved by: | Xav Paice |
Approved revision: | 98174e23a023bad96dbaa1b6ab396d05d0046301 |
Merged at revision: | 1ec74c351769c8e778ae23604e379b1b3c6540f3 |
Proposed branch: | ~vultaire/charm-logrotated:black-20.08 |
Merge into: | charm-logrotated:master |
Prerequisite: | ~vultaire/charm-logrotated:makefile-20.08 |
Diff against target: |
668 lines (+147/-122) 10 files modified
src/actions/actions.py (+1/-1) src/lib/lib_cron.py (+22/-12) src/lib/lib_logrotate.py (+33/-28) src/reactive/logrotate.py (+15/-15) src/tests/functional/conftest.py (+11/-10) src/tests/functional/juju_tools.py (+13/-11) src/tests/functional/test_logrotate.py (+15/-19) src/tests/unit/conftest.py (+14/-12) src/tests/unit/test_logrotate.py (+21/-9) src/tox.ini (+2/-5) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Xav Paice (community) | Approve | ||
Canonical IS Reviewers | Pending | ||
Review via email: mp+388839@code.launchpad.net |
Commit message
Blackened repository to 88 lines
Description of the change
To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Revision history for this message
Paul Goins (vultaire) wrote : | # |
Just rebased today.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote : | # |
Change successfully merged at revision 1ec74c351769c8e
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/src/actions/actions.py b/src/actions/actions.py | |||
2 | index 8178850..dd311d4 100755 | |||
3 | --- a/src/actions/actions.py | |||
4 | +++ b/src/actions/actions.py | |||
5 | @@ -10,7 +10,7 @@ from lib_cron import CronHelper | |||
6 | 10 | 10 | ||
7 | 11 | from lib_logrotate import LogrotateHelper | 11 | from lib_logrotate import LogrotateHelper |
8 | 12 | 12 | ||
10 | 13 | sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib')) | 13 | sys.path.insert(0, os.path.join(os.environ["CHARM_DIR"], "lib")) |
11 | 14 | 14 | ||
12 | 15 | hooks = hookenv.Hooks() | 15 | hooks = hookenv.Hooks() |
13 | 16 | logrotate = LogrotateHelper() | 16 | logrotate = LogrotateHelper() |
14 | diff --git a/src/lib/lib_cron.py b/src/lib/lib_cron.py | |||
15 | index b7d24c4..5c17738 100644 | |||
16 | --- a/src/lib/lib_cron.py | |||
17 | +++ b/src/lib/lib_cron.py | |||
18 | @@ -24,9 +24,9 @@ class CronHelper: | |||
19 | 24 | """ | 24 | """ |
20 | 25 | config_file = open(self.cronjob_etc_config, "r") | 25 | config_file = open(self.cronjob_etc_config, "r") |
21 | 26 | lines = config_file.read() | 26 | lines = config_file.read() |
23 | 27 | lines = lines.split('\n') | 27 | lines = lines.split("\n") |
24 | 28 | 28 | ||
26 | 29 | if lines[0] == 'True': | 29 | if lines[0] == "True": |
27 | 30 | self.cronjob_enabled = True | 30 | self.cronjob_enabled = True |
28 | 31 | else: | 31 | else: |
29 | 32 | self.cronjob_enabled = False | 32 | self.cronjob_enabled = False |
30 | @@ -43,17 +43,22 @@ class CronHelper: | |||
31 | 43 | 43 | ||
32 | 44 | if self.cronjob_enabled is True: | 44 | if self.cronjob_enabled is True: |
33 | 45 | cronjob_path = os.path.realpath(__file__) | 45 | cronjob_path = os.path.realpath(__file__) |
37 | 46 | cron_file_path = self.cronjob_base_path\ | 46 | cron_file_path = ( |
38 | 47 | + self.cronjob_check_paths[clean_up_file]\ | 47 | self.cronjob_base_path |
39 | 48 | + "/" + self.cronjob_logrotate_cron_file | 48 | + self.cronjob_check_paths[clean_up_file] |
40 | 49 | + "/" | ||
41 | 50 | + self.cronjob_logrotate_cron_file | ||
42 | 51 | ) | ||
43 | 49 | 52 | ||
44 | 50 | logrotate_unit = hookenv.local_unit() | 53 | logrotate_unit = hookenv.local_unit() |
46 | 51 | python_venv_path = os.getcwd().replace('charm', '') + '.venv/bin/python3' | 54 | python_venv_path = os.getcwd().replace("charm", "") + ".venv/bin/python3" |
47 | 52 | # upgrade to template if logic increases | 55 | # upgrade to template if logic increases |
49 | 53 | cron_file = open(cron_file_path, 'w') | 56 | cron_file = open(cron_file_path, "w") |
50 | 54 | cron_job = """#!/bin/bash | 57 | cron_job = """#!/bin/bash |
51 | 55 | /usr/bin/sudo /usr/bin/juju-run {} "{} {}" | 58 | /usr/bin/sudo /usr/bin/juju-run {} "{} {}" |
53 | 56 | """.format(logrotate_unit, python_venv_path, cronjob_path) | 59 | """.format( |
54 | 60 | logrotate_unit, python_venv_path, cronjob_path | ||
55 | 61 | ) | ||
56 | 57 | cron_file.write(cron_job) | 62 | cron_file.write(cron_job) |
57 | 58 | cron_file.close() | 63 | cron_file.close() |
58 | 59 | os.chmod(cron_file_path, 700) | 64 | os.chmod(cron_file_path, 700) |
59 | @@ -64,7 +69,12 @@ class CronHelper: | |||
60 | 64 | """Cleanup previous config.""" | 69 | """Cleanup previous config.""" |
61 | 65 | if frequency == -1: | 70 | if frequency == -1: |
62 | 66 | for check_path in self.cronjob_check_paths: | 71 | for check_path in self.cronjob_check_paths: |
64 | 67 | path = self.cronjob_base_path + check_path + "/" + self.cronjob_logrotate_cron_file | 72 | path = ( |
65 | 73 | self.cronjob_base_path | ||
66 | 74 | + check_path | ||
67 | 75 | + "/" | ||
68 | 76 | + self.cronjob_logrotate_cron_file | ||
69 | 77 | ) | ||
70 | 68 | if os.path.exists(path): | 78 | if os.path.exists(path): |
71 | 69 | os.remove(path) | 79 | os.remove(path) |
72 | 70 | if os.path.exists(self.cronjob_etc_config): | 80 | if os.path.exists(self.cronjob_etc_config): |
73 | @@ -79,13 +89,13 @@ class CronHelper: | |||
74 | 79 | 89 | ||
75 | 80 | def main(): | 90 | def main(): |
76 | 81 | """Ran by cron.""" | 91 | """Ran by cron.""" |
78 | 82 | hookenv.status_set('maintenance', 'Executing cron job.') | 92 | hookenv.status_set("maintenance", "Executing cron job.") |
79 | 83 | cronhelper = CronHelper() | 93 | cronhelper = CronHelper() |
80 | 84 | cronhelper.read_config() | 94 | cronhelper.read_config() |
81 | 85 | cronhelper.update_logrotate_etc() | 95 | cronhelper.update_logrotate_etc() |
82 | 86 | cronhelper.install_cronjob() | 96 | cronhelper.install_cronjob() |
84 | 87 | hookenv.status_set('active', 'Unit is ready.') | 97 | hookenv.status_set("active", "Unit is ready.") |
85 | 88 | 98 | ||
86 | 89 | 99 | ||
88 | 90 | if __name__ == '__main__': | 100 | if __name__ == "__main__": |
89 | 91 | main() | 101 | main() |
90 | diff --git a/src/lib/lib_logrotate.py b/src/lib/lib_logrotate.py | |||
91 | index d8c4327..497f609 100644 | |||
92 | --- a/src/lib/lib_logrotate.py | |||
93 | +++ b/src/lib/lib_logrotate.py | |||
94 | @@ -13,9 +13,9 @@ class LogrotateHelper: | |||
95 | 13 | 13 | ||
96 | 14 | def __init__(self): | 14 | def __init__(self): |
97 | 15 | """Init function.""" | 15 | """Init function.""" |
99 | 16 | self.retention = hookenv.config('logrotate-retention') | 16 | self.retention = hookenv.config("logrotate-retention") |
100 | 17 | self.override_interval_regex = re.compile("(daily|weekly|monthly|yearly)") | 17 | self.override_interval_regex = re.compile("(daily|weekly|monthly|yearly)") |
102 | 18 | self.override = json.loads(hookenv.config('override')) | 18 | self.override = json.loads(hookenv.config("override")) |
103 | 19 | self.override_files = self.get_override_files() | 19 | self.override_files = self.get_override_files() |
104 | 20 | 20 | ||
105 | 21 | def read_config(self): | 21 | def read_config(self): |
106 | @@ -26,7 +26,7 @@ class LogrotateHelper: | |||
107 | 26 | """ | 26 | """ |
108 | 27 | config_file = open("/etc/logrotate_cronjob_config", "r") | 27 | config_file = open("/etc/logrotate_cronjob_config", "r") |
109 | 28 | lines = config_file.read() | 28 | lines = config_file.read() |
111 | 29 | lines = lines.split('\n') | 29 | lines = lines.split("\n") |
112 | 30 | 30 | ||
113 | 31 | self.retention = int(lines[2]) | 31 | self.retention = int(lines[2]) |
114 | 32 | 32 | ||
115 | @@ -35,7 +35,7 @@ class LogrotateHelper: | |||
116 | 35 | for config_file in os.listdir(LOGROTATE_DIR): | 35 | for config_file in os.listdir(LOGROTATE_DIR): |
117 | 36 | file_path = LOGROTATE_DIR + config_file | 36 | file_path = LOGROTATE_DIR + config_file |
118 | 37 | 37 | ||
120 | 38 | logrotate_file = open(file_path, 'r') | 38 | logrotate_file = open(file_path, "r") |
121 | 39 | content = logrotate_file.read() | 39 | content = logrotate_file.read() |
122 | 40 | logrotate_file.close() | 40 | logrotate_file.close() |
123 | 41 | 41 | ||
124 | @@ -43,14 +43,17 @@ class LogrotateHelper: | |||
125 | 43 | 43 | ||
126 | 44 | mod_contents = self.modify_header(mod_contents) | 44 | mod_contents = self.modify_header(mod_contents) |
127 | 45 | 45 | ||
129 | 46 | logrotate_file = open(file_path, 'w') | 46 | logrotate_file = open(file_path, "w") |
130 | 47 | logrotate_file.write(mod_contents) | 47 | logrotate_file.write(mod_contents) |
131 | 48 | logrotate_file.close() | 48 | logrotate_file.close() |
132 | 49 | 49 | ||
133 | 50 | def get_override_files(self): | 50 | def get_override_files(self): |
134 | 51 | """Return paths for files to be overrided.""" | 51 | """Return paths for files to be overrided.""" |
137 | 52 | return [path['path'] for path in self.override | 52 | return [ |
138 | 53 | if set(path.keys()) == {'path', 'rotate', 'interval'}] | 53 | path["path"] |
139 | 54 | for path in self.override | ||
140 | 55 | if set(path.keys()) == {"path", "rotate", "interval"} | ||
141 | 56 | ] | ||
142 | 54 | 57 | ||
143 | 55 | def get_override_settings(self, file_path): | 58 | def get_override_settings(self, file_path): |
144 | 56 | """Return settings in key:value pairs for the file_path requested. | 59 | """Return settings in key:value pairs for the file_path requested. |
145 | @@ -58,22 +61,22 @@ class LogrotateHelper: | |||
146 | 58 | param: file_path: path to the file for manual settings. | 61 | param: file_path: path to the file for manual settings. |
147 | 59 | """ | 62 | """ |
148 | 60 | for override_entry in self.override: | 63 | for override_entry in self.override: |
153 | 61 | if file_path == override_entry['path']: | 64 | if file_path == override_entry["path"]: |
154 | 62 | rotate = override_entry['rotate'] | 65 | rotate = override_entry["rotate"] |
155 | 63 | interval = override_entry['interval'] | 66 | interval = override_entry["interval"] |
156 | 64 | return {'rotate': rotate, 'interval': interval} | 67 | return {"rotate": rotate, "interval": interval} |
157 | 65 | 68 | ||
158 | 66 | def modify_content(self, content, file_path): | 69 | def modify_content(self, content, file_path): |
159 | 67 | """Edit the content of a logrotate file.""" | 70 | """Edit the content of a logrotate file.""" |
160 | 68 | # Split the contents in a logrotate file in separate entries (if | 71 | # Split the contents in a logrotate file in separate entries (if |
161 | 69 | # multiple are found in the file) and put in a list for further | 72 | # multiple are found in the file) and put in a list for further |
162 | 70 | # processing | 73 | # processing |
164 | 71 | split = content.split('\n') | 74 | split = content.split("\n") |
165 | 72 | items = [] | 75 | items = [] |
166 | 73 | string = "" | 76 | string = "" |
167 | 74 | for row in split: | 77 | for row in split: |
170 | 75 | string += row + '\n' | 78 | string += row + "\n" |
171 | 76 | if '}' in row: | 79 | if "}" in row: |
172 | 77 | items.append(string) | 80 | items.append(string) |
173 | 78 | string = "" | 81 | string = "" |
174 | 79 | continue | 82 | continue |
175 | @@ -84,35 +87,37 @@ class LogrotateHelper: | |||
176 | 84 | for item in items: | 87 | for item in items: |
177 | 85 | # Override rotate, if defined | 88 | # Override rotate, if defined |
178 | 86 | if file_path in self.override_files: | 89 | if file_path in self.override_files: |
180 | 87 | count = self.get_override_settings(file_path)['rotate'] | 90 | count = self.get_override_settings(file_path)["rotate"] |
181 | 88 | else: | 91 | else: |
182 | 89 | count = self.calculate_count(item, self.retention) | 92 | count = self.calculate_count(item, self.retention) |
184 | 90 | rotate = 'rotate {}'.format(count) | 93 | rotate = "rotate {}".format(count) |
185 | 91 | # if rotate is missing, add it as last line in the item entry | 94 | # if rotate is missing, add it as last line in the item entry |
188 | 92 | if 'rotate' in item: | 95 | if "rotate" in item: |
189 | 93 | result = re.sub(r'rotate \d+\.?[0-9]*', rotate, item) | 96 | result = re.sub(r"rotate \d+\.?[0-9]*", rotate, item) |
190 | 94 | else: | 97 | else: |
192 | 95 | result = item.replace('}', ' ' + rotate + '\n}') | 98 | result = item.replace("}", " " + rotate + "\n}") |
193 | 96 | results.append(result) | 99 | results.append(result) |
194 | 97 | 100 | ||
196 | 98 | results = '\n'.join(results) | 101 | results = "\n".join(results) |
197 | 99 | 102 | ||
198 | 100 | # Override interval, if defined | 103 | # Override interval, if defined |
199 | 101 | if file_path in self.override_files: | 104 | if file_path in self.override_files: |
201 | 102 | interval = self.get_override_settings(file_path)['interval'] | 105 | interval = self.get_override_settings(file_path)["interval"] |
202 | 103 | results = self.override_interval_regex.sub(interval, results) | 106 | results = self.override_interval_regex.sub(interval, results) |
203 | 104 | 107 | ||
204 | 105 | return results | 108 | return results |
205 | 106 | 109 | ||
206 | 107 | def modify_header(self, content): | 110 | def modify_header(self, content): |
207 | 108 | """Add Juju headers to the file.""" | 111 | """Add Juju headers to the file.""" |
209 | 109 | header = "# Configuration file maintained by Juju. Local changes may be overwritten" | 112 | header = ( |
210 | 113 | "# Configuration file maintained by Juju. Local changes may be overwritten" | ||
211 | 114 | ) | ||
212 | 110 | 115 | ||
214 | 111 | split = content.split('\n') | 116 | split = content.split("\n") |
215 | 112 | if split[0].startswith(header): | 117 | if split[0].startswith(header): |
216 | 113 | result = content | 118 | result = content |
217 | 114 | else: | 119 | else: |
219 | 115 | result = header + '\n' + content | 120 | result = header + "\n" + content |
220 | 116 | 121 | ||
221 | 117 | return result | 122 | return result |
222 | 118 | 123 | ||
223 | @@ -123,16 +128,16 @@ class LogrotateHelper: | |||
224 | 123 | # better to keep the logs than lose them | 128 | # better to keep the logs than lose them |
225 | 124 | count = retention | 129 | count = retention |
226 | 125 | # Daily 1:1 to configuration retention period (in days) | 130 | # Daily 1:1 to configuration retention period (in days) |
228 | 126 | if 'daily' in item: | 131 | if "daily" in item: |
229 | 127 | count = retention | 132 | count = retention |
230 | 128 | # Weekly rounding up, as weeks are 7 days | 133 | # Weekly rounding up, as weeks are 7 days |
232 | 129 | if 'weekly' in item: | 134 | if "weekly" in item: |
233 | 130 | count = int(round(retention / 7)) | 135 | count = int(round(retention / 7)) |
234 | 131 | # Monthly default 30 days and round up because of 28/31 days months | 136 | # Monthly default 30 days and round up because of 28/31 days months |
236 | 132 | if 'monthly' in item: | 137 | if "monthly" in item: |
237 | 133 | count = int(round(retention / 30)) | 138 | count = int(round(retention / 30)) |
238 | 134 | # For every 360 days - add 1 year | 139 | # For every 360 days - add 1 year |
240 | 135 | if 'yearly' in item: | 140 | if "yearly" in item: |
241 | 136 | count = retention // 360 + 1 if retention > 360 else 1 | 141 | count = retention // 360 + 1 if retention > 360 else 1 |
242 | 137 | 142 | ||
243 | 138 | return count | 143 | return count |
244 | diff --git a/src/reactive/logrotate.py b/src/reactive/logrotate.py | |||
245 | index b0e349a..119ac96 100644 | |||
246 | --- a/src/reactive/logrotate.py | |||
247 | +++ b/src/reactive/logrotate.py | |||
248 | @@ -13,7 +13,7 @@ logrotate = LogrotateHelper() | |||
249 | 13 | cron = CronHelper() | 13 | cron = CronHelper() |
250 | 14 | 14 | ||
251 | 15 | 15 | ||
253 | 16 | @when_not('logrotate.installed') | 16 | @when_not("logrotate.installed") |
254 | 17 | def install_logrotate(): | 17 | def install_logrotate(): |
255 | 18 | """Install the logrotate charm.""" | 18 | """Install the logrotate charm.""" |
256 | 19 | try: | 19 | try: |
257 | @@ -23,32 +23,32 @@ def install_logrotate(): | |||
258 | 23 | logrotate.modify_configs() | 23 | logrotate.modify_configs() |
259 | 24 | cron.install_cronjob() | 24 | cron.install_cronjob() |
260 | 25 | except Exception as ex: | 25 | except Exception as ex: |
264 | 26 | hookenv.status_set('blocked', str(ex)) | 26 | hookenv.status_set("blocked", str(ex)) |
265 | 27 | hookenv.status_set('active', 'Unit is ready.') | 27 | hookenv.status_set("active", "Unit is ready.") |
266 | 28 | set_flag('logrotate.installed') | 28 | set_flag("logrotate.installed") |
267 | 29 | 29 | ||
268 | 30 | 30 | ||
270 | 31 | @when('config.changed') | 31 | @when("config.changed") |
271 | 32 | def config_changed(): | 32 | def config_changed(): |
272 | 33 | """Run when configuration changes.""" | 33 | """Run when configuration changes.""" |
273 | 34 | try: | 34 | try: |
274 | 35 | dump_config_to_disk() | 35 | dump_config_to_disk() |
275 | 36 | cron.read_config() | 36 | cron.read_config() |
276 | 37 | logrotate.read_config() | 37 | logrotate.read_config() |
278 | 38 | hookenv.status_set('maintenance', 'Modifying configs.') | 38 | hookenv.status_set("maintenance", "Modifying configs.") |
279 | 39 | logrotate.modify_configs() | 39 | logrotate.modify_configs() |
280 | 40 | cron.install_cronjob() | 40 | cron.install_cronjob() |
281 | 41 | except Exception as ex: | 41 | except Exception as ex: |
284 | 42 | hookenv.status_set('blocked', str(ex)) | 42 | hookenv.status_set("blocked", str(ex)) |
285 | 43 | hookenv.status_set('active', 'Unit is ready.') | 43 | hookenv.status_set("active", "Unit is ready.") |
286 | 44 | 44 | ||
287 | 45 | 45 | ||
288 | 46 | def dump_config_to_disk(): | 46 | def dump_config_to_disk(): |
289 | 47 | """Dump configurations to disk.""" | 47 | """Dump configurations to disk.""" |
297 | 48 | cronjob_enabled = hookenv.config('logrotate-cronjob') | 48 | cronjob_enabled = hookenv.config("logrotate-cronjob") |
298 | 49 | cronjob_frequency = hookenv.config('logrotate-cronjob-frequency') | 49 | cronjob_frequency = hookenv.config("logrotate-cronjob-frequency") |
299 | 50 | logrotate_retention = hookenv.config('logrotate-retention') | 50 | logrotate_retention = hookenv.config("logrotate-retention") |
300 | 51 | with open('/etc/logrotate_cronjob_config', 'w+') as cronjob_config_file: | 51 | with open("/etc/logrotate_cronjob_config", "w+") as cronjob_config_file: |
301 | 52 | cronjob_config_file.write(str(cronjob_enabled) + '\n') | 52 | cronjob_config_file.write(str(cronjob_enabled) + "\n") |
302 | 53 | cronjob_config_file.write(str(cronjob_frequency) + '\n') | 53 | cronjob_config_file.write(str(cronjob_frequency) + "\n") |
303 | 54 | cronjob_config_file.write(str(logrotate_retention) + '\n') | 54 | cronjob_config_file.write(str(logrotate_retention) + "\n") |
304 | diff --git a/src/tests/functional/conftest.py b/src/tests/functional/conftest.py | |||
305 | index 1b22cb8..2cc4343 100644 | |||
306 | --- a/src/tests/functional/conftest.py | |||
307 | +++ b/src/tests/functional/conftest.py | |||
308 | @@ -21,7 +21,7 @@ from juju_tools import JujuTools | |||
309 | 21 | import pytest | 21 | import pytest |
310 | 22 | 22 | ||
311 | 23 | 23 | ||
313 | 24 | @pytest.fixture(scope='module') | 24 | @pytest.fixture(scope="module") |
314 | 25 | def event_loop(): | 25 | def event_loop(): |
315 | 26 | """Override the default pytest event loop. | 26 | """Override the default pytest event loop. |
316 | 27 | 27 | ||
317 | @@ -35,7 +35,7 @@ def event_loop(): | |||
318 | 35 | asyncio.set_event_loop(None) | 35 | asyncio.set_event_loop(None) |
319 | 36 | 36 | ||
320 | 37 | 37 | ||
322 | 38 | @pytest.fixture(scope='module') | 38 | @pytest.fixture(scope="module") |
323 | 39 | async def controller(): | 39 | async def controller(): |
324 | 40 | """Connect to the current controller.""" | 40 | """Connect to the current controller.""" |
325 | 41 | _controller = Controller() | 41 | _controller = Controller() |
326 | @@ -44,27 +44,28 @@ async def controller(): | |||
327 | 44 | await _controller.disconnect() | 44 | await _controller.disconnect() |
328 | 45 | 45 | ||
329 | 46 | 46 | ||
331 | 47 | @pytest.fixture(scope='module') | 47 | @pytest.fixture(scope="module") |
332 | 48 | async def model(controller): | 48 | async def model(controller): |
333 | 49 | """Live only for the duration of the test.""" | 49 | """Live only for the duration of the test.""" |
334 | 50 | model_name = "functest-{}".format(str(uuid.uuid4())[-12:]) | 50 | model_name = "functest-{}".format(str(uuid.uuid4())[-12:]) |
339 | 51 | _model = await controller.add_model(model_name, | 51 | _model = await controller.add_model( |
340 | 52 | cloud_name=os.getenv('PYTEST_CLOUD_NAME'), | 52 | model_name, |
341 | 53 | region=os.getenv('PYTEST_CLOUD_REGION'), | 53 | cloud_name=os.getenv("PYTEST_CLOUD_NAME"), |
342 | 54 | ) | 54 | region=os.getenv("PYTEST_CLOUD_REGION"), |
343 | 55 | ) | ||
344 | 55 | # https://github.com/juju/python-libjuju/issues/267 | 56 | # https://github.com/juju/python-libjuju/issues/267 |
346 | 56 | subprocess.check_call(['juju', 'models']) | 57 | subprocess.check_call(["juju", "models"]) |
347 | 57 | while model_name not in await controller.list_models(): | 58 | while model_name not in await controller.list_models(): |
348 | 58 | await asyncio.sleep(1) | 59 | await asyncio.sleep(1) |
349 | 59 | yield _model | 60 | yield _model |
350 | 60 | await _model.disconnect() | 61 | await _model.disconnect() |
352 | 61 | if not os.getenv('PYTEST_KEEP_MODEL'): | 62 | if not os.getenv("PYTEST_KEEP_MODEL"): |
353 | 62 | await controller.destroy_model(model_name) | 63 | await controller.destroy_model(model_name) |
354 | 63 | while model_name in await controller.list_models(): | 64 | while model_name in await controller.list_models(): |
355 | 64 | await asyncio.sleep(1) | 65 | await asyncio.sleep(1) |
356 | 65 | 66 | ||
357 | 66 | 67 | ||
359 | 67 | @pytest.fixture(scope='module') | 68 | @pytest.fixture(scope="module") |
360 | 68 | async def jujutools(controller, model): | 69 | async def jujutools(controller, model): |
361 | 69 | """Juju tools.""" | 70 | """Juju tools.""" |
362 | 70 | tools = JujuTools(controller, model) | 71 | tools = JujuTools(controller, model) |
363 | diff --git a/src/tests/functional/juju_tools.py b/src/tests/functional/juju_tools.py | |||
364 | index 5e4a1cc..6ce6f10 100644 | |||
365 | --- a/src/tests/functional/juju_tools.py | |||
366 | +++ b/src/tests/functional/juju_tools.py | |||
367 | @@ -37,14 +37,17 @@ class JujuTools: | |||
368 | 37 | :param target: Unit object or unit name string | 37 | :param target: Unit object or unit name string |
369 | 38 | """ | 38 | """ |
370 | 39 | python3 = "python3 -c '{}'" | 39 | python3 = "python3 -c '{}'" |
376 | 40 | python_cmd = ('import pickle;' | 40 | python_cmd = ( |
377 | 41 | 'import base64;' | 41 | "import pickle;" |
378 | 42 | '{}' | 42 | "import base64;" |
379 | 43 | 'print(base64.b64encode(pickle.dumps({})), end="")' | 43 | "{}" |
380 | 44 | .format(imports, remote_cmd)) | 44 | 'print(base64.b64encode(pickle.dumps({})), end="")'.format( |
381 | 45 | imports, remote_cmd | ||
382 | 46 | ) | ||
383 | 47 | ) | ||
384 | 45 | cmd = python3.format(python_cmd) | 48 | cmd = python3.format(python_cmd) |
385 | 46 | results = await self.run_command(cmd, target) | 49 | results = await self.run_command(cmd, target) |
387 | 47 | return pickle.loads(base64.b64decode(bytes(results['Stdout'][2:-1], 'utf8'))) | 50 | return pickle.loads(base64.b64decode(bytes(results["Stdout"][2:-1], "utf8"))) |
388 | 48 | 51 | ||
389 | 49 | async def file_stat(self, path, target): | 52 | async def file_stat(self, path, target): |
390 | 50 | """Run stat on a file. | 53 | """Run stat on a file. |
391 | @@ -52,9 +55,8 @@ class JujuTools: | |||
392 | 52 | :param path: File path | 55 | :param path: File path |
393 | 53 | :param target: Unit object or unit name string | 56 | :param target: Unit object or unit name string |
394 | 54 | """ | 57 | """ |
398 | 55 | imports = 'import os;' | 58 | imports = "import os;" |
399 | 56 | python_cmd = ('os.stat("{}")' | 59 | python_cmd = 'os.stat("{}")'.format(path) |
397 | 57 | .format(path)) | ||
400 | 58 | print("Calling remote cmd: " + python_cmd) | 60 | print("Calling remote cmd: " + python_cmd) |
401 | 59 | return await self.remote_object(imports, python_cmd, target) | 61 | return await self.remote_object(imports, python_cmd, target) |
402 | 60 | 62 | ||
403 | @@ -64,6 +66,6 @@ class JujuTools: | |||
404 | 64 | :param path: File path | 66 | :param path: File path |
405 | 65 | :param target: Unit object or unit name string | 67 | :param target: Unit object or unit name string |
406 | 66 | """ | 68 | """ |
408 | 67 | cmd = 'cat {}'.format(path) | 69 | cmd = "cat {}".format(path) |
409 | 68 | result = await self.run_command(cmd, target) | 70 | result = await self.run_command(cmd, target) |
411 | 69 | return result['Stdout'] | 71 | return result["Stdout"] |
412 | diff --git a/src/tests/functional/test_logrotate.py b/src/tests/functional/test_logrotate.py | |||
413 | index 936c577..68ecce0 100644 | |||
414 | --- a/src/tests/functional/test_logrotate.py | |||
415 | +++ b/src/tests/functional/test_logrotate.py | |||
416 | @@ -6,48 +6,44 @@ import os | |||
417 | 6 | import pytest | 6 | import pytest |
418 | 7 | 7 | ||
419 | 8 | pytestmark = pytest.mark.asyncio | 8 | pytestmark = pytest.mark.asyncio |
424 | 9 | SERIES = ['xenial', | 9 | SERIES = [ |
425 | 10 | 'bionic', | 10 | "xenial", |
426 | 11 | 'focal', | 11 | "bionic", |
427 | 12 | ] | 12 | "focal", |
428 | 13 | ] | ||
429 | 13 | 14 | ||
430 | 14 | 15 | ||
431 | 15 | ############ | 16 | ############ |
432 | 16 | # FIXTURES # | 17 | # FIXTURES # |
433 | 17 | ############ | 18 | ############ |
434 | 18 | 19 | ||
437 | 19 | @pytest.fixture(scope='module', | 20 | |
438 | 20 | params=SERIES) | 21 | @pytest.fixture(scope="module", params=SERIES) |
439 | 21 | async def deploy_app(request, model): | 22 | async def deploy_app(request, model): |
440 | 22 | """Deploy the logrotate charm as a subordinate of ubuntu.""" | 23 | """Deploy the logrotate charm as a subordinate of ubuntu.""" |
441 | 23 | release = request.param | 24 | release = request.param |
442 | 24 | 25 | ||
443 | 25 | await model.deploy( | 26 | await model.deploy( |
448 | 26 | 'ubuntu', | 27 | "ubuntu", application_name="ubuntu-" + release, series=release, channel="stable" |
445 | 27 | application_name='ubuntu-' + release, | ||
446 | 28 | series=release, | ||
447 | 29 | channel='stable' | ||
449 | 30 | ) | 28 | ) |
450 | 31 | logrotate_app = await model.deploy( | 29 | logrotate_app = await model.deploy( |
453 | 32 | '{}/logrotated'.format(os.getenv('CHARM_BUILD_DIR')), | 30 | "{}/logrotated".format(os.getenv("CHARM_BUILD_DIR")), |
454 | 33 | application_name='logrotate-' + release, | 31 | application_name="logrotate-" + release, |
455 | 34 | series=release, | 32 | series=release, |
456 | 35 | num_units=0, | 33 | num_units=0, |
457 | 36 | ) | 34 | ) |
462 | 37 | await model.add_relation( | 35 | await model.add_relation("ubuntu-" + release, "logrotate-" + release) |
459 | 38 | 'ubuntu-' + release, | ||
460 | 39 | 'logrotate-' + release | ||
461 | 40 | ) | ||
463 | 41 | 36 | ||
465 | 42 | await model.block_until(lambda: logrotate_app.status == 'active') | 37 | await model.block_until(lambda: logrotate_app.status == "active") |
466 | 43 | yield logrotate_app | 38 | yield logrotate_app |
467 | 44 | 39 | ||
468 | 45 | 40 | ||
470 | 46 | @pytest.fixture(scope='module') | 41 | @pytest.fixture(scope="module") |
471 | 47 | async def unit(deploy_app): | 42 | async def unit(deploy_app): |
472 | 48 | """Return the logrotate unit we've deployed.""" | 43 | """Return the logrotate unit we've deployed.""" |
473 | 49 | return deploy_app.units.pop() | 44 | return deploy_app.units.pop() |
474 | 50 | 45 | ||
475 | 46 | |||
476 | 51 | ######### | 47 | ######### |
477 | 52 | # TESTS # | 48 | # TESTS # |
478 | 53 | ######### | 49 | ######### |
479 | @@ -55,4 +51,4 @@ async def unit(deploy_app): | |||
480 | 55 | 51 | ||
481 | 56 | async def test_deploy(deploy_app): | 52 | async def test_deploy(deploy_app): |
482 | 57 | """Tst the deployment.""" | 53 | """Tst the deployment.""" |
484 | 58 | assert deploy_app.status == 'active' | 54 | assert deploy_app.status == "active" |
485 | diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py | |||
486 | index b4c0517..2bb8eb8 100644 | |||
487 | --- a/src/tests/unit/conftest.py | |||
488 | +++ b/src/tests/unit/conftest.py | |||
489 | @@ -12,19 +12,20 @@ import pytest | |||
490 | 12 | def mock_layers(monkeypatch): | 12 | def mock_layers(monkeypatch): |
491 | 13 | """Layers mock.""" | 13 | """Layers mock.""" |
492 | 14 | import sys | 14 | import sys |
495 | 15 | sys.modules['charms.layer'] = mock.Mock() | 15 | |
496 | 16 | sys.modules['reactive'] = mock.Mock() | 16 | sys.modules["charms.layer"] = mock.Mock() |
497 | 17 | sys.modules["reactive"] = mock.Mock() | ||
498 | 17 | # Mock any functions in layers that need to be mocked here | 18 | # Mock any functions in layers that need to be mocked here |
499 | 18 | 19 | ||
500 | 19 | def options(layer): | 20 | def options(layer): |
501 | 20 | # mock options for layers here | 21 | # mock options for layers here |
504 | 21 | if layer == 'example-layer': | 22 | if layer == "example-layer": |
505 | 22 | options = {'port': 9999} | 23 | options = {"port": 9999} |
506 | 23 | return options | 24 | return options |
507 | 24 | else: | 25 | else: |
508 | 25 | return None | 26 | return None |
509 | 26 | 27 | ||
511 | 27 | monkeypatch.setattr('lib_logrotate.layer.options', options) | 28 | monkeypatch.setattr("lib_logrotate.layer.options", options) |
512 | 28 | 29 | ||
513 | 29 | 30 | ||
514 | 30 | @pytest.fixture | 31 | @pytest.fixture |
515 | @@ -34,38 +35,39 @@ def mock_hookenv_config(monkeypatch): | |||
516 | 34 | 35 | ||
517 | 35 | def mock_config(): | 36 | def mock_config(): |
518 | 36 | cfg = {} | 37 | cfg = {} |
520 | 37 | yml = yaml.load(open('./config.yaml')) | 38 | yml = yaml.load(open("./config.yaml")) |
521 | 38 | 39 | ||
522 | 39 | # Load all defaults | 40 | # Load all defaults |
525 | 40 | for key, value in yml['options'].items(): | 41 | for key, value in yml["options"].items(): |
526 | 41 | cfg[key] = value['default'] | 42 | cfg[key] = value["default"] |
527 | 42 | 43 | ||
528 | 43 | # Manually add cfg from other layers | 44 | # Manually add cfg from other layers |
529 | 44 | # cfg['my-other-layer'] = 'mock' | 45 | # cfg['my-other-layer'] = 'mock' |
530 | 45 | return cfg | 46 | return cfg |
531 | 46 | 47 | ||
533 | 47 | monkeypatch.setattr('lib_logrotate.hookenv.config', mock_config) | 48 | monkeypatch.setattr("lib_logrotate.hookenv.config", mock_config) |
534 | 48 | 49 | ||
535 | 49 | 50 | ||
536 | 50 | @pytest.fixture | 51 | @pytest.fixture |
537 | 51 | def mock_remote_unit(monkeypatch): | 52 | def mock_remote_unit(monkeypatch): |
538 | 52 | """Remote unit mock.""" | 53 | """Remote unit mock.""" |
540 | 53 | monkeypatch.setattr('lib_logrotate.hookenv.remote_unit', lambda: 'unit-mock/0') | 54 | monkeypatch.setattr("lib_logrotate.hookenv.remote_unit", lambda: "unit-mock/0") |
541 | 54 | 55 | ||
542 | 55 | 56 | ||
543 | 56 | @pytest.fixture | 57 | @pytest.fixture |
544 | 57 | def mock_charm_dir(monkeypatch): | 58 | def mock_charm_dir(monkeypatch): |
545 | 58 | """Charm dir mock.""" | 59 | """Charm dir mock.""" |
547 | 59 | monkeypatch.setattr('lib_logrotate.hookenv.charm_dir', lambda: '/mock/charm/dir') | 60 | monkeypatch.setattr("lib_logrotate.hookenv.charm_dir", lambda: "/mock/charm/dir") |
548 | 60 | 61 | ||
549 | 61 | 62 | ||
550 | 62 | @pytest.fixture | 63 | @pytest.fixture |
551 | 63 | def logrotate(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch): | 64 | def logrotate(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch): |
552 | 64 | """Logrotate fixture.""" | 65 | """Logrotate fixture.""" |
553 | 65 | from lib_logrotate import LogrotateHelper | 66 | from lib_logrotate import LogrotateHelper |
554 | 67 | |||
555 | 66 | helper = LogrotateHelper | 68 | helper = LogrotateHelper |
556 | 67 | 69 | ||
557 | 68 | # Any other functions that load helper will get this version | 70 | # Any other functions that load helper will get this version |
559 | 69 | monkeypatch.setattr('lib_logrotate.LogrotateHelper', lambda: helper) | 71 | monkeypatch.setattr("lib_logrotate.LogrotateHelper", lambda: helper) |
560 | 70 | 72 | ||
561 | 71 | return helper | 73 | return helper |
562 | diff --git a/src/tests/unit/test_logrotate.py b/src/tests/unit/test_logrotate.py | |||
563 | index 68ed164..b317257 100644 | |||
564 | --- a/src/tests/unit/test_logrotate.py | |||
565 | +++ b/src/tests/unit/test_logrotate.py | |||
566 | @@ -1,7 +1,7 @@ | |||
567 | 1 | """Main unit test module.""" | 1 | """Main unit test module.""" |
568 | 2 | 2 | ||
569 | 3 | 3 | ||
571 | 4 | class TestLogrotateHelper(): | 4 | class TestLogrotateHelper: |
572 | 5 | """Main test class.""" | 5 | """Main test class.""" |
573 | 6 | 6 | ||
574 | 7 | def test_pytest(self): | 7 | def test_pytest(self): |
575 | @@ -11,28 +11,28 @@ class TestLogrotateHelper(): | |||
576 | 11 | def test_daily_retention_count(self, logrotate): | 11 | def test_daily_retention_count(self, logrotate): |
577 | 12 | """Test daily retention count.""" | 12 | """Test daily retention count.""" |
578 | 13 | logrotate.retention = 90 | 13 | logrotate.retention = 90 |
580 | 14 | contents = '/var/log/some.log {\n rotate 123\n daily\n}' | 14 | contents = "/var/log/some.log {\n rotate 123\n daily\n}" |
581 | 15 | count = logrotate.calculate_count(contents, logrotate.retention) | 15 | count = logrotate.calculate_count(contents, logrotate.retention) |
582 | 16 | assert count == 90 | 16 | assert count == 90 |
583 | 17 | 17 | ||
584 | 18 | def test_weekly_retention_count(self, logrotate): | 18 | def test_weekly_retention_count(self, logrotate): |
585 | 19 | """Test weekly retention count.""" | 19 | """Test weekly retention count.""" |
586 | 20 | logrotate.retention = 21 | 20 | logrotate.retention = 21 |
588 | 21 | contents = '/var/log/some.log {\n rotate 123\n weekly\n}' | 21 | contents = "/var/log/some.log {\n rotate 123\n weekly\n}" |
589 | 22 | count = logrotate.calculate_count(contents, logrotate.retention) | 22 | count = logrotate.calculate_count(contents, logrotate.retention) |
590 | 23 | assert count == 3 | 23 | assert count == 3 |
591 | 24 | 24 | ||
592 | 25 | def test_monthly_retention_count(self, logrotate): | 25 | def test_monthly_retention_count(self, logrotate): |
593 | 26 | """Test monthly retention count.""" | 26 | """Test monthly retention count.""" |
594 | 27 | logrotate.retention = 60 | 27 | logrotate.retention = 60 |
596 | 28 | contents = '/var/log/some.log {\n rotate 123\n monthly\n}' | 28 | contents = "/var/log/some.log {\n rotate 123\n monthly\n}" |
597 | 29 | count = logrotate.calculate_count(contents, logrotate.retention) | 29 | count = logrotate.calculate_count(contents, logrotate.retention) |
598 | 30 | assert count == 2 | 30 | assert count == 2 |
599 | 31 | 31 | ||
600 | 32 | def test_yearly_retention_count(self, logrotate): | 32 | def test_yearly_retention_count(self, logrotate): |
601 | 33 | """Test yearly retention count.""" | 33 | """Test yearly retention count.""" |
602 | 34 | logrotate.retention = 180 | 34 | logrotate.retention = 180 |
604 | 35 | contents = '/var/log/some.log {\n rotate 123\n yearly\n}' | 35 | contents = "/var/log/some.log {\n rotate 123\n yearly\n}" |
605 | 36 | count = logrotate.calculate_count(contents, logrotate.retention) | 36 | count = logrotate.calculate_count(contents, logrotate.retention) |
606 | 37 | assert count == 1 | 37 | assert count == 1 |
607 | 38 | 38 | ||
608 | @@ -42,9 +42,15 @@ class TestLogrotateHelper(): | |||
609 | 42 | logrotate.retention = 42 | 42 | logrotate.retention = 42 |
610 | 43 | logrotate.override = [] | 43 | logrotate.override = [] |
611 | 44 | logrotate.override_files = [] | 44 | logrotate.override_files = [] |
613 | 45 | contents = '/log/some.log {\n rotate 123\n daily\n}\n/log/other.log {\n rotate 456\n weekly\n}' | 45 | contents = ( |
614 | 46 | "/log/some.log {\n rotate 123\n daily\n}\n" | ||
615 | 47 | "/log/other.log {\n rotate 456\n weekly\n}" | ||
616 | 48 | ) | ||
617 | 46 | mod_contents = logrotate.modify_content(logrotate, contents, file_path) | 49 | mod_contents = logrotate.modify_content(logrotate, contents, file_path) |
619 | 47 | expected_contents = '/log/some.log {\n rotate 42\n daily\n}\n\n/log/other.log {\n rotate 6\n weekly\n}\n' | 50 | expected_contents = ( |
620 | 51 | "/log/some.log {\n rotate 42\n daily\n}\n\n" | ||
621 | 52 | "/log/other.log {\n rotate 6\n weekly\n}\n" | ||
622 | 53 | ) | ||
623 | 48 | assert mod_contents == expected_contents | 54 | assert mod_contents == expected_contents |
624 | 49 | 55 | ||
625 | 50 | def test_modify_content_override(self, logrotate): | 56 | def test_modify_content_override(self, logrotate): |
626 | @@ -53,7 +59,13 @@ class TestLogrotateHelper(): | |||
627 | 53 | logrotate.retention = 42 | 59 | logrotate.retention = 42 |
628 | 54 | logrotate.override = [] | 60 | logrotate.override = [] |
629 | 55 | logrotate.override_files = [] | 61 | logrotate.override_files = [] |
631 | 56 | contents = '/log/some.log {\n rotate 123\n daily\n}\n/log/other.log {\n rotate 456\n weekly\n}' | 62 | contents = ( |
632 | 63 | "/log/some.log {\n rotate 123\n daily\n}\n" | ||
633 | 64 | "/log/other.log {\n rotate 456\n weekly\n}" | ||
634 | 65 | ) | ||
635 | 57 | mod_contents = logrotate.modify_content(logrotate, contents, file_path) | 66 | mod_contents = logrotate.modify_content(logrotate, contents, file_path) |
637 | 58 | expected_contents = '/log/some.log {\n rotate 42\n daily\n}\n\n/log/other.log {\n rotate 6\n weekly\n}\n' | 67 | expected_contents = ( |
638 | 68 | "/log/some.log {\n rotate 42\n daily\n}\n\n" | ||
639 | 69 | "/log/other.log {\n rotate 6\n weekly\n}\n" | ||
640 | 70 | ) | ||
641 | 59 | assert mod_contents == expected_contents | 71 | assert mod_contents == expected_contents |
642 | diff --git a/src/tox.ini b/src/tox.ini | |||
643 | index 78da1be..2900ead 100644 | |||
644 | --- a/src/tox.ini | |||
645 | +++ b/src/tox.ini | |||
646 | @@ -25,7 +25,7 @@ passenv = | |||
647 | 25 | [testenv:lint] | 25 | [testenv:lint] |
648 | 26 | commands = | 26 | commands = |
649 | 27 | flake8 | 27 | flake8 |
651 | 28 | #TODO black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" . | 28 | black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" . |
652 | 29 | deps = | 29 | deps = |
653 | 30 | black | 30 | black |
654 | 31 | flake8 | 31 | flake8 |
655 | @@ -43,12 +43,9 @@ exclude = | |||
656 | 43 | mod, | 43 | mod, |
657 | 44 | .build | 44 | .build |
658 | 45 | 45 | ||
660 | 46 | #max-line-length = 88 | 46 | max-line-length = 88 |
661 | 47 | max-complexity = 10 | 47 | max-complexity = 10 |
662 | 48 | 48 | ||
663 | 49 | # from old tox.ini | ||
664 | 50 | max-line-length = 120 | ||
665 | 51 | |||
666 | 52 | [testenv:black] | 49 | [testenv:black] |
667 | 53 | commands = | 50 | commands = |
668 | 54 | black --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" . | 51 | black --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" . |
This merge proposal is being monitored by mergebot. Change the status to Approved to merge.