Merge ~silverdrake11/ubuntu/+source/landscape-client:ubuntu/mantic-devel into ubuntu/+source/landscape-client:ubuntu/mantic-devel
- Git
- lp:~silverdrake11/ubuntu/+source/landscape-client
- ubuntu/mantic-devel
- Merge into ubuntu/mantic-devel
Status: | Merged |
---|---|
Merged at revision: | 08afd8dad6238cb5f8f50865e928296f20169759 |
Proposed branch: | ~silverdrake11/ubuntu/+source/landscape-client:ubuntu/mantic-devel |
Merge into: | ubuntu/+source/landscape-client:ubuntu/mantic-devel |
Diff against target: |
57671 lines (+22146/-11153) 300 files modified
.flake8 (+5/-0) .gitignore (+6/-0) .pre-commit-config.yaml (+43/-0) LICENSE (+5/-5) Makefile (+45/-4) README (+103/-2) debian/README.source (+1/-1) debian/changelog (+37/-15) debian/copyright (+0/-1) debian/landscape-client.postrm (+1/-1) debian/watch (+1/-1) dev/landscape-client-vm (+2/-2) dev/null (+0/-66) dev/upload-to-ppa (+1/-1) display_py2_testresults (+6/-4) example.conf (+17/-1) landscape-client.conf (+0/-1) landscape/__init__.py (+2/-2) landscape/client/accumulate.py (+15/-8) landscape/client/amp.py (+9/-7) landscape/client/broker/amp.py (+24/-19) landscape/client/broker/client.py (+44/-25) landscape/client/broker/config.py (+62/-31) landscape/client/broker/exchange.py (+109/-65) landscape/client/broker/exchangestore.py (+21/-8) landscape/client/broker/ping.py (+40/-20) landscape/client/broker/registration.py (+62/-43) landscape/client/broker/server.py (+35/-19) landscape/client/broker/service.py (+60/-24) landscape/client/broker/store.py (+78/-19) landscape/client/broker/tests/helpers.py (+82/-45) landscape/client/broker/tests/test_amp.py (+28/-19) landscape/client/broker/tests/test_client.py (+33/-18) landscape/client/broker/tests/test_config.py (+28/-17) landscape/client/broker/tests/test_exchange.py (+276/-154) landscape/client/broker/tests/test_exchangestore.py (+21/-12) landscape/client/broker/tests/test_ping.py (+42/-27) landscape/client/broker/tests/test_registration.py (+136/-85) landscape/client/broker/tests/test_server.py (+109/-54) landscape/client/broker/tests/test_service.py (+7/-7) landscape/client/broker/tests/test_store.py (+173/-68) landscape/client/broker/tests/test_transport.py (+75/-35) landscape/client/broker/transport.py (+60/-27) landscape/client/configuration.py (+326/-232) landscape/client/deployment.py (+95/-50) landscape/client/lockfile.py (+2/-2) landscape/client/manager/aptsources.py (+43/-21) landscape/client/manager/config.py (+41/-22) landscape/client/manager/customgraph.py (+75/-34) landscape/client/manager/fakepackagemanager.py (+40/-24) landscape/client/manager/hardwareinfo.py (+10/-4) landscape/client/manager/keystonetoken.py (+23/-14) landscape/client/manager/manager.py (+2/-2) landscape/client/manager/packagemanager.py (+30/-16) landscape/client/manager/plugin.py (+17/-9) landscape/client/manager/processkiller.py (+35/-21) landscape/client/manager/scriptexecution.py (+97/-55) landscape/client/manager/service.py (+21/-13) landscape/client/manager/shutdownmanager.py (+47/-29) landscape/client/manager/snapmanager.py (+271/-0) landscape/client/manager/store.py (+30/-16) landscape/client/manager/tests/test_aptsources.py (+237/-92) landscape/client/manager/tests/test_config.py (+26/-13) landscape/client/manager/tests/test_customgraph.py (+460/-229) landscape/client/manager/tests/test_fakepackagemanager.py (+39/-20) landscape/client/manager/tests/test_hardwareinfo.py (+9/-6) landscape/client/manager/tests/test_keystonetoken.py (+20/-15) landscape/client/manager/tests/test_manager.py (+2/-2) landscape/client/manager/tests/test_packagemanager.py (+51/-29) landscape/client/manager/tests/test_plugin.py (+44/-17) landscape/client/manager/tests/test_processkiller.py (+173/-79) landscape/client/manager/tests/test_scriptexecution.py (+377/-176) landscape/client/manager/tests/test_service.py (+8/-6) landscape/client/manager/tests/test_shutdownmanager.py (+48/-18) landscape/client/manager/tests/test_snapmanager.py (+259/-0) landscape/client/manager/tests/test_store.py (+10/-12) landscape/client/manager/tests/test_usermanager.py (+1068/-563) landscape/client/manager/usermanager.py (+70/-44) landscape/client/monitor/activeprocessinfo.py (+18/-10) landscape/client/monitor/aptpreferences.py (+10/-7) landscape/client/monitor/cephusage.py (+49/-22) landscape/client/monitor/computerinfo.py (+75/-38) landscape/client/monitor/computertags.py (+1/-1) landscape/client/monitor/computeruptime.py (+24/-13) landscape/client/monitor/config.py (+32/-11) landscape/client/monitor/cpuusage.py (+40/-19) landscape/client/monitor/livepatch.py (+71/-0) landscape/client/monitor/loadaverage.py (+34/-15) landscape/client/monitor/memoryinfo.py (+37/-16) landscape/client/monitor/monitor.py (+10/-5) landscape/client/monitor/mountinfo.py (+48/-28) landscape/client/monitor/networkactivity.py (+30/-13) landscape/client/monitor/networkdevice.py (+12/-9) landscape/client/monitor/packagemonitor.py (+54/-29) landscape/client/monitor/plugin.py (+15/-7) landscape/client/monitor/processorinfo.py (+44/-23) landscape/client/monitor/rebootrequired.py (+14/-8) landscape/client/monitor/service.py (+41/-17) landscape/client/monitor/snapmonitor.py (+44/-0) landscape/client/monitor/swiftusage.py (+37/-18) landscape/client/monitor/temperature.py (+40/-18) landscape/client/monitor/tests/test_activeprocessinfo.py (+679/-288) landscape/client/monitor/tests/test_aptpreferences.py (+84/-41) landscape/client/monitor/tests/test_cephusage.py (+28/-14) landscape/client/monitor/tests/test_computerinfo.py (+108/-56) landscape/client/monitor/tests/test_computertags.py (+14/-13) landscape/client/monitor/tests/test_computeruptime.py (+112/-40) landscape/client/monitor/tests/test_config.py (+6/-4) landscape/client/monitor/tests/test_cpuusage.py (+14/-10) landscape/client/monitor/tests/test_livepatch.py (+140/-0) landscape/client/monitor/tests/test_loadaverage.py (+52/-23) landscape/client/monitor/tests/test_memoryinfo.py (+48/-22) landscape/client/monitor/tests/test_monitor.py (+12/-6) landscape/client/monitor/tests/test_mountinfo.py (+333/-139) landscape/client/monitor/tests/test_networkactivity.py (+46/-25) landscape/client/monitor/tests/test_networkdevice.py (+7/-6) landscape/client/monitor/tests/test_packagemonitor.py (+40/-26) landscape/client/monitor/tests/test_plugin.py (+31/-14) landscape/client/monitor/tests/test_processorinfo.py (+106/-78) landscape/client/monitor/tests/test_rebootrequired.py (+49/-27) landscape/client/monitor/tests/test_service.py (+11/-9) landscape/client/monitor/tests/test_snapmonitor.py (+50/-0) landscape/client/monitor/tests/test_swiftusage.py (+154/-91) landscape/client/monitor/tests/test_temperature.py (+59/-35) landscape/client/monitor/tests/test_ubuntuproinfo.py (+5/-5) landscape/client/monitor/tests/test_ubuntuprorebootrequired.py (+29/-0) landscape/client/monitor/tests/test_updatemanager.py (+16/-10) landscape/client/monitor/tests/test_usermonitor.py (+327/-144) landscape/client/monitor/ubuntuproinfo.py (+11/-7) landscape/client/monitor/ubuntuprorebootrequired.py (+27/-0) landscape/client/monitor/updatemanager.py (+11/-12) landscape/client/monitor/usermonitor.py (+40/-21) landscape/client/package/changer.py (+134/-69) landscape/client/package/releaseupgrader.py (+101/-49) landscape/client/package/reporter.py (+200/-126) landscape/client/package/taskhandler.py (+42/-25) landscape/client/package/tests/test_changer.py (+705/-355) landscape/client/package/tests/test_releaseupgrader.py (+349/-214) landscape/client/package/tests/test_reporter.py (+663/-303) landscape/client/package/tests/test_taskhandler.py (+82/-39) landscape/client/patch.py (+8/-6) landscape/client/reactor.py (+1/-1) landscape/client/service.py (+30/-17) landscape/client/serviceconfig.py (+130/-0) landscape/client/snap/__init__.py (+0/-0) landscape/client/snap/http.py (+302/-0) landscape/client/snap/tests/__init__.py (+0/-0) landscape/client/snap/tests/test_http.py (+51/-0) landscape/client/tests/clock.py (+66/-46) landscape/client/tests/helpers.py (+76/-53) landscape/client/tests/subunit.py (+133/-106) landscape/client/tests/test_accumulate.py (+3/-2) landscape/client/tests/test_amp.py (+33/-27) landscape/client/tests/test_configuration.py (+1241/-862) landscape/client/tests/test_deployment.py (+44/-29) landscape/client/tests/test_diff.py (+4/-4) landscape/client/tests/test_lockfile.py (+7/-3) landscape/client/tests/test_patch.py (+11/-8) landscape/client/tests/test_reactor.py (+1/-2) landscape/client/tests/test_service.py (+14/-11) landscape/client/tests/test_serviceconfig.py (+223/-0) landscape/client/tests/test_watchdog.py (+377/-226) landscape/client/upgraders/__init__.py (+5/-2) landscape/client/upgraders/tests/test_broker.py (+1/-3) landscape/client/upgraders/tests/test_monitor.py (+1/-3) landscape/client/upgraders/tests/test_package.py (+1/-3) landscape/client/user/changes.py (+13/-7) landscape/client/user/management.py (+142/-68) landscape/client/user/provider.py (+83/-35) landscape/client/user/tests/helpers.py (+78/-35) landscape/client/user/tests/test_changes.py (+121/-63) landscape/client/user/tests/test_management.py (+406/-168) landscape/client/user/tests/test_provider.py (+503/-230) landscape/client/watchdog.py (+187/-96) landscape/constants.py (+15/-2) landscape/lib/amp.py (+94/-50) landscape/lib/apt/package/facade.py (+178/-107) landscape/lib/apt/package/skeleton.py (+89/-44) landscape/lib/apt/package/store.py (+111/-84) landscape/lib/apt/package/testing.py (+243/-186) landscape/lib/apt/package/tests/test_facade.py (+1063/-411) landscape/lib/apt/package/tests/test_skeleton.py (+90/-37) landscape/lib/apt/package/tests/test_store.py (+87/-55) landscape/lib/backoff.py (+1/-1) landscape/lib/base64.py (+0/-2) landscape/lib/bootstrap.py (+4/-8) landscape/lib/bpickle.py (+67/-63) landscape/lib/cli.py (+9/-4) landscape/lib/cloud.py (+8/-4) landscape/lib/compat.py (+5/-0) landscape/lib/config.py (+52/-33) landscape/lib/disk.py (+44/-17) landscape/lib/fd.py (+0/-1) landscape/lib/fetch.py (+40/-19) landscape/lib/format.py (+5/-5) landscape/lib/fs.py (+0/-1) landscape/lib/gpg.py (+25/-14) landscape/lib/jiffies.py (+3/-3) landscape/lib/juju.py (+3/-4) landscape/lib/lock.py (+2/-2) landscape/lib/log.py (+0/-2) landscape/lib/logging.py (+51/-23) landscape/lib/lsb_release.py (+4/-3) landscape/lib/message.py (+3/-2) landscape/lib/monitor.py (+70/-37) landscape/lib/network.py (+63/-37) landscape/lib/persist.py (+53/-35) landscape/lib/plugin.py (+2/-4) landscape/lib/process.py (+35/-17) landscape/lib/reactor.py (+31/-19) landscape/lib/schema.py (+63/-36) landscape/lib/scriptcontent.py (+1/-1) landscape/lib/sequenceranges.py (+9/-8) landscape/lib/store.py (+3/-0) landscape/lib/sysstats.py (+42/-26) landscape/lib/testing.py (+184/-115) landscape/lib/tests/test_amp.py (+128/-84) landscape/lib/tests/test_backoff.py (+5/-6) landscape/lib/tests/test_bootstrap.py (+17/-12) landscape/lib/tests/test_bpickle.py (+11/-13) landscape/lib/tests/test_cloud.py (+56/-27) landscape/lib/tests/test_config.py (+113/-75) landscape/lib/tests/test_disk.py (+42/-24) landscape/lib/tests/test_encoding.py (+12/-11) landscape/lib/tests/test_fd.py (+4/-5) landscape/lib/tests/test_fetch.py (+253/-170) landscape/lib/tests/test_format.py (+15/-11) landscape/lib/tests/test_fs.py (+35/-27) landscape/lib/tests/test_gpg.py (+37/-21) landscape/lib/tests/test_juju.py (+43/-25) landscape/lib/tests/test_lock.py (+4/-4) landscape/lib/tests/test_logging.py (+22/-10) landscape/lib/tests/test_lsb_release.py (+46/-29) landscape/lib/tests/test_monitor.py (+54/-34) landscape/lib/tests/test_network.py (+217/-138) landscape/lib/tests/test_persist.py (+94/-74) landscape/lib/tests/test_plugin.py (+8/-6) landscape/lib/tests/test_process.py (+33/-24) landscape/lib/tests/test_reactor.py (+26/-12) landscape/lib/tests/test_schema.py (+55/-32) landscape/lib/tests/test_scriptcontent.py (+7/-6) landscape/lib/tests/test_sequenceranges.py (+25/-21) landscape/lib/tests/test_sysstats.py (+82/-48) landscape/lib/tests/test_tag.py (+23/-19) landscape/lib/tests/test_timestamp.py (+1/-1) landscape/lib/tests/test_twisted_util.py (+27/-12) landscape/lib/tests/test_versioning.py (+2/-3) landscape/lib/tests/test_vm_info.py (+10/-8) landscape/lib/tests/test_warning.py (+9/-6) landscape/lib/twisted_util.py (+43/-18) landscape/lib/user.py (+1/-2) landscape/lib/versioning.py (+6/-4) landscape/lib/vm_info.py (+4/-3) landscape/lib/warning.py (+0/-1) landscape/message_schemas/__init__.py (+0/-1) landscape/message_schemas/message.py (+8/-4) landscape/message_schemas/server_bound.py (+682/-374) landscape/message_schemas/test_message.py (+15/-9) landscape/sysinfo/deployment.py (+67/-29) landscape/sysinfo/disk.py (+26/-16) landscape/sysinfo/landscapelink.py (+3/-3) landscape/sysinfo/load.py (+4/-3) landscape/sysinfo/loggedinusers.py (+2/-2) landscape/sysinfo/memory.py (+9/-6) landscape/sysinfo/network.py (+15/-7) landscape/sysinfo/processes.py (+18/-8) landscape/sysinfo/sysinfo.py (+40/-21) landscape/sysinfo/temperature.py (+4/-5) landscape/sysinfo/testplugin.py (+1/-2) landscape/sysinfo/tests/test_deployment.py (+93/-52) landscape/sysinfo/tests/test_disk.py (+113/-50) landscape/sysinfo/tests/test_landscapelink.py (+7/-5) landscape/sysinfo/tests/test_load.py (+4/-7) landscape/sysinfo/tests/test_loggedinusers.py (+14/-10) landscape/sysinfo/tests/test_memory.py (+8/-7) landscape/sysinfo/tests/test_network.py (+54/-39) landscape/sysinfo/tests/test_processes.py (+38/-17) landscape/sysinfo/tests/test_sysinfo.py (+182/-136) landscape/sysinfo/tests/test_temperature.py (+11/-9) man/landscape-client.1 (+4/-4) man/landscape-client.txt (+4/-4) man/landscape-config.1 (+28/-20) man/landscape-config.txt (+18/-14) man/landscape-sysinfo.txt (+6/-7) pqm-tests.sh (+0/-1) pyproject.toml (+13/-0) scripts/landscape-broker (+3/-1) scripts/landscape-client (+5/-2) scripts/landscape-config (+4/-1) scripts/landscape-manager (+3/-1) scripts/landscape-monitor (+3/-1) scripts/landscape-package-changer (+3/-1) scripts/landscape-package-reporter (+3/-1) scripts/landscape-release-upgrader (+3/-1) scripts/landscape-sysinfo (+6/-2) setup.py (+34/-29) setup_client.py (+30/-29) setup_lib.py (+19/-18) setup_sysinfo.py (+8/-9) snap/snapcraft.yaml (+98/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Lucas Kanashiro (community) | Approve | ||
git-ubuntu import | Pending | ||
Review via email: mp+449306@code.launchpad.net |
Commit message
Description of the change
Kevin Nasto (silverdrake11) wrote : | # |
Lucas Kanashiro (lucaskanashiro) wrote : | # |
Thanks for this MP Kevin!
Initially, I needed to update the d/watch to be able to fetch the upstream tarball:
diff --git a/debian/watch b/debian/watch
index 3592b51..ba7ea91 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,3 +1,3 @@
version=4
opts=filenamem
- https:/
+ https:/
I'd recommend to incorporate that change to your package.
I talked to Kevin privately and also asked him to update this line:
https:/
to 23.08 (new upstream release).
The only other change related to the package itself that I found is in this commit:
commit a0ecf857a8a883d
Author: Kevin Nasto <email address hidden>
Date: Fri Mar 10 13:25:12 2023 -0600
Changed gpg file name to be less generic (LP: #2008432) (#137)
This is the change and I believe it is fine to get in:
diff --git a/debian/
index 10f79b8..aa34ed2 100644
--- a/debian/
+++ b/debian/
@@ -29,7 +29,7 @@ case "$1" in
rm -f "${LOG_
rm -f "${LOG_
- rm -f "${GPG_
+ rm -f "${GPG_
rm -rf "${DATA_
rm -rf "${DATA_
There are 2 lintian errors which are red flags in a first glance:
E: landscape-client source: alien-tag dh_python-
N:
N: The given override refers to an unknown tag.
N:
N: Please refer to Format of override files (Section 2.4.1) in the Lintian
N: User's Manual for details.
N:
N: Visibility: error
N: Show-Always: yes
N: Check: debian/
N:
N:
E: landscape-common: depends-
N:
N: The package depends on a package that has been superseded. If the
N: superseded package is part of an ORed group, it should not be the first
N: package in the group.
N:
N: Visibility: error
N: Show-Always: no
N: Check: fields/
N:
N:
The first one seems to me you added a lintian overrides which will be used just in some ubuntu releases. But it seems this tag does not exist anymore, at least in Mantic's lintian version. I'd remove that TBH.
The second one is about the dependency on lsb-base. I'd consider its removal as well since it is obsolete, but if you are thinking about backporting this to other releases, please check if it is obsolete there as well.
Lucas Kanashiro (lucaskanashiro) : | # |
Lucas Kanashiro (lucaskanashiro) wrote : | # |
Thanks for addressing my comments Kevin!
Since you decided to remove the dependency on lsb-base, I think you should remove it from here as well:
https:/
Lucas Kanashiro (lucaskanashiro) wrote : | # |
As discussed with Kevin, let's keep lsb-base so he can test it later to make sure it will not impact other supported ubuntu releases.
There are also some improvements that can be made in the package reported by lintian, I will not block this MP because of this, the feature freeze is coming, let's get this uploaded.
Lucas Kanashiro (lucaskanashiro) wrote : | # |
Package uploaded:
Uploading landscape-
Uploading landscape-
Uploading landscape-
Uploading landscape-
Uploading landscape-
Preview Diff
1 | diff --git a/.flake8 b/.flake8 |
2 | new file mode 100644 |
3 | index 0000000..c3a3cd2 |
4 | --- /dev/null |
5 | +++ b/.flake8 |
6 | @@ -0,0 +1,5 @@ |
7 | +[flake8] |
8 | +max-line-length = 79 |
9 | +max-complexity = 18 |
10 | +select = B,C,E,F,W,T4,B9 |
11 | +ignore = E203, W503 |
12 | diff --git a/.gitignore b/.gitignore |
13 | index ca1df98..8ce4558 100644 |
14 | --- a/.gitignore |
15 | +++ b/.gitignore |
16 | @@ -25,3 +25,9 @@ tags |
17 | _last_py2_res |
18 | *.pyc |
19 | .cache |
20 | +_trial_temp* |
21 | +*.snap |
22 | +landscape-client_amd64*.txt |
23 | +landscape-client_arm64*.txt |
24 | +landscape-client_ppc64el*.txt |
25 | +landscape-client_s390x*.txt |
26 | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml |
27 | new file mode 100644 |
28 | index 0000000..df96450 |
29 | --- /dev/null |
30 | +++ b/.pre-commit-config.yaml |
31 | @@ -0,0 +1,43 @@ |
32 | +# See https://pre-commit.com for more information |
33 | +# See https://pre-commit.com/hooks.html for more hooks |
34 | +repos: |
35 | +- repo: https://github.com/pre-commit/pre-commit-hooks |
36 | + rev: v4.4.0 |
37 | + hooks: |
38 | + - id: trailing-whitespace |
39 | + - id: end-of-file-fixer |
40 | + - id: check-yaml |
41 | + - id: check-added-large-files |
42 | + - id: debug-statements |
43 | +- repo: https://github.com/pre-commit/pre-commit-hooks |
44 | + rev: v2.3.0 |
45 | + hooks: |
46 | + - id: flake8 |
47 | + args: |
48 | + - "--max-line-length=79" |
49 | + - "--select=B,C,E,F,W,T4,B9" |
50 | + - "--ignore=E203,W503" |
51 | +- repo: https://github.com/psf/black |
52 | + rev: 22.12.0 |
53 | + hooks: |
54 | + - id: black |
55 | + args: |
56 | + - --line-length=79 |
57 | + - --include='\.pyi?$' |
58 | +- repo: https://github.com/asottile/reorder_python_imports |
59 | + rev: v2.3.0 |
60 | + hooks: |
61 | + - id: reorder-python-imports |
62 | + args: [--py3-plus] |
63 | +- repo: https://github.com/asottile/add-trailing-comma |
64 | + rev: v2.0.1 |
65 | + hooks: |
66 | + - id: add-trailing-comma |
67 | + args: [--py36-plus] |
68 | +exclude: > |
69 | + (?x)( |
70 | + \.git |
71 | + | \.csv$ |
72 | + | \.__pycache__ |
73 | + | \.log$ |
74 | + ) |
75 | diff --git a/LICENSE b/LICENSE |
76 | index 5b6e7c6..dcfa4c2 100644 |
77 | --- a/LICENSE |
78 | +++ b/LICENSE |
79 | @@ -55,7 +55,7 @@ patent must be licensed for everyone's free use or not licensed at all. |
80 | |
81 | The precise terms and conditions for copying, distribution and |
82 | modification follow. |
83 | - |
84 | |
85 | + |
86 | GNU GENERAL PUBLIC LICENSE |
87 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
88 | |
89 | @@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions: |
90 | License. (Exception: if the Program itself is interactive but |
91 | does not normally print such an announcement, your work based on |
92 | the Program is not required to print an announcement.) |
93 | - |
94 | |
95 | + |
96 | These requirements apply to the modified work as a whole. If |
97 | identifiable sections of that work are not derived from the Program, |
98 | and can be reasonably considered independent and separate works in |
99 | @@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent |
100 | access to copy the source code from the same place counts as |
101 | distribution of the source code, even though third parties are not |
102 | compelled to copy the source along with the object code. |
103 | - |
104 | |
105 | + |
106 | 4. You may not copy, modify, sublicense, or distribute the Program |
107 | except as expressly provided under this License. Any attempt |
108 | otherwise to copy, modify, sublicense or distribute the Program is |
109 | @@ -225,7 +225,7 @@ impose that choice. |
110 | |
111 | This section is intended to make thoroughly clear what is believed to |
112 | be a consequence of the rest of this License. |
113 | - |
114 | |
115 | + |
116 | 8. If the distribution and/or use of the Program is restricted in |
117 | certain countries either by patents or by copyrighted interfaces, the |
118 | original copyright holder who places the Program under this License |
119 | @@ -278,7 +278,7 @@ PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE |
120 | POSSIBILITY OF SUCH DAMAGES. |
121 | |
122 | END OF TERMS AND CONDITIONS |
123 | - |
124 | |
125 | + |
126 | How to Apply These Terms to Your New Programs |
127 | |
128 | If you develop a new program, and you want it to be of the greatest |
129 | diff --git a/Makefile b/Makefile |
130 | index fe183ec..09ade0e 100644 |
131 | --- a/Makefile |
132 | +++ b/Makefile |
133 | @@ -2,9 +2,15 @@ PYDOCTOR ?= pydoctor |
134 | TXT2MAN ?= txt2man |
135 | PYTHON2 ?= python2 |
136 | PYTHON3 ?= python3 |
137 | +SNAPCRAFT = SNAPCRAFT_BUILD_INFO=1 snapcraft |
138 | TRIAL ?= -m twisted.trial |
139 | TRIAL_ARGS ?= |
140 | |
141 | +# PEP8 rules ignored: |
142 | +# W503 https://www.flake8rules.com/rules/W503.html |
143 | +# E203 Whitespace before ':' (enforced by Black) |
144 | +PEP8_IGNORED = W503,E203 |
145 | + |
146 | .PHONY: help |
147 | help: ## Print help about available targets |
148 | @grep -h -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' |
149 | @@ -15,11 +21,15 @@ depends: depends3 ## py2 is deprecated |
150 | |
151 | .PHONY: depends2 |
152 | depends2: |
153 | - sudo apt-get -y install python-twisted-core python-distutils-extra python-mock python-configobj python-netifaces python-pycurl |
154 | + sudo apt-get -y install python-twisted-core python-distutils-extra python-mock python-configobj python-netifaces python-pycurl python-pip |
155 | + pip install pre-commit |
156 | + pre-commit install |
157 | |
158 | .PHONY: depends3 |
159 | depends3: |
160 | - sudo apt-get -y install python3-twisted python3-distutils-extra python3-mock python3-configobj python3-netifaces python3-pycurl |
161 | + sudo apt-get -y install python3-twisted python3-distutils-extra python3-mock python3-configobj python3-netifaces python3-pycurl python3-pip |
162 | + pip3 install pre-commit |
163 | + pre-commit install |
164 | |
165 | all: build |
166 | |
167 | @@ -56,13 +66,15 @@ coverage: |
168 | |
169 | .PHONY: lint |
170 | lint: |
171 | - $(PYTHON3) -m flake8 --ignore E24,E121,E123,E125,E126,E221,E226,E266,E704,E265,W504 \ |
172 | - `find landscape -name \*.py` |
173 | + $(PYTHON3) -m flake8 --ignore $(PEP8_IGNORED) `find landscape -name \*.py` |
174 | |
175 | .PHONY: pyflakes |
176 | pyflakes: |
177 | -pyflakes `find landscape -name \*.py` |
178 | |
179 | +pre-commit: |
180 | + -pre-commit run -a |
181 | + |
182 | clean: |
183 | -find landscape -name __pycache__ -exec rm -rf {} \; |
184 | -find landscape -name \*.pyc -exec rm -f {} \; |
185 | @@ -115,6 +127,35 @@ tags: |
186 | etags: |
187 | -etags --languages=python -R . |
188 | |
189 | +snap-install: |
190 | + sudo snap install --devmode landscape-client_0.1_amd64.snap |
191 | +.PHONY: snap-install |
192 | + |
193 | +snap-remote-build: |
194 | + snapcraft remote-build |
195 | +.PHONY: snap-remote-build |
196 | + |
197 | +snap-remove: |
198 | + sudo snap remove --purge landscape-client |
199 | +.PHONY: snap-remove |
200 | + |
201 | +snap-shell: snap-install |
202 | + sudo snap run --shell landscape-client.landscape-client |
203 | +.PHONY: snap-shell |
204 | + |
205 | +snap-debug: |
206 | + $(SNAPCRAFT) -v --debug |
207 | +.PHONY: snap-debug |
208 | + |
209 | +snap-clean: snap-remove |
210 | + $(SNAPCRAFT) clean |
211 | + -rm landscape-client_0.1_amd64.snap |
212 | +.PHONY: snap-clean |
213 | + |
214 | +snap: |
215 | + $(SNAPCRAFT) |
216 | +.PHONY: snap |
217 | + |
218 | include Makefile.packaging |
219 | |
220 | .DEFAULT_GOAL := help |
221 | diff --git a/README b/README |
222 | index 06be0e1..8751ef3 100644 |
223 | --- a/README |
224 | +++ b/README |
225 | @@ -5,7 +5,7 @@ |
226 | |
227 | Add our beta PPA to get the latest updates to the landscape-client package |
228 | |
229 | -#### Add repo to an Ubuntu series |
230 | +#### Add repo to an Ubuntu series |
231 | ``` |
232 | sudo add-apt-repository ppa:landscape/self-hosted-beta |
233 | ``` |
234 | @@ -50,7 +50,7 @@ monitor_only = true |
235 | |
236 | ## Running |
237 | |
238 | -Now you can complete the configuration of your client and register with the |
239 | +Now you can complete the configuration of your client and register with the |
240 | Landscape service. There are two ways to do this: |
241 | |
242 | 1. `sudo landscape-config` and answer interactive prompts to finalize your configuration |
243 | @@ -86,3 +86,104 @@ Before opening a PR, make sure to run the full testsuite and lint |
244 | make check3 |
245 | make lint |
246 | ``` |
247 | + |
248 | +### Building the Landscape Client snap |
249 | + |
250 | +First, you need to ensure that you have the appropriate tools installed: |
251 | +``` |
252 | +$ sudo snap install snapcraft --classic |
253 | +$ lxd init --auto |
254 | +``` |
255 | + |
256 | +There are various make targets defined to assist in the lifecycle of |
257 | +building and testing the snap. To simply build the snap with the minimum |
258 | +of debug information displayed: |
259 | +``` |
260 | +$ make snap |
261 | +``` |
262 | + |
263 | +If you would prefer to see more information displayed showing the progress |
264 | +of the build, and would like to get dropped into a debug shell within the |
265 | +snap container in the event of an error: |
266 | +``` |
267 | +$ make snap-debug |
268 | +``` |
269 | + |
270 | +To install the resulting snap: |
271 | +``` |
272 | +$ make snap-install |
273 | +``` |
274 | + |
275 | +To remove a previously installed snap: |
276 | +``` |
277 | +$ make snap-remove |
278 | +``` |
279 | + |
280 | +To clean the intermediate files as well as the snap itself from the local |
281 | +build environment: |
282 | +``` |
283 | +$ make snap-clean |
284 | +``` |
285 | + |
286 | +To enter into a shell environment within the snap container: |
287 | +``` |
288 | +$ make snap-shell |
289 | +``` |
290 | + |
291 | +If you wish to upload the snap to the store, you will first need to get |
292 | +credentials with the store that allow you to log in locally and publish |
293 | +binaries. This can be done at: |
294 | + |
295 | +https://snapcraft.io/docs/creating-your-developer-account |
296 | + |
297 | +After obtaining and confirming your store credentials, you then need to |
298 | +log in using the snapcraft tool: |
299 | +``` |
300 | +$ snapcraft login |
301 | +``` |
302 | + |
303 | +Since snapcraft version 7.x and higher, the credentials are stored in the |
304 | +gnome keyring on your local workstation. If you are building in an |
305 | +environment without a GUI (e.g. in a multipass or lxc container), you |
306 | +will need to install the gnome keyring tools: |
307 | +``` |
308 | +$ sudo apt install gnome-keyring |
309 | +``` |
310 | + |
311 | +You will then need to initialze the default keyring as follows: |
312 | +``` |
313 | +$ dbus-run-session -- bash |
314 | +$ gnome-keyring-daemon --unlock |
315 | +``` |
316 | +The gnome-keyring-daemon will prompt you (without a prompt) to type in |
317 | +the initial unlock password (typically the same password for the account |
318 | +you are using - if you are using the default multipass or lxc "ubuntu" |
319 | +login, use sudo passwd ubuntu to set it to a known value before doing |
320 | +the above step). |
321 | + |
322 | +Type the login password and hit <ENTER> followed by <CTRL>+D to end |
323 | +the input. |
324 | + |
325 | +At this point, you should be able to log into snapcraft: |
326 | +``` |
327 | +$ snapcraft login |
328 | +``` |
329 | +You will be prompted for your UbuntuOne email address, password and, |
330 | +if set up this way, your second factor for authentication. If you |
331 | +are successful, you should be able to query your login credentials |
332 | +with: |
333 | +``` |
334 | +$ snapcraft whoami |
335 | +``` |
336 | +A common mistake that first-time users of this process might make |
337 | +is that after running the gnome-keyring-daemon command, they will |
338 | +exit the dbus session shell. Do NOT do that. Do all subsequent |
339 | +work in that bash shell that dbus set up for you because it will |
340 | +have access to your gnome-keyring. |
341 | + |
342 | +If you need to leave the environment and get back in, keep in mind |
343 | +that you do not have to be logged into the store UNLESS you are |
344 | +uploading the snap or otherwise manipulating things in your store |
345 | +account. You will need to repeat the dbus-run-session and |
346 | +gnome-keyring-daemon steps BEFORE logging in if you do need to be |
347 | +logged into the store. |
348 | diff --git a/debian/README.source b/debian/README.source |
349 | index d21d7e4..20371fc 100644 |
350 | --- a/debian/README.source |
351 | +++ b/debian/README.source |
352 | @@ -12,4 +12,4 @@ appreciated if you also updated the UPSTREAM_VERSION variable in |
353 | landscape/__init__.py to include the entire new client version number. This |
354 | helps us keep track of exact version of clients in use. There's no need to |
355 | update the DEBIAN_REVISION variable, as it gets automatically set at build |
356 | -time. |
357 | +time. |
358 | diff --git a/debian/changelog b/debian/changelog |
359 | index 4ba984f..2479e40 100644 |
360 | --- a/debian/changelog |
361 | +++ b/debian/changelog |
362 | @@ -1,3 +1,25 @@ |
363 | +landscape-client (23.08-0ubuntu1) mantic; urgency=medium |
364 | + |
365 | + * New upstream release 23.08 |
366 | + - Restructure landscape-config wizard (LP: #2031673) |
367 | + - Add SnapMonitor, SnapManager, and related machinery (LP: #2031682) |
368 | + - Limit message data directory size (LP: #2004591) |
369 | + - Add zfs and btrfs to stable fs-lists (LP: #1499104) |
370 | + - Test for broken control file (LP: #1813442) |
371 | + - Config man page and help info fixes (LP: #1662222) |
372 | + - Removed unnecesary select to the database (LP: #1994951) |
373 | + - Last apt-key removal (LP: #1990435) |
374 | + - Added a logging level check to provide a better error (LP: #2027521) |
375 | + - Broker is able to bootstrap the landscape-client folder (LP: #1868730) |
376 | + - Changed gpg file name to be less generic (LP: #2008432) |
377 | + - Improve Dependency data is read from the deb packages (LP: #1813442) |
378 | + - Fix error in swift plugin (LP: #2031674) |
379 | + - Repository profiles do not overwrite all configurations (LP: #2031680) |
380 | + - Remove old plugins (LP: #1989968) |
381 | + - Send ubuntu pro reboot output (LP: #2031684) |
382 | + |
383 | + -- Kevin Nasto <kevin.nasto@canonical.com> Thu, 17 Aug 2023 13:41:21 -0500 |
384 | + |
385 | landscape-client (23.02-0ubuntu1) lunar; urgency=medium |
386 | |
387 | * New upstream release 23.02: |
388 | @@ -934,11 +956,11 @@ landscape-client (1.0.21.1-0ubuntu2) intrepid; urgency=low |
389 | |
390 | landscape-client (1.0.21.1-0ubuntu1) intrepid; urgency=low |
391 | |
392 | - * New upstream version: |
393 | + * New upstream version: |
394 | * Add ok-no-register option to landscape-config script to not fail if |
395 | dbus isn't started or landscape-client isn't running. |
396 | * lower timeout related to package management in landscape. |
397 | - * debian/control: Depend on cron. |
398 | + * debian/control: Depend on cron. |
399 | * debian/landscape-client.postinst: use ok-no-register option so that the |
400 | postinst script doesn't fail when run from the installer. (LP: #274573). |
401 | |
402 | @@ -986,7 +1008,7 @@ landscape-client (1.0.18-0ubuntu4) intrepid; urgency=low |
403 | [ Mathias Gug ] |
404 | * debian/landscape-common.postinst, debian/landscape-common.prerm: don't |
405 | call update-motd init script as it's no longer available in the |
406 | - update-motd package. Call directly /usr/sbin/update-motd instead. |
407 | + update-motd package. Call directly /usr/sbin/update-motd instead. |
408 | (LP: #271854) |
409 | |
410 | -- Mathias Gug <mathiaz@ubuntu.com> Thu, 18 Sep 2008 16:47:08 -0400 |
411 | @@ -1006,15 +1028,15 @@ landscape-client (1.0.18-0ubuntu2) intrepid; urgency=low |
412 | command. A landscape account is not required to use this package. |
413 | - landscape-client: has all the binaries required to run the |
414 | landscape-client. Requires a landscape account. |
415 | - - debian/control: |
416 | + - debian/control: |
417 | + move some dependencies to landscape-client so that |
418 | - landscape-common doesn't install unecessary packages in the |
419 | + landscape-common doesn't install unecessary packages in the |
420 | default -server install. |
421 | + move python-gobject to a Pre-Depends so that landscape-config can |
422 | register the system during the postinst (LP: #268838). |
423 | * debian/control: |
424 | - depend on python-smartpm instead of smartpm-core. |
425 | - * debian/landscape-client.postrm: delete /etc/landscape/client.conf when |
426 | + * debian/landscape-client.postrm: delete /etc/landscape/client.conf when |
427 | the package is purged. |
428 | * debian/landscape-client.postinst: remove sysinfo_in_motd debconf question |
429 | as it wasn't used. |
430 | @@ -1030,7 +1052,7 @@ landscape-client (1.0.18-0ubuntu2) intrepid; urgency=low |
431 | |
432 | landscape-client (1.0.18-0ubuntu1) intrepid; urgency=low |
433 | |
434 | - * New upstream release |
435 | + * New upstream release |
436 | |
437 | -- Rick Clark <rick.clark@ubuntu.com> Mon, 08 Sep 2008 16:35:57 -0500 |
438 | |
439 | @@ -1149,7 +1171,7 @@ landscape-client (1.0.11-hardy1-landscape1) hardy; urgency=low |
440 | |
441 | landscape-client (1.0.10-hardy1-landscape1) hardy; urgency=low |
442 | |
443 | - * Change the utilisation of the csv module to be compatible with |
444 | + * Change the utilisation of the csv module to be compatible with |
445 | python 2.4 as used in Dapper. |
446 | |
447 | -- Andreas Hasenack <andreas@canonical.com> Thu, 12 Jun 2008 17:58:05 +0000 |
448 | @@ -1398,7 +1420,7 @@ landscape-client (0.10.3-1ubuntu1) feisty; urgency=low |
449 | fixed (#114829). |
450 | |
451 | -- Landscape Team <landscape-team@canonical.com> Mon, 15 May 2007 16:31:00 -0700 |
452 | - |
453 | + |
454 | landscape-client (0.10.2-1ubuntu1) feisty; urgency=low |
455 | |
456 | * New upstream release. |
457 | @@ -1412,7 +1434,7 @@ landscape-client (0.10.1-1ubuntu1) feisty; urgency=low |
458 | * Minor fix in package management plugin timings. |
459 | |
460 | -- Landscape Team <landscape-devel@lists.canonical.com> Thu, 10 May 2007 10:00:00 -0700 |
461 | - |
462 | + |
463 | landscape-client (0.10.0-1ubuntu1) feisty; urgency=low |
464 | |
465 | * New upstream release. |
466 | @@ -1422,9 +1444,9 @@ landscape-client (0.10.0-1ubuntu1) feisty; urgency=low |
467 | * The client uses the new operations system. Support for the now |
468 | unused action info system is gone. |
469 | * A minor bpickle bug was fixed. |
470 | - |
471 | + |
472 | -- Jamshed Kakar <jamshed.kakar@canonical.com> Mon, 7 May 2007 20:16:00 -0700 |
473 | - |
474 | + |
475 | landscape-client (0.9.6-1ubuntu1) feisty; urgency=low |
476 | |
477 | * New upstream release. |
478 | @@ -1507,7 +1529,7 @@ landscape-client (0.8.1-1) unstable; urgency=low |
479 | * New upstream release. |
480 | * Account registration log message no longer exposes account |
481 | password. |
482 | - |
483 | + |
484 | -- Jamshed Kakar <jamshed.kakar@canonical.com> Thu, 18 Jan 2007 23:07:00 -0800 |
485 | |
486 | landscape-client (0.8.0-1) unstable; urgency=low |
487 | @@ -1518,7 +1540,7 @@ landscape-client (0.8.0-1) unstable; urgency=low |
488 | * Client includes an SSL certificate to verify the server with. |
489 | * Package depends on python2.4-pycurl, which is necessary for the |
490 | new SSL support. |
491 | - |
492 | + |
493 | -- Jamshed Kakar <jamshed.kakar@canonical.com> Thu, 18 Jan 2007 10:48:00 -0800 |
494 | |
495 | landscape-client (0.7.0-1) unstable; urgency=low |
496 | @@ -1529,7 +1551,7 @@ landscape-client (0.7.0-1) unstable; urgency=low |
497 | added to control log verbosity. |
498 | * Package depends on perl-modules, which is necessary for bare-bones |
499 | server installs. |
500 | - |
501 | + |
502 | -- Jamshed Kakar <jamshed.kakar@canonical.com> Tue, 2 Jan 2007 12:54:00 -0800 |
503 | |
504 | landscape-client (0.6.1-1) unstable; urgency=low |
505 | diff --git a/debian/copyright b/debian/copyright |
506 | index 479d234..8b528c8 100644 |
507 | --- a/debian/copyright |
508 | +++ b/debian/copyright |
509 | @@ -33,4 +33,3 @@ License: |
510 | |
511 | On Debian systems, the complete text of the GNU General |
512 | Public License can be found in `/usr/share/common-licenses/GPL-2'. |
513 | - |
514 | diff --git a/debian/landscape-client.postrm b/debian/landscape-client.postrm |
515 | index 10f79b8..aa34ed2 100644 |
516 | --- a/debian/landscape-client.postrm |
517 | +++ b/debian/landscape-client.postrm |
518 | @@ -29,7 +29,7 @@ case "$1" in |
519 | rm -f "${LOG_DIR}/package-reporter.log"* |
520 | rm -f "${LOG_DIR}/package-changer.log"* |
521 | |
522 | - rm -f "${GPG_DIR}/landscape-server"*.asc |
523 | + rm -f "${GPG_DIR}/landscape-server-mirror"*.asc |
524 | |
525 | rm -rf "${DATA_DIR}/client" |
526 | rm -rf "${DATA_DIR}/.gnupg" |
527 | diff --git a/debian/source.lintian-overrides b/debian/source.lintian-overrides |
528 | deleted file mode 100644 |
529 | index 720d1be..0000000 |
530 | --- a/debian/source.lintian-overrides |
531 | +++ /dev/null |
532 | @@ -1,4 +0,0 @@ |
533 | -# we use dh_python or dh_python2 depending on the ubuntu release |
534 | -# the package is being built on, this is detected dynamically |
535 | -# in the rules file |
536 | -landscape-client source: dh_python-is-obsolete |
537 | \ No newline at end of file |
538 | diff --git a/debian/watch b/debian/watch |
539 | index 3592b51..ba7ea91 100644 |
540 | --- a/debian/watch |
541 | +++ b/debian/watch |
542 | @@ -1,3 +1,3 @@ |
543 | version=4 |
544 | opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/landscape-client-$1\.tar\.gz/ \ |
545 | - https://github.com/CanonicalLtd/landscape-client/tags .*/?(\d{2}\.\d.\d)\.tar\.gz |
546 | + https://github.com/CanonicalLtd/landscape-client/tags .*/?(\d{2}\.\d{2})\.tar\.gz |
547 | diff --git a/dev/landscape-client-vm b/dev/landscape-client-vm |
548 | index 4d13b6f..a2a1e57 100755 |
549 | --- a/dev/landscape-client-vm |
550 | +++ b/dev/landscape-client-vm |
551 | @@ -37,7 +37,7 @@ landscape-devel account on the Landscape staging server (or you can specify |
552 | another account with the --account parameter). |
553 | |
554 | The built VM will be stored under ./build/intrepid along with some other |
555 | -files. To launch the VM, cd to ./build/intrepid and issue: |
556 | +files. To launch the VM, cd to ./build/intrepid and issue: |
557 | $ ./run |
558 | Once it's booted you can log into it with: |
559 | $ ./ssh |
560 | @@ -136,7 +136,7 @@ cat > script <<EOF |
561 | #!/bin/sh -e |
562 | chown landscape /etc/landscape/client.conf |
563 | chmod 600 /etc/landscape/client.conf |
564 | -apt-key add /root/ppa-key |
565 | +cp /root/ppa-key /etc/apt/trusted.gpg.d/landscape-server-mirror-root-ppa-key.asc |
566 | echo "RUN=1" > /etc/default/landscape-client |
567 | EOF |
568 | chmod 755 script |
569 | diff --git a/dev/upload-to-ppa b/dev/upload-to-ppa |
570 | index 2cc01b8..f65b42d 100755 |
571 | --- a/dev/upload-to-ppa |
572 | +++ b/dev/upload-to-ppa |
573 | @@ -112,7 +112,7 @@ for release in $releases; do |
574 | else |
575 | message="Built for $codename, no source changes" |
576 | fi |
577 | - cp debian/changelog ../ |
578 | + cp debian/changelog ../ |
579 | dch --force-distribution -b -v $version -D $codename -m $message |
580 | dpkg-buildpackage -S $source_opt -k$key |
581 | dput $ppa ../${package}_${version}_source.changes |
582 | diff --git a/display_py2_testresults b/display_py2_testresults |
583 | index 021681d..e683c1d 100755 |
584 | --- a/display_py2_testresults |
585 | +++ b/display_py2_testresults |
586 | @@ -1,5 +1,5 @@ |
587 | #!/usr/bin/python |
588 | -with open('_last_py2_res', 'r') as py2res: |
589 | +with open("_last_py2_res", "r") as py2res: |
590 | lines = py2res.readlines() |
591 | |
592 | lastline = lines[-1] |
593 | @@ -7,7 +7,9 @@ lastline = lines[-1] |
594 | time, total, total, err, fail, skip = lastline.split() |
595 | |
596 | if "".join((err, fail, skip)) != "000": |
597 | - print("Python 2: \033[91mFAILED\033[0m (skips={}, failures={}, " |
598 | - "errors={}, total={})".format(skip, fail, err, total)) |
599 | + print( |
600 | + "Python 2: \033[91mFAILED\033[0m (skips={}, failures={}, " |
601 | + "errors={}, total={})".format(skip, fail, err, total), |
602 | + ) |
603 | else: |
604 | - print("Python 2: \033[92mOK\033[0m (total={})".format(total)) |
605 | + print(f"Python 2: \033[92mOK\033[0m (total={total})") |
606 | diff --git a/example.conf b/example.conf |
607 | index 4b7fd94..16b710e 100644 |
608 | --- a/example.conf |
609 | +++ b/example.conf |
610 | @@ -77,7 +77,6 @@ ignore_sigusr1 = False |
611 | # |
612 | # ActiveProcessInfo - lists active processes |
613 | # ComputerInfo - various information |
614 | -# HardwareInventory - information provided by the "lshw" command |
615 | # LoadAverage - load information |
616 | # MemoryInfo - memory information |
617 | # MountInfo - information about mount points (space available, used) |
618 | @@ -86,9 +85,17 @@ ignore_sigusr1 = False |
619 | # PackageMonitor - packages installed, available, versions |
620 | # UserMonitor - users, groups |
621 | # RebootRequired - whether a reboot is required or not |
622 | +# AptPreferences - system APT preferences configuration |
623 | # NetworkActivity - network information (TX, RX) |
624 | # NetworkDevice - a list of connected network devices |
625 | # UpdateManager - controls when distribution upgrades are prompted |
626 | +# CPUUsage - CPU usage information |
627 | +# SwiftUsage - Swift cluster usage |
628 | +# CephUsage - Ceph usage information |
629 | +# ComputerTags - changes in computer tags |
630 | +# UbuntuProInfo - Ubuntu Pro registration information |
631 | +# LivePatch - Livepath status information |
632 | +# UbuntuProRebootRequired - informs if the system needs to be rebooted |
633 | # |
634 | # The special value "ALL" is an alias for the full list of plugins. |
635 | monitor_plugins = ALL |
636 | @@ -130,6 +137,9 @@ apt_update_interval = 21600 |
637 | # The number of seconds between package monitor runs. |
638 | package_monitor_interval = 1800 |
639 | |
640 | +# The number of seconds between snap monitor runs. |
641 | +snap_monitor_interval = 1800 |
642 | + |
643 | # The URL of the http proxy to use, if any. |
644 | # This value is optional. |
645 | # |
646 | @@ -182,3 +192,9 @@ script_users = ALL |
647 | # The default is 512kB |
648 | # 2MB is allowed in this example |
649 | #script_output_limit=2048 |
650 | + |
651 | +# Whether files in /etc/apt/sources.list.d are removed when a repository |
652 | +# profile is added to this machine. |
653 | +# |
654 | +# The default is True |
655 | +#manage_sources_list_d = True |
656 | diff --git a/landscape-client.conf b/landscape-client.conf |
657 | index cf96100..af4faaf 100644 |
658 | --- a/landscape-client.conf |
659 | +++ b/landscape-client.conf |
660 | @@ -9,4 +9,3 @@ log_dir = /tmp/landscape/ |
661 | log_level = debug |
662 | pid_file = /tmp/landscape/landscape-client.pid |
663 | ping_url = http://localhost:8081/ping |
664 | - |
665 | diff --git a/landscape/__init__.py b/landscape/__init__.py |
666 | index 23f8f79..1077067 100644 |
667 | --- a/landscape/__init__.py |
668 | +++ b/landscape/__init__.py |
669 | @@ -1,6 +1,6 @@ |
670 | DEBIAN_REVISION = "" |
671 | -UPSTREAM_VERSION = "23.02" |
672 | -VERSION = "%s%s" % (UPSTREAM_VERSION, DEBIAN_REVISION) |
673 | +UPSTREAM_VERSION = "23.08" |
674 | +VERSION = f"{UPSTREAM_VERSION}{DEBIAN_REVISION}" |
675 | |
676 | # The minimum server API version that all Landscape servers are known to speak |
677 | # and support. It can serve as fallback in case higher versions are not there. |
678 | diff --git a/landscape/client/accumulate.py b/landscape/client/accumulate.py |
679 | index 2d17c06..ce14c88 100644 |
680 | --- a/landscape/client/accumulate.py |
681 | +++ b/landscape/client/accumulate.py |
682 | @@ -72,24 +72,31 @@ representative data at each step boundary. |
683 | """ |
684 | |
685 | |
686 | -class Accumulator(object): |
687 | - |
688 | +class Accumulator: |
689 | def __init__(self, persist, step_size): |
690 | self._persist = persist |
691 | self._step_size = step_size |
692 | |
693 | def __call__(self, new_timestamp, new_free_space, key): |
694 | previous_timestamp, accumulated_value = self._persist.get(key, (0, 0)) |
695 | - accumulated_value, step_data = \ |
696 | - accumulate(previous_timestamp, accumulated_value, |
697 | - new_timestamp, new_free_space, self._step_size) |
698 | + accumulated_value, step_data = accumulate( |
699 | + previous_timestamp, |
700 | + accumulated_value, |
701 | + new_timestamp, |
702 | + new_free_space, |
703 | + self._step_size, |
704 | + ) |
705 | self._persist.set(key, (new_timestamp, accumulated_value)) |
706 | return step_data |
707 | |
708 | |
709 | -def accumulate(previous_timestamp, accumulated_value, |
710 | - new_timestamp, new_value, |
711 | - step_size): |
712 | +def accumulate( |
713 | + previous_timestamp, |
714 | + accumulated_value, |
715 | + new_timestamp, |
716 | + new_value, |
717 | + step_size, |
718 | +): |
719 | previous_step = previous_timestamp // step_size |
720 | new_step = new_timestamp // step_size |
721 | step_boundary = new_step * step_size |
722 | diff --git a/landscape/client/amp.py b/landscape/client/amp.py |
723 | index df4ef92..5b5d448 100644 |
724 | --- a/landscape/client/amp.py |
725 | +++ b/landscape/client/amp.py |
726 | @@ -10,14 +10,15 @@ This module implements a few conveniences built around L{landscape.lib.amp} to |
727 | let the various services connect to each other in an easy and idiomatic way, |
728 | and have them respond to standard requests like "ping" or "exit". |
729 | """ |
730 | -import os |
731 | import logging |
732 | +import os |
733 | |
734 | -from landscape.lib.amp import ( |
735 | - MethodCallClientFactory, MethodCallServerFactory, RemoteObject) |
736 | +from landscape.lib.amp import MethodCallClientFactory |
737 | +from landscape.lib.amp import MethodCallServerFactory |
738 | +from landscape.lib.amp import RemoteObject |
739 | |
740 | |
741 | -class ComponentPublisher(object): |
742 | +class ComponentPublisher: |
743 | """Publish a Landscape client component using a UNIX socket. |
744 | |
745 | Other Landscape client processes can then connect to the socket and invoke |
746 | @@ -72,7 +73,7 @@ def remote(method): |
747 | return method |
748 | |
749 | |
750 | -class ComponentConnector(object): |
751 | +class ComponentConnector: |
752 | """Utility superclass for creating connections with a Landscape component. |
753 | |
754 | @cvar component: The class of the component to connect to, it is expected |
755 | @@ -90,6 +91,7 @@ class ComponentConnector(object): |
756 | |
757 | @see: L{MethodCallClientFactory}. |
758 | """ |
759 | + |
760 | factory = MethodCallClientFactory |
761 | component = None # Must be defined by sub-classes |
762 | remote = RemoteObject |
763 | @@ -123,14 +125,14 @@ class ComponentConnector(object): |
764 | factory.factor = factor |
765 | |
766 | def fire_reconnect(ignored): |
767 | - self._reactor.fire("%s-reconnect" % self.component.name) |
768 | + self._reactor.fire(f"{self.component.name}-reconnect") |
769 | |
770 | def connected(remote): |
771 | factory.notifyOnConnect(fire_reconnect) |
772 | return remote |
773 | |
774 | def log_error(failure): |
775 | - logging.error("Error while connecting to %s", self.component.name) |
776 | + logging.error(f"Error while connecting to {self.component.name}") |
777 | return failure |
778 | |
779 | socket_path = _get_socket_path(self.component, self._config) |
780 | diff --git a/landscape/client/broker/amp.py b/landscape/client/broker/amp.py |
781 | index 94a1fa2..2278b08 100644 |
782 | --- a/landscape/client/broker/amp.py |
783 | +++ b/landscape/client/broker/amp.py |
784 | @@ -1,16 +1,19 @@ |
785 | -from twisted.internet.defer import maybeDeferred, execute, succeed |
786 | +from twisted.internet.defer import execute |
787 | +from twisted.internet.defer import maybeDeferred |
788 | +from twisted.internet.defer import succeed |
789 | from twisted.python.compat import iteritems |
790 | |
791 | -from landscape.lib.amp import RemoteObject, MethodCallArgument |
792 | -from landscape.client.amp import ComponentConnector, get_remote_methods |
793 | -from landscape.client.broker.server import BrokerServer |
794 | +from landscape.client.amp import ComponentConnector |
795 | +from landscape.client.amp import get_remote_methods |
796 | from landscape.client.broker.client import BrokerClient |
797 | -from landscape.client.monitor.monitor import Monitor |
798 | +from landscape.client.broker.server import BrokerServer |
799 | from landscape.client.manager.manager import Manager |
800 | +from landscape.client.monitor.monitor import Monitor |
801 | +from landscape.lib.amp import MethodCallArgument |
802 | +from landscape.lib.amp import RemoteObject |
803 | |
804 | |
805 | class RemoteBroker(RemoteObject): |
806 | - |
807 | def call_if_accepted(self, type, callable, *args): |
808 | """Call C{callable} if C{type} is an accepted message type.""" |
809 | deferred_types = self.get_accepted_message_types() |
810 | @@ -18,6 +21,7 @@ class RemoteBroker(RemoteObject): |
811 | def got_accepted_types(result): |
812 | if type in result: |
813 | return callable(*args) |
814 | + |
815 | deferred_types.addCallback(got_accepted_types) |
816 | return deferred_types |
817 | |
818 | @@ -30,11 +34,10 @@ class RemoteBroker(RemoteObject): |
819 | callable will be fired. |
820 | """ |
821 | result = self.listen_events(list(handlers.keys())) |
822 | - return result.addCallback( |
823 | - lambda args: handlers[args[0]](**args[1])) |
824 | + return result.addCallback(lambda args: handlers[args[0]](**args[1])) |
825 | |
826 | |
827 | -class FakeRemoteBroker(object): |
828 | +class FakeRemoteBroker: |
829 | """Looks like L{RemoteBroker}, but actually talks to local objects.""" |
830 | |
831 | def __init__(self, exchanger, message_store, broker_server): |
832 | @@ -48,16 +51,19 @@ class FakeRemoteBroker(object): |
833 | that they're encodable with AMP. |
834 | """ |
835 | original = getattr(self.broker_server, name, None) |
836 | - if (name in get_remote_methods(self.broker_server) and |
837 | - original is not None and |
838 | - callable(original) |
839 | - ): |
840 | + if ( |
841 | + name in get_remote_methods(self.broker_server) |
842 | + and original is not None |
843 | + and callable(original) |
844 | + ): |
845 | + |
846 | def method(*args, **kwargs): |
847 | for arg in args: |
848 | assert MethodCallArgument.check(arg) |
849 | for k, v in iteritems(kwargs): |
850 | assert MethodCallArgument.check(v) |
851 | return execute(original, *args, **kwargs) |
852 | + |
853 | return method |
854 | else: |
855 | raise AttributeError(name) |
856 | @@ -76,8 +82,7 @@ class FakeRemoteBroker(object): |
857 | callable will be fired. |
858 | """ |
859 | result = self.broker_server.listen_events(handlers.keys()) |
860 | - return result.addCallback( |
861 | - lambda args: handlers[args[0]](**args[1])) |
862 | + return result.addCallback(lambda args: handlers[args[0]](**args[1])) |
863 | |
864 | def register(self): |
865 | return succeed(None) |
866 | @@ -114,8 +119,8 @@ def get_component_registry(): |
867 | RemoteBrokerConnector, |
868 | RemoteClientConnector, |
869 | RemoteMonitorConnector, |
870 | - RemoteManagerConnector |
871 | + RemoteManagerConnector, |
872 | ] |
873 | - return dict( |
874 | - (connector.component.name, connector) |
875 | - for connector in all_connectors) |
876 | + return { |
877 | + connector.component.name: connector for connector in all_connectors |
878 | + } |
879 | diff --git a/landscape/client/broker/client.py b/landscape/client/broker/client.py |
880 | index 042c18a..edbc2c2 100644 |
881 | --- a/landscape/client/broker/client.py |
882 | +++ b/landscape/client/broker/client.py |
883 | @@ -1,19 +1,23 @@ |
884 | -from logging import info, exception, error, debug |
885 | -import sys |
886 | import random |
887 | +import sys |
888 | +from logging import debug |
889 | +from logging import error |
890 | +from logging import exception |
891 | +from logging import info |
892 | |
893 | -from twisted.internet.defer import maybeDeferred, succeed |
894 | +from twisted.internet.defer import maybeDeferred |
895 | +from twisted.internet.defer import succeed |
896 | |
897 | +from landscape.client.amp import remote |
898 | from landscape.lib.format import format_object |
899 | from landscape.lib.twisted_util import gather_results |
900 | -from landscape.client.amp import remote |
901 | |
902 | |
903 | class HandlerNotFoundError(Exception): |
904 | """A handler for the given message type was not found.""" |
905 | |
906 | |
907 | -class BrokerClientPlugin(object): |
908 | +class BrokerClientPlugin: |
909 | """A convenience for writing L{BrokerClient} plugins. |
910 | |
911 | This provides a register method which will set up a bunch of |
912 | @@ -32,6 +36,7 @@ class BrokerClientPlugin(object): |
913 | sent. See L{landscape.broker.server.BrokerServer.send_message} for |
914 | more details. |
915 | """ |
916 | + |
917 | run_interval = 5 |
918 | run_immediately = False |
919 | scope = None # Global scope |
920 | @@ -58,8 +63,10 @@ class BrokerClientPlugin(object): |
921 | if acceptance: |
922 | return callable(*args, **kwargs) |
923 | |
924 | - self.client.reactor.call_on(("message-type-acceptance-changed", type), |
925 | - acceptance_changed) |
926 | + self.client.reactor.call_on( |
927 | + ("message-type-acceptance-changed", type), |
928 | + acceptance_changed, |
929 | + ) |
930 | |
931 | def _resynchronize(self, scopes=None): |
932 | """ |
933 | @@ -106,18 +113,27 @@ class BrokerClientPlugin(object): |
934 | if self.run_immediately: |
935 | self._run_with_error_log() |
936 | if self.run_interval is not None: |
937 | - delay = (random.random() * self.run_interval * |
938 | - self.client.config.stagger_launch) |
939 | - debug("delaying start of %s for %d seconds", |
940 | - format_object(self), delay) |
941 | + delay = ( |
942 | + random.random() |
943 | + * self.run_interval |
944 | + * self.client.config.stagger_launch |
945 | + ) |
946 | + debug( |
947 | + "delaying start of %s for %d seconds", |
948 | + format_object(self), |
949 | + delay, |
950 | + ) |
951 | self._loop = self.client.reactor.call_later( |
952 | - delay, self._start_loop) |
953 | + delay, |
954 | + self._start_loop, |
955 | + ) |
956 | |
957 | def _start_loop(self): |
958 | """Launch the client loop.""" |
959 | self._loop = self.client.reactor.call_every( |
960 | self.run_interval, |
961 | - self._run_with_error_log) |
962 | + self._run_with_error_log, |
963 | + ) |
964 | |
965 | def _run_with_error_log(self): |
966 | """Wrap self.run in a Deferred with a logging error handler.""" |
967 | @@ -134,7 +150,7 @@ class BrokerClientPlugin(object): |
968 | return failure |
969 | |
970 | |
971 | -class BrokerClient(object): |
972 | +class BrokerClient: |
973 | """Basic plugin registry for clients that have to deal with the broker. |
974 | |
975 | This knows about the needs of a client when dealing with the Landscape |
976 | @@ -148,10 +164,11 @@ class BrokerClient(object): |
977 | |
978 | @param reactor: A L{LandscapeReactor}. |
979 | """ |
980 | + |
981 | name = "client" |
982 | |
983 | def __init__(self, reactor, config): |
984 | - super(BrokerClient, self).__init__() |
985 | + super().__init__() |
986 | self.reactor = reactor |
987 | self.broker = None |
988 | self.config = config |
989 | @@ -179,7 +196,7 @@ class BrokerClient(object): |
990 | """ |
991 | info("Registering plugin %s.", format_object(plugin)) |
992 | self._plugins.append(plugin) |
993 | - if hasattr(plugin, 'plugin_name'): |
994 | + if hasattr(plugin, "plugin_name"): |
995 | self._plugin_names[plugin.plugin_name] = plugin |
996 | plugin.register(self) |
997 | |
998 | @@ -210,15 +227,16 @@ class BrokerClient(object): |
999 | @return: The return value of the handler, if found. |
1000 | @raises: HandlerNotFoundError if the handler was not found |
1001 | """ |
1002 | - type = message["type"] |
1003 | - handler = self._registered_messages.get(type) |
1004 | + typ = message["type"] |
1005 | + handler = self._registered_messages.get(typ) |
1006 | if handler is None: |
1007 | - raise HandlerNotFoundError(type) |
1008 | + raise HandlerNotFoundError(typ) |
1009 | try: |
1010 | return handler(message) |
1011 | except Exception: |
1012 | - exception("Error running message handler for type %r: %r" |
1013 | - % (type, handler)) |
1014 | + exception( |
1015 | + f"Error running message handler for type {typ!r}: {handler!r}", |
1016 | + ) |
1017 | |
1018 | @remote |
1019 | def message(self, message): |
1020 | @@ -259,8 +277,9 @@ class BrokerClient(object): |
1021 | results = self.reactor.fire((event_type, message_type), acceptance) |
1022 | else: |
1023 | results = self.reactor.fire(event_type, *args, **kwargs) |
1024 | - return gather_results([ |
1025 | - maybeDeferred(lambda x: x, result) for result in results]) |
1026 | + return gather_results( |
1027 | + [maybeDeferred(lambda x: x, result) for result in results], |
1028 | + ) |
1029 | |
1030 | def handle_reconnect(self): |
1031 | """Called when the connection with the broker is established again. |
1032 | @@ -273,8 +292,8 @@ class BrokerClient(object): |
1033 | - Re-register ourselves as client, so the broker knows we exist and |
1034 | will talk to us firing events and dispatching messages. |
1035 | """ |
1036 | - for type in self._registered_messages: |
1037 | - self.broker.register_client_accepted_message_type(type) |
1038 | + for typ in self._registered_messages: |
1039 | + self.broker.register_client_accepted_message_type(typ) |
1040 | self.broker.register_client(self.name) |
1041 | |
1042 | @remote |
1043 | diff --git a/landscape/client/broker/config.py b/landscape/client/broker/config.py |
1044 | index 71e65e1..6b222fb 100644 |
1045 | --- a/landscape/client/broker/config.py |
1046 | +++ b/landscape/client/broker/config.py |
1047 | @@ -1,5 +1,4 @@ |
1048 | """Configuration class for the broker.""" |
1049 | - |
1050 | import os |
1051 | |
1052 | from landscape.client.deployment import Configuration |
1053 | @@ -12,7 +11,7 @@ class BrokerConfiguration(Configuration): |
1054 | """ |
1055 | |
1056 | def __init__(self): |
1057 | - super(BrokerConfiguration, self).__init__() |
1058 | + super().__init__() |
1059 | self._original_http_proxy = os.environ.get("http_proxy") |
1060 | self._original_https_proxy = os.environ.get("https_proxy") |
1061 | |
1062 | @@ -33,35 +32,67 @@ class BrokerConfiguration(Configuration): |
1063 | - C{http_proxy} |
1064 | - C{https_proxy} |
1065 | """ |
1066 | - parser = super(BrokerConfiguration, self).make_parser() |
1067 | + parser = super().make_parser() |
1068 | |
1069 | - parser.add_option("-a", "--account-name", metavar="NAME", |
1070 | - help="The account this computer belongs to.") |
1071 | - parser.add_option("-p", "--registration-key", metavar="KEY", |
1072 | - help="The account-wide key used for " |
1073 | - "registering clients.") |
1074 | - parser.add_option("-t", "--computer-title", metavar="TITLE", |
1075 | - help="The title of this computer") |
1076 | - parser.add_option("--exchange-interval", default=15 * 60, type="int", |
1077 | - metavar="INTERVAL", |
1078 | - help="The number of seconds between server " |
1079 | - "exchanges.") |
1080 | - parser.add_option("--urgent-exchange-interval", default=1 * 60, |
1081 | - type="int", metavar="INTERVAL", |
1082 | - help="The number of seconds between urgent server " |
1083 | - "exchanges.") |
1084 | - parser.add_option("--ping-interval", default=30, type="int", |
1085 | - metavar="INTERVAL", |
1086 | - help="The number of seconds between pings.") |
1087 | - parser.add_option("--http-proxy", metavar="URL", |
1088 | - help="The URL of the HTTP proxy, if one is needed.") |
1089 | - parser.add_option("--https-proxy", metavar="URL", |
1090 | - help="The URL of the HTTPS proxy, if one is needed.") |
1091 | - parser.add_option("--access-group", default="", |
1092 | - help="Suggested access group for this computer.") |
1093 | - parser.add_option("--tags", |
1094 | - help="Comma separated list of tag names to be sent " |
1095 | - "to the server.") |
1096 | + parser.add_option( |
1097 | + "-a", |
1098 | + "--account-name", |
1099 | + metavar="NAME", |
1100 | + help="The account this computer belongs to.", |
1101 | + ) |
1102 | + parser.add_option( |
1103 | + "-p", |
1104 | + "--registration-key", |
1105 | + metavar="KEY", |
1106 | + help="The account-wide key used for " "registering clients.", |
1107 | + ) |
1108 | + parser.add_option( |
1109 | + "-t", |
1110 | + "--computer-title", |
1111 | + metavar="TITLE", |
1112 | + help="The title of this computer", |
1113 | + ) |
1114 | + parser.add_option( |
1115 | + "--exchange-interval", |
1116 | + default=15 * 60, |
1117 | + type="int", |
1118 | + metavar="INTERVAL", |
1119 | + help="The number of seconds between server " "exchanges.", |
1120 | + ) |
1121 | + parser.add_option( |
1122 | + "--urgent-exchange-interval", |
1123 | + default=1 * 60, |
1124 | + type="int", |
1125 | + metavar="INTERVAL", |
1126 | + help="The number of seconds between urgent server " "exchanges.", |
1127 | + ) |
1128 | + parser.add_option( |
1129 | + "--ping-interval", |
1130 | + default=30, |
1131 | + type="int", |
1132 | + metavar="INTERVAL", |
1133 | + help="The number of seconds between pings.", |
1134 | + ) |
1135 | + parser.add_option( |
1136 | + "--http-proxy", |
1137 | + metavar="URL", |
1138 | + help="The URL of the HTTP proxy, if one is needed.", |
1139 | + ) |
1140 | + parser.add_option( |
1141 | + "--https-proxy", |
1142 | + metavar="URL", |
1143 | + help="The URL of the HTTPS proxy, if one is needed.", |
1144 | + ) |
1145 | + parser.add_option( |
1146 | + "--access-group", |
1147 | + default="", |
1148 | + help="Suggested access group for this computer.", |
1149 | + ) |
1150 | + parser.add_option( |
1151 | + "--tags", |
1152 | + help="Comma separated list of tag names to be sent " |
1153 | + "to the server.", |
1154 | + ) |
1155 | |
1156 | return parser |
1157 | |
1158 | @@ -78,7 +109,7 @@ class BrokerConfiguration(Configuration): |
1159 | C{http_proxy} and C{https_proxy} environment variables based on |
1160 | that config data. |
1161 | """ |
1162 | - super(BrokerConfiguration, self).load(args) |
1163 | + super().load(args) |
1164 | if self.http_proxy: |
1165 | os.environ["http_proxy"] = self.http_proxy |
1166 | elif self._original_http_proxy: |
1167 | diff --git a/landscape/client/broker/exchange.py b/landscape/client/broker/exchange.py |
1168 | index 924cb9a..31f32ff 100644 |
1169 | --- a/landscape/client/broker/exchange.py |
1170 | +++ b/landscape/client/broker/exchange.py |
1171 | @@ -342,23 +342,28 @@ Diagram:: |
1172 | 14. Schedule exchange |
1173 | |
1174 | """ |
1175 | -import time |
1176 | import logging |
1177 | -from landscape.lib.hashlib import md5 |
1178 | +import time |
1179 | |
1180 | -from twisted.internet.defer import Deferred, succeed |
1181 | -from landscape.lib.compat import _PY3 |
1182 | +from twisted.internet.defer import Deferred |
1183 | +from twisted.internet.defer import succeed |
1184 | |
1185 | +from landscape import CLIENT_API |
1186 | +from landscape import DEFAULT_SERVER_API |
1187 | +from landscape import SERVER_API |
1188 | from landscape.lib.backoff import ExponentialBackoff |
1189 | -from landscape.lib.fetch import HTTPCodeError, PyCurlError |
1190 | +from landscape.lib.compat import _PY3 |
1191 | +from landscape.lib.fetch import HTTPCodeError |
1192 | +from landscape.lib.fetch import PyCurlError |
1193 | from landscape.lib.format import format_delta |
1194 | -from landscape.lib.message import got_next_expected, RESYNC |
1195 | -from landscape.lib.versioning import is_version_higher, sort_versions |
1196 | - |
1197 | -from landscape import DEFAULT_SERVER_API, SERVER_API, CLIENT_API |
1198 | +from landscape.lib.hashlib import md5 |
1199 | +from landscape.lib.message import got_next_expected |
1200 | +from landscape.lib.message import RESYNC |
1201 | +from landscape.lib.versioning import is_version_higher |
1202 | +from landscape.lib.versioning import sort_versions |
1203 | |
1204 | |
1205 | -class MessageExchange(object): |
1206 | +class MessageExchange: |
1207 | """Schedule and handle message exchanges with the server. |
1208 | |
1209 | The L{MessageExchange} is the place where messages are sent to go out |
1210 | @@ -376,8 +381,16 @@ class MessageExchange(object): |
1211 | # The highest server API that we are capable of speaking |
1212 | _api = SERVER_API |
1213 | |
1214 | - def __init__(self, reactor, store, transport, registration_info, |
1215 | - exchange_store, config, max_messages=100): |
1216 | + def __init__( |
1217 | + self, |
1218 | + reactor, |
1219 | + store, |
1220 | + transport, |
1221 | + registration_info, |
1222 | + exchange_store, |
1223 | + config, |
1224 | + max_messages=100, |
1225 | + ): |
1226 | """ |
1227 | @param reactor: The L{LandscapeReactor} used to fire events in response |
1228 | to messages received by the server. |
1229 | @@ -421,15 +434,16 @@ class MessageExchange(object): |
1230 | A message is considered obsolete if the secure ID changed since it was |
1231 | received. |
1232 | """ |
1233 | - if 'operation-id' not in message: |
1234 | + if "operation-id" not in message: |
1235 | return False |
1236 | |
1237 | - operation_id = message['operation-id'] |
1238 | + operation_id = message["operation-id"] |
1239 | context = self._exchange_store.get_message_context(operation_id) |
1240 | if context is None: |
1241 | logging.warning( |
1242 | - "No message context for message with operation-id: %s" |
1243 | - % operation_id) |
1244 | + "No message context for message with " |
1245 | + f"operation-id: {operation_id}", |
1246 | + ) |
1247 | return False |
1248 | |
1249 | # Compare the current secure ID with the one that was in effect when |
1250 | @@ -450,7 +464,7 @@ class MessageExchange(object): |
1251 | max_bytes = self._max_log_text_bytes |
1252 | if len(value) > max_bytes: |
1253 | value = value[:max_bytes] |
1254 | - value += '...MESSAGE TRUNCATED DUE TO SIZE' |
1255 | + value += "...MESSAGE TRUNCATED DUE TO SIZE" |
1256 | message[field] = value |
1257 | |
1258 | def send(self, message, urgent=False): |
1259 | @@ -463,14 +477,15 @@ class MessageExchange(object): |
1260 | """ |
1261 | if self._message_is_obsolete(message): |
1262 | logging.info( |
1263 | - "Response message with operation-id %s was discarded " |
1264 | - "because the client's secure ID has changed in the meantime" |
1265 | - % message.get('operation-id')) |
1266 | + "Response message with operation-id " |
1267 | + f"{message.get('operation-id')} was discarded " |
1268 | + "because the client's secure ID has changed in the meantime", |
1269 | + ) |
1270 | return None |
1271 | |
1272 | # These fields sometimes have really long output we need to trim |
1273 | - self.truncate_message_field('err', message) |
1274 | - self.truncate_message_field('result-text', message) |
1275 | + self.truncate_message_field("err", message) |
1276 | + self.truncate_message_field("result-text", message) |
1277 | |
1278 | if "timestamp" not in message: |
1279 | message["timestamp"] = int(self._reactor.time()) |
1280 | @@ -535,12 +550,16 @@ class MessageExchange(object): |
1281 | def _handle_set_intervals(self, message): |
1282 | if "exchange" in message: |
1283 | self._config.exchange_interval = message["exchange"] |
1284 | - logging.info("Exchange interval set to %d seconds." % |
1285 | - self._config.exchange_interval) |
1286 | + logging.info( |
1287 | + "Exchange interval set " |
1288 | + f"to {self._config.exchange_interval:d} seconds.", |
1289 | + ) |
1290 | if "urgent-exchange" in message: |
1291 | self._config.urgent_exchange_interval = message["urgent-exchange"] |
1292 | - logging.info("Urgent exchange interval set to %d seconds." % |
1293 | - self._config.urgent_exchange_interval) |
1294 | + logging.info( |
1295 | + "Urgent exchange interval set " |
1296 | + f"to {self._config.urgent_exchange_interval:d} seconds.", |
1297 | + ) |
1298 | self._config.write() |
1299 | |
1300 | def exchange(self): |
1301 | @@ -565,19 +584,24 @@ class MessageExchange(object): |
1302 | |
1303 | start_time = time.time() |
1304 | if self._urgent_exchange: |
1305 | - logging.info("Starting urgent message exchange with %s." |
1306 | - % self._transport.get_url()) |
1307 | + logging.info( |
1308 | + "Starting urgent message exchange " |
1309 | + f"with {self._transport.get_url()}.", |
1310 | + ) |
1311 | else: |
1312 | - logging.info("Starting message exchange with %s." |
1313 | - % self._transport.get_url()) |
1314 | + logging.info( |
1315 | + f"Starting message exchange with {self._transport.get_url()}.", |
1316 | + ) |
1317 | |
1318 | deferred = Deferred() |
1319 | |
1320 | def exchange_completed(): |
1321 | self.schedule_exchange(force=True) |
1322 | self._reactor.fire("exchange-done") |
1323 | - logging.info("Message exchange completed in %s.", |
1324 | - format_delta(time.time() - start_time)) |
1325 | + logging.info( |
1326 | + "Message exchange completed in %s.", |
1327 | + format_delta(time.time() - start_time), |
1328 | + ) |
1329 | deferred.callback(None) |
1330 | |
1331 | def handle_result(result): |
1332 | @@ -627,7 +651,7 @@ class MessageExchange(object): |
1333 | # The error returned is an SSL error, most likely the server |
1334 | # is using a self-signed certificate. Let's fire a special |
1335 | # event so that the GUI can display a nice message. |
1336 | - logging.error("Message exchange failed: %s" % error.message) |
1337 | + logging.error(f"Message exchange failed: {error.message}") |
1338 | ssl_error = True |
1339 | |
1340 | self._reactor.fire("exchange-failed", ssl_error=ssl_error) |
1341 | @@ -636,16 +660,19 @@ class MessageExchange(object): |
1342 | logging.info("Message exchange failed.") |
1343 | exchange_completed() |
1344 | |
1345 | - self._reactor.call_in_thread(handle_result, handle_failure, |
1346 | - self._transport.exchange, payload, |
1347 | - self._registration_info.secure_id, |
1348 | - self._get_exchange_token(), |
1349 | - payload.get("server-api")) |
1350 | + self._reactor.call_in_thread( |
1351 | + handle_result, |
1352 | + handle_failure, |
1353 | + self._transport.exchange, |
1354 | + payload, |
1355 | + self._registration_info.secure_id, |
1356 | + self._get_exchange_token(), |
1357 | + payload.get("server-api"), |
1358 | + ) |
1359 | return deferred |
1360 | |
1361 | def is_urgent(self): |
1362 | - """Return a bool showing whether there is an urgent exchange scheduled. |
1363 | - """ |
1364 | + """Return bool showing whether there is an urgent exchange scheduled""" |
1365 | return self._urgent_exchange |
1366 | |
1367 | def schedule_exchange(self, urgent=False, force=False): |
1368 | @@ -666,9 +693,12 @@ class MessageExchange(object): |
1369 | # The 'not self._exchanging' check below is currently untested. |
1370 | # It's a bit tricky to test as it is preventing rehooking 'exchange' |
1371 | # while there's a background thread doing the exchange itself. |
1372 | - if (not self._exchanging and |
1373 | - (force or self._exchange_id is None or |
1374 | - urgent and not self._urgent_exchange)): |
1375 | + if not self._exchanging and ( |
1376 | + force |
1377 | + or self._exchange_id is None |
1378 | + or urgent |
1379 | + and not self._urgent_exchange |
1380 | + ): |
1381 | if urgent: |
1382 | self._urgent_exchange = True |
1383 | if self._exchange_id: |
1384 | @@ -680,18 +710,24 @@ class MessageExchange(object): |
1385 | interval = self._config.exchange_interval |
1386 | backoff_delay = self._backoff_counter.get_random_delay() |
1387 | if backoff_delay: |
1388 | - logging.warning("Server is busy. Backing off client for {} " |
1389 | - "seconds".format(backoff_delay)) |
1390 | + logging.warning( |
1391 | + "Server is busy. Backing off client for {} " |
1392 | + "seconds".format(backoff_delay), |
1393 | + ) |
1394 | interval += backoff_delay |
1395 | |
1396 | if self._notification_id is not None: |
1397 | self._reactor.cancel_call(self._notification_id) |
1398 | notification_interval = interval - 10 |
1399 | self._notification_id = self._reactor.call_later( |
1400 | - notification_interval, self._notify_impending_exchange) |
1401 | + notification_interval, |
1402 | + self._notify_impending_exchange, |
1403 | + ) |
1404 | |
1405 | self._exchange_id = self._reactor.call_later( |
1406 | - interval, self.exchange) |
1407 | + interval, |
1408 | + self.exchange, |
1409 | + ) |
1410 | |
1411 | def _get_exchange_token(self): |
1412 | """Get the token given us by the server at the last exchange. |
1413 | @@ -743,13 +779,15 @@ class MessageExchange(object): |
1414 | del messages[i:] |
1415 | else: |
1416 | server_api = store.get_server_api() |
1417 | - payload = {"server-api": server_api, |
1418 | - "client-api": CLIENT_API, |
1419 | - "sequence": store.get_sequence(), |
1420 | - "accepted-types": accepted_types_digest, |
1421 | - "messages": messages, |
1422 | - "total-messages": total_messages, |
1423 | - "next-expected-sequence": store.get_server_sequence()} |
1424 | + payload = { |
1425 | + "server-api": server_api, |
1426 | + "client-api": CLIENT_API, |
1427 | + "sequence": store.get_sequence(), |
1428 | + "accepted-types": accepted_types_digest, |
1429 | + "messages": messages, |
1430 | + "total-messages": total_messages, |
1431 | + "next-expected-sequence": store.get_server_sequence(), |
1432 | + } |
1433 | accepted_client_types = self.get_client_accepted_message_types() |
1434 | accepted_client_types_hash = self._hash_types(accepted_client_types) |
1435 | if accepted_client_types_hash != self._client_accepted_types_hash: |
1436 | @@ -776,7 +814,8 @@ class MessageExchange(object): |
1437 | """ |
1438 | message_store = self._message_store |
1439 | self._client_accepted_types_hash = result.get( |
1440 | - "client-accepted-types-hash") |
1441 | + "client-accepted-types-hash", |
1442 | + ) |
1443 | next_expected = result.get("next-expected-sequence") |
1444 | old_sequence = message_store.get_sequence() |
1445 | if next_expected is None: |
1446 | @@ -793,8 +832,10 @@ class MessageExchange(object): |
1447 | # let's fire an event to tell all the plugins that they |
1448 | # ought to generate new messages so the server gets some |
1449 | # up-to-date data. |
1450 | - logging.info("Server asked for ancient data: resynchronizing all " |
1451 | - "state with the server.") |
1452 | + logging.info( |
1453 | + "Server asked for ancient data: resynchronizing all " |
1454 | + "state with the server.", |
1455 | + ) |
1456 | self.send({"type": "resynchronize"}) |
1457 | self._reactor.fire("resynchronize-clients") |
1458 | |
1459 | @@ -808,8 +849,9 @@ class MessageExchange(object): |
1460 | if new_uuid and isinstance(new_uuid, bytes): |
1461 | new_uuid = new_uuid.decode("ascii") |
1462 | if new_uuid != old_uuid: |
1463 | - logging.info("Server UUID changed (old=%s, new=%s)." |
1464 | - % (old_uuid, new_uuid)) |
1465 | + logging.info( |
1466 | + f"Server UUID changed (old={old_uuid}, new={new_uuid}).", |
1467 | + ) |
1468 | self._reactor.fire("server-uuid-changed", old_uuid, new_uuid) |
1469 | message_store.set_server_uuid(new_uuid) |
1470 | |
1471 | @@ -874,12 +916,14 @@ class MessageExchange(object): |
1472 | Any message handlers registered with L{register_message} will |
1473 | be called. |
1474 | """ |
1475 | - if 'operation-id' in message: |
1476 | + if "operation-id" in message: |
1477 | # This is a message that requires a response. Store the secure ID |
1478 | # so we can check for obsolete results later. |
1479 | self._exchange_store.add_message_context( |
1480 | - message['operation-id'], self._registration_info.secure_id, |
1481 | - message['type']) |
1482 | + message["operation-id"], |
1483 | + self._registration_info.secure_id, |
1484 | + message["type"], |
1485 | + ) |
1486 | |
1487 | self._reactor.fire("message", message) |
1488 | # This has plan interference! but whatever. |
1489 | @@ -903,9 +947,9 @@ def get_accepted_types_diff(old_types, new_types): |
1490 | stable_types = old_types & new_types |
1491 | removed_types = old_types - new_types |
1492 | diff = [] |
1493 | - diff.extend(["+%s" % type for type in added_types]) |
1494 | - diff.extend(["%s" % type for type in stable_types]) |
1495 | - diff.extend(["-%s" % type for type in removed_types]) |
1496 | + diff.extend([f"+{typ}" for typ in added_types]) |
1497 | + diff.extend([f"{typ}" for typ in stable_types]) |
1498 | + diff.extend([f"-{typ}" for typ in removed_types]) |
1499 | return " ".join(diff) |
1500 | |
1501 | |
1502 | diff --git a/landscape/client/broker/exchangestore.py b/landscape/client/broker/exchangestore.py |
1503 | index aaa9192..4fb855a 100644 |
1504 | --- a/landscape/client/broker/exchangestore.py |
1505 | +++ b/landscape/client/broker/exchangestore.py |
1506 | @@ -9,7 +9,7 @@ except ImportError: |
1507 | from landscape.lib.store import with_cursor |
1508 | |
1509 | |
1510 | -class MessageContext(object): |
1511 | +class MessageContext: |
1512 | """Stores a context for incoming messages that require a response. |
1513 | |
1514 | The context consists of |
1515 | @@ -39,10 +39,11 @@ class MessageContext(object): |
1516 | def remove(self, cursor): |
1517 | cursor.execute( |
1518 | "DELETE FROM message_context WHERE operation_id=?", |
1519 | - (self.operation_id,)) |
1520 | + (self.operation_id,), |
1521 | + ) |
1522 | |
1523 | |
1524 | -class ExchangeStore(object): |
1525 | +class ExchangeStore: |
1526 | """Message meta data required by the L{MessageExchange}. |
1527 | |
1528 | The implementation uses a SQLite database as backend, with a single table |
1529 | @@ -51,6 +52,7 @@ class ExchangeStore(object): |
1530 | |
1531 | @param filename: The name of the file that contains the sqlite database. |
1532 | """ |
1533 | + |
1534 | _db = None |
1535 | |
1536 | def __init__(self, filename): |
1537 | @@ -61,13 +63,20 @@ class ExchangeStore(object): |
1538 | |
1539 | @with_cursor |
1540 | def add_message_context( |
1541 | - self, cursor, operation_id, secure_id, message_type): |
1542 | + self, |
1543 | + cursor, |
1544 | + operation_id, |
1545 | + secure_id, |
1546 | + message_type, |
1547 | + ): |
1548 | """Add a L{MessageContext} with the given data.""" |
1549 | params = (operation_id, secure_id, message_type, time.time()) |
1550 | cursor.execute( |
1551 | "INSERT INTO message_context " |
1552 | " (operation_id, secure_id, message_type, timestamp) " |
1553 | - " VALUES (?,?,?,?)", params) |
1554 | + " VALUES (?,?,?,?)", |
1555 | + params, |
1556 | + ) |
1557 | return MessageContext(self._db, *params) |
1558 | |
1559 | @with_cursor |
1560 | @@ -75,7 +84,9 @@ class ExchangeStore(object): |
1561 | """The L{MessageContext} for the given C{operation_id} or C{None}.""" |
1562 | cursor.execute( |
1563 | "SELECT operation_id, secure_id, message_type, timestamp " |
1564 | - "FROM message_context WHERE operation_id=?", (operation_id,)) |
1565 | + "FROM message_context WHERE operation_id=?", |
1566 | + (operation_id,), |
1567 | + ) |
1568 | row = cursor.fetchone() |
1569 | if row: |
1570 | return MessageContext(self._db, *row) |
1571 | @@ -101,10 +112,12 @@ def ensure_exchange_schema(db): |
1572 | "CREATE TABLE message_context" |
1573 | " (id INTEGER PRIMARY KEY, timestamp TIMESTAMP, " |
1574 | " secure_id TEXT NOT NULL, operation_id INTEGER NOT NULL, " |
1575 | - " message_type text NOT NULL)") |
1576 | + " message_type text NOT NULL)", |
1577 | + ) |
1578 | cursor.execute( |
1579 | "CREATE UNIQUE INDEX msgctx_operationid_idx ON " |
1580 | - "message_context(operation_id)") |
1581 | + "message_context(operation_id)", |
1582 | + ) |
1583 | except (sqlite3.OperationalError, sqlite3.DatabaseError): |
1584 | cursor.close() |
1585 | db.rollback() |
1586 | diff --git a/landscape/client/broker/ping.py b/landscape/client/broker/ping.py |
1587 | index 5c8062e..153be3c 100644 |
1588 | --- a/landscape/client/broker/ping.py |
1589 | +++ b/landscape/client/broker/ping.py |
1590 | @@ -48,7 +48,7 @@ from landscape.lib.fetch import fetch |
1591 | from landscape.lib.log import log_failure |
1592 | |
1593 | |
1594 | -class PingClient(object): |
1595 | +class PingClient: |
1596 | """An HTTP client which knows how to talk to the ping server.""" |
1597 | |
1598 | def __init__(self, reactor, get_page=None): |
1599 | @@ -74,10 +74,16 @@ class PingClient(object): |
1600 | |
1601 | def errback(type, value, tb): |
1602 | page_deferred.errback(Failure(value, type, tb)) |
1603 | - self._reactor.call_in_thread(page_deferred.callback, errback, |
1604 | - self.get_page, url, |
1605 | - post=True, data=data, |
1606 | - headers=headers) |
1607 | + |
1608 | + self._reactor.call_in_thread( |
1609 | + page_deferred.callback, |
1610 | + errback, |
1611 | + self.get_page, |
1612 | + url, |
1613 | + post=True, |
1614 | + data=data, |
1615 | + headers=headers, |
1616 | + ) |
1617 | page_deferred.addCallback(self._got_result) |
1618 | return page_deferred |
1619 | return defer.succeed(False) |
1620 | @@ -92,7 +98,7 @@ class PingClient(object): |
1621 | return True |
1622 | |
1623 | |
1624 | -class Pinger(object): |
1625 | +class Pinger: |
1626 | """ |
1627 | A plugin which pings the Landscape server with HTTP requests to |
1628 | see if a full exchange should be initiated. |
1629 | @@ -107,8 +113,14 @@ class Pinger(object): |
1630 | scheduled ping. |
1631 | """ |
1632 | |
1633 | - def __init__(self, reactor, identity, exchanger, config, |
1634 | - ping_client_factory=PingClient): |
1635 | + def __init__( |
1636 | + self, |
1637 | + reactor, |
1638 | + identity, |
1639 | + exchanger, |
1640 | + config, |
1641 | + ping_client_factory=PingClient, |
1642 | + ): |
1643 | self._config = config |
1644 | self._identity = identity |
1645 | self._reactor = reactor |
1646 | @@ -132,33 +144,42 @@ class Pinger(object): |
1647 | def ping(self): |
1648 | """Perform a ping; if there are messages, fire an exchange.""" |
1649 | deferred = self._ping_client.ping( |
1650 | - self._config.ping_url, self._identity.insecure_id) |
1651 | + self._config.ping_url, |
1652 | + self._identity.insecure_id, |
1653 | + ) |
1654 | deferred.addCallback(self._got_result) |
1655 | deferred.addErrback(self._got_error) |
1656 | deferred.addBoth(lambda _: self._schedule()) |
1657 | |
1658 | def _got_result(self, exchange): |
1659 | if exchange: |
1660 | - info("Ping indicates message available. " |
1661 | - "Scheduling an urgent exchange.") |
1662 | + info( |
1663 | + "Ping indicates message available. " |
1664 | + "Scheduling an urgent exchange.", |
1665 | + ) |
1666 | self._exchanger.schedule_exchange(urgent=True) |
1667 | |
1668 | def _got_error(self, failure): |
1669 | - log_failure(failure, |
1670 | - "Error contacting ping server at %s" % |
1671 | - (self._ping_client.url,)) |
1672 | + log_failure( |
1673 | + failure, |
1674 | + f"Error contacting ping server at {self._ping_client.url}", |
1675 | + ) |
1676 | |
1677 | def _schedule(self): |
1678 | """Schedule a new ping using the current ping interval.""" |
1679 | - self._call_id = self._reactor.call_later(self._config.ping_interval, |
1680 | - self.ping) |
1681 | + self._call_id = self._reactor.call_later( |
1682 | + self._config.ping_interval, |
1683 | + self.ping, |
1684 | + ) |
1685 | |
1686 | def _handle_set_intervals(self, message): |
1687 | if message["type"] == "set-intervals" and "ping" in message: |
1688 | self._config.ping_interval = message["ping"] |
1689 | self._config.write() |
1690 | - info("Ping interval set to %d seconds." % |
1691 | - self._config.ping_interval) |
1692 | + info( |
1693 | + f"Ping interval set to {self._config.ping_interval:d} " |
1694 | + "seconds.", |
1695 | + ) |
1696 | if self._call_id is not None: |
1697 | self._reactor.cancel_call(self._call_id) |
1698 | self._schedule() |
1699 | @@ -170,8 +191,7 @@ class Pinger(object): |
1700 | self._call_id = None |
1701 | |
1702 | |
1703 | -class FakePinger(object): |
1704 | - |
1705 | +class FakePinger: |
1706 | def __init__(self, *args, **kwargs): |
1707 | pass |
1708 | |
1709 | diff --git a/landscape/client/broker/registration.py b/landscape/client/broker/registration.py |
1710 | index 864ce99..c21186e 100644 |
1711 | --- a/landscape/client/broker/registration.py |
1712 | +++ b/landscape/client/broker/registration.py |
1713 | @@ -16,10 +16,11 @@ from twisted.internet.defer import Deferred |
1714 | from landscape.client.broker.exchange import maybe_bytes |
1715 | from landscape.client.monitor.ubuntuproinfo import get_ubuntu_pro_info |
1716 | from landscape.lib.juju import get_juju_info |
1717 | -from landscape.lib.tag import is_valid_tag_list |
1718 | from landscape.lib.network import get_fqdn |
1719 | -from landscape.lib.vm_info import get_vm_info, get_container_info |
1720 | +from landscape.lib.tag import is_valid_tag_list |
1721 | from landscape.lib.versioning import is_version_higher |
1722 | +from landscape.lib.vm_info import get_container_info |
1723 | +from landscape.lib.vm_info import get_vm_info |
1724 | |
1725 | |
1726 | class RegistrationError(Exception): |
1727 | @@ -31,7 +32,6 @@ class RegistrationError(Exception): |
1728 | |
1729 | |
1730 | def persist_property(name): |
1731 | - |
1732 | def get(self): |
1733 | value = self._persist.get(name) |
1734 | try: |
1735 | @@ -46,14 +46,13 @@ def persist_property(name): |
1736 | |
1737 | |
1738 | def config_property(name): |
1739 | - |
1740 | def get(self): |
1741 | return getattr(self._config, name) |
1742 | |
1743 | return property(get) |
1744 | |
1745 | |
1746 | -class Identity(object): |
1747 | +class Identity: |
1748 | """Maintains details about the identity of this Landscape client. |
1749 | |
1750 | @ivar secure_id: A server-provided ID for secure message exchange. |
1751 | @@ -83,7 +82,7 @@ class Identity(object): |
1752 | self._persist = persist.root_at("registration") |
1753 | |
1754 | |
1755 | -class RegistrationHandler(object): |
1756 | +class RegistrationHandler: |
1757 | """ |
1758 | An object from which registration can be requested of the server, |
1759 | and which will handle forced ID changes from the server. |
1760 | @@ -91,8 +90,16 @@ class RegistrationHandler(object): |
1761 | L{register} should be used to perform initial registration. |
1762 | """ |
1763 | |
1764 | - def __init__(self, config, identity, reactor, exchange, pinger, |
1765 | - message_store, fetch_async=None): |
1766 | + def __init__( |
1767 | + self, |
1768 | + config, |
1769 | + identity, |
1770 | + reactor, |
1771 | + exchange, |
1772 | + pinger, |
1773 | + message_store, |
1774 | + fetch_async=None, |
1775 | + ): |
1776 | self._config = config |
1777 | self._identity = identity |
1778 | self._reactor = reactor |
1779 | @@ -104,8 +111,10 @@ class RegistrationHandler(object): |
1780 | self._reactor.call_on("exchange-done", self._handle_exchange_done) |
1781 | self._exchange.register_message("set-id", self._handle_set_id) |
1782 | self._exchange.register_message("unknown-id", self._handle_unknown_id) |
1783 | - self._exchange.register_message("registration", |
1784 | - self._handle_registration) |
1785 | + self._exchange.register_message( |
1786 | + "registration", |
1787 | + self._handle_registration, |
1788 | + ) |
1789 | self._should_register = None |
1790 | self._fetch_async = fetch_async |
1791 | self._juju_data = None |
1792 | @@ -116,9 +125,11 @@ class RegistrationHandler(object): |
1793 | if id.secure_id: |
1794 | return False |
1795 | |
1796 | - return bool(id.computer_title and |
1797 | - id.account_name and |
1798 | - self._message_store.accepts("register")) |
1799 | + return bool( |
1800 | + id.computer_title |
1801 | + and id.account_name |
1802 | + and self._message_store.accepts("register"), |
1803 | + ) |
1804 | |
1805 | def register(self): |
1806 | """ |
1807 | @@ -186,14 +197,16 @@ class RegistrationHandler(object): |
1808 | tags = None |
1809 | logging.error("Invalid tags provided for registration.") |
1810 | |
1811 | - message = {"type": "register", |
1812 | - "hostname": get_fqdn(), |
1813 | - "account_name": account_name, |
1814 | - "computer_title": identity.computer_title, |
1815 | - "registration_password": identity.registration_key, |
1816 | - "tags": tags, |
1817 | - "container-info": get_container_info(), |
1818 | - "vm-info": get_vm_info()} |
1819 | + message = { |
1820 | + "type": "register", |
1821 | + "hostname": get_fqdn(), |
1822 | + "account_name": account_name, |
1823 | + "computer_title": identity.computer_title, |
1824 | + "registration_password": identity.registration_key, |
1825 | + "tags": tags, |
1826 | + "container-info": get_container_info(), |
1827 | + "vm-info": get_vm_info(), |
1828 | + } |
1829 | |
1830 | if self._clone_secure_id: |
1831 | # We use the secure id here because the registration is encrypted |
1832 | @@ -216,19 +229,20 @@ class RegistrationHandler(object): |
1833 | message["juju-info"] = { |
1834 | "environment-uuid": self._juju_data["environment-uuid"], |
1835 | "api-addresses": self._juju_data["api-addresses"], |
1836 | - "machine-id": self._juju_data["machine-id"]} |
1837 | + "machine-id": self._juju_data["machine-id"], |
1838 | + } |
1839 | |
1840 | # The computer is a normal computer, possibly a container. |
1841 | with_word = "with" if bool(registration_key) else "without" |
1842 | - with_tags = "and tags %s " % tags if tags else "" |
1843 | - with_group = "in access group '%s' " % group if group else "" |
1844 | + with_tags = f"and tags {tags} " if tags else "" |
1845 | + with_group = f"in access group '{group}' " if group else "" |
1846 | |
1847 | message["ubuntu_pro_info"] = json.dumps(get_ubuntu_pro_info()) |
1848 | |
1849 | logging.info( |
1850 | - u"Queueing message to register with account %r %s%s" |
1851 | - "%s a password." % ( |
1852 | - account_name, with_group, with_tags, with_word)) |
1853 | + f"Queueing message to register with account {account_name!r} " |
1854 | + f"{with_group}{with_tags}{with_word} a password.", |
1855 | + ) |
1856 | self._exchange.send(message) |
1857 | |
1858 | def _handle_set_id(self, message): |
1859 | @@ -239,15 +253,18 @@ class RegistrationHandler(object): |
1860 | |
1861 | Fire C{"registration-done"} and C{"resynchronize-clients"}. |
1862 | """ |
1863 | - id = self._identity |
1864 | - if id.secure_id: |
1865 | - logging.info("Overwriting secure_id with '%s'" % id.secure_id) |
1866 | + cid = self._identity |
1867 | + if cid.secure_id: |
1868 | + logging.info(f"Overwriting secure_id with '{cid.secure_id}'") |
1869 | |
1870 | - id.secure_id = message.get("id") |
1871 | - id.insecure_id = message.get("insecure-id") |
1872 | - logging.info("Using new secure-id ending with %s for account %s.", |
1873 | - id.secure_id[-10:], id.account_name) |
1874 | - logging.debug("Using new secure-id: %s", id.secure_id) |
1875 | + cid.secure_id = message.get("id") |
1876 | + cid.insecure_id = message.get("insecure-id") |
1877 | + logging.info( |
1878 | + "Using new secure-id ending with %s for account %s.", |
1879 | + cid.secure_id[-10:], |
1880 | + cid.account_name, |
1881 | + ) |
1882 | + logging.debug("Using new secure-id: %s", cid.secure_id) |
1883 | self._reactor.fire("registration-done") |
1884 | self._reactor.fire("resynchronize-clients") |
1885 | |
1886 | @@ -257,19 +274,21 @@ class RegistrationHandler(object): |
1887 | self._reactor.fire("registration-failed", reason=message_info) |
1888 | |
1889 | def _handle_unknown_id(self, message): |
1890 | - id = self._identity |
1891 | + cid = self._identity |
1892 | clone = message.get("clone-of") |
1893 | if clone is None: |
1894 | - logging.info("Client has unknown secure-id for account %s." |
1895 | - % id.account_name) |
1896 | + logging.info( |
1897 | + "Client has unknown secure-id for account " |
1898 | + f"{cid.account_name}.", |
1899 | + ) |
1900 | else: # Save the secure id as the clone, and clear it so it's renewed |
1901 | - logging.info("Client is clone of computer %s" % clone) |
1902 | - self._clone_secure_id = id.secure_id |
1903 | - id.secure_id = None |
1904 | - id.insecure_id = None |
1905 | + logging.info(f"Client is clone of computer {clone}") |
1906 | + self._clone_secure_id = cid.secure_id |
1907 | + cid.secure_id = None |
1908 | + cid.insecure_id = None |
1909 | |
1910 | |
1911 | -class RegistrationResponse(object): |
1912 | +class RegistrationResponse: |
1913 | """A helper for dealing with the response of a single registration request. |
1914 | |
1915 | @ivar deferred: The L{Deferred} that will be fired as per |
1916 | diff --git a/landscape/client/broker/server.py b/landscape/client/broker/server.py |
1917 | index 1f8d708..766c6a0 100644 |
1918 | --- a/landscape/client/broker/server.py |
1919 | +++ b/landscape/client/broker/server.py |
1920 | @@ -42,15 +42,14 @@ Diagram:: |
1921 | : exchange |
1922 | |
1923 | """ |
1924 | - |
1925 | import logging |
1926 | |
1927 | from twisted.internet.defer import Deferred |
1928 | -from landscape.lib.compat import _PY3 |
1929 | |
1930 | -from landscape.lib.twisted_util import gather_results |
1931 | from landscape.client.amp import remote |
1932 | from landscape.client.manager.manager import FAILED |
1933 | +from landscape.lib.compat import _PY3 |
1934 | +from landscape.lib.twisted_util import gather_results |
1935 | |
1936 | |
1937 | def event(method): |
1938 | @@ -71,7 +70,7 @@ def event(method): |
1939 | return broadcast_event |
1940 | |
1941 | |
1942 | -class BrokerServer(object): |
1943 | +class BrokerServer: |
1944 | """ |
1945 | A broker server capable of handling messages from plugins connected using |
1946 | the L{BrokerProtocol}. |
1947 | @@ -82,11 +81,20 @@ class BrokerServer(object): |
1948 | @param registration: The {RegistrationHandler}. |
1949 | @param message_store: The broker's L{MessageStore}. |
1950 | """ |
1951 | + |
1952 | name = "broker" |
1953 | |
1954 | - def __init__(self, config, reactor, exchange, registration, |
1955 | - message_store, pinger): |
1956 | + def __init__( |
1957 | + self, |
1958 | + config, |
1959 | + reactor, |
1960 | + exchange, |
1961 | + registration, |
1962 | + message_store, |
1963 | + pinger, |
1964 | + ): |
1965 | from landscape.client.broker.amp import get_component_registry |
1966 | + |
1967 | self.connectors_registry = get_component_registry() |
1968 | self._config = config |
1969 | self._reactor = reactor |
1970 | @@ -99,8 +107,10 @@ class BrokerServer(object): |
1971 | |
1972 | reactor.call_on("message", self.broadcast_message) |
1973 | reactor.call_on("impending-exchange", self.impending_exchange) |
1974 | - reactor.call_on("message-type-acceptance-changed", |
1975 | - self.message_type_acceptance_changed) |
1976 | + reactor.call_on( |
1977 | + "message-type-acceptance-changed", |
1978 | + self.message_type_acceptance_changed, |
1979 | + ) |
1980 | reactor.call_on("server-uuid-changed", self.server_uuid_changed) |
1981 | reactor.call_on("package-data-changed", self.package_data_changed) |
1982 | reactor.call_on("resynchronize-clients", self.resynchronize) |
1983 | @@ -201,7 +211,9 @@ class BrokerServer(object): |
1984 | message = {k.decode("ascii"): v for k, v in message.items()} |
1985 | message["type"] = message["type"].decode("ascii") |
1986 | if isinstance(session_id, bool) and message["type"] in ( |
1987 | - "operation-result", "change-packages-result"): |
1988 | + "operation-result", |
1989 | + "change-packages-result", |
1990 | + ): |
1991 | # XXX This means we're performing a Landscape-driven upgrade and |
1992 | # we're being invoked by a package-changer or release-upgrader |
1993 | # process that is running code which doesn't know about the |
1994 | @@ -218,7 +230,8 @@ class BrokerServer(object): |
1995 | |
1996 | if session_id is None: |
1997 | raise RuntimeError( |
1998 | - "Session ID must be set before attempting to send a message") |
1999 | + "Session ID must be set before attempting to send a message", |
2000 | + ) |
2001 | if self._message_store.is_valid_session_id(session_id): |
2002 | return self._exchanger.send(message, urgent=urgent) |
2003 | |
2004 | @@ -320,7 +333,6 @@ class BrokerServer(object): |
2005 | calls = [] |
2006 | |
2007 | def get_handler(event_type): |
2008 | - |
2009 | def handler(**kwargs): |
2010 | for call in calls: |
2011 | self._reactor.cancel_call(call) |
2012 | @@ -367,26 +379,30 @@ class BrokerServer(object): |
2013 | indicating as such. |
2014 | """ |
2015 | opid = message.get("operation-id") |
2016 | - if (True not in results and |
2017 | - opid is not None and |
2018 | - message["type"] != "resynchronize" |
2019 | - ): |
2020 | + if ( |
2021 | + True not in results |
2022 | + and opid is not None |
2023 | + and message["type"] != "resynchronize" |
2024 | + ): |
2025 | |
2026 | mtype = message["type"] |
2027 | - logging.error("Nobody handled the %s message." % (mtype,)) |
2028 | + logging.error(f"Nobody handled the {mtype} message.") |
2029 | |
2030 | result_text = """\ |
2031 | -Landscape client failed to handle this request (%s) because the |
2032 | +Landscape client failed to handle this request ({}) because the |
2033 | plugin which should handle it isn't available. This could mean that the |
2034 | plugin has been intentionally disabled, or that the client isn't running |
2035 | properly, or you may be running an older version of the client that doesn't |
2036 | support this feature. |
2037 | -""" % (mtype,) |
2038 | +""".format( |
2039 | + mtype, |
2040 | + ) |
2041 | response = { |
2042 | "type": "operation-result", |
2043 | "status": FAILED, |
2044 | "result-text": result_text, |
2045 | - "operation-id": opid} |
2046 | + "operation-id": opid, |
2047 | + } |
2048 | self._exchanger.send(response, urgent=True) |
2049 | |
2050 | @remote |
2051 | diff --git a/landscape/client/broker/service.py b/landscape/client/broker/service.py |
2052 | index 7e36149..9c86267 100644 |
2053 | --- a/landscape/client/broker/service.py |
2054 | +++ b/landscape/client/broker/service.py |
2055 | @@ -1,17 +1,19 @@ |
2056 | """Deployment code for the monitor.""" |
2057 | - |
2058 | import os |
2059 | |
2060 | -from landscape.client.service import LandscapeService, run_landscape_service |
2061 | from landscape.client.amp import ComponentPublisher |
2062 | -from landscape.client.broker.registration import RegistrationHandler, Identity |
2063 | from landscape.client.broker.config import BrokerConfiguration |
2064 | -from landscape.client.broker.transport import HTTPTransport |
2065 | from landscape.client.broker.exchange import MessageExchange |
2066 | from landscape.client.broker.exchangestore import ExchangeStore |
2067 | from landscape.client.broker.ping import Pinger |
2068 | -from landscape.client.broker.store import get_default_message_store |
2069 | +from landscape.client.broker.registration import Identity |
2070 | +from landscape.client.broker.registration import RegistrationHandler |
2071 | from landscape.client.broker.server import BrokerServer |
2072 | +from landscape.client.broker.store import get_default_message_store |
2073 | +from landscape.client.broker.transport import HTTPTransport |
2074 | +from landscape.client.service import LandscapeService |
2075 | +from landscape.client.service import run_landscape_service |
2076 | +from landscape.client.watchdog import bootstrap_list |
2077 | |
2078 | |
2079 | class BrokerService(LandscapeService): |
2080 | @@ -44,48 +46,82 @@ class BrokerService(LandscapeService): |
2081 | service_name = BrokerServer.name |
2082 | |
2083 | def __init__(self, config): |
2084 | + self._config = config |
2085 | self.persist_filename = os.path.join( |
2086 | - config.data_path, "%s.bpickle" % (self.service_name,)) |
2087 | - super(BrokerService, self).__init__(config) |
2088 | + config.data_path, |
2089 | + f"{self.service_name}.bpickle", |
2090 | + ) |
2091 | + super().__init__(config) |
2092 | |
2093 | self.transport = self.transport_factory( |
2094 | - self.reactor, config.url, config.ssl_public_key) |
2095 | + self.reactor, |
2096 | + config.url, |
2097 | + config.ssl_public_key, |
2098 | + ) |
2099 | self.message_store = get_default_message_store( |
2100 | - self.persist, config.message_store_path) |
2101 | + self.persist, |
2102 | + config.message_store_path, |
2103 | + ) |
2104 | self.identity = Identity(self.config, self.persist) |
2105 | exchange_store = ExchangeStore(self.config.exchange_store_path) |
2106 | self.exchanger = MessageExchange( |
2107 | - self.reactor, self.message_store, self.transport, self.identity, |
2108 | - exchange_store, config) |
2109 | + self.reactor, |
2110 | + self.message_store, |
2111 | + self.transport, |
2112 | + self.identity, |
2113 | + exchange_store, |
2114 | + config, |
2115 | + ) |
2116 | self.pinger = self.pinger_factory( |
2117 | - self.reactor, self.identity, self.exchanger, config) |
2118 | + self.reactor, |
2119 | + self.identity, |
2120 | + self.exchanger, |
2121 | + config, |
2122 | + ) |
2123 | self.registration = RegistrationHandler( |
2124 | - config, self.identity, self.reactor, self.exchanger, self.pinger, |
2125 | - self.message_store) |
2126 | - self.broker = BrokerServer(self.config, self.reactor, self.exchanger, |
2127 | - self.registration, self.message_store, |
2128 | - self.pinger) |
2129 | - self.publisher = ComponentPublisher(self.broker, self.reactor, |
2130 | - self.config) |
2131 | - |
2132 | - def startService(self): |
2133 | + config, |
2134 | + self.identity, |
2135 | + self.reactor, |
2136 | + self.exchanger, |
2137 | + self.pinger, |
2138 | + self.message_store, |
2139 | + ) |
2140 | + self.broker = BrokerServer( |
2141 | + self.config, |
2142 | + self.reactor, |
2143 | + self.exchanger, |
2144 | + self.registration, |
2145 | + self.message_store, |
2146 | + self.pinger, |
2147 | + ) |
2148 | + self.publisher = ComponentPublisher( |
2149 | + self.broker, |
2150 | + self.reactor, |
2151 | + self.config, |
2152 | + ) |
2153 | + |
2154 | + def startService(self): # noqa: N802 |
2155 | """Start the broker. |
2156 | |
2157 | Create a L{BrokerServer} listening on C{broker_socket_path} for clients |
2158 | connecting with the L{BrokerServerConnector}, and start the |
2159 | L{MessageExchange} and L{Pinger} services. |
2160 | """ |
2161 | - super(BrokerService, self).startService() |
2162 | + super().startService() |
2163 | + bootstrap_list.bootstrap( |
2164 | + data_path=self._config.data_path, |
2165 | + log_dir=self._config.log_dir, |
2166 | + ) |
2167 | self.publisher.start() |
2168 | self.exchanger.start() |
2169 | self.pinger.start() |
2170 | |
2171 | - def stopService(self): |
2172 | + def stopService(self): # noqa: N802 |
2173 | """Stop the broker.""" |
2174 | deferred = self.publisher.stop() |
2175 | self.exchanger.stop() |
2176 | self.pinger.stop() |
2177 | - super(BrokerService, self).stopService() |
2178 | + super().stopService() |
2179 | return deferred |
2180 | |
2181 | |
2182 | diff --git a/landscape/client/broker/store.py b/landscape/client/broker/store.py |
2183 | index ebab5cf..7557d45 100644 |
2184 | --- a/landscape/client/broker/store.py |
2185 | +++ b/landscape/client/broker/store.py |
2186 | @@ -91,25 +91,28 @@ See L{MessageStore} for details about how messages are stored on the file |
2187 | system and L{landscape.lib.message.got_next_expected} to check how the |
2188 | strategy for updating the pending offset and the sequence is implemented. |
2189 | """ |
2190 | - |
2191 | import itertools |
2192 | import logging |
2193 | import os |
2194 | +import shutil |
2195 | +import traceback |
2196 | import uuid |
2197 | |
2198 | from twisted.python.compat import iteritems |
2199 | |
2200 | from landscape import DEFAULT_SERVER_API |
2201 | from landscape.lib import bpickle |
2202 | -from landscape.lib.fs import create_binary_file, read_binary_file |
2203 | -from landscape.lib.versioning import sort_versions, is_version_higher |
2204 | +from landscape.lib.fs import create_binary_file |
2205 | +from landscape.lib.fs import read_binary_file |
2206 | +from landscape.lib.versioning import is_version_higher |
2207 | +from landscape.lib.versioning import sort_versions |
2208 | |
2209 | |
2210 | HELD = "h" |
2211 | BROKEN = "b" |
2212 | |
2213 | |
2214 | -class MessageStore(object): |
2215 | +class MessageStore: |
2216 | """A message store which stores its messages in a file system hierarchy. |
2217 | |
2218 | Beside the "sequence" and the "pending offset" values described in the |
2219 | @@ -134,9 +137,12 @@ class MessageStore(object): |
2220 | # in case the server supports it. |
2221 | _api = DEFAULT_SERVER_API |
2222 | |
2223 | - def __init__(self, persist, directory, directory_size=1000): |
2224 | + def __init__(self, persist, directory, directory_size=1000, max_dirs=4, |
2225 | + max_size_mb=400): |
2226 | self._directory = directory |
2227 | self._directory_size = directory_size |
2228 | + self._max_dirs = max_dirs # Maximum number of directories in store |
2229 | + self._max_size_mb = max_size_mb # Maximum size of message store |
2230 | self._schemas = {} |
2231 | self._original_persist = persist |
2232 | self._persist = persist.root_at("message-store") |
2233 | @@ -273,7 +279,7 @@ class MessageStore(object): |
2234 | logging.exception(e) |
2235 | self._add_flags(filename, BROKEN) |
2236 | else: |
2237 | - if u"type" not in message: |
2238 | + if "type" not in message: |
2239 | # Special case to decode keys for messages which were |
2240 | # serialized by py27 prior to py3 upgrade, and having |
2241 | # implicit byte message keys. Message may still get |
2242 | @@ -281,8 +287,9 @@ class MessageStore(object): |
2243 | # broker. (lp: #1718689) |
2244 | message = { |
2245 | (k if isinstance(k, str) else k.decode("ascii")): v |
2246 | - for k, v in message.items()} |
2247 | - message[u"type"] = message[u"type"].decode("ascii") |
2248 | + for k, v in message.items() |
2249 | + } |
2250 | + message["type"] = message["type"].decode("ascii") |
2251 | |
2252 | unknown_type = message["type"] not in accepted_types |
2253 | unknown_api = not is_version_higher(server_api, message["api"]) |
2254 | @@ -292,10 +299,53 @@ class MessageStore(object): |
2255 | messages.append(message) |
2256 | return messages |
2257 | |
2258 | + def get_messages_total_size(self): |
2259 | + """Get total size of messages directory""" |
2260 | + sizes = [] |
2261 | + for dirname in os.listdir(self._directory): |
2262 | + dirpath = os.path.join(self._directory, dirname) |
2263 | + dirsize = sum(file.stat().st_size for file in os.scandir(dirpath)) |
2264 | + sizes.append(dirsize) |
2265 | + return sum(sizes) |
2266 | + |
2267 | + def delete_messages_over_limit(self): |
2268 | + """ |
2269 | + Delete messages dirs if there's any over the max, which happens if |
2270 | + messages are queued up but not able to be sent |
2271 | + """ |
2272 | + |
2273 | + cur_dirs = os.listdir(self._directory) |
2274 | + cur_dirs.sort(key=int) # Since you could have 0, .., 9, 10 |
2275 | + num_dirs = len(cur_dirs) |
2276 | + |
2277 | + num_dirs_to_delete = max(0, num_dirs - self._max_dirs) # No negatives |
2278 | + dirs_to_delete = cur_dirs[:num_dirs_to_delete] # Chop off beginning |
2279 | + |
2280 | + for dirname in dirs_to_delete: |
2281 | + dirpath = os.path.join(self._directory, dirname) |
2282 | + try: |
2283 | + logging.debug(f"Trimming message store: {dirpath}") |
2284 | + shutil.rmtree(dirpath) |
2285 | + except Exception: # We want to continue like normal if any error |
2286 | + logging.warning(traceback.format_exc()) |
2287 | + logging.warning("Unable to delete message directory!") |
2288 | + logging.warning(dirpath) |
2289 | + |
2290 | + # Something is wrong if after deleting a bunch of files, we are still |
2291 | + # using too much space. Rather then look around for big files, we just |
2292 | + # start over. |
2293 | + num_bytes = self.get_messages_total_size() |
2294 | + num_mb = num_bytes / 1e6 |
2295 | + if num_mb > self._max_size_mb: |
2296 | + logging.warning("Messages too large! Clearing all messages!") |
2297 | + self.delete_all_messages() |
2298 | + |
2299 | def delete_old_messages(self): |
2300 | """Delete messages which are unlikely to be needed in the future.""" |
2301 | - for fn in itertools.islice(self._walk_messages(exclude=HELD + BROKEN), |
2302 | - self.get_pending_offset()): |
2303 | + for fn in itertools.islice( |
2304 | + self._walk_messages(exclude=HELD + BROKEN), |
2305 | + self.get_pending_offset(), |
2306 | + ): |
2307 | os.unlink(fn) |
2308 | containing_dir = os.path.split(fn)[0] |
2309 | if not os.listdir(containing_dir): |
2310 | @@ -326,9 +376,9 @@ class MessageStore(object): |
2311 | pending_offset = self.get_pending_offset() |
2312 | for filename in self._walk_messages(exclude=BROKEN): |
2313 | flags = self._get_flags(filename) |
2314 | - if ((HELD in flags or i >= pending_offset) and |
2315 | - os.stat(filename).st_ino == message_id |
2316 | - ): |
2317 | + if (HELD in flags or i >= pending_offset) and os.stat( |
2318 | + filename, |
2319 | + ).st_ino == message_id: |
2320 | return True |
2321 | if BROKEN not in flags and HELD not in flags: |
2322 | i += 1 |
2323 | @@ -347,7 +397,8 @@ class MessageStore(object): |
2324 | if not self._persist.has("first-failure-time"): |
2325 | self._persist.set("first-failure-time", timestamp) |
2326 | continued_failure_time = timestamp - self._persist.get( |
2327 | - "first-failure-time") |
2328 | + "first-failure-time", |
2329 | + ) |
2330 | if self._persist.get("blackhole-messages"): |
2331 | # Already added the resync message |
2332 | return |
2333 | @@ -357,7 +408,8 @@ class MessageStore(object): |
2334 | self._persist.set("blackhole-messages", True) |
2335 | logging.warning( |
2336 | "Unable to succesfully communicate with Landscape server " |
2337 | - "for more than a week. Waiting for resync.") |
2338 | + "for more than a week. Waiting for resync.", |
2339 | + ) |
2340 | |
2341 | def add(self, message): |
2342 | """Queue a message for delivery. |
2343 | @@ -373,6 +425,8 @@ class MessageStore(object): |
2344 | logging.debug("Dropped message, awaiting resync.") |
2345 | return |
2346 | |
2347 | + self.delete_messages_over_limit() |
2348 | + |
2349 | server_api = self.get_server_api() |
2350 | |
2351 | if "api" not in message: |
2352 | @@ -432,7 +486,8 @@ class MessageStore(object): |
2353 | """Walk the files which are definitely pending.""" |
2354 | pending_offset = self.get_pending_offset() |
2355 | for i, filename in enumerate( |
2356 | - self._walk_messages(exclude=HELD + BROKEN)): |
2357 | + self._walk_messages(exclude=HELD + BROKEN), |
2358 | + ): |
2359 | if i >= pending_offset: |
2360 | yield filename |
2361 | |
2362 | @@ -443,12 +498,15 @@ class MessageStore(object): |
2363 | for message_dir in message_dirs: |
2364 | for filename in self._get_sorted_filenames(message_dir): |
2365 | flags = set(self._get_flags(filename)) |
2366 | - if (not exclude or not exclude & flags): |
2367 | + if not exclude or not exclude & flags: |
2368 | yield self._message_dir(message_dir, filename) |
2369 | |
2370 | def _get_sorted_filenames(self, dir=""): |
2371 | - message_files = [x for x in os.listdir(self._message_dir(dir)) |
2372 | - if not x.endswith(".tmp")] |
2373 | + message_files = [ |
2374 | + x |
2375 | + for x in os.listdir(self._message_dir(dir)) |
2376 | + if not x.endswith(".tmp") |
2377 | + ] |
2378 | message_files.sort(key=lambda x: int(x.split("_")[0])) |
2379 | return message_files |
2380 | |
2381 | @@ -549,6 +607,7 @@ def get_default_message_store(*args, **kwargs): |
2382 | Get a L{MessageStore} object with all Landscape message schemas added. |
2383 | """ |
2384 | from landscape.message_schemas.server_bound import message_schemas |
2385 | + |
2386 | store = MessageStore(*args, **kwargs) |
2387 | for schema in message_schemas: |
2388 | store.add_schema(schema) |
2389 | diff --git a/landscape/client/broker/tests/helpers.py b/landscape/client/broker/tests/helpers.py |
2390 | index 367a03f..2ce52b0 100644 |
2391 | --- a/landscape/client/broker/tests/helpers.py |
2392 | +++ b/landscape/client/broker/tests/helpers.py |
2393 | @@ -7,23 +7,24 @@ connected to remote test L{BrokerClient}. |
2394 | """ |
2395 | import os |
2396 | |
2397 | -from landscape.lib.persist import Persist |
2398 | -from landscape.lib.testing import FakeReactor |
2399 | -from landscape.client.watchdog import bootstrap_list |
2400 | from landscape.client.amp import ComponentPublisher |
2401 | -from landscape.client.broker.transport import FakeTransport |
2402 | +from landscape.client.broker.amp import RemoteBrokerConnector |
2403 | +from landscape.client.broker.client import BrokerClient |
2404 | +from landscape.client.broker.config import BrokerConfiguration |
2405 | from landscape.client.broker.exchange import MessageExchange |
2406 | from landscape.client.broker.exchangestore import ExchangeStore |
2407 | -from landscape.client.broker.store import get_default_message_store |
2408 | -from landscape.client.broker.registration import Identity, RegistrationHandler |
2409 | from landscape.client.broker.ping import Pinger |
2410 | -from landscape.client.broker.config import BrokerConfiguration |
2411 | +from landscape.client.broker.registration import Identity |
2412 | +from landscape.client.broker.registration import RegistrationHandler |
2413 | from landscape.client.broker.server import BrokerServer |
2414 | -from landscape.client.broker.amp import RemoteBrokerConnector |
2415 | -from landscape.client.broker.client import BrokerClient |
2416 | +from landscape.client.broker.store import get_default_message_store |
2417 | +from landscape.client.broker.transport import FakeTransport |
2418 | +from landscape.client.watchdog import bootstrap_list |
2419 | +from landscape.lib.persist import Persist |
2420 | +from landscape.lib.testing import FakeReactor |
2421 | |
2422 | |
2423 | -class BrokerConfigurationHelper(object): |
2424 | +class BrokerConfigurationHelper: |
2425 | """Setup a L{BrokerConfiguration} instance with some test config values. |
2426 | |
2427 | The following attributes will be set on your test case: |
2428 | @@ -37,8 +38,10 @@ class BrokerConfigurationHelper(object): |
2429 | def set_up(self, test_case): |
2430 | data_path = test_case.makeDir() |
2431 | log_dir = test_case.makeDir() |
2432 | - test_case.config_filename = os.path.join(test_case.makeDir(), |
2433 | - "client.conf") |
2434 | + test_case.config_filename = os.path.join( |
2435 | + test_case.makeDir(), |
2436 | + "client.conf", |
2437 | + ) |
2438 | |
2439 | with open(test_case.config_filename, "w") as fh: |
2440 | fh.write( |
2441 | @@ -47,8 +50,9 @@ class BrokerConfigurationHelper(object): |
2442 | "computer_title = Some Computer\n" |
2443 | "account_name = some_account\n" |
2444 | "ping_url = http://localhost:91910\n" |
2445 | - "data_path = %s\n" |
2446 | - "log_dir = %s\n" % (data_path, log_dir)) |
2447 | + f"data_path = {data_path}\n" |
2448 | + f"log_dir = {log_dir}\n", |
2449 | + ) |
2450 | |
2451 | bootstrap_list.bootstrap(data_path=data_path, log_dir=log_dir) |
2452 | |
2453 | @@ -87,20 +91,31 @@ class ExchangeHelper(BrokerConfigurationHelper): |
2454 | """ |
2455 | |
2456 | def set_up(self, test_case): |
2457 | - super(ExchangeHelper, self).set_up(test_case) |
2458 | + super().set_up(test_case) |
2459 | test_case.persist_filename = test_case.makePersistFile() |
2460 | test_case.persist = Persist(filename=test_case.persist_filename) |
2461 | test_case.mstore = get_default_message_store( |
2462 | - test_case.persist, test_case.config.message_store_path) |
2463 | + test_case.persist, |
2464 | + test_case.config.message_store_path, |
2465 | + ) |
2466 | test_case.identity = Identity(test_case.config, test_case.persist) |
2467 | - test_case.transport = FakeTransport(None, test_case.config.url, |
2468 | - test_case.config.ssl_public_key) |
2469 | + test_case.transport = FakeTransport( |
2470 | + None, |
2471 | + test_case.config.url, |
2472 | + test_case.config.ssl_public_key, |
2473 | + ) |
2474 | test_case.reactor = FakeReactor() |
2475 | test_case.exchange_store = ExchangeStore( |
2476 | - test_case.config.exchange_store_path) |
2477 | + test_case.config.exchange_store_path, |
2478 | + ) |
2479 | test_case.exchanger = MessageExchange( |
2480 | - test_case.reactor, test_case.mstore, test_case.transport, |
2481 | - test_case.identity, test_case.exchange_store, test_case.config) |
2482 | + test_case.reactor, |
2483 | + test_case.mstore, |
2484 | + test_case.transport, |
2485 | + test_case.identity, |
2486 | + test_case.exchange_store, |
2487 | + test_case.config, |
2488 | + ) |
2489 | |
2490 | |
2491 | class RegistrationHelper(ExchangeHelper): |
2492 | @@ -116,16 +131,27 @@ class RegistrationHelper(ExchangeHelper): |
2493 | """ |
2494 | |
2495 | def set_up(self, test_case): |
2496 | - super(RegistrationHelper, self).set_up(test_case) |
2497 | - test_case.pinger = Pinger(test_case.reactor, test_case.identity, |
2498 | - test_case.exchanger, test_case.config) |
2499 | + super().set_up(test_case) |
2500 | + test_case.pinger = Pinger( |
2501 | + test_case.reactor, |
2502 | + test_case.identity, |
2503 | + test_case.exchanger, |
2504 | + test_case.config, |
2505 | + ) |
2506 | test_case.config.cloud = getattr(test_case, "cloud", False) |
2507 | if hasattr(test_case, "juju_contents"): |
2508 | test_case.makeFile( |
2509 | - test_case.juju_contents, path=test_case.config.juju_filename) |
2510 | + test_case.juju_contents, |
2511 | + path=test_case.config.juju_filename, |
2512 | + ) |
2513 | test_case.handler = RegistrationHandler( |
2514 | - test_case.config, test_case.identity, test_case.reactor, |
2515 | - test_case.exchanger, test_case.pinger, test_case.mstore) |
2516 | + test_case.config, |
2517 | + test_case.identity, |
2518 | + test_case.reactor, |
2519 | + test_case.exchanger, |
2520 | + test_case.pinger, |
2521 | + test_case.mstore, |
2522 | + ) |
2523 | |
2524 | |
2525 | class BrokerServerHelper(RegistrationHelper): |
2526 | @@ -139,10 +165,15 @@ class BrokerServerHelper(RegistrationHelper): |
2527 | """ |
2528 | |
2529 | def set_up(self, test_case): |
2530 | - super(BrokerServerHelper, self).set_up(test_case) |
2531 | - test_case.broker = BrokerServer(test_case.config, test_case.reactor, |
2532 | - test_case.exchanger, test_case.handler, |
2533 | - test_case.mstore, test_case.pinger) |
2534 | + super().set_up(test_case) |
2535 | + test_case.broker = BrokerServer( |
2536 | + test_case.config, |
2537 | + test_case.reactor, |
2538 | + test_case.exchanger, |
2539 | + test_case.handler, |
2540 | + test_case.mstore, |
2541 | + test_case.pinger, |
2542 | + ) |
2543 | |
2544 | |
2545 | class RemoteBrokerHelper(BrokerServerHelper): |
2546 | @@ -168,13 +199,17 @@ class RemoteBrokerHelper(BrokerServerHelper): |
2547 | """ |
2548 | |
2549 | def set_up(self, test_case): |
2550 | - super(RemoteBrokerHelper, self).set_up(test_case) |
2551 | - |
2552 | - self._publisher = ComponentPublisher(test_case.broker, |
2553 | - test_case.reactor, |
2554 | - test_case.config) |
2555 | - self._connector = RemoteBrokerConnector(test_case.reactor, |
2556 | - test_case.config) |
2557 | + super().set_up(test_case) |
2558 | + |
2559 | + self._publisher = ComponentPublisher( |
2560 | + test_case.broker, |
2561 | + test_case.reactor, |
2562 | + test_case.config, |
2563 | + ) |
2564 | + self._connector = RemoteBrokerConnector( |
2565 | + test_case.reactor, |
2566 | + test_case.config, |
2567 | + ) |
2568 | |
2569 | self._publisher.start() |
2570 | deferred = self._connector.connect() |
2571 | @@ -183,7 +218,7 @@ class RemoteBrokerHelper(BrokerServerHelper): |
2572 | def tear_down(self, test_case): |
2573 | self._connector.disconnect() |
2574 | self._publisher.stop() |
2575 | - super(RemoteBrokerHelper, self).tear_down(test_case) |
2576 | + super().tear_down(test_case) |
2577 | |
2578 | |
2579 | class BrokerClientHelper(RemoteBrokerHelper): |
2580 | @@ -204,7 +239,7 @@ class BrokerClientHelper(RemoteBrokerHelper): |
2581 | """ |
2582 | |
2583 | def set_up(self, test_case): |
2584 | - super(BrokerClientHelper, self).set_up(test_case) |
2585 | + super().set_up(test_case) |
2586 | # The client needs its own reactor to avoid infinite loops |
2587 | # when the broker broadcasts and event |
2588 | test_case.client_reactor = FakeReactor() |
2589 | @@ -227,10 +262,12 @@ class RemoteClientHelper(BrokerClientHelper): |
2590 | """ |
2591 | |
2592 | def set_up(self, test_case): |
2593 | - super(RemoteClientHelper, self).set_up(test_case) |
2594 | - self._client_publisher = ComponentPublisher(test_case.client, |
2595 | - test_case.reactor, |
2596 | - test_case.config) |
2597 | + super().set_up(test_case) |
2598 | + self._client_publisher = ComponentPublisher( |
2599 | + test_case.client, |
2600 | + test_case.reactor, |
2601 | + test_case.config, |
2602 | + ) |
2603 | self._client_publisher.start() |
2604 | test_case.remote.register_client("client") |
2605 | test_case.remote_client = test_case.broker.get_client("client") |
2606 | @@ -239,4 +276,4 @@ class RemoteClientHelper(BrokerClientHelper): |
2607 | def tear_down(self, test_case): |
2608 | self._client_connector.disconnect() |
2609 | self._client_publisher.stop() |
2610 | - super(RemoteClientHelper, self).tear_down(test_case) |
2611 | + super().tear_down(test_case) |
2612 | diff --git a/landscape/client/broker/tests/test_amp.py b/landscape/client/broker/tests/test_amp.py |
2613 | index a017dc1..bc992b4 100644 |
2614 | --- a/landscape/client/broker/tests/test_amp.py |
2615 | +++ b/landscape/client/broker/tests/test_amp.py |
2616 | @@ -1,10 +1,10 @@ |
2617 | -import mock |
2618 | +from unittest import mock |
2619 | |
2620 | +from landscape.client.broker.tests.helpers import RemoteBrokerHelper |
2621 | +from landscape.client.broker.tests.helpers import RemoteClientHelper |
2622 | +from landscape.client.tests.helpers import DEFAULT_ACCEPTED_TYPES |
2623 | +from landscape.client.tests.helpers import LandscapeTest |
2624 | from landscape.lib.amp import MethodCallError |
2625 | -from landscape.client.tests.helpers import ( |
2626 | - LandscapeTest, DEFAULT_ACCEPTED_TYPES) |
2627 | -from landscape.client.broker.tests.helpers import ( |
2628 | - RemoteBrokerHelper, RemoteClientHelper) |
2629 | |
2630 | |
2631 | class RemoteBrokerTest(LandscapeTest): |
2632 | @@ -41,13 +41,13 @@ class RemoteBrokerTest(LandscapeTest): |
2633 | |
2634 | session_id = self.successResultOf(self.remote.get_session_id()) |
2635 | message_id = self.successResultOf( |
2636 | - self.remote.send_message(message, session_id)) |
2637 | + self.remote.send_message(message, session_id), |
2638 | + ) |
2639 | |
2640 | self.assertTrue(isinstance(message_id, int)) |
2641 | self.assertTrue(self.mstore.is_pending(message_id)) |
2642 | self.assertFalse(self.exchanger.is_urgent()) |
2643 | - self.assertMessages(self.mstore.get_pending_messages(), |
2644 | - [message]) |
2645 | + self.assertMessages(self.mstore.get_pending_messages(), [message]) |
2646 | |
2647 | def test_send_message_with_urgent(self): |
2648 | """ |
2649 | @@ -56,8 +56,9 @@ class RemoteBrokerTest(LandscapeTest): |
2650 | message = {"type": "test"} |
2651 | self.mstore.set_accepted_types(["test"]) |
2652 | session_id = self.successResultOf(self.remote.get_session_id()) |
2653 | - message_id = self.successResultOf(self.remote.send_message( |
2654 | - message, session_id, urgent=True)) |
2655 | + message_id = self.successResultOf( |
2656 | + self.remote.send_message(message, session_id, urgent=True), |
2657 | + ) |
2658 | self.assertTrue(isinstance(message_id, int)) |
2659 | self.assertTrue(self.exchanger.is_urgent()) |
2660 | |
2661 | @@ -95,8 +96,9 @@ class RemoteBrokerTest(LandscapeTest): |
2662 | a L{Deferred}. |
2663 | """ |
2664 | # This should make the registration succeed |
2665 | - self.transport.responses.append([{"type": "set-id", "id": "abc", |
2666 | - "insecure-id": "def"}]) |
2667 | + self.transport.responses.append( |
2668 | + [{"type": "set-id", "id": "abc", "insecure-id": "def"}], |
2669 | + ) |
2670 | result = self.remote.register() |
2671 | return self.assertSuccess(result, None) |
2672 | |
2673 | @@ -130,7 +132,8 @@ class RemoteBrokerTest(LandscapeTest): |
2674 | self.assertEqual(response, None) |
2675 | self.assertEqual( |
2676 | self.exchanger.get_client_accepted_message_types(), |
2677 | - sorted(["type"] + DEFAULT_ACCEPTED_TYPES)) |
2678 | + sorted(["type"] + DEFAULT_ACCEPTED_TYPES), |
2679 | + ) |
2680 | |
2681 | result = self.remote.register_client_accepted_message_type("type") |
2682 | return result.addCallback(assert_response) |
2683 | @@ -159,8 +162,11 @@ class RemoteBrokerTest(LandscapeTest): |
2684 | The L{RemoteBroker.call_if_accepted} method doesn't do anything if the |
2685 | given message type is not accepted. |
2686 | """ |
2687 | - function = (lambda: 1 / 0) |
2688 | - result = self.remote.call_if_accepted("test", function) |
2689 | + |
2690 | + def division_by_zero(): |
2691 | + raise ZeroDivisionError() |
2692 | + |
2693 | + result = self.remote.call_if_accepted("test", division_by_zero) |
2694 | return self.assertSuccess(result, None) |
2695 | |
2696 | def test_listen_events(self): |
2697 | @@ -181,8 +187,9 @@ class RemoteBrokerTest(LandscapeTest): |
2698 | """ |
2699 | callback1 = mock.Mock() |
2700 | callback2 = mock.Mock(return_value=123) |
2701 | - deferred = self.remote.call_on_event({"event1": callback1, |
2702 | - "event2": callback2}) |
2703 | + deferred = self.remote.call_on_event( |
2704 | + {"event1": callback1, "event2": callback2}, |
2705 | + ) |
2706 | self.reactor.call_later(0.05, self.reactor.fire, "event2") |
2707 | self.reactor.advance(0.05) |
2708 | self.remote._factory.fake_connection.flush() |
2709 | @@ -228,8 +235,10 @@ class RemoteClientTest(LandscapeTest): |
2710 | a L{Deferred}. |
2711 | """ |
2712 | handler = mock.Mock() |
2713 | - with mock.patch.object(self.client.broker, |
2714 | - "register_client_accepted_message_type") as m: |
2715 | + with mock.patch.object( |
2716 | + self.client.broker, |
2717 | + "register_client_accepted_message_type", |
2718 | + ) as m: |
2719 | # We need to register a test message handler to let the dispatch |
2720 | # message method call succeed |
2721 | self.client.register_message("test", handler) |
2722 | diff --git a/landscape/client/broker/tests/test_client.py b/landscape/client/broker/tests/test_client.py |
2723 | index 3295b02..219cc0c 100644 |
2724 | --- a/landscape/client/broker/tests/test_client.py |
2725 | +++ b/landscape/client/broker/tests/test_client.py |
2726 | @@ -1,14 +1,14 @@ |
2727 | -import mock |
2728 | +from unittest import mock |
2729 | |
2730 | from twisted.internet import reactor |
2731 | from twisted.internet.defer import Deferred |
2732 | |
2733 | -from landscape.lib.twisted_util import gather_results |
2734 | -from landscape.client.tests.helpers import ( |
2735 | - LandscapeTest, DEFAULT_ACCEPTED_TYPES) |
2736 | +from landscape.client.broker.client import BrokerClientPlugin |
2737 | +from landscape.client.broker.client import HandlerNotFoundError |
2738 | from landscape.client.broker.tests.helpers import BrokerClientHelper |
2739 | -from landscape.client.broker.client import ( |
2740 | - BrokerClientPlugin, HandlerNotFoundError) |
2741 | +from landscape.client.tests.helpers import DEFAULT_ACCEPTED_TYPES |
2742 | +from landscape.client.tests.helpers import LandscapeTest |
2743 | +from landscape.lib.twisted_util import gather_results |
2744 | |
2745 | |
2746 | class BrokerClientTest(LandscapeTest): |
2747 | @@ -45,7 +45,8 @@ class BrokerClientTest(LandscapeTest): |
2748 | getting a session id. |
2749 | """ |
2750 | test_session_id = self.successResultOf( |
2751 | - self.client.broker.get_session_id(scope="test")) |
2752 | + self.client.broker.get_session_id(scope="test"), |
2753 | + ) |
2754 | plugin = BrokerClientPlugin() |
2755 | plugin.scope = "test" |
2756 | self.client.add(plugin) |
2757 | @@ -130,8 +131,10 @@ class BrokerClientTest(LandscapeTest): |
2758 | If a plugin has a run method, the reactor will call it every |
2759 | run_interval, but will stop and log if it raises unhandled exceptions. |
2760 | """ |
2761 | + |
2762 | class RunFailure(Exception): |
2763 | pass |
2764 | + |
2765 | # log helper should not complain on the error we're testing |
2766 | self.log_helper.ignore_errors("BrokerClientPlugin.*") |
2767 | plugin = BrokerClientPlugin() |
2768 | @@ -146,7 +149,8 @@ class BrokerClientTest(LandscapeTest): |
2769 | # message entry that would be present on a live client. |
2770 | self.assertIn( |
2771 | "ERROR: BrokerClientPlugin raised an uncaught exception", |
2772 | - self.logfile.getvalue()) |
2773 | + self.logfile.getvalue(), |
2774 | + ) |
2775 | |
2776 | def test_run_interval_blocked_during_resynch(self): |
2777 | """ |
2778 | @@ -220,7 +224,8 @@ class BrokerClientTest(LandscapeTest): |
2779 | def got_result(result): |
2780 | self.assertEqual( |
2781 | self.exchanger.get_client_accepted_message_types(), |
2782 | - sorted(["bar", "foo"] + DEFAULT_ACCEPTED_TYPES)) |
2783 | + sorted(["bar", "foo"] + DEFAULT_ACCEPTED_TYPES), |
2784 | + ) |
2785 | |
2786 | return gather_results([result1, result2]).addCallback(got_result) |
2787 | |
2788 | @@ -251,8 +256,10 @@ class BrokerClientTest(LandscapeTest): |
2789 | |
2790 | def dispatch_message(result): |
2791 | self.assertIs(self.client.dispatch_message(message), None) |
2792 | - self.assertTrue("Error running message handler for type 'foo'" in |
2793 | - self.logfile.getvalue()) |
2794 | + self.assertTrue( |
2795 | + "Error running message handler for type 'foo'" |
2796 | + in self.logfile.getvalue(), |
2797 | + ) |
2798 | handle_message.assert_called_once_with(message) |
2799 | |
2800 | result = self.client.register_message("foo", handle_message) |
2801 | @@ -263,8 +270,11 @@ class BrokerClientTest(LandscapeTest): |
2802 | L{BrokerClient.dispatch_message} raises an error if no handler was |
2803 | found for the given message. |
2804 | """ |
2805 | - error = self.assertRaises(HandlerNotFoundError, |
2806 | - self.client.dispatch_message, {"type": "x"}) |
2807 | + error = self.assertRaises( |
2808 | + HandlerNotFoundError, |
2809 | + self.client.dispatch_message, |
2810 | + {"type": "x"}, |
2811 | + ) |
2812 | self.assertEqual(str(error), "x") |
2813 | |
2814 | def test_message(self): |
2815 | @@ -326,8 +336,9 @@ class BrokerClientTest(LandscapeTest): |
2816 | self.client.add(plugin1) |
2817 | self.client.add(plugin2) |
2818 | self.client.exchange() |
2819 | - self.assertTrue("Error during plugin exchange" in |
2820 | - self.logfile.getvalue()) |
2821 | + self.assertTrue( |
2822 | + "Error during plugin exchange" in self.logfile.getvalue(), |
2823 | + ) |
2824 | self.assertTrue("ZeroDivisionError" in self.logfile.getvalue()) |
2825 | plugin1.exchange.assert_called_once_with() |
2826 | plugin2.exchange.assert_called_once_with() |
2827 | @@ -342,8 +353,10 @@ class BrokerClientTest(LandscapeTest): |
2828 | plugin.exchange = mock.Mock() |
2829 | self.client.add(plugin) |
2830 | self.client_reactor.fire("impending-exchange") |
2831 | - self.assertTrue("Got notification of impending exchange. " |
2832 | - "Notifying all plugins." in self.logfile.getvalue()) |
2833 | + self.assertTrue( |
2834 | + "Got notification of impending exchange. " |
2835 | + "Notifying all plugins." in self.logfile.getvalue(), |
2836 | + ) |
2837 | plugin.exchange.assert_called_once_with() |
2838 | |
2839 | def test_fire_event(self): |
2840 | @@ -415,7 +428,9 @@ class BrokerClientTest(LandscapeTest): |
2841 | calls = [mock.call("bar"), mock.call("foo")] |
2842 | |
2843 | broker.register_client_accepted_message_type.assert_has_calls( |
2844 | - calls, any_order=True) |
2845 | + calls, |
2846 | + any_order=True, |
2847 | + ) |
2848 | broker.register_client.assert_called_once_with("client") |
2849 | |
2850 | return gather_results([result1, result2]).addCallback(got_result) |
2851 | diff --git a/landscape/client/broker/tests/test_config.py b/landscape/client/broker/tests/test_config.py |
2852 | index 0b60fc4..b5236ae 100644 |
2853 | --- a/landscape/client/broker/tests/test_config.py |
2854 | +++ b/landscape/client/broker/tests/test_config.py |
2855 | @@ -1,8 +1,8 @@ |
2856 | import os |
2857 | |
2858 | from landscape.client.broker.config import BrokerConfiguration |
2859 | -from landscape.lib.testing import EnvironSaverHelper |
2860 | from landscape.client.tests.helpers import LandscapeTest |
2861 | +from landscape.lib.testing import EnvironSaverHelper |
2862 | |
2863 | |
2864 | class ConfigurationTests(LandscapeTest): |
2865 | @@ -20,9 +20,16 @@ class ConfigurationTests(LandscapeTest): |
2866 | del os.environ["https_proxy"] |
2867 | |
2868 | configuration = BrokerConfiguration() |
2869 | - configuration.load(["--http-proxy", "foo", |
2870 | - "--https-proxy", "bar", |
2871 | - "--url", "whatever"]) |
2872 | + configuration.load( |
2873 | + [ |
2874 | + "--http-proxy", |
2875 | + "foo", |
2876 | + "--https-proxy", |
2877 | + "bar", |
2878 | + "--url", |
2879 | + "whatever", |
2880 | + ], |
2881 | + ) |
2882 | self.assertEqual(os.environ["http_proxy"], "foo") |
2883 | self.assertEqual(os.environ["https_proxy"], "bar") |
2884 | |
2885 | @@ -53,9 +60,9 @@ class ConfigurationTests(LandscapeTest): |
2886 | os.environ["https_proxy"] = "originals" |
2887 | |
2888 | configuration = BrokerConfiguration() |
2889 | - configuration.load(["--http-proxy", "x", |
2890 | - "--https-proxy", "y", |
2891 | - "--url", "whatever"]) |
2892 | + configuration.load( |
2893 | + ["--http-proxy", "x", "--https-proxy", "y", "--url", "whatever"], |
2894 | + ) |
2895 | self.assertEqual(os.environ["http_proxy"], "x") |
2896 | self.assertEqual(os.environ["https_proxy"], "y") |
2897 | |
2898 | @@ -74,10 +81,12 @@ class ConfigurationTests(LandscapeTest): |
2899 | The 'urgent_exchange_interval, 'exchange_interval' and 'ping_interval' |
2900 | values specified in the configuration file are converted to integers. |
2901 | """ |
2902 | - filename = self.makeFile("[client]\n" |
2903 | - "urgent_exchange_interval = 12\n" |
2904 | - "exchange_interval = 34\n" |
2905 | - "ping_interval = 6\n") |
2906 | + filename = self.makeFile( |
2907 | + "[client]\n" |
2908 | + "urgent_exchange_interval = 12\n" |
2909 | + "exchange_interval = 34\n" |
2910 | + "ping_interval = 6\n", |
2911 | + ) |
2912 | |
2913 | configuration = BrokerConfiguration() |
2914 | configuration.load(["--config", filename, "--url", "whatever"]) |
2915 | @@ -91,8 +100,9 @@ class ConfigurationTests(LandscapeTest): |
2916 | The 'tags' value specified in the configuration file is not converted |
2917 | to a list (it must be a string). See bug #1228301. |
2918 | """ |
2919 | - filename = self.makeFile("[client]\n" |
2920 | - "tags = check,linode,profile-test") |
2921 | + filename = self.makeFile( |
2922 | + "[client]\ntags = check,linode,profile-test", |
2923 | + ) |
2924 | |
2925 | configuration = BrokerConfiguration() |
2926 | configuration.load(["--config", filename, "--url", "whatever"]) |
2927 | @@ -104,8 +114,7 @@ class ConfigurationTests(LandscapeTest): |
2928 | The 'access_group' value specified in the configuration file is |
2929 | passed through. |
2930 | """ |
2931 | - filename = self.makeFile("[client]\n" |
2932 | - "access_group = webserver") |
2933 | + filename = self.makeFile("[client]\naccess_group = webserver") |
2934 | |
2935 | configuration = BrokerConfiguration() |
2936 | configuration.load(["--config", filename, "--url", "whatever"]) |
2937 | @@ -122,5 +131,7 @@ class ConfigurationTests(LandscapeTest): |
2938 | configuration = BrokerConfiguration() |
2939 | configuration.load(["--config", filename]) |
2940 | |
2941 | - self.assertEqual(configuration.url, |
2942 | - "https://landscape.canonical.com/message-system") |
2943 | + self.assertEqual( |
2944 | + configuration.url, |
2945 | + "https://landscape.canonical.com/message-system", |
2946 | + ) |
2947 | diff --git a/landscape/client/broker/tests/test_exchange.py b/landscape/client/broker/tests/test_exchange.py |
2948 | index 3736bd4..bc7fb5f 100644 |
2949 | --- a/landscape/client/broker/tests/test_exchange.py |
2950 | +++ b/landscape/client/broker/tests/test_exchange.py |
2951 | @@ -1,22 +1,23 @@ |
2952 | -import mock |
2953 | +from unittest import mock |
2954 | |
2955 | from landscape import CLIENT_API |
2956 | -from landscape.lib.persist import Persist |
2957 | -from landscape.lib.fetch import HTTPCodeError, PyCurlError |
2958 | -from landscape.lib.hashlib import md5 |
2959 | -from landscape.lib.schema import Int |
2960 | -from landscape.message_schemas.message import Message |
2961 | from landscape.client.broker.config import BrokerConfiguration |
2962 | -from landscape.client.broker.exchange import ( |
2963 | - get_accepted_types_diff, MessageExchange) |
2964 | -from landscape.client.broker.transport import FakeTransport |
2965 | -from landscape.client.broker.store import MessageStore |
2966 | +from landscape.client.broker.exchange import get_accepted_types_diff |
2967 | +from landscape.client.broker.exchange import MessageExchange |
2968 | from landscape.client.broker.ping import Pinger |
2969 | from landscape.client.broker.registration import RegistrationHandler |
2970 | -from landscape.client.tests.helpers import ( |
2971 | - LandscapeTest, DEFAULT_ACCEPTED_TYPES) |
2972 | -from landscape.client.broker.tests.helpers import ExchangeHelper |
2973 | from landscape.client.broker.server import BrokerServer |
2974 | +from landscape.client.broker.store import MessageStore |
2975 | +from landscape.client.broker.tests.helpers import ExchangeHelper |
2976 | +from landscape.client.broker.transport import FakeTransport |
2977 | +from landscape.client.tests.helpers import DEFAULT_ACCEPTED_TYPES |
2978 | +from landscape.client.tests.helpers import LandscapeTest |
2979 | +from landscape.lib.fetch import HTTPCodeError |
2980 | +from landscape.lib.fetch import PyCurlError |
2981 | +from landscape.lib.hashlib import md5 |
2982 | +from landscape.lib.persist import Persist |
2983 | +from landscape.lib.schema import Int |
2984 | +from landscape.message_schemas.message import Message |
2985 | |
2986 | |
2987 | class MessageExchangeTest(LandscapeTest): |
2988 | @@ -24,11 +25,11 @@ class MessageExchangeTest(LandscapeTest): |
2989 | helpers = [ExchangeHelper] |
2990 | |
2991 | def setUp(self): |
2992 | - super(MessageExchangeTest, self).setUp() |
2993 | + super().setUp() |
2994 | self.mstore.add_schema(Message("empty", {})) |
2995 | self.mstore.add_schema(Message("data", {"data": Int()})) |
2996 | self.mstore.add_schema(Message("holdme", {})) |
2997 | - self.identity.secure_id = 'needs-to-be-set-for-tests-to-pass' |
2998 | + self.identity.secure_id = "needs-to-be-set-for-tests-to-pass" |
2999 | |
3000 | def wait_for_exchange(self, urgent=False, factor=1, delta=0): |
3001 | if urgent: |
3002 | @@ -52,9 +53,14 @@ class MessageExchangeTest(LandscapeTest): |
3003 | session IDs are expired, so any new messages being sent with those IDs |
3004 | will be discarded. |
3005 | """ |
3006 | - broker = BrokerServer(self.config, self.reactor, |
3007 | - self.exchanger, None, |
3008 | - self.mstore, None) |
3009 | + broker = BrokerServer( |
3010 | + self.config, |
3011 | + self.reactor, |
3012 | + self.exchanger, |
3013 | + None, |
3014 | + self.mstore, |
3015 | + None, |
3016 | + ) |
3017 | |
3018 | disk_session_id = self.mstore.get_session_id(scope="disk") |
3019 | package_session_id = self.mstore.get_session_id(scope="package") |
3020 | @@ -72,9 +78,14 @@ class MessageExchangeTest(LandscapeTest): |
3021 | When a resynchronisation event occurs with a scope existing session IDs |
3022 | for that scope are expired, all other session IDs are unaffected. |
3023 | """ |
3024 | - broker = BrokerServer(self.config, self.reactor, |
3025 | - self.exchanger, None, |
3026 | - self.mstore, None) |
3027 | + broker = BrokerServer( |
3028 | + self.config, |
3029 | + self.reactor, |
3030 | + self.exchanger, |
3031 | + None, |
3032 | + self.mstore, |
3033 | + None, |
3034 | + ) |
3035 | |
3036 | disk_session_id = self.mstore.get_session_id(scope="disk") |
3037 | package_session_id = self.mstore.get_session_id(scope="package") |
3038 | @@ -105,9 +116,10 @@ class MessageExchangeTest(LandscapeTest): |
3039 | self.exchanger.exchange() |
3040 | self.assertEqual(len(self.transport.payloads), 1) |
3041 | messages = self.transport.payloads[0]["messages"] |
3042 | - self.assertEqual(messages, [{"type": "empty", |
3043 | - "timestamp": 0, |
3044 | - "api": b"3.2"}]) |
3045 | + self.assertEqual( |
3046 | + messages, |
3047 | + [{"type": "empty", "timestamp": 0, "api": b"3.2"}], |
3048 | + ) |
3049 | |
3050 | def test_send_urgent(self): |
3051 | """ |
3052 | @@ -118,8 +130,10 @@ class MessageExchangeTest(LandscapeTest): |
3053 | self.exchanger.send({"type": "empty"}, urgent=True) |
3054 | self.wait_for_exchange(urgent=True) |
3055 | self.assertEqual(len(self.transport.payloads), 1) |
3056 | - self.assertMessages(self.transport.payloads[0]["messages"], |
3057 | - [{"type": "empty"}]) |
3058 | + self.assertMessages( |
3059 | + self.transport.payloads[0]["messages"], |
3060 | + [{"type": "empty"}], |
3061 | + ) |
3062 | |
3063 | def test_send_urgent_wont_reschedule(self): |
3064 | """ |
3065 | @@ -132,8 +146,10 @@ class MessageExchangeTest(LandscapeTest): |
3066 | self.exchanger.send({"type": "empty"}, urgent=True) |
3067 | self.wait_for_exchange(urgent=True, factor=0.5) |
3068 | self.assertEqual(len(self.transport.payloads), 1) |
3069 | - self.assertMessages(self.transport.payloads[0]["messages"], |
3070 | - [{"type": "empty"}, {"type": "empty"}]) |
3071 | + self.assertMessages( |
3072 | + self.transport.payloads[0]["messages"], |
3073 | + [{"type": "empty"}, {"type": "empty"}], |
3074 | + ) |
3075 | |
3076 | def test_send_returns_message_id(self): |
3077 | """ |
3078 | @@ -151,14 +167,15 @@ class MessageExchangeTest(LandscapeTest): |
3079 | """ |
3080 | self.mstore.set_accepted_types(["package-reporter-result"]) |
3081 | self.exchanger._max_log_text_bytes = 5 |
3082 | - self.exchanger.send({"type": "package-reporter-result", "err": "E"*10, |
3083 | - "code": 0}) |
3084 | + self.exchanger.send( |
3085 | + {"type": "package-reporter-result", "err": "E" * 10, "code": 0}, |
3086 | + ) |
3087 | self.exchanger.exchange() |
3088 | self.assertEqual(len(self.transport.payloads), 1) |
3089 | messages = self.transport.payloads[0]["messages"] |
3090 | - self.assertIn('TRUNCATED', messages[0]['err']) |
3091 | - self.assertIn('EEEEE', messages[0]['err']) |
3092 | - self.assertNotIn('EEEEEE', messages[0]['err']) |
3093 | + self.assertIn("TRUNCATED", messages[0]["err"]) |
3094 | + self.assertIn("EEEEE", messages[0]["err"]) |
3095 | + self.assertNotIn("EEEEEE", messages[0]["err"]) |
3096 | |
3097 | def test_send_big_message_trimmed_result(self): |
3098 | """ |
3099 | @@ -166,14 +183,21 @@ class MessageExchangeTest(LandscapeTest): |
3100 | """ |
3101 | self.mstore.set_accepted_types(["operation-result"]) |
3102 | self.exchanger._max_log_text_bytes = 5 |
3103 | - self.exchanger.send({"type": "operation-result", "result-text": "E"*10, |
3104 | - "code": 0, "status": 0, "operation-id": 0}) |
3105 | + self.exchanger.send( |
3106 | + { |
3107 | + "type": "operation-result", |
3108 | + "result-text": "E" * 10, |
3109 | + "code": 0, |
3110 | + "status": 0, |
3111 | + "operation-id": 0, |
3112 | + }, |
3113 | + ) |
3114 | self.exchanger.exchange() |
3115 | self.assertEqual(len(self.transport.payloads), 1) |
3116 | messages = self.transport.payloads[0]["messages"] |
3117 | - self.assertIn('TRUNCATED', messages[0]['result-text']) |
3118 | - self.assertIn('EEEEE', messages[0]['result-text']) |
3119 | - self.assertNotIn('EEEEEE', messages[0]['result-text']) |
3120 | + self.assertIn("TRUNCATED", messages[0]["result-text"]) |
3121 | + self.assertIn("EEEEE", messages[0]["result-text"]) |
3122 | + self.assertNotIn("EEEEEE", messages[0]["result-text"]) |
3123 | |
3124 | def test_send_small_message_not_trimmed(self): |
3125 | """ |
3126 | @@ -181,13 +205,14 @@ class MessageExchangeTest(LandscapeTest): |
3127 | """ |
3128 | self.mstore.set_accepted_types(["package-reporter-result"]) |
3129 | self.exchanger._max_log_text_bytes = 4 |
3130 | - self.exchanger.send({"type": "package-reporter-result", "err": "E"*4, |
3131 | - "code": 0}) |
3132 | + self.exchanger.send( |
3133 | + {"type": "package-reporter-result", "err": "E" * 4, "code": 0}, |
3134 | + ) |
3135 | self.exchanger.exchange() |
3136 | self.assertEqual(len(self.transport.payloads), 1) |
3137 | messages = self.transport.payloads[0]["messages"] |
3138 | - self.assertNotIn('TRUNCATED', messages[0]['err']) |
3139 | - self.assertIn('EEEE', messages[0]['err']) |
3140 | + self.assertNotIn("TRUNCATED", messages[0]["err"]) |
3141 | + self.assertIn("EEEE", messages[0]["err"]) |
3142 | |
3143 | def test_wb_include_accepted_types(self): |
3144 | """ |
3145 | @@ -204,7 +229,8 @@ class MessageExchangeTest(LandscapeTest): |
3146 | types. |
3147 | """ |
3148 | self.exchanger.handle_message( |
3149 | - {"type": "accepted-types", "types": ["foo"]}) |
3150 | + {"type": "accepted-types", "types": ["foo"]}, |
3151 | + ) |
3152 | self.assertEqual(self.mstore.get_accepted_types(), ["foo"]) |
3153 | |
3154 | def test_message_type_acceptance_changed_event(self): |
3155 | @@ -212,13 +238,18 @@ class MessageExchangeTest(LandscapeTest): |
3156 | |
3157 | def callback(type, accepted): |
3158 | stash.append((type, accepted)) |
3159 | + |
3160 | self.reactor.call_on("message-type-acceptance-changed", callback) |
3161 | self.exchanger.handle_message( |
3162 | - {"type": "accepted-types", "types": ["a", "b"]}) |
3163 | + {"type": "accepted-types", "types": ["a", "b"]}, |
3164 | + ) |
3165 | self.exchanger.handle_message( |
3166 | - {"type": "accepted-types", "types": ["b", "c"]}) |
3167 | - self.assertCountEqual(stash, [("a", True), ("b", True), |
3168 | - ("a", False), ("c", True)]) |
3169 | + {"type": "accepted-types", "types": ["b", "c"]}, |
3170 | + ) |
3171 | + self.assertCountEqual( |
3172 | + stash, |
3173 | + [("a", True), ("b", True), ("a", False), ("c", True)], |
3174 | + ) |
3175 | |
3176 | def test_wb_accepted_types_roundtrip(self): |
3177 | """ |
3178 | @@ -226,11 +257,11 @@ class MessageExchangeTest(LandscapeTest): |
3179 | should affect its future payloads. |
3180 | """ |
3181 | self.exchanger.handle_message( |
3182 | - {"type": "accepted-types", "types": ["ack", "bar"]}) |
3183 | + {"type": "accepted-types", "types": ["ack", "bar"]}, |
3184 | + ) |
3185 | payload = self.exchanger._make_payload() |
3186 | self.assertIn("accepted-types", payload) |
3187 | - self.assertEqual(payload["accepted-types"], |
3188 | - md5(b"ack;bar").digest()) |
3189 | + self.assertEqual(payload["accepted-types"], md5(b"ack;bar").digest()) |
3190 | |
3191 | def test_accepted_types_causes_urgent_if_held_messages_exist(self): |
3192 | """ |
3193 | @@ -240,11 +271,14 @@ class MessageExchangeTest(LandscapeTest): |
3194 | self.exchanger.send({"type": "holdme"}) |
3195 | self.assertEqual(self.mstore.get_pending_messages(), []) |
3196 | self.exchanger.handle_message( |
3197 | - {"type": "accepted-types", "types": ["holdme"]}) |
3198 | + {"type": "accepted-types", "types": ["holdme"]}, |
3199 | + ) |
3200 | self.wait_for_exchange(urgent=True) |
3201 | self.assertEqual(len(self.transport.payloads), 1) |
3202 | - self.assertMessages(self.transport.payloads[0]["messages"], |
3203 | - [{"type": "holdme"}]) |
3204 | + self.assertMessages( |
3205 | + self.transport.payloads[0]["messages"], |
3206 | + [{"type": "holdme"}], |
3207 | + ) |
3208 | |
3209 | def test_accepted_types_no_urgent_without_held(self): |
3210 | """ |
3211 | @@ -253,8 +287,10 @@ class MessageExchangeTest(LandscapeTest): |
3212 | """ |
3213 | self.exchanger.send({"type": "holdme"}) |
3214 | self.assertEqual(self.transport.payloads, []) |
3215 | - self.reactor.fire("message", |
3216 | - {"type": "accepted-types", "types": ["irrelevant"]}) |
3217 | + self.reactor.fire( |
3218 | + "message", |
3219 | + {"type": "accepted-types", "types": ["irrelevant"]}, |
3220 | + ) |
3221 | self.assertEqual(len(self.transport.payloads), 0) |
3222 | |
3223 | def test_sequence_is_committed_immediately(self): |
3224 | @@ -294,8 +330,7 @@ class MessageExchangeTest(LandscapeTest): |
3225 | def handler(message): |
3226 | Persist(filename=self.persist_filename) |
3227 | store = MessageStore(self.persist, self.config.message_store_path) |
3228 | - self.assertEqual(store.get_server_sequence(), |
3229 | - self.message_counter) |
3230 | + self.assertEqual(store.get_server_sequence(), self.message_counter) |
3231 | self.message_counter += 1 |
3232 | handled.append(True) |
3233 | |
3234 | @@ -324,8 +359,10 @@ class MessageExchangeTest(LandscapeTest): |
3235 | self.wait_for_exchange(urgent=True) |
3236 | |
3237 | self.assertEqual(len(self.transport.payloads), 2) |
3238 | - self.assertMessages(self.transport.payloads[1]["messages"], |
3239 | - [{"type": "empty"}]) |
3240 | + self.assertMessages( |
3241 | + self.transport.payloads[1]["messages"], |
3242 | + [{"type": "empty"}], |
3243 | + ) |
3244 | |
3245 | def test_server_expects_older_messages(self): |
3246 | """ |
3247 | @@ -361,22 +398,29 @@ class MessageExchangeTest(LandscapeTest): |
3248 | self.assertEqual(exchanged, [True]) |
3249 | |
3250 | payload = self.transport.payloads[-1] |
3251 | - self.assertMessages(payload["messages"], |
3252 | - [{"type": "data", "data": 1}, |
3253 | - {"type": "data", "data": 2}, |
3254 | - {"type": "data", "data": 3}]) |
3255 | + self.assertMessages( |
3256 | + payload["messages"], |
3257 | + [ |
3258 | + {"type": "data", "data": 1}, |
3259 | + {"type": "data", "data": 2}, |
3260 | + {"type": "data", "data": 3}, |
3261 | + ], |
3262 | + ) |
3263 | self.assertEqual(payload["sequence"], 1) |
3264 | self.assertEqual(payload["next-expected-sequence"], 0) |
3265 | |
3266 | - @mock.patch("landscape.client.broker.store.MessageStore" |
3267 | - ".delete_old_messages") |
3268 | - def test_pending_offset_when_next_expected_too_high(self, |
3269 | - mock_rm_all_messages): |
3270 | - ''' |
3271 | + @mock.patch( |
3272 | + "landscape.client.broker.store.MessageStore.delete_old_messages", |
3273 | + ) |
3274 | + def test_pending_offset_when_next_expected_too_high( |
3275 | + self, |
3276 | + mock_rm_all_messages, |
3277 | + ): |
3278 | + """ |
3279 | When next expected sequence received from server is too high, then the |
3280 | pending offset should reset to zero. This will cause the client to |
3281 | resend the pending messages. |
3282 | - ''' |
3283 | + """ |
3284 | |
3285 | self.mstore.set_accepted_types(["data"]) |
3286 | self.mstore.add({"type": "data", "data": 0}) |
3287 | @@ -399,12 +443,12 @@ class MessageExchangeTest(LandscapeTest): |
3288 | self.assertTrue(mock_rm_all_messages.called) |
3289 | |
3290 | def test_payloads_when_next_expected_too_high(self): |
3291 | - ''' |
3292 | + """ |
3293 | When next expected sequence received from server is too high, then the |
3294 | current messages should get sent again since we don't have confirmation |
3295 | that the server received it. Also previous messages should not get |
3296 | repeated. |
3297 | - ''' |
3298 | + """ |
3299 | |
3300 | self.mstore.set_accepted_types(["data"]) |
3301 | |
3302 | @@ -426,17 +470,16 @@ class MessageExchangeTest(LandscapeTest): |
3303 | self.assertTrue(last_messages) |
3304 | |
3305 | # Confirm earlier messages are not resent |
3306 | - self.assertNotIn(message0["data"], |
3307 | - [m["data"] for m in last_messages]) |
3308 | + self.assertNotIn(message0["data"], [m["data"] for m in last_messages]) |
3309 | |
3310 | # Confirm contents of payload |
3311 | self.assertEqual([message1, message2], last_messages) |
3312 | |
3313 | def test_resync_when_next_expected_too_high(self): |
3314 | - ''' |
3315 | + """ |
3316 | When next expected sequence received from the server is too high, then |
3317 | a resynchronize should happen |
3318 | - ''' |
3319 | + """ |
3320 | |
3321 | self.mstore.set_accepted_types(["empty", "resynchronize"]) |
3322 | self.mstore.add({"type": "empty"}) |
3323 | @@ -447,17 +490,24 @@ class MessageExchangeTest(LandscapeTest): |
3324 | self.reactor.call_on("resynchronize-clients", lambda scope=None: None) |
3325 | |
3326 | self.exchanger.exchange() |
3327 | - self.assertMessage(self.mstore.get_pending_messages()[-1], |
3328 | - {"type": "resynchronize"}) |
3329 | + self.assertMessage( |
3330 | + self.mstore.get_pending_messages()[-1], |
3331 | + {"type": "resynchronize"}, |
3332 | + ) |
3333 | |
3334 | def test_start_with_urgent_exchange(self): |
3335 | """ |
3336 | Immediately after registration, an urgent exchange should be scheduled. |
3337 | """ |
3338 | transport = FakeTransport() |
3339 | - exchanger = MessageExchange(self.reactor, self.mstore, transport, |
3340 | - self.identity, self.exchange_store, |
3341 | - self.config) |
3342 | + exchanger = MessageExchange( |
3343 | + self.reactor, |
3344 | + self.mstore, |
3345 | + transport, |
3346 | + self.identity, |
3347 | + self.exchange_store, |
3348 | + self.config, |
3349 | + ) |
3350 | exchanger.start() |
3351 | self.wait_for_exchange(urgent=True) |
3352 | self.assertEqual(len(transport.payloads), 1) |
3353 | @@ -499,13 +549,17 @@ class MessageExchangeTest(LandscapeTest): |
3354 | self.mstore.record_success = mock_record_success |
3355 | |
3356 | exchanger = MessageExchange( |
3357 | - self.reactor, self.mstore, self.transport, |
3358 | - self.identity, self.exchange_store, self.config) |
3359 | + self.reactor, |
3360 | + self.mstore, |
3361 | + self.transport, |
3362 | + self.identity, |
3363 | + self.exchange_store, |
3364 | + self.config, |
3365 | + ) |
3366 | exchanger.exchange() |
3367 | |
3368 | mock_record_success.assert_called_with(mock.ANY) |
3369 | - self.assertTrue( |
3370 | - type(mock_record_success.call_args[0][0]) is int) |
3371 | + self.assertTrue(type(mock_record_success.call_args[0][0]) is int) |
3372 | |
3373 | def test_ancient_causes_resynchronize(self): |
3374 | """ |
3375 | @@ -530,15 +584,20 @@ class MessageExchangeTest(LandscapeTest): |
3376 | # should come AFTER the "resynchronize" message that is generated |
3377 | # by the exchange code itself. |
3378 | self.mstore.add({"type": "data", "data": 999}) |
3379 | + |
3380 | self.reactor.call_on("resynchronize-clients", resynchronize) |
3381 | |
3382 | # This exchange call will notice the server is asking for an old |
3383 | # message and fire the event: |
3384 | self.exchanger.exchange() |
3385 | - self.assertMessages(self.mstore.get_pending_messages(), |
3386 | - [{"type": "empty"}, |
3387 | - {"type": "resynchronize"}, |
3388 | - {"type": "data", "data": 999}]) |
3389 | + self.assertMessages( |
3390 | + self.mstore.get_pending_messages(), |
3391 | + [ |
3392 | + {"type": "empty"}, |
3393 | + {"type": "resynchronize"}, |
3394 | + {"type": "data", "data": 999}, |
3395 | + ], |
3396 | + ) |
3397 | |
3398 | def test_resynchronize_msg_causes_resynchronize_response_then_event(self): |
3399 | """ |
3400 | @@ -551,15 +610,20 @@ class MessageExchangeTest(LandscapeTest): |
3401 | |
3402 | def resynchronized(scopes=None): |
3403 | self.mstore.add({"type": "empty"}) |
3404 | + |
3405 | self.reactor.call_on("resynchronize-clients", resynchronized) |
3406 | |
3407 | - self.transport.responses.append([{"type": "resynchronize", |
3408 | - "operation-id": 123}]) |
3409 | + self.transport.responses.append( |
3410 | + [{"type": "resynchronize", "operation-id": 123}], |
3411 | + ) |
3412 | self.exchanger.exchange() |
3413 | - self.assertMessages(self.mstore.get_pending_messages(), |
3414 | - [{"type": "resynchronize", |
3415 | - "operation-id": 123}, |
3416 | - {"type": "empty"}]) |
3417 | + self.assertMessages( |
3418 | + self.mstore.get_pending_messages(), |
3419 | + [ |
3420 | + {"type": "resynchronize", "operation-id": 123}, |
3421 | + {"type": "empty"}, |
3422 | + ], |
3423 | + ) |
3424 | |
3425 | def test_scopes_are_copied_from_incoming_resynchronize_messages(self): |
3426 | """ |
3427 | @@ -574,9 +638,15 @@ class MessageExchangeTest(LandscapeTest): |
3428 | |
3429 | self.reactor.call_on("resynchronize-clients", resynchronized) |
3430 | |
3431 | - self.transport.responses.append([{"type": "resynchronize", |
3432 | - "operation-id": 123, |
3433 | - "scopes": ["disk", "users"]}]) |
3434 | + self.transport.responses.append( |
3435 | + [ |
3436 | + { |
3437 | + "type": "resynchronize", |
3438 | + "operation-id": 123, |
3439 | + "scopes": ["disk", "users"], |
3440 | + }, |
3441 | + ], |
3442 | + ) |
3443 | self.exchanger.exchange() |
3444 | self.assertEqual(["disk", "users"], fired_scopes) |
3445 | |
3446 | @@ -622,8 +692,10 @@ class MessageExchangeTest(LandscapeTest): |
3447 | |
3448 | def test_old_sequence_id_does_not_cause_resynchronize(self): |
3449 | resynchronized = [] |
3450 | - self.reactor.call_on("resynchronize", |
3451 | - lambda: resynchronized.append(True)) |
3452 | + self.reactor.call_on( |
3453 | + "resynchronize", |
3454 | + lambda: resynchronized.append(True), |
3455 | + ) |
3456 | |
3457 | self.mstore.set_accepted_types(["empty"]) |
3458 | self.mstore.add({"type": "empty"}) |
3459 | @@ -663,9 +735,10 @@ class MessageExchangeTest(LandscapeTest): |
3460 | self.exchanger.exchange() |
3461 | |
3462 | payload = self.transport.payloads[-1] |
3463 | - self.assertMessages(payload["messages"], |
3464 | - [{"type": "a", "api": b"1.0"}, |
3465 | - {"type": "b", "api": b"1.0"}]) |
3466 | + self.assertMessages( |
3467 | + payload["messages"], |
3468 | + [{"type": "a", "api": b"1.0"}, {"type": "b", "api": b"1.0"}], |
3469 | + ) |
3470 | self.assertEqual(payload.get("client-api"), CLIENT_API) |
3471 | self.assertEqual(payload.get("server-api"), b"1.0") |
3472 | self.assertEqual(self.transport.message_api, b"1.0") |
3473 | @@ -673,9 +746,10 @@ class MessageExchangeTest(LandscapeTest): |
3474 | self.exchanger.exchange() |
3475 | |
3476 | payload = self.transport.payloads[-1] |
3477 | - self.assertMessages(payload["messages"], |
3478 | - [{"type": "c", "api": b"1.1"}, |
3479 | - {"type": "d", "api": b"1.1"}]) |
3480 | + self.assertMessages( |
3481 | + payload["messages"], |
3482 | + [{"type": "c", "api": b"1.1"}, {"type": "d", "api": b"1.1"}], |
3483 | + ) |
3484 | self.assertEqual(payload.get("client-api"), CLIENT_API) |
3485 | self.assertEqual(payload.get("server-api"), b"1.1") |
3486 | self.assertEqual(self.transport.message_api, b"1.1") |
3487 | @@ -732,9 +806,15 @@ class MessageExchangeTest(LandscapeTest): |
3488 | the total-messages is equivalent to the total number of messages |
3489 | pending. |
3490 | """ |
3491 | - exchanger = MessageExchange(self.reactor, self.mstore, self.transport, |
3492 | - self.identity, self.exchange_store, |
3493 | - self.config, max_messages=1) |
3494 | + exchanger = MessageExchange( |
3495 | + self.reactor, |
3496 | + self.mstore, |
3497 | + self.transport, |
3498 | + self.identity, |
3499 | + self.exchange_store, |
3500 | + self.config, |
3501 | + max_messages=1, |
3502 | + ) |
3503 | self.mstore.set_accepted_types(["empty"]) |
3504 | self.mstore.add({"type": "empty"}) |
3505 | self.mstore.add({"type": "empty"}) |
3506 | @@ -763,9 +843,14 @@ class MessageExchangeTest(LandscapeTest): |
3507 | # fixture has an urgent exchange interval of 10 seconds, which makes |
3508 | # testing this awkward. |
3509 | self.config.urgent_exchange_interval = 20 |
3510 | - exchanger = MessageExchange(self.reactor, self.mstore, self.transport, |
3511 | - self.identity, self.exchange_store, |
3512 | - self.config) |
3513 | + exchanger = MessageExchange( |
3514 | + self.reactor, |
3515 | + self.mstore, |
3516 | + self.transport, |
3517 | + self.identity, |
3518 | + self.exchange_store, |
3519 | + self.config, |
3520 | + ) |
3521 | exchanger.schedule_exchange(urgent=True) |
3522 | events = [] |
3523 | self.reactor.call_on("impending-exchange", lambda: events.append(True)) |
3524 | @@ -783,9 +868,14 @@ class MessageExchangeTest(LandscapeTest): |
3525 | """ |
3526 | self.config.exchange_interval = 60 * 60 |
3527 | self.config.urgent_exchange_interval = 20 |
3528 | - exchanger = MessageExchange(self.reactor, self.mstore, self.transport, |
3529 | - self.identity, self.exchange_store, |
3530 | - self.config) |
3531 | + exchanger = MessageExchange( |
3532 | + self.reactor, |
3533 | + self.mstore, |
3534 | + self.transport, |
3535 | + self.identity, |
3536 | + self.exchange_store, |
3537 | + self.config, |
3538 | + ) |
3539 | events = [] |
3540 | self.reactor.call_on("impending-exchange", lambda: events.append(True)) |
3541 | # This call will: |
3542 | @@ -806,11 +896,12 @@ class MessageExchangeTest(LandscapeTest): |
3543 | # schedule a regular exchange. |
3544 | # Let's make sure that that *original* impending-exchange event has |
3545 | # been cancelled: |
3546 | - TIME_UNTIL_EXCHANGE = 60 * 60 |
3547 | - TIME_UNTIL_NOTIFY = 10 |
3548 | - TIME_ADVANCED = 20 # time that we've already advanced |
3549 | - self.reactor.advance(TIME_UNTIL_EXCHANGE - |
3550 | - (TIME_UNTIL_NOTIFY + TIME_ADVANCED)) |
3551 | + time_until_exchange = 60 * 60 |
3552 | + time_until_notify = 10 |
3553 | + time_advanced = 20 |
3554 | + self.reactor.advance( |
3555 | + time_until_exchange - (time_until_notify + time_advanced), |
3556 | + ) |
3557 | self.assertEqual(events, [True]) |
3558 | # Ok, so no new events means that the original call was |
3559 | # cancelled. great. |
3560 | @@ -877,8 +968,13 @@ class MessageExchangeTest(LandscapeTest): |
3561 | the L{MessageExchange} are changed, the configuration values as well, |
3562 | and the configuration is written to disk to be persisted. |
3563 | """ |
3564 | - server_message = [{"type": "set-intervals", |
3565 | - "urgent-exchange": 1234, "exchange": 5678}] |
3566 | + server_message = [ |
3567 | + { |
3568 | + "type": "set-intervals", |
3569 | + "urgent-exchange": 1234, |
3570 | + "exchange": 5678, |
3571 | + }, |
3572 | + ] |
3573 | self.transport.responses.append(server_message) |
3574 | |
3575 | self.exchanger.exchange() |
3576 | @@ -993,6 +1089,7 @@ class MessageExchangeTest(LandscapeTest): |
3577 | |
3578 | def server_uuid_changed(old_uuid, new_uuid): |
3579 | called.append((old_uuid, new_uuid)) |
3580 | + |
3581 | self.reactor.call_on("server-uuid-changed", server_uuid_changed) |
3582 | |
3583 | # Set it for the first time, and it should emit the event |
3584 | @@ -1028,6 +1125,7 @@ class MessageExchangeTest(LandscapeTest): |
3585 | |
3586 | def server_uuid_changed(old_uuid, new_uuid): |
3587 | called.append((old_uuid, new_uuid)) |
3588 | + |
3589 | self.reactor.call_on("server-uuid-changed", server_uuid_changed) |
3590 | |
3591 | self.mstore.set_server_uuid("the-uuid") |
3592 | @@ -1039,8 +1137,10 @@ class MessageExchangeTest(LandscapeTest): |
3593 | self.transport.extra["server-uuid"] = "the-uuid" |
3594 | self.exchanger.exchange() |
3595 | |
3596 | - self.assertIn("INFO: Server UUID changed (old=None, new=the-uuid).", |
3597 | - self.logfile.getvalue()) |
3598 | + self.assertIn( |
3599 | + "INFO: Server UUID changed (old=None, new=the-uuid).", |
3600 | + self.logfile.getvalue(), |
3601 | + ) |
3602 | |
3603 | # An exchange with the same UUID shouldn't be logged. |
3604 | self.logfile.truncate(0) |
3605 | @@ -1063,9 +1163,11 @@ class MessageExchangeTest(LandscapeTest): |
3606 | [message] = messages |
3607 | self.assertIsNot( |
3608 | None, |
3609 | - self.exchange_store.get_message_context(message['operation-id'])) |
3610 | + self.exchange_store.get_message_context(message["operation-id"]), |
3611 | + ) |
3612 | message_context = self.exchange_store.get_message_context( |
3613 | - message['operation-id']) |
3614 | + message["operation-id"], |
3615 | + ) |
3616 | self.assertEqual(message_context.operation_id, 123456) |
3617 | self.assertEqual(message_context.message_type, "type-R") |
3618 | |
3619 | @@ -1099,12 +1201,13 @@ class MessageExchangeTest(LandscapeTest): |
3620 | self.exchanger.exchange() |
3621 | |
3622 | # Change the secure ID so that the response message gets discarded. |
3623 | - self.identity.secure_id = 'brand-new' |
3624 | + self.identity.secure_id = "brand-new" |
3625 | ids_before = self.exchange_store.all_operation_ids() |
3626 | |
3627 | self.mstore.set_accepted_types(["resynchronize"]) |
3628 | message_id = self.exchanger.send( |
3629 | - {"type": "resynchronize", "operation-id": 234567}) |
3630 | + {"type": "resynchronize", "operation-id": 234567}, |
3631 | + ) |
3632 | self.exchanger.exchange() |
3633 | self.assertEqual(2, len(self.transport.payloads)) |
3634 | messages = self.transport.payloads[1]["messages"] |
3635 | @@ -1112,13 +1215,14 @@ class MessageExchangeTest(LandscapeTest): |
3636 | self.assertIs(None, message_id) |
3637 | expected_log_entry = ( |
3638 | "Response message with operation-id 234567 was discarded because " |
3639 | - "the client's secure ID has changed in the meantime") |
3640 | + "the client's secure ID has changed in the meantime" |
3641 | + ) |
3642 | self.assertIn(expected_log_entry, self.logfile.getvalue()) |
3643 | |
3644 | # The MessageContext was removed after utilisation. |
3645 | ids_after = self.exchange_store.all_operation_ids() |
3646 | self.assertEqual(len(ids_after), len(ids_before) - 1) |
3647 | - self.assertNotIn('234567', ids_after) |
3648 | + self.assertNotIn("234567", ids_after) |
3649 | |
3650 | def test_error_exchanging_causes_failed_exchange(self): |
3651 | """ |
3652 | @@ -1135,13 +1239,14 @@ class MessageExchangeTest(LandscapeTest): |
3653 | self.exchanger.exchange() |
3654 | self.assertEqual([None], events) |
3655 | |
3656 | - def test_SSL_error_exchanging_causes_failed_exchange(self): |
3657 | + def test_SSL_error_exchanging_causes_failed_exchange(self): # noqa: N802 |
3658 | """ |
3659 | If an SSL error occurs when exchanging, the 'exchange-failed' |
3660 | event should be fired with the optional "ssl_error" flag set to True. |
3661 | """ |
3662 | - self.log_helper.ignore_errors("Message exchange failed: Failed to " |
3663 | - "communicate.") |
3664 | + self.log_helper.ignore_errors( |
3665 | + "Message exchange failed: Failed to communicate.", |
3666 | + ) |
3667 | events = [] |
3668 | |
3669 | def failed_exchange(ssl_error): |
3670 | @@ -1149,8 +1254,9 @@ class MessageExchangeTest(LandscapeTest): |
3671 | events.append(None) |
3672 | |
3673 | self.reactor.call_on("exchange-failed", failed_exchange) |
3674 | - self.transport.responses.append(PyCurlError(60, |
3675 | - "Failed to communicate.")) |
3676 | + self.transport.responses.append( |
3677 | + PyCurlError(60, "Failed to communicate."), |
3678 | + ) |
3679 | self.exchanger.exchange() |
3680 | self.assertEqual([None], events) |
3681 | |
3682 | @@ -1167,8 +1273,9 @@ class MessageExchangeTest(LandscapeTest): |
3683 | events.append(None) |
3684 | |
3685 | self.reactor.call_on("exchange-failed", failed_exchange) |
3686 | - self.transport.responses.append(PyCurlError(10, # Not 60 |
3687 | - "Failed to communicate.")) |
3688 | + self.transport.responses.append( |
3689 | + PyCurlError(10, "Failed to communicate."), # Not 60 |
3690 | + ) |
3691 | self.exchanger.exchange() |
3692 | self.assertEqual([None], events) |
3693 | |
3694 | @@ -1278,14 +1385,23 @@ class AcceptedTypesMessageExchangeTest(LandscapeTest): |
3695 | helpers = [ExchangeHelper] |
3696 | |
3697 | def setUp(self): |
3698 | - super(AcceptedTypesMessageExchangeTest, self).setUp() |
3699 | - self.pinger = Pinger(self.reactor, self.identity, self.exchanger, |
3700 | - self.config) |
3701 | + super().setUp() |
3702 | + self.pinger = Pinger( |
3703 | + self.reactor, |
3704 | + self.identity, |
3705 | + self.exchanger, |
3706 | + self.config, |
3707 | + ) |
3708 | # The __init__ method of RegistrationHandler registers a few default |
3709 | # message types that we want to catch as well |
3710 | self.handler = RegistrationHandler( |
3711 | - self.config, self.identity, self.reactor, self.exchanger, |
3712 | - self.pinger, self.mstore) |
3713 | + self.config, |
3714 | + self.identity, |
3715 | + self.reactor, |
3716 | + self.exchanger, |
3717 | + self.pinger, |
3718 | + self.mstore, |
3719 | + ) |
3720 | |
3721 | def test_register_accepted_message_type(self): |
3722 | self.exchanger.register_client_accepted_message_type("type-B") |
3723 | @@ -1293,9 +1409,10 @@ class AcceptedTypesMessageExchangeTest(LandscapeTest): |
3724 | self.exchanger.register_client_accepted_message_type("type-C") |
3725 | self.exchanger.register_client_accepted_message_type("type-A") |
3726 | types = self.exchanger.get_client_accepted_message_types() |
3727 | - self.assertEqual(types, |
3728 | - sorted(["type-A", "type-B", "type-C"] + |
3729 | - DEFAULT_ACCEPTED_TYPES)) |
3730 | + self.assertEqual( |
3731 | + types, |
3732 | + sorted(["type-A", "type-B", "type-C"] + DEFAULT_ACCEPTED_TYPES), |
3733 | + ) |
3734 | |
3735 | def test_exchange_sends_message_type_when_no_hash(self): |
3736 | self.exchanger.register_client_accepted_message_type("type-A") |
3737 | @@ -1303,15 +1420,17 @@ class AcceptedTypesMessageExchangeTest(LandscapeTest): |
3738 | self.exchanger.exchange() |
3739 | self.assertEqual( |
3740 | self.transport.payloads[0]["client-accepted-types"], |
3741 | - sorted(["type-A", "type-B"] + DEFAULT_ACCEPTED_TYPES)) |
3742 | + sorted(["type-A", "type-B"] + DEFAULT_ACCEPTED_TYPES), |
3743 | + ) |
3744 | |
3745 | def test_exchange_does_not_send_message_types_when_hash_matches(self): |
3746 | self.exchanger.register_client_accepted_message_type("type-A") |
3747 | self.exchanger.register_client_accepted_message_type("type-B") |
3748 | types = sorted(["type-A", "type-B"] + DEFAULT_ACCEPTED_TYPES) |
3749 | accepted_types_digest = md5(";".join(types).encode("ascii")).digest() |
3750 | - self.transport.extra["client-accepted-types-hash"] = \ |
3751 | - accepted_types_digest |
3752 | + self.transport.extra[ |
3753 | + "client-accepted-types-hash" |
3754 | + ] = accepted_types_digest |
3755 | self.exchanger.exchange() |
3756 | self.exchanger.exchange() |
3757 | self.assertNotIn("client-accepted-types", self.transport.payloads[1]) |
3758 | @@ -1327,7 +1446,8 @@ class AcceptedTypesMessageExchangeTest(LandscapeTest): |
3759 | self.exchanger.exchange() |
3760 | self.assertEqual( |
3761 | self.transport.payloads[1]["client-accepted-types"], |
3762 | - sorted(["type-A", "type-B"] + DEFAULT_ACCEPTED_TYPES)) |
3763 | + sorted(["type-A", "type-B"] + DEFAULT_ACCEPTED_TYPES), |
3764 | + ) |
3765 | |
3766 | def test_exchange_sends_new_accepted_types_hash(self): |
3767 | """ |
3768 | @@ -1342,7 +1462,8 @@ class AcceptedTypesMessageExchangeTest(LandscapeTest): |
3769 | self.exchanger.exchange() |
3770 | self.assertEqual( |
3771 | self.transport.payloads[1]["client-accepted-types"], |
3772 | - sorted(["type-A", "type-B"] + DEFAULT_ACCEPTED_TYPES)) |
3773 | + sorted(["type-A", "type-B"] + DEFAULT_ACCEPTED_TYPES), |
3774 | + ) |
3775 | |
3776 | def test_exchange_sends_new_types_when_server_screws_up(self): |
3777 | """ |
3778 | @@ -1359,7 +1480,8 @@ class AcceptedTypesMessageExchangeTest(LandscapeTest): |
3779 | self.exchanger.exchange() |
3780 | self.assertEqual( |
3781 | self.transport.payloads[2]["client-accepted-types"], |
3782 | - sorted(["type-A"] + DEFAULT_ACCEPTED_TYPES)) |
3783 | + sorted(["type-A"] + DEFAULT_ACCEPTED_TYPES), |
3784 | + ) |
3785 | |
3786 | def test_register_message_adds_accepted_type(self): |
3787 | """ |
3788 | @@ -1373,7 +1495,6 @@ class AcceptedTypesMessageExchangeTest(LandscapeTest): |
3789 | |
3790 | |
3791 | class GetAcceptedTypesDiffTest(LandscapeTest): |
3792 | - |
3793 | def test_diff_empty(self): |
3794 | self.assertEqual(get_accepted_types_diff([], []), "") |
3795 | |
3796 | @@ -1387,6 +1508,7 @@ class GetAcceptedTypesDiffTest(LandscapeTest): |
3797 | self.assertEqual(get_accepted_types_diff(["ooga"], ["ooga"]), "ooga") |
3798 | |
3799 | def test_diff_complex(self): |
3800 | - self.assertEqual(get_accepted_types_diff(["foo", "bar"], |
3801 | - ["foo", "ooga"]), |
3802 | - "+ooga foo -bar") |
3803 | + self.assertEqual( |
3804 | + get_accepted_types_diff(["foo", "bar"], ["foo", "ooga"]), |
3805 | + "+ooga foo -bar", |
3806 | + ) |
3807 | diff --git a/landscape/client/broker/tests/test_exchangestore.py b/landscape/client/broker/tests/test_exchangestore.py |
3808 | index 45354db..76a7d9f 100644 |
3809 | --- a/landscape/client/broker/tests/test_exchangestore.py |
3810 | +++ b/landscape/client/broker/tests/test_exchangestore.py |
3811 | @@ -14,7 +14,7 @@ class ExchangeStoreTest(LandscapeTest): |
3812 | """Unit tests for the C{ExchangeStore}.""" |
3813 | |
3814 | def setUp(self): |
3815 | - super(ExchangeStoreTest, self).setUp() |
3816 | + super().setUp() |
3817 | |
3818 | self.filename = self.makeFile() |
3819 | self.store1 = ExchangeStore(self.filename) |
3820 | @@ -23,19 +23,21 @@ class ExchangeStoreTest(LandscapeTest): |
3821 | def test_add_message_context(self): |
3822 | """Adding a message context works correctly.""" |
3823 | now = time.time() |
3824 | - self.store1.add_message_context(123, 'abc', 'change-packages') |
3825 | + self.store1.add_message_context(123, "abc", "change-packages") |
3826 | |
3827 | db = sqlite3.connect(self.store2._filename) |
3828 | cursor = db.cursor() |
3829 | cursor.execute( |
3830 | "SELECT operation_id, secure_id, message_type, timestamp " |
3831 | - "FROM message_context WHERE operation_id=?", (123,)) |
3832 | + "FROM message_context WHERE operation_id=?", |
3833 | + (123,), |
3834 | + ) |
3835 | results = cursor.fetchall() |
3836 | self.assertEqual(1, len(results)) |
3837 | [row] = results |
3838 | self.assertEqual(123, row[0]) |
3839 | - self.assertEqual('abc', row[1]) |
3840 | - self.assertEqual('change-packages', row[2]) |
3841 | + self.assertEqual("abc", row[1]) |
3842 | + self.assertEqual("change-packages", row[2]) |
3843 | self.assertTrue(row[3] > now) |
3844 | |
3845 | def test_add_message_context_with_duplicate_operation_id(self): |
3846 | @@ -43,18 +45,22 @@ class ExchangeStoreTest(LandscapeTest): |
3847 | self.store1.add_message_context(123, "abc", "change-packages") |
3848 | self.assertRaises( |
3849 | (sqlite3.IntegrityError, sqlite3.OperationalError), |
3850 | - self.store1.add_message_context, 123, "def", "change-packages") |
3851 | + self.store1.add_message_context, |
3852 | + 123, |
3853 | + "def", |
3854 | + "change-packages", |
3855 | + ) |
3856 | |
3857 | def test_get_message_context(self): |
3858 | """ |
3859 | Accessing a C{MessageContext} with an existing C{operation-id} works. |
3860 | """ |
3861 | now = time.time() |
3862 | - self.store1.add_message_context(234, 'bcd', 'change-packages') |
3863 | + self.store1.add_message_context(234, "bcd", "change-packages") |
3864 | context = self.store2.get_message_context(234) |
3865 | self.assertEqual(234, context.operation_id) |
3866 | - self.assertEqual('bcd', context.secure_id) |
3867 | - self.assertEqual('change-packages', context.message_type) |
3868 | + self.assertEqual("bcd", context.secure_id) |
3869 | + self.assertEqual("change-packages", context.message_type) |
3870 | self.assertTrue(context.timestamp > now) |
3871 | |
3872 | def test_get_message_context_with_nonexistent_operation_id(self): |
3873 | @@ -65,7 +71,10 @@ class ExchangeStoreTest(LandscapeTest): |
3874 | def test_message_context_remove(self): |
3875 | """C{MessageContext}s are deleted correctly.""" |
3876 | context = self.store1.add_message_context( |
3877 | - 345, 'opq', 'change-packages') |
3878 | + 345, |
3879 | + "opq", |
3880 | + "change-packages", |
3881 | + ) |
3882 | context.remove() |
3883 | self.assertIs(None, self.store1.get_message_context(345)) |
3884 | |
3885 | @@ -78,7 +87,7 @@ class ExchangeStoreTest(LandscapeTest): |
3886 | |
3887 | def test_all_operation_ids(self): |
3888 | """C{all_operation_ids} works correctly.""" |
3889 | - self.store1.add_message_context(456, 'cde', 'change-packages') |
3890 | + self.store1.add_message_context(456, "cde", "change-packages") |
3891 | self.assertEqual([456], self.store2.all_operation_ids()) |
3892 | - self.store2.add_message_context(567, 'def', 'change-packages') |
3893 | + self.store2.add_message_context(567, "def", "change-packages") |
3894 | self.assertEqual([456, 567], self.store1.all_operation_ids()) |
3895 | diff --git a/landscape/client/broker/tests/test_ping.py b/landscape/client/broker/tests/test_ping.py |
3896 | index b095b5a..843b984 100644 |
3897 | --- a/landscape/client/broker/tests/test_ping.py |
3898 | +++ b/landscape/client/broker/tests/test_ping.py |
3899 | @@ -1,15 +1,15 @@ |
3900 | -from landscape.client.tests.helpers import LandscapeTest |
3901 | - |
3902 | from twisted.internet.defer import fail |
3903 | |
3904 | +from landscape.client.broker.ping import PingClient |
3905 | +from landscape.client.broker.ping import Pinger |
3906 | +from landscape.client.broker.tests.helpers import ExchangeHelper |
3907 | +from landscape.client.tests.helpers import LandscapeTest |
3908 | from landscape.lib import bpickle |
3909 | from landscape.lib.fetch import fetch |
3910 | from landscape.lib.testing import FakeReactor |
3911 | -from landscape.client.broker.ping import PingClient, Pinger |
3912 | -from landscape.client.broker.tests.helpers import ExchangeHelper |
3913 | |
3914 | |
3915 | -class FakePageGetter(object): |
3916 | +class FakePageGetter: |
3917 | """An fake web client.""" |
3918 | |
3919 | def __init__(self, response): |
3920 | @@ -39,9 +39,8 @@ class FakePageGetter(object): |
3921 | |
3922 | |
3923 | class PingClientTest(LandscapeTest): |
3924 | - |
3925 | def setUp(self): |
3926 | - super(PingClientTest, self).setUp() |
3927 | + super().setUp() |
3928 | self.reactor = FakeReactor() |
3929 | |
3930 | def test_default_get_page(self): |
3931 | @@ -64,8 +63,15 @@ class PingClientTest(LandscapeTest): |
3932 | pinger.ping(url, insecure_id) |
3933 | self.assertEqual( |
3934 | client.fetches, |
3935 | - [(url, True, {"Content-Type": "application/x-www-form-urlencoded"}, |
3936 | - "insecure_id=10")]) |
3937 | + [ |
3938 | + ( |
3939 | + url, |
3940 | + True, |
3941 | + {"Content-Type": "application/x-www-form-urlencoded"}, |
3942 | + "insecure_id=10", |
3943 | + ), |
3944 | + ], |
3945 | + ) |
3946 | |
3947 | def test_ping_no_insecure_id(self): |
3948 | """ |
3949 | @@ -100,6 +106,7 @@ class PingClientTest(LandscapeTest): |
3950 | |
3951 | def errback(failure): |
3952 | failures.append(failure) |
3953 | + |
3954 | d.addErrback(errback) |
3955 | self.assertEqual(len(failures), 1) |
3956 | self.assertEqual(failures[0].getErrorMessage(), "That's a failure!") |
3957 | @@ -116,7 +123,7 @@ class PingerTest(LandscapeTest): |
3958 | install_exchanger = False |
3959 | |
3960 | def setUp(self): |
3961 | - super(PingerTest, self).setUp() |
3962 | + super().setUp() |
3963 | self.page_getter = FakePageGetter(None) |
3964 | |
3965 | def factory(reactor): |
3966 | @@ -125,21 +132,25 @@ class PingerTest(LandscapeTest): |
3967 | self.config.ping_url = "http://localhost:8081/whatever" |
3968 | self.config.ping_interval = 10 |
3969 | |
3970 | - self.pinger = Pinger(self.reactor, |
3971 | - self.identity, |
3972 | - self.exchanger, |
3973 | - self.config, |
3974 | - ping_client_factory=factory) |
3975 | + self.pinger = Pinger( |
3976 | + self.reactor, |
3977 | + self.identity, |
3978 | + self.exchanger, |
3979 | + self.config, |
3980 | + ping_client_factory=factory, |
3981 | + ) |
3982 | |
3983 | def test_default_ping_client(self): |
3984 | """ |
3985 | The C{ping_client_factory} argument to L{Pinger} should be optional, |
3986 | and default to L{PingClient}. |
3987 | """ |
3988 | - pinger = Pinger(self.reactor, |
3989 | - self.identity, |
3990 | - self.exchanger, |
3991 | - self.config) |
3992 | + pinger = Pinger( |
3993 | + self.reactor, |
3994 | + self.identity, |
3995 | + self.exchanger, |
3996 | + self.config, |
3997 | + ) |
3998 | self.assertEqual(pinger.ping_client_factory, PingClient) |
3999 | |
4000 | def test_occasional_ping(self): |
4001 | @@ -195,7 +206,7 @@ class PingerTest(LandscapeTest): |
4002 | self.log_helper.ignore_errors(ZeroDivisionError) |
4003 | self.identity.insecure_id = 42 |
4004 | |
4005 | - class BadPingClient(object): |
4006 | + class BadPingClient: |
4007 | def __init__(self, *args, **kwargs): |
4008 | pass |
4009 | |
4010 | @@ -204,11 +215,13 @@ class PingerTest(LandscapeTest): |
4011 | return fail(ZeroDivisionError("Couldn't fetch page")) |
4012 | |
4013 | self.config.ping_url = "http://foo.com/" |
4014 | - pinger = Pinger(self.reactor, |
4015 | - self.identity, |
4016 | - self.exchanger, |
4017 | - self.config, |
4018 | - ping_client_factory=BadPingClient) |
4019 | + pinger = Pinger( |
4020 | + self.reactor, |
4021 | + self.identity, |
4022 | + self.exchanger, |
4023 | + self.config, |
4024 | + ping_client_factory=BadPingClient, |
4025 | + ) |
4026 | pinger.start() |
4027 | |
4028 | self.reactor.advance(30) |
4029 | @@ -238,8 +251,10 @@ class PingerTest(LandscapeTest): |
4030 | self.assertEqual(len(self.page_getter.fetches), 1) |
4031 | |
4032 | def test_get_url(self): |
4033 | - self.assertEqual(self.pinger.get_url(), |
4034 | - "http://localhost:8081/whatever") |
4035 | + self.assertEqual( |
4036 | + self.pinger.get_url(), |
4037 | + "http://localhost:8081/whatever", |
4038 | + ) |
4039 | |
4040 | def test_config_url(self): |
4041 | """ |
4042 | diff --git a/landscape/client/broker/tests/test_registration.py b/landscape/client/broker/tests/test_registration.py |
4043 | index 8ca0cb4..fe1d256 100644 |
4044 | --- a/landscape/client/broker/tests/test_registration.py |
4045 | +++ b/landscape/client/broker/tests/test_registration.py |
4046 | @@ -1,14 +1,14 @@ |
4047 | import json |
4048 | import logging |
4049 | import socket |
4050 | -import mock |
4051 | +from unittest import mock |
4052 | |
4053 | -from landscape.lib.compat import _PY3 |
4054 | - |
4055 | -from landscape.client.broker.registration import RegistrationError, Identity |
4056 | +from landscape.client.broker.registration import Identity |
4057 | +from landscape.client.broker.registration import RegistrationError |
4058 | +from landscape.client.broker.tests.helpers import BrokerConfigurationHelper |
4059 | +from landscape.client.broker.tests.helpers import RegistrationHelper |
4060 | from landscape.client.tests.helpers import LandscapeTest |
4061 | -from landscape.client.broker.tests.helpers import ( |
4062 | - BrokerConfigurationHelper, RegistrationHelper) |
4063 | +from landscape.lib.compat import _PY3 |
4064 | from landscape.lib.persist import Persist |
4065 | |
4066 | |
4067 | @@ -17,33 +17,43 @@ class IdentityTest(LandscapeTest): |
4068 | helpers = [BrokerConfigurationHelper] |
4069 | |
4070 | def setUp(self): |
4071 | - super(IdentityTest, self).setUp() |
4072 | + super().setUp() |
4073 | self.persist = Persist(filename=self.makePersistFile()) |
4074 | self.identity = Identity(self.config, self.persist) |
4075 | |
4076 | def check_persist_property(self, attr, persist_name): |
4077 | value = "VALUE" |
4078 | - self.assertEqual(getattr(self.identity, attr), None, |
4079 | - "%r attribute should default to None, not %r" % |
4080 | - (attr, getattr(self.identity, attr))) |
4081 | + self.assertEqual( |
4082 | + getattr(self.identity, attr), |
4083 | + None, |
4084 | + f"{attr!r} attribute should default to None, " |
4085 | + f"not {getattr(self.identity, attr)!r}", |
4086 | + ) |
4087 | setattr(self.identity, attr, value) |
4088 | - self.assertEqual(getattr(self.identity, attr), value, |
4089 | - "%r attribute should be %r, not %r" % |
4090 | - (attr, value, getattr(self.identity, attr))) |
4091 | self.assertEqual( |
4092 | - self.persist.get(persist_name), value, |
4093 | - "%r not set to %r in persist" % (persist_name, value)) |
4094 | + getattr(self.identity, attr), |
4095 | + value, |
4096 | + f"{attr!r} attribute should be {value!r}, " |
4097 | + f"not {getattr(self.identity, attr)!r}", |
4098 | + ) |
4099 | + self.assertEqual( |
4100 | + self.persist.get(persist_name), |
4101 | + value, |
4102 | + f"{persist_name!r} not set to {value!r} in persist", |
4103 | + ) |
4104 | |
4105 | def check_config_property(self, attr): |
4106 | value = "VALUE" |
4107 | setattr(self.config, attr, value) |
4108 | - self.assertEqual(getattr(self.identity, attr), value, |
4109 | - "%r attribute should be %r, not %r" % |
4110 | - (attr, value, getattr(self.identity, attr))) |
4111 | + self.assertEqual( |
4112 | + getattr(self.identity, attr), |
4113 | + value, |
4114 | + f"{attr!r} attribute should be {value!r}, " |
4115 | + f"not {getattr(self.identity, attr)!r}", |
4116 | + ) |
4117 | |
4118 | def test_secure_id(self): |
4119 | - self.check_persist_property("secure_id", |
4120 | - "registration.secure-id") |
4121 | + self.check_persist_property("secure_id", "registration.secure-id") |
4122 | |
4123 | def test_secure_id_as_unicode(self): |
4124 | """secure-id is expected to be retrieved as unicode.""" |
4125 | @@ -51,8 +61,7 @@ class IdentityTest(LandscapeTest): |
4126 | self.assertEqual(self.identity.secure_id, "spam") |
4127 | |
4128 | def test_insecure_id(self): |
4129 | - self.check_persist_property("insecure_id", |
4130 | - "registration.insecure-id") |
4131 | + self.check_persist_property("insecure_id", "registration.insecure-id") |
4132 | |
4133 | def test_computer_title(self): |
4134 | self.check_config_property("computer_title") |
4135 | @@ -75,7 +84,7 @@ class RegistrationHandlerTestBase(LandscapeTest): |
4136 | helpers = [RegistrationHelper] |
4137 | |
4138 | def setUp(self): |
4139 | - super(RegistrationHandlerTestBase, self).setUp() |
4140 | + super().setUp() |
4141 | logging.getLogger().setLevel(logging.INFO) |
4142 | self.hostname = "ooga.local" |
4143 | self.addCleanup(setattr, socket, "getfqdn", socket.getfqdn) |
4144 | @@ -83,14 +92,14 @@ class RegistrationHandlerTestBase(LandscapeTest): |
4145 | |
4146 | |
4147 | class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4148 | - |
4149 | def test_server_initiated_id_changing(self): |
4150 | """ |
4151 | The server must be able to ask a client to change its secure |
4152 | and insecure ids even if no requests were sent. |
4153 | """ |
4154 | self.exchanger.handle_message( |
4155 | - {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}) |
4156 | + {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}, |
4157 | + ) |
4158 | self.assertEqual(self.identity.secure_id, "abc") |
4159 | self.assertEqual(self.identity.insecure_id, "def") |
4160 | |
4161 | @@ -101,7 +110,8 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4162 | """ |
4163 | reactor_fire_mock = self.reactor.fire = mock.Mock() |
4164 | self.exchanger.handle_message( |
4165 | - {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}) |
4166 | + {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}, |
4167 | + ) |
4168 | reactor_fire_mock.assert_any_call("registration-done") |
4169 | |
4170 | def test_unknown_id(self): |
4171 | @@ -120,9 +130,12 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4172 | self.config.computer_title = "Wu" |
4173 | self.mstore.set_accepted_types(["register"]) |
4174 | self.exchanger.handle_message( |
4175 | - {"type": b"unknown-id", "clone-of": "Wu"}) |
4176 | - self.assertIn("Client is clone of computer Wu", |
4177 | - self.logfile.getvalue()) |
4178 | + {"type": b"unknown-id", "clone-of": "Wu"}, |
4179 | + ) |
4180 | + self.assertIn( |
4181 | + "Client is clone of computer Wu", |
4182 | + self.logfile.getvalue(), |
4183 | + ) |
4184 | |
4185 | def test_clone_secure_id_saved(self): |
4186 | """ |
4187 | @@ -134,7 +147,8 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4188 | self.config.computer_title = "Wu" |
4189 | self.mstore.set_accepted_types(["register"]) |
4190 | self.exchanger.handle_message( |
4191 | - {"type": b"unknown-id", "clone-of": "Wu"}) |
4192 | + {"type": b"unknown-id", "clone-of": "Wu"}, |
4193 | + ) |
4194 | self.assertEqual(self.handler._clone_secure_id, secure_id) |
4195 | self.assertIsNone(self.identity.secure_id) |
4196 | |
4197 | @@ -148,7 +162,8 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4198 | self.mstore.set_accepted_types(["register"]) |
4199 | self.mstore.set_server_api(b"3.3") # Note this is only for later api |
4200 | self.exchanger.handle_message( |
4201 | - {"type": b"unknown-id", "clone-of": "Wu"}) |
4202 | + {"type": b"unknown-id", "clone-of": "Wu"}, |
4203 | + ) |
4204 | self.reactor.fire("pre-exchange") |
4205 | messages = self.mstore.get_pending_messages() |
4206 | self.assertEqual(messages[0]["clone_secure_id"], secure_id) |
4207 | @@ -192,9 +207,11 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4208 | messages = self.mstore.get_pending_messages() |
4209 | self.assertEqual(1, len(messages)) |
4210 | self.assertEqual("register", messages[0]["type"]) |
4211 | - self.assertEqual(self.logfile.getvalue().strip(), |
4212 | - "INFO: Queueing message to register with account " |
4213 | - "'account_name' without a password.") |
4214 | + self.assertEqual( |
4215 | + self.logfile.getvalue().strip(), |
4216 | + "INFO: Queueing message to register with account " |
4217 | + "'account_name' without a password.", |
4218 | + ) |
4219 | |
4220 | @mock.patch("landscape.client.broker.registration.get_vm_info") |
4221 | def test_queue_message_on_exchange_with_vm_info(self, get_vm_info_mock): |
4222 | @@ -210,14 +227,18 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4223 | self.reactor.fire("pre-exchange") |
4224 | messages = self.mstore.get_pending_messages() |
4225 | self.assertEqual(b"vmware", messages[0]["vm-info"]) |
4226 | - self.assertEqual(self.logfile.getvalue().strip(), |
4227 | - "INFO: Queueing message to register with account " |
4228 | - "'account_name' without a password.") |
4229 | + self.assertEqual( |
4230 | + self.logfile.getvalue().strip(), |
4231 | + "INFO: Queueing message to register with account " |
4232 | + "'account_name' without a password.", |
4233 | + ) |
4234 | get_vm_info_mock.assert_called_once_with() |
4235 | |
4236 | @mock.patch("landscape.client.broker.registration.get_container_info") |
4237 | def test_queue_message_on_exchange_with_lxc_container( |
4238 | - self, get_container_info_mock): |
4239 | + self, |
4240 | + get_container_info_mock, |
4241 | + ): |
4242 | """ |
4243 | If the client is running in an LXC container, the information is |
4244 | included in the registration message. |
4245 | @@ -241,9 +262,11 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4246 | messages = self.mstore.get_pending_messages() |
4247 | password = messages[0]["registration_password"] |
4248 | self.assertEqual("SEKRET", password) |
4249 | - self.assertEqual(self.logfile.getvalue().strip(), |
4250 | - "INFO: Queueing message to register with account " |
4251 | - "'account_name' with a password.") |
4252 | + self.assertEqual( |
4253 | + self.logfile.getvalue().strip(), |
4254 | + "INFO: Queueing message to register with account " |
4255 | + "'account_name' with a password.", |
4256 | + ) |
4257 | |
4258 | def test_queue_message_on_exchange_with_tags(self): |
4259 | """ |
4260 | @@ -254,14 +277,16 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4261 | self.config.computer_title = "Computer Title" |
4262 | self.config.account_name = "account_name" |
4263 | self.config.registration_key = "SEKRET" |
4264 | - self.config.tags = u"computer,tag" |
4265 | + self.config.tags = "computer,tag" |
4266 | self.reactor.fire("pre-exchange") |
4267 | messages = self.mstore.get_pending_messages() |
4268 | self.assertEqual("computer,tag", messages[0]["tags"]) |
4269 | - self.assertEqual(self.logfile.getvalue().strip(), |
4270 | - "INFO: Queueing message to register with account " |
4271 | - "'account_name' and tags computer,tag with a " |
4272 | - "password.") |
4273 | + self.assertEqual( |
4274 | + self.logfile.getvalue().strip(), |
4275 | + "INFO: Queueing message to register with account " |
4276 | + "'account_name' and tags computer,tag with a " |
4277 | + "password.", |
4278 | + ) |
4279 | |
4280 | def test_queue_message_on_exchange_with_invalid_tags(self): |
4281 | """ |
4282 | @@ -273,14 +298,16 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4283 | self.config.computer_title = "Computer Title" |
4284 | self.config.account_name = "account_name" |
4285 | self.config.registration_key = "SEKRET" |
4286 | - self.config.tags = u"<script>alert()</script>" |
4287 | + self.config.tags = "<script>alert()</script>" |
4288 | self.reactor.fire("pre-exchange") |
4289 | messages = self.mstore.get_pending_messages() |
4290 | self.assertIs(None, messages[0]["tags"]) |
4291 | - self.assertEqual(self.logfile.getvalue().strip(), |
4292 | - "ERROR: Invalid tags provided for registration.\n " |
4293 | - "INFO: Queueing message to register with account " |
4294 | - "'account_name' with a password.") |
4295 | + self.assertEqual( |
4296 | + self.logfile.getvalue().strip(), |
4297 | + "ERROR: Invalid tags provided for registration.\n " |
4298 | + "INFO: Queueing message to register with account " |
4299 | + "'account_name' with a password.", |
4300 | + ) |
4301 | |
4302 | def test_queue_message_on_exchange_with_unicode_tags(self): |
4303 | """ |
4304 | @@ -291,10 +318,10 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4305 | self.config.computer_title = "Computer Title" |
4306 | self.config.account_name = "account_name" |
4307 | self.config.registration_key = "SEKRET" |
4308 | - self.config.tags = u"prova\N{LATIN SMALL LETTER J WITH CIRCUMFLEX}o" |
4309 | + self.config.tags = "prova\N{LATIN SMALL LETTER J WITH CIRCUMFLEX}o" |
4310 | self.reactor.fire("pre-exchange") |
4311 | messages = self.mstore.get_pending_messages() |
4312 | - expected = u"prova\N{LATIN SMALL LETTER J WITH CIRCUMFLEX}o" |
4313 | + expected = "prova\N{LATIN SMALL LETTER J WITH CIRCUMFLEX}o" |
4314 | self.assertEqual(expected, messages[0]["tags"]) |
4315 | |
4316 | logs = self.logfile.getvalue().strip() |
4317 | @@ -306,10 +333,12 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4318 | # here, to circumvent that problem. |
4319 | if _PY3: |
4320 | logs = logs.encode("utf-8") |
4321 | - self.assertEqual(logs, |
4322 | - b"INFO: Queueing message to register with account " |
4323 | - b"'account_name' and tags prova\xc4\xb5o " |
4324 | - b"with a password.") |
4325 | + self.assertEqual( |
4326 | + logs, |
4327 | + b"INFO: Queueing message to register with account " |
4328 | + b"'account_name' and tags prova\xc4\xb5o " |
4329 | + b"with a password.", |
4330 | + ) |
4331 | |
4332 | def test_queue_message_on_exchange_with_access_group(self): |
4333 | """ |
4334 | @@ -318,15 +347,17 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4335 | """ |
4336 | self.mstore.set_accepted_types(["register"]) |
4337 | self.config.account_name = "account_name" |
4338 | - self.config.access_group = u"dinosaurs" |
4339 | - self.config.tags = u"server,london" |
4340 | + self.config.access_group = "dinosaurs" |
4341 | + self.config.tags = "server,london" |
4342 | self.reactor.fire("pre-exchange") |
4343 | messages = self.mstore.get_pending_messages() |
4344 | self.assertEqual("dinosaurs", messages[0]["access_group"]) |
4345 | - self.assertEqual(self.logfile.getvalue().strip(), |
4346 | - "INFO: Queueing message to register with account " |
4347 | - "'account_name' in access group 'dinosaurs' and " |
4348 | - "tags server,london without a password.") |
4349 | + self.assertEqual( |
4350 | + self.logfile.getvalue().strip(), |
4351 | + "INFO: Queueing message to register with account " |
4352 | + "'account_name' in access group 'dinosaurs' and " |
4353 | + "tags server,london without a password.", |
4354 | + ) |
4355 | |
4356 | def test_queue_message_on_exchange_with_empty_access_group(self): |
4357 | """ |
4358 | @@ -334,7 +365,7 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4359 | an "access_group" key. |
4360 | """ |
4361 | self.mstore.set_accepted_types(["register"]) |
4362 | - self.config.access_group = u"" |
4363 | + self.config.access_group = "" |
4364 | self.reactor.fire("pre-exchange") |
4365 | messages = self.mstore.get_pending_messages() |
4366 | # Make sure the key does not appear in the outgoing message. |
4367 | @@ -368,8 +399,7 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4368 | self.assertEqual(messages[0]["type"], "register") |
4369 | |
4370 | def test_no_message_when_should_register_is_false(self): |
4371 | - """If we already have a secure id, do not queue a register message. |
4372 | - """ |
4373 | + """If we already have a secure id, do not queue a register message.""" |
4374 | self.mstore.set_accepted_types(["register"]) |
4375 | self.config.computer_title = "Computer Title" |
4376 | self.config.account_name = "account_name" |
4377 | @@ -395,9 +425,12 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4378 | """ |
4379 | reactor_fire_mock = self.reactor.fire = mock.Mock() |
4380 | self.exchanger.handle_message( |
4381 | - {"type": b"registration", "info": b"unknown-account"}) |
4382 | + {"type": b"registration", "info": b"unknown-account"}, |
4383 | + ) |
4384 | reactor_fire_mock.assert_called_with( |
4385 | - "registration-failed", reason="unknown-account") |
4386 | + "registration-failed", |
4387 | + reason="unknown-account", |
4388 | + ) |
4389 | |
4390 | def test_registration_failed_event_max_pending_computers(self): |
4391 | """ |
4392 | @@ -407,9 +440,12 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4393 | """ |
4394 | reactor_fire_mock = self.reactor.fire = mock.Mock() |
4395 | self.exchanger.handle_message( |
4396 | - {"type": b"registration", "info": b"max-pending-computers"}) |
4397 | + {"type": b"registration", "info": b"max-pending-computers"}, |
4398 | + ) |
4399 | reactor_fire_mock.assert_called_with( |
4400 | - "registration-failed", reason="max-pending-computers") |
4401 | + "registration-failed", |
4402 | + reason="max-pending-computers", |
4403 | + ) |
4404 | |
4405 | def test_registration_failed_event_not_fired_when_uncertain(self): |
4406 | """ |
4407 | @@ -418,7 +454,8 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4408 | """ |
4409 | reactor_fire_mock = self.reactor.fire = mock.Mock() |
4410 | self.exchanger.handle_message( |
4411 | - {"type": b"registration", "info": b"blah-blah"}) |
4412 | + {"type": b"registration", "info": b"blah-blah"}, |
4413 | + ) |
4414 | for name, args, kwargs in reactor_fire_mock.mock_calls: |
4415 | self.assertNotEquals("registration-failed", args[0]) |
4416 | |
4417 | @@ -449,13 +486,15 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4418 | |
4419 | # This should somehow callback the deferred. |
4420 | self.exchanger.handle_message( |
4421 | - {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}) |
4422 | + {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}, |
4423 | + ) |
4424 | |
4425 | self.assertEqual(calls, [1]) |
4426 | |
4427 | # Doing it again to ensure that the deferred isn't called twice. |
4428 | self.exchanger.handle_message( |
4429 | - {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}) |
4430 | + {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}, |
4431 | + ) |
4432 | |
4433 | self.assertEqual(calls, [1]) |
4434 | |
4435 | @@ -477,7 +516,8 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4436 | |
4437 | # This should somehow callback the deferred. |
4438 | self.exchanger.handle_message( |
4439 | - {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}) |
4440 | + {"type": b"set-id", "id": b"abc", "insecure-id": b"def"}, |
4441 | + ) |
4442 | |
4443 | self.assertEqual(results, [None]) |
4444 | |
4445 | @@ -502,13 +542,15 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4446 | |
4447 | # This should somehow callback the deferred. |
4448 | self.exchanger.handle_message( |
4449 | - {"type": b"registration", "info": b"unknown-account"}) |
4450 | + {"type": b"registration", "info": b"unknown-account"}, |
4451 | + ) |
4452 | |
4453 | self.assertEqual(calls, [True]) |
4454 | |
4455 | # Doing it again to ensure that the deferred isn't called twice. |
4456 | self.exchanger.handle_message( |
4457 | - {"type": b"registration", "info": b"unknown-account"}) |
4458 | + {"type": b"registration", "info": b"unknown-account"}, |
4459 | + ) |
4460 | |
4461 | self.assertEqual(calls, [True]) |
4462 | |
4463 | @@ -534,13 +576,15 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4464 | d.addErrback(add_call) |
4465 | |
4466 | self.exchanger.handle_message( |
4467 | - {"type": b"registration", "info": b"max-pending-computers"}) |
4468 | + {"type": b"registration", "info": b"max-pending-computers"}, |
4469 | + ) |
4470 | |
4471 | self.assertEqual(calls, [True]) |
4472 | |
4473 | # Doing it again to ensure that the deferred isn't called twice. |
4474 | self.exchanger.handle_message( |
4475 | - {"type": b"registration", "info": b"max-pending-computers"}) |
4476 | + {"type": b"registration", "info": b"max-pending-computers"}, |
4477 | + ) |
4478 | |
4479 | self.assertEqual(calls, [True]) |
4480 | |
4481 | @@ -575,9 +619,13 @@ class RegistrationHandlerTest(RegistrationHandlerTestBase): |
4482 | |
4483 | class JujuRegistrationHandlerTest(RegistrationHandlerTestBase): |
4484 | |
4485 | - juju_contents = json.dumps({"environment-uuid": "DEAD-BEEF", |
4486 | - "machine-id": "1", |
4487 | - "api-addresses": "10.0.3.1:17070"}) |
4488 | + juju_contents = json.dumps( |
4489 | + { |
4490 | + "environment-uuid": "DEAD-BEEF", |
4491 | + "machine-id": "1", |
4492 | + "api-addresses": "10.0.3.1:17070", |
4493 | + }, |
4494 | + ) |
4495 | |
4496 | def test_juju_info_added_when_present(self): |
4497 | """ |
4498 | @@ -593,10 +641,13 @@ class JujuRegistrationHandlerTest(RegistrationHandlerTestBase): |
4499 | |
4500 | messages = self.mstore.get_pending_messages() |
4501 | self.assertEqual( |
4502 | - {"environment-uuid": "DEAD-BEEF", |
4503 | - "machine-id": "1", |
4504 | - "api-addresses": ["10.0.3.1:17070"]}, |
4505 | - messages[0]["juju-info"]) |
4506 | + { |
4507 | + "environment-uuid": "DEAD-BEEF", |
4508 | + "machine-id": "1", |
4509 | + "api-addresses": ["10.0.3.1:17070"], |
4510 | + }, |
4511 | + messages[0]["juju-info"], |
4512 | + ) |
4513 | |
4514 | def test_juju_info_skipped_with_old_server(self): |
4515 | """ |
4516 | diff --git a/landscape/client/broker/tests/test_server.py b/landscape/client/broker/tests/test_server.py |
4517 | index 99fa65a..13461eb 100644 |
4518 | --- a/landscape/client/broker/tests/test_server.py |
4519 | +++ b/landscape/client/broker/tests/test_server.py |
4520 | @@ -1,23 +1,23 @@ |
4521 | import random |
4522 | +from unittest.mock import Mock |
4523 | |
4524 | from configobj import ConfigObj |
4525 | -from mock import Mock |
4526 | -from twisted.internet.defer import succeed, fail |
4527 | +from twisted.internet.defer import fail |
4528 | +from twisted.internet.defer import succeed |
4529 | |
4530 | -from landscape.client.manager.manager import FAILED |
4531 | -from landscape.client.tests.helpers import ( |
4532 | - LandscapeTest, DEFAULT_ACCEPTED_TYPES) |
4533 | -from landscape.client.broker.tests.helpers import ( |
4534 | - BrokerServerHelper, RemoteClientHelper) |
4535 | +from landscape.client.broker.tests.helpers import BrokerServerHelper |
4536 | +from landscape.client.broker.tests.helpers import RemoteClientHelper |
4537 | from landscape.client.broker.tests.test_ping import FakePageGetter |
4538 | +from landscape.client.manager.manager import FAILED |
4539 | +from landscape.client.tests.helpers import DEFAULT_ACCEPTED_TYPES |
4540 | +from landscape.client.tests.helpers import LandscapeTest |
4541 | |
4542 | |
4543 | -class FakeClient(object): |
4544 | +class FakeClient: |
4545 | pass |
4546 | |
4547 | |
4548 | -class FakeCreator(object): |
4549 | - |
4550 | +class FakeCreator: |
4551 | def __init__(self, reactor, config): |
4552 | pass |
4553 | |
4554 | @@ -105,7 +105,11 @@ class BrokerServerTest(LandscapeTest): |
4555 | message = {"type": "test"} |
4556 | self.mstore.set_accepted_types(["test"]) |
4557 | self.assertRaises( |
4558 | - RuntimeError, self.broker.send_message, message, None) |
4559 | + RuntimeError, |
4560 | + self.broker.send_message, |
4561 | + message, |
4562 | + None, |
4563 | + ) |
4564 | |
4565 | def test_send_message_with_old_release_upgrader(self): |
4566 | """ |
4567 | @@ -123,8 +127,11 @@ class BrokerServerTest(LandscapeTest): |
4568 | If we receive a message from an old package-changer process that |
4569 | doesn't know about session IDs, we just let the message in. |
4570 | """ |
4571 | - message = {"type": "change-packages-result", "operation-id": 99, |
4572 | - "result-code": 123} |
4573 | + message = { |
4574 | + "type": "change-packages-result", |
4575 | + "operation-id": 99, |
4576 | + "result-code": 123, |
4577 | + } |
4578 | self.mstore.set_accepted_types(["change-packages-result"]) |
4579 | self.broker.send_message(message, True) |
4580 | self.assertMessages(self.mstore.get_pending_messages(), [message]) |
4581 | @@ -138,14 +145,17 @@ class BrokerServerTest(LandscapeTest): |
4582 | legacy_message = { |
4583 | b"type": b"change-packages-result", |
4584 | b"operation-id": 99, |
4585 | - b"result-code": 123} |
4586 | + b"result-code": 123, |
4587 | + } |
4588 | self.mstore.set_accepted_types(["change-packages-result"]) |
4589 | self.broker.send_message(legacy_message, True) |
4590 | - expected = [{ |
4591 | - "type": "change-packages-result", |
4592 | - "operation-id": 99, |
4593 | - "result-code": 123 |
4594 | - }] |
4595 | + expected = [ |
4596 | + { |
4597 | + "type": "change-packages-result", |
4598 | + "operation-id": 99, |
4599 | + "result-code": 123, |
4600 | + }, |
4601 | + ] |
4602 | self.assertMessages(self.mstore.get_pending_messages(), expected) |
4603 | self.assertTrue(self.exchanger.is_urgent()) |
4604 | |
4605 | @@ -176,9 +186,11 @@ class BrokerServerTest(LandscapeTest): |
4606 | self.assertEqual(len(self.broker.get_clients()), 1) |
4607 | self.assertEqual(len(self.broker.get_connectors()), 1) |
4608 | self.assertTrue( |
4609 | - isinstance(self.broker.get_client("test"), FakeClient)) |
4610 | + isinstance(self.broker.get_client("test"), FakeClient), |
4611 | + ) |
4612 | self.assertTrue( |
4613 | - isinstance(self.broker.get_connector("test"), FakeCreator)) |
4614 | + isinstance(self.broker.get_connector("test"), FakeCreator), |
4615 | + ) |
4616 | |
4617 | self.broker.connectors_registry = {"test": FakeCreator} |
4618 | result = self.broker.register_client("test") |
4619 | @@ -190,8 +202,10 @@ class BrokerServerTest(LandscapeTest): |
4620 | of each registered client, and returns a deferred resulting in C{None} |
4621 | if all C{exit} calls were successful. |
4622 | """ |
4623 | - self.broker.connectors_registry = {"foo": FakeCreator, |
4624 | - "bar": FakeCreator} |
4625 | + self.broker.connectors_registry = { |
4626 | + "foo": FakeCreator, |
4627 | + "bar": FakeCreator, |
4628 | + } |
4629 | self.broker.register_client("foo") |
4630 | self.broker.register_client("bar") |
4631 | for client in self.broker.get_clients(): |
4632 | @@ -203,8 +217,10 @@ class BrokerServerTest(LandscapeTest): |
4633 | The L{BrokerServer.stop_clients} method calls the C{exit} method of |
4634 | each registered client, and raises an exception if any calls fail. |
4635 | """ |
4636 | - self.broker.connectors_registry = {"foo": FakeCreator, |
4637 | - "bar": FakeCreator} |
4638 | + self.broker.connectors_registry = { |
4639 | + "foo": FakeCreator, |
4640 | + "bar": FakeCreator, |
4641 | + } |
4642 | self.broker.register_client("foo") |
4643 | self.broker.register_client("bar") |
4644 | [client1, client2] = self.broker.get_clients() |
4645 | @@ -221,8 +237,12 @@ class BrokerServerTest(LandscapeTest): |
4646 | config_obj["client"]["computer_title"] = "New Title" |
4647 | config_obj.write() |
4648 | result = self.broker.reload_configuration() |
4649 | - result.addCallback(lambda x: self.assertEqual( |
4650 | - self.config.computer_title, "New Title")) |
4651 | + result.addCallback( |
4652 | + lambda x: self.assertEqual( |
4653 | + self.config.computer_title, |
4654 | + "New Title", |
4655 | + ), |
4656 | + ) |
4657 | return result |
4658 | |
4659 | def test_reload_configuration_stops_clients(self): |
4660 | @@ -230,8 +250,10 @@ class BrokerServerTest(LandscapeTest): |
4661 | The L{BrokerServer.reload_configuration} method forces the config |
4662 | file associated with the broker server to be reloaded. |
4663 | """ |
4664 | - self.broker.connectors_registry = {"foo": FakeCreator, |
4665 | - "bar": FakeCreator} |
4666 | + self.broker.connectors_registry = { |
4667 | + "foo": FakeCreator, |
4668 | + "bar": FakeCreator, |
4669 | + } |
4670 | self.broker.register_client("foo") |
4671 | self.broker.register_client("bar") |
4672 | for client in self.broker.get_clients(): |
4673 | @@ -245,8 +267,9 @@ class BrokerServerTest(LandscapeTest): |
4674 | """ |
4675 | registered = self.broker.register() |
4676 | # This should callback the deferred. |
4677 | - self.exchanger.handle_message({"type": "set-id", "id": "abc", |
4678 | - "insecure-id": "def"}) |
4679 | + self.exchanger.handle_message( |
4680 | + {"type": "set-id", "id": "abc", "insecure-id": "def"}, |
4681 | + ) |
4682 | return self.assertSuccess(registered) |
4683 | |
4684 | def test_get_accepted_types_empty(self): |
4685 | @@ -263,8 +286,10 @@ class BrokerServerTest(LandscapeTest): |
4686 | message types accepted by the Landscape server. |
4687 | """ |
4688 | self.mstore.set_accepted_types(["foo", "bar"]) |
4689 | - self.assertEqual(sorted(self.broker.get_accepted_message_types()), |
4690 | - ["bar", "foo"]) |
4691 | + self.assertEqual( |
4692 | + sorted(self.broker.get_accepted_message_types()), |
4693 | + ["bar", "foo"], |
4694 | + ) |
4695 | |
4696 | def test_get_server_uuid_with_unset_uuid(self): |
4697 | """ |
4698 | @@ -288,8 +313,10 @@ class BrokerServerTest(LandscapeTest): |
4699 | """ |
4700 | self.broker.register_client_accepted_message_type("type1") |
4701 | self.broker.register_client_accepted_message_type("type2") |
4702 | - self.assertEqual(self.exchanger.get_client_accepted_message_types(), |
4703 | - sorted(["type1", "type2"] + DEFAULT_ACCEPTED_TYPES)) |
4704 | + self.assertEqual( |
4705 | + self.exchanger.get_client_accepted_message_types(), |
4706 | + sorted(["type1", "type2"] + DEFAULT_ACCEPTED_TYPES), |
4707 | + ) |
4708 | |
4709 | def test_fire_event(self): |
4710 | """ |
4711 | @@ -304,8 +331,10 @@ class BrokerServerTest(LandscapeTest): |
4712 | """ |
4713 | The L{BrokerServer.exit} method stops all registered clients. |
4714 | """ |
4715 | - self.broker.connectors_registry = {"foo": FakeCreator, |
4716 | - "bar": FakeCreator} |
4717 | + self.broker.connectors_registry = { |
4718 | + "foo": FakeCreator, |
4719 | + "bar": FakeCreator, |
4720 | + } |
4721 | self.broker.register_client("foo") |
4722 | self.broker.register_client("bar") |
4723 | for client in self.broker.get_clients(): |
4724 | @@ -430,8 +459,10 @@ class EventTest(LandscapeTest): |
4725 | """ |
4726 | callback = Mock(return_value="foo") |
4727 | self.client_reactor.call_on("resynchronize", callback) |
4728 | - return self.assertSuccess(self.broker.resynchronize(["foo"]), |
4729 | - [["foo"]]) |
4730 | + return self.assertSuccess( |
4731 | + self.broker.resynchronize(["foo"]), |
4732 | + [["foo"]], |
4733 | + ) |
4734 | |
4735 | def test_impending_exchange(self): |
4736 | """ |
4737 | @@ -448,7 +479,9 @@ class EventTest(LandscapeTest): |
4738 | plugin.exchange.assert_called_once_with() |
4739 | |
4740 | deferred = self.assertSuccess( |
4741 | - self.broker.impending_exchange(), [[None]]) |
4742 | + self.broker.impending_exchange(), |
4743 | + [[None]], |
4744 | + ) |
4745 | deferred.addCallback(assert_called) |
4746 | return deferred |
4747 | |
4748 | @@ -464,12 +497,15 @@ class EventTest(LandscapeTest): |
4749 | self.remote.register_client = Mock() |
4750 | |
4751 | def assert_called_made(ignored): |
4752 | - self.remote.register_client_accepted_message_type\ |
4753 | - .assert_called_once_with("type") |
4754 | + self.remote.register_client_accepted_message_type.assert_called_once_with( # noqa: E501 |
4755 | + "type", |
4756 | + ) |
4757 | self.remote.register_client.assert_called_once_with("client") |
4758 | |
4759 | deferred = self.assertSuccess( |
4760 | - self.broker.broker_reconnect(), [[None]]) |
4761 | + self.broker.broker_reconnect(), |
4762 | + [[None]], |
4763 | + ) |
4764 | return deferred.addCallback(assert_called_made) |
4765 | |
4766 | registered = self.client.register_message("type", lambda x: None) |
4767 | @@ -488,7 +524,9 @@ class EventTest(LandscapeTest): |
4768 | |
4769 | self.client_reactor.call_on("server-uuid-changed", callback) |
4770 | deferred = self.assertSuccess( |
4771 | - self.broker.server_uuid_changed(None, "abc"), [[return_value]]) |
4772 | + self.broker.server_uuid_changed(None, "abc"), |
4773 | + [[return_value]], |
4774 | + ) |
4775 | return deferred.addCallback(assert_called) |
4776 | |
4777 | def test_message_type_acceptance_changed(self): |
4778 | @@ -499,7 +537,9 @@ class EventTest(LandscapeTest): |
4779 | return_value = random.randint(1, 100) |
4780 | callback = Mock(return_value=return_value) |
4781 | self.client_reactor.call_on( |
4782 | - ("message-type-acceptance-changed", "type"), callback) |
4783 | + ("message-type-acceptance-changed", "type"), |
4784 | + callback, |
4785 | + ) |
4786 | result = self.broker.message_type_acceptance_changed("type", True) |
4787 | return self.assertSuccess(result, [[return_value]]) |
4788 | |
4789 | @@ -512,7 +552,9 @@ class EventTest(LandscapeTest): |
4790 | callback = Mock(return_value=return_value) |
4791 | self.client_reactor.call_on("package-data-changed", callback) |
4792 | return self.assertSuccess( |
4793 | - self.broker.package_data_changed(), [[return_value]]) |
4794 | + self.broker.package_data_changed(), |
4795 | + [[return_value]], |
4796 | + ) |
4797 | |
4798 | |
4799 | class HandlersTest(LandscapeTest): |
4800 | @@ -520,7 +562,7 @@ class HandlersTest(LandscapeTest): |
4801 | helpers = [BrokerServerHelper] |
4802 | |
4803 | def setUp(self): |
4804 | - super(HandlersTest, self).setUp() |
4805 | + super().setUp() |
4806 | self.broker.connectors_registry = {"test": FakeCreator} |
4807 | self.broker.register_client("test") |
4808 | self.client = self.broker.get_client("test") |
4809 | @@ -549,18 +591,25 @@ class HandlersTest(LandscapeTest): |
4810 | result = self.reactor.fire("message", message) |
4811 | result = [i for i in result if i is not None][0] |
4812 | |
4813 | - class StartsWith(object): |
4814 | - |
4815 | + class StartsWith: |
4816 | def __eq__(self, other): |
4817 | return other.startswith( |
4818 | - "Landscape client failed to handle this request (foobar)") |
4819 | + "Landscape client failed to handle this request (foobar)", |
4820 | + ) |
4821 | |
4822 | def broadcasted(ignored): |
4823 | self.client.message.assert_called_once_with(message) |
4824 | self.assertMessages( |
4825 | self.mstore.get_pending_messages(), |
4826 | - [{"type": "operation-result", "status": FAILED, |
4827 | - "result-text": StartsWith(), "operation-id": 4}]) |
4828 | + [ |
4829 | + { |
4830 | + "type": "operation-result", |
4831 | + "status": FAILED, |
4832 | + "result-text": StartsWith(), |
4833 | + "operation-id": 4, |
4834 | + }, |
4835 | + ], |
4836 | + ) |
4837 | |
4838 | result.addCallback(broadcasted) |
4839 | return result |
4840 | @@ -582,7 +631,10 @@ class HandlersTest(LandscapeTest): |
4841 | self.client.fire_event = Mock(return_value=succeed(None)) |
4842 | self.reactor.fire("message-type-acceptance-changed", "test", True) |
4843 | self.client.fire_event.assert_called_once_with( |
4844 | - "message-type-acceptance-changed", "test", True) |
4845 | + "message-type-acceptance-changed", |
4846 | + "test", |
4847 | + True, |
4848 | + ) |
4849 | |
4850 | def test_server_uuid_changed(self): |
4851 | """ |
4852 | @@ -592,7 +644,10 @@ class HandlersTest(LandscapeTest): |
4853 | self.client.fire_event = Mock(return_value=succeed(None)) |
4854 | self.reactor.fire("server-uuid-changed", None, 123) |
4855 | self.client.fire_event.assert_called_once_with( |
4856 | - "server-uuid-changed", None, 123) |
4857 | + "server-uuid-changed", |
4858 | + None, |
4859 | + 123, |
4860 | + ) |
4861 | |
4862 | def test_package_data_changed(self): |
4863 | """ |
4864 | diff --git a/landscape/client/broker/tests/test_service.py b/landscape/client/broker/tests/test_service.py |
4865 | index 580f64e..e99f9ac 100644 |
4866 | --- a/landscape/client/broker/tests/test_service.py |
4867 | +++ b/landscape/client/broker/tests/test_service.py |
4868 | @@ -1,12 +1,11 @@ |
4869 | import os |
4870 | +from unittest.mock import Mock |
4871 | |
4872 | -from mock import Mock |
4873 | - |
4874 | -from landscape.client.tests.helpers import LandscapeTest |
4875 | -from landscape.client.broker.tests.helpers import BrokerConfigurationHelper |
4876 | +from landscape.client.broker.amp import RemoteBrokerConnector |
4877 | from landscape.client.broker.service import BrokerService |
4878 | +from landscape.client.broker.tests.helpers import BrokerConfigurationHelper |
4879 | from landscape.client.broker.transport import HTTPTransport |
4880 | -from landscape.client.broker.amp import RemoteBrokerConnector |
4881 | +from landscape.client.tests.helpers import LandscapeTest |
4882 | from landscape.lib.testing import FakeReactor |
4883 | |
4884 | |
4885 | @@ -15,7 +14,7 @@ class BrokerServiceTest(LandscapeTest): |
4886 | helpers = [BrokerConfigurationHelper] |
4887 | |
4888 | def setUp(self): |
4889 | - super(BrokerServiceTest, self).setUp() |
4890 | + super().setUp() |
4891 | |
4892 | class FakeBrokerService(BrokerService): |
4893 | reactor_factory = FakeReactor |
4894 | @@ -28,7 +27,8 @@ class BrokerServiceTest(LandscapeTest): |
4895 | """ |
4896 | self.assertEqual( |
4897 | self.service.persist.filename, |
4898 | - os.path.join(self.config.data_path, "broker.bpickle")) |
4899 | + os.path.join(self.config.data_path, "broker.bpickle"), |
4900 | + ) |
4901 | |
4902 | def test_transport(self): |
4903 | """ |
4904 | diff --git a/landscape/client/broker/tests/test_store.py b/landscape/client/broker/tests/test_store.py |
4905 | index 208c75c..b61edf3 100644 |
4906 | --- a/landscape/client/broker/tests/test_store.py |
4907 | +++ b/landscape/client/broker/tests/test_store.py |
4908 | @@ -1,22 +1,22 @@ |
4909 | import os |
4910 | -import mock |
4911 | - |
4912 | +from unittest import mock |
4913 | |
4914 | from twisted.python.compat import intToBytes |
4915 | |
4916 | +from landscape.client.broker.store import MessageStore |
4917 | +from landscape.client.tests.helpers import LandscapeTest |
4918 | from landscape.lib.bpickle import dumps |
4919 | from landscape.lib.persist import Persist |
4920 | -from landscape.lib.schema import InvalidError, Int, Bytes, Unicode |
4921 | +from landscape.lib.schema import Bytes |
4922 | +from landscape.lib.schema import Int |
4923 | +from landscape.lib.schema import InvalidError |
4924 | +from landscape.lib.schema import Unicode |
4925 | from landscape.message_schemas.message import Message |
4926 | -from landscape.client.broker.store import MessageStore |
4927 | - |
4928 | -from landscape.client.tests.helpers import LandscapeTest |
4929 | |
4930 | |
4931 | class MessageStoreTest(LandscapeTest): |
4932 | - |
4933 | def setUp(self): |
4934 | - super(MessageStoreTest, self).setUp() |
4935 | + super().setUp() |
4936 | self.temp_dir = self.makeDir() |
4937 | self.persist_filename = self.makeFile() |
4938 | self.store = self.create_store() |
4939 | @@ -137,13 +137,87 @@ class MessageStoreTest(LandscapeTest): |
4940 | self.assertEqual(self.store.get_pending_offset(), 0) |
4941 | self.assertEqual(self.store.get_pending_messages(), []) |
4942 | |
4943 | + def test_messages_over_limit(self): |
4944 | + """ |
4945 | + Create six messages, two per directory. Since there is a limit of |
4946 | + one directory then only the last 2 messages should be in the queue |
4947 | + """ |
4948 | + |
4949 | + self.store._directory_size = 2 |
4950 | + self.store._max_dirs = 1 |
4951 | + for num in range(6): # 0,1 2,3 4,5 |
4952 | + message = {"type": "data", "data": f"{num}".encode()} |
4953 | + self.store.add(message) |
4954 | + messages = self.store.get_pending_messages(200) |
4955 | + self.assertMessages( |
4956 | + messages, |
4957 | + [{"type": "data", "data": b"4"}, {"type": "data", "data": b"5"}], |
4958 | + ) |
4959 | + |
4960 | + def test_messages_under_limit(self): |
4961 | + """ |
4962 | + Create six messages, all of which should be in the queue, since 3 |
4963 | + directories are active |
4964 | + """ |
4965 | + |
4966 | + self.store._directory_size = 2 |
4967 | + self.store._max_dirs = 3 |
4968 | + messages_sent = [] |
4969 | + for num in range(6): # 0,1 2,3 4,5 |
4970 | + message = {"type": "data", "data": f"{num}".encode()} |
4971 | + messages_sent.append(message) |
4972 | + self.store.add(message) |
4973 | + messages = self.store.get_pending_messages(200) |
4974 | + self.assertMessages(messages, messages_sent) |
4975 | + |
4976 | + def test_messages_over_mb(self): |
4977 | + """ |
4978 | + Create three messages with the second one being very large. The |
4979 | + max size should get triggered, so all should be cleared except for the |
4980 | + last one. |
4981 | + """ |
4982 | + |
4983 | + self.store._directory_size = 2 |
4984 | + self.store._max_size_mb = 0.01 |
4985 | + self.store.add({"type": "data", "data": b"a"}) |
4986 | + self.store.add({"type": "data", "data": b"b" * 15000}) |
4987 | + self.store.add({"type": "data", "data": b"c"}) |
4988 | + messages = self.store.get_pending_messages(200) |
4989 | + self.assertMessages( |
4990 | + messages, |
4991 | + [{"type": "data", "data": b"c"}], |
4992 | + ) |
4993 | + |
4994 | + @mock.patch("shutil.rmtree") |
4995 | + def test_exception_on_message_limit(self, rmtree_mock): |
4996 | + """ |
4997 | + If an exception occurs while deleting it shouldn't affect the next |
4998 | + message sent |
4999 | + """ |
5000 | + rmtree_mock.side_effect = IOError("Error!") |
PPA with this package is here https:/ /launchpad. net/~silverdrak e11/+archive/ ubuntu/ landscape- client