Compare commits

..

159 Commits

Author SHA1 Message Date
ludeeus
e415923553 Trigger backup sync when backup is complete 2024-10-16 04:54:29 +00:00
dependabot[bot]
95c638991d Bump coverage from 7.6.2 to 7.6.3 (#5351) 2024-10-14 08:16:23 +02:00
Stefan Agner
e2ada42001 Fix log follow mode without range header (#5347) 2024-10-11 19:54:53 +02:00
dependabot[bot]
22e50b4ace Bump aiohttp from 3.10.9 to 3.10.10 (#5345)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-11 10:31:09 +02:00
dependabot[bot]
334484de7f Bump debugpy from 1.8.6 to 1.8.7 (#5346)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-11 10:12:26 +02:00
Stefan Agner
180a7c3990 Throttle connectivity check on connectivity issue (#5342)
* Throttle connectivity check on connectivity issue

If Supervisor detects a connectivity issue, currenlty every function
which requires internet get delayed by 10s due to the connectivity
check. This especially slows down initial startup when there are
connectivity issues. It is unlikely to resolve immeaditly, so throttle
the connectivity check to check every 30s.

* Fix pytest

* Reset throttle in test and refactor helper

* CodeRabbit suggestion

---------

Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
2024-10-10 22:57:16 +02:00
dependabot[bot]
d5f33de808 Bump coverage from 7.6.1 to 7.6.2 (#5344)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.6.1 to 7.6.2.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.1...7.6.2)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-10 09:46:41 +02:00
dependabot[bot]
6539f0df6f Bump actions/upload-artifact from 4.4.2 to 4.4.3 (#5343)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.4.2 to 4.4.3.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4.4.2...v4.4.3)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-10 09:46:18 +02:00
Stefan Agner
1504278223 Recreate aiohttp session on connectivity check (#5332)
It seems to actually get a proper connectivity check run, we need a new
vanilla ClientSession() object.
2024-10-09 21:41:46 +02:00
Jan Čermák
9f3767b23d Return cursor of the first host logs entry via headers (#5333)
* Return cursor of the first host logs entry via headers

Return first entry's cursor via custom `X-First-Cursor` header that can
be consumed by the client and used for continual requesting of the
historic logs. Once the first fetch returns data, the cursor can be
supplied as the first argument to the Range header in another call,
fetching accurate slice of the journal with the previous log entries
using the `Range: entries=cursor[[:num_skip]:num_entries]` syntax.

Let's say we fetch logs with the Range header `entries=:-19:20` (to
fetch very last 20 lines of the logs, see below why not
`entries:-20:20`) and we get `cursor50` as the reply (the actual value
will be much more complex and with no guaranteed format). To fetch
previous slice of the logs, we use `entries=cursor50:-20:20`, which
would return 20 lines previous to `cursor50` and `cursor30` in the
cursor header. This way we can go all the way back to the history.

One problem with the cursor is that it's not possible to determine when
the negative num_skip points beyond the first log entry. In that case
the client either needs to know what the first entry is (via
`entries=:0:1`) or can iterate naively and stop once two subsequent
requests return the same first cursor.

Another caveat, even though it's unlikely it will be hit in real usage,
is that it's not possible to fetch the last line only - if no cursor is
provided, negative num_skip argument is needed, and in that case we're
pointing one record back from the current cursor, which is the previous
record. The least we can return without knowing any cursor is thus
`entries=👎2` (where the `2` can be omitted, however with
`entries=👎1` we would lose the last line). This also explains why
different `num_skip` and `num_entries` must be used for the first fetch.

* Fix typo (fallback->callback)

* Refactor journal_logs_reader to always return the cursor

* Update tests for new cursor handling
2024-10-09 20:27:29 +02:00
Jan Čermák
e0d7985369 Fix number of lines returned with host logs' query argument (#5334)
If no cursor is specified and negative num_skip is used, we're pointing
one record back from the last one, so host logs always returned 101
lines as the default. This was also the case of the lines query argument
that used the number directly as num_skip. Instead of doing that, point
N-1 records to the back and then get N records. Handle 1 record and
invalid numbers silently to avoid the need for error handling in
unpractical edge cases.
2024-10-09 20:27:18 +02:00
Stefan Agner
2968a5717c Update DNS plug-in on network change (#5331)
* Update DNS plug-in on network change

Restart the DNS plug-in when the primary network changes network
changes. This makes sure any potential host OS DNS configuration
changes get picked up by the DNS plug-in as well.

* Add a test case

---------

Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
2024-10-09 20:16:36 +02:00
Matheson Steplock
e2b25fe7ce Drop support for Debian 11 Bullseye (#5335) 2024-10-09 12:18:45 +02:00
dependabot[bot]
8601f5c49a Bump sentry-sdk from 2.15.0 to 2.16.0 (#5338)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.15.0 to 2.16.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.15.0...2.16.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 11:19:47 +02:00
dependabot[bot]
42279461e0 Bump pre-commit from 4.0.0 to 4.0.1 (#5337)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v4.0.0...v4.0.1)

---
updated-dependencies:
- dependency-name: pre-commit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 11:19:31 +02:00
dependabot[bot]
409447d6ca Bump actions/cache from 4.1.0 to 4.1.1 (#5340)
Bumps [actions/cache](https://github.com/actions/cache) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4.1.0...v4.1.1)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 11:19:02 +02:00
dependabot[bot]
5b313db49d Bump time-machine from 2.15.0 to 2.16.0 (#5336)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 09:27:57 +02:00
dependabot[bot]
d64618600d Bump actions/upload-artifact from 4.4.1 to 4.4.2 (#5339)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 09:26:23 +02:00
dependabot[bot]
1ee01b1d5e Bump actions/checkout from 4.2.0 to 4.2.1 (#5329)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-08 09:04:52 +02:00
dependabot[bot]
af590202c3 Bump actions/upload-artifact from 4.4.0 to 4.4.1 (#5330)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-08 09:04:36 +02:00
dependabot[bot]
12ca2fb624 Bump ruff from 0.6.8 to 0.6.9 (#5326)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 09:22:50 +02:00
dependabot[bot]
ea95f83742 Bump dbus-fast from 2.24.2 to 2.24.3 (#5328)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 09:18:12 +02:00
dependabot[bot]
e4d4da601c Bump aiohttp from 3.10.8 to 3.10.9 (#5327)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 09:01:00 +02:00
dependabot[bot]
0582f6fd39 Bump pre-commit from 3.8.0 to 4.0.0 (#5325)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 08:45:43 +02:00
dependabot[bot]
f254af8326 Bump actions/cache from 4.0.2 to 4.1.0 (#5323)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 08:40:52 +02:00
dependabot[bot]
3333770246 Bump sigstore/cosign-installer from 3.6.0 to 3.7.0 (#5324)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-07 08:37:08 +02:00
Stefan Agner
ee5ded29ac Allow Supervisor token authentication from landing page (#5321)
The landing page provides the Supervisor token as authentication, so
consider the landingpage as new enough too.
2024-10-03 18:17:13 +02:00
dependabot[bot]
f530db98ff Bump cpe from 1.3.0 to 1.3.1 (#5320)
* Bump cpe from 1.3.0 to 1.3.1

Bumps [cpe](https://github.com/nilp0inter/cpe) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/nilp0inter/cpe/releases)
- [Changelog](https://github.com/nilp0inter/cpe/blob/main/NEWS.txt)
- [Commits](https://github.com/nilp0inter/cpe/compare/v1.3.0...v1.3.1)

---
updated-dependencies:
- dependency-name: cpe
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* Revert "Suppress SyntaxWarning from CPE until fixed (#5227)"

This reverts commit c95df56e8d.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stefan Agner <stefan@agner.ch>
2024-10-03 18:08:19 +02:00
dependabot[bot]
911f9d661f Bump sentry-sdk from 2.14.0 to 2.15.0 (#5319)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 09:55:24 +02:00
dependabot[bot]
9935eac146 Bump codecov/codecov-action from 4.5.0 to 4.6.0 (#5318)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 08:25:59 +02:00
Darren Griffin
eae2c9e221 Add OHF logo to README (#5316) 2024-09-30 18:42:08 +02:00
Paulus Schoutsen
1a67fe8a83 Exclude Text-to-Speech cache from backups (#5313) 2024-09-30 08:41:18 +02:00
J. Nick Koston
3af565267b Bump aiohttp to 3.10.8 (#5314) 2024-09-30 08:40:31 +02:00
dependabot[bot]
d09460a971 Bump ruff from 0.6.7 to 0.6.8 (#5312)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.7 to 0.6.8.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.7...0.6.8)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-27 09:22:38 +02:00
dependabot[bot]
c65329442a Bump actions/checkout from 4.1.7 to 4.2.0 (#5310)
Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.7 to 4.2.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4.1.7...v4.2.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-26 09:13:30 +02:00
dependabot[bot]
48430dfa28 Bump pylint from 3.3.0 to 3.3.1 (#5311)
Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v3.3.0...v3.3.1)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-26 09:13:00 +02:00
dependabot[bot]
70e2de372d Bump debugpy from 1.8.5 to 1.8.6 (#5309)
Bumps [debugpy](https://github.com/microsoft/debugpy) from 1.8.5 to 1.8.6.
- [Release notes](https://github.com/microsoft/debugpy/releases)
- [Commits](https://github.com/microsoft/debugpy/compare/v1.8.5...v1.8.6)

---
updated-dependencies:
- dependency-name: debugpy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-25 17:58:41 +02:00
dependabot[bot]
75784480ab Bump pylint from 3.2.7 to 3.3.0 (#5306)
* Bump pylint from 3.2.7 to 3.3.0

Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.2.7 to 3.3.0.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v3.2.7...v3.3.0)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Set positional arguments limit to 10

This makes the current codebase pass with pylint 3.3.0 while still
warning in case many positional arguments are used.

* Move to design section

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stefan Agner <stefan@agner.ch>
2024-09-25 17:57:55 +02:00
J. Nick Koston
8a70ba841d Bump aiohttp to 3.10.6 (#5308) 2024-09-24 22:28:00 +02:00
dependabot[bot]
77733829d7 Bump ruff from 0.6.6 to 0.6.7 (#5307)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-23 09:46:50 +02:00
dependabot[bot]
d4b67f1946 Bump ruff from 0.6.5 to 0.6.6 (#5305) 2024-09-20 09:40:55 +02:00
dependabot[bot]
51ab138bb1 Bump setuptools from 75.0.0 to 75.1.0 (#5303)
Bumps [setuptools](https://github.com/pypa/setuptools) from 75.0.0 to 75.1.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v75.0.0...v75.1.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-17 09:20:42 +02:00
dependabot[bot]
b81413c8b2 Bump ruff from 0.6.4 to 0.6.5 (#5301)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.4 to 0.6.5.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.4...0.6.5)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 10:52:19 +02:00
dependabot[bot]
2ec33c6ef3 Bump setuptools from 74.1.2 to 75.0.0 (#5302)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 08:57:28 +02:00
dependabot[bot]
68b2c38c7c Bump urllib3 from 2.2.2 to 2.2.3 (#5299)
Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.2.2 to 2.2.3.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/2.2.2...2.2.3)

---
updated-dependencies:
- dependency-name: urllib3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-13 10:50:19 +02:00
Stefan Agner
1ca22799d1 Improve WiFi settings error handling (#5293)
* Improve WiFi settings error handling

Currently, the frontend potentially provides no WiFi settings dictionary
but still tries to update other (IP address) settings on the interface.
This leads to a stack trace since network manager is not able to fetch
the WiFi settings from the settings dictionary. Simply fill out what
we can and let NetworkManager provide an error.

Also allow to disable a network interface which has no configuration.
This avoids an error when switching to auto and back to disabled then
press save on a new wireless network interface.

* Add debug message when already disabled

* Add pytest for incomplete WiFi settings as psoted by frontend

Simulate the frontend posting no WiFi settings. Make sure the Supervisor
handles this gracefully.
2024-09-11 17:53:36 +02:00
dependabot[bot]
549dddcb11 Bump pytest from 8.3.2 to 8.3.3 (#5297) 2024-09-11 09:19:44 +02:00
dependabot[bot]
131af90469 Bump sentry-sdk from 2.13.0 to 2.14.0 (#5296)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.13.0 to 2.14.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.13.0...2.14.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-10 12:55:35 +02:00
dependabot[bot]
c7c39da7c6 Bump ruff from 0.6.3 to 0.6.4 (#5294)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.3 to 0.6.4.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.3...0.6.4)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-09 09:09:51 +02:00
dependabot[bot]
8310c426f0 Bump dbus-fast from 2.24.0 to 2.24.2 (#5295)
Bumps [dbus-fast](https://github.com/bluetooth-devices/dbus-fast) from 2.24.0 to 2.24.2.
- [Release notes](https://github.com/bluetooth-devices/dbus-fast/releases)
- [Changelog](https://github.com/Bluetooth-Devices/dbus-fast/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bluetooth-devices/dbus-fast/compare/v2.24.0...v2.24.2)

---
updated-dependencies:
- dependency-name: dbus-fast
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-09 09:09:39 +02:00
dependabot[bot]
bb8f91e39a Bump orjson from 3.9.15 to 3.10.7 (#5238)
Bumps [orjson](https://github.com/ijl/orjson) from 3.9.15 to 3.10.7.
- [Release notes](https://github.com/ijl/orjson/releases)
- [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ijl/orjson/compare/3.9.15...3.10.7)

---
updated-dependencies:
- dependency-name: orjson
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-05 10:42:45 +02:00
dependabot[bot]
a359b9a3d5 Bump actions/upload-artifact from 4.3.6 to 4.4.0 (#5284)
* Bump actions/upload-artifact from 4.3.6 to 4.4.0

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.6 to 4.4.0.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4.3.6...v4.4.0)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Explicitly include hidden files

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stefan Agner <stefan@agner.ch>
2024-09-05 10:38:27 +02:00
dependabot[bot]
e130ebad1f Bump setuptools from 74.0.0 to 74.1.2 (#5291)
Bumps [setuptools](https://github.com/pypa/setuptools) from 74.0.0 to 74.1.2.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v74.0.0...v74.1.2)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-05 09:19:37 +02:00
Stefan Agner
f5b996b66c Make network API replace IP/WiFi settings (#5283)
* Allow to set user DNS through API with auto mode

Currently it is only possible to set DNS servers when in static mode.
However, there are use cases to set DNS servers when in auto mode as
well, e.g. if no local DNS server is provided by the DHCP, or the provided
DNS turns out to be non-working.

* Fix use separate data structure for IP configuration fallout

Make sure gateway is correctly converted to the internal IP
representation. Fix type info.

* Overwrite WiFi settings completely too

* Add test for DNS configuration

* Run ruff format

* ruff format

* Use schema validation as source for API defaults

Instead of using replace() simply set the API defaults in the API
schema.

* Revert "Use schema validation as source for API defaults"

This reverts commit 885506fd37.

* Use explicit dataclass initialization

This avoid the unnecessary replaces from before. It also makes it more
obvious that this part of the API doesn't patch existing settings.
2024-09-05 09:19:13 +02:00
Jan Čermák
05e0c7c3ab Add "lines" and "verbose" query parameters for advanced logs (#5287)
Since headers are clumsy considering the Core proxy between the frontend
and Supervisor, add a way to adjust number of lines and verbose log
format using query parameters as well. If both query parameters and
headers are supplied, prefer the former, as it's more prominent when
reading through the request logs.
2024-09-04 16:11:37 +02:00
dependabot[bot]
6c1203e4bf Bump cryptography from 43.0.0 to 43.0.1 (#5289)
Bumps [cryptography](https://github.com/pyca/cryptography) from 43.0.0 to 43.0.1.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/43.0.0...43.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-04 08:42:43 +02:00
dependabot[bot]
5fbcaa8edd Bump pylint from 3.2.6 to 3.2.7 (#5285)
Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.2.6 to 3.2.7.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v3.2.6...v3.2.7)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-02 09:51:35 +02:00
Stefan Agner
00d217b5f7 Make IPv4 and IPv6 parse errors raise an API error (#5282)
* Make IPv4 and IPv6 parse errors raise an API error

Currently, IP address parsing errors lead to an execption which is not
handled by the `api_validate()` call. By using concrete IPv4 and IPv6
types and `vol.Coerce()` parsing errors are properly handled.

* ruff format

* ruff check
2024-08-30 18:20:20 +02:00
Stefan Agner
c0e35376f3 Improve connection settings tests (#5278)
* Improve connection settings fixture

Make the connection settings fixture behave more closely to the actual
NetworkManager. The behavior has been tested with NetworkManager 1.42.4
(Debian 12) and 1.44.2 (HAOS 13.1). This likely behaves similar in older
versions too.

* Introduce separate skeleton and settings for wireless

Instead of having a combined network settings object which has
Ethernet and Wirless settings, create a separate settings object for
wireless.

* Handle addresses/address-data property like NetworkManager

* Address ruff check

* Improve network API test

Add a test which changes from "static" to "auto". Validate that settings
are updated accordingly. Specifically, today this does clear the DNS
setting (by not providing the property).

* ruff format

* ruff check

* Complete TEST_INTERFACE rename

* Add partial network update as test case
2024-08-30 16:07:04 +02:00
Mike Degatano
2be84e1282 Keep shared images on update (#5268)
* Test stub for keeping shared images after update

* Keep shared images on addon update

* ImageNotFound should only skip the one image not all

* Fix tests and nonetype error

* Normalize logic between two cleanup methods
2024-08-30 15:29:13 +02:00
Jan Čermák
08f10c96ef Persist currently selected slot on successful boot (#5276)
When boot slot is selected manually in GRUB, the system boots into this
slot and marks it as good. However, the boot order is not changed, so in
the next boot (after an explicit or unexpected reboot) HAOS returns to
the version in the other slot. This might be confusing because if the
system has been running for some time, the user can forget they have
changed the boot slot to fix issue they had.

This gets more confusing if the "other" boot slot is selected manually
three times in a row. Let's say we have ORDER="A B". This means that
every time GRUB starts, it wants to boot slot A. If the slot B is
selected instead, only A_TRY is incremented, system boots into slot B
and marks slot B as good (B_OK=1, B_TRY=0). On another boot, this
repeats, yet A_TRY is incremented again. Until it reaches 3, the slot A
would be always chosen automatically, only after that it would boot to
slot B, presuming slot A is dead. The ORDER variable will be still
unchanged though.

This commit only makes sure that when the system is marked as healthy,
the slot is both marked as good AND active, updating the ORDER variable
as well. Because the X_TRY counter is incremented by GRUB, if we want
the other slot not to be marked as bad, we need to adjust the logic in
OS's grub.cfg as well, because Supervisor can't know whether it's
apppropriate to change other slot's state or not.

I also took the courtesy to adjust the logging a bit, to include the
stack trace in the error log if marking the slot fails somehow.
2024-08-30 15:18:44 +02:00
dependabot[bot]
12f8ccdf02 Bump ruff from 0.6.2 to 0.6.3 (#5280)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.2 to 0.6.3.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.2...0.6.3)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-30 10:13:08 +02:00
dependabot[bot]
d63e78cf34 Bump deepmerge from 1.1.1 to 2.0 (#5279)
Bumps [deepmerge](https://github.com/toumorokoshi/deepmerge) from 1.1.1 to 2.0.
- [Release notes](https://github.com/toumorokoshi/deepmerge/releases)
- [Commits](https://github.com/toumorokoshi/deepmerge/compare/v1.1.1...v2.0)

---
updated-dependencies:
- dependency-name: deepmerge
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-30 10:12:50 +02:00
dependabot[bot]
65d97ca924 Bump actions/setup-python from 5.1.1 to 5.2.0 (#5281)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.1.1 to 5.2.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5.1.1...v5.2.0)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-30 10:11:57 +02:00
dependabot[bot]
5770cafea9 Bump setuptools from 73.0.1 to 74.0.0 (#5277)
Bumps [setuptools](https://github.com/pypa/setuptools) from 73.0.1 to 74.0.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v73.0.1...v74.0.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-28 09:32:19 +02:00
Mike Degatano
0177cd9528 Add manual_only option to addon boot config (#5272)
* Add manual_forced option to addon boot config

* Include client library in pull request template

* Add boot_config to api output so frontend can use it

* `manual_forced` to `manual_only`
2024-08-27 17:59:52 +02:00
dependabot[bot]
91a8fae9b5 Bump dbus-fast from 2.23.0 to 2.24.0 (#5274)
Bumps [dbus-fast](https://github.com/bluetooth-devices/dbus-fast) from 2.23.0 to 2.24.0.
- [Release notes](https://github.com/bluetooth-devices/dbus-fast/releases)
- [Changelog](https://github.com/Bluetooth-Devices/dbus-fast/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bluetooth-devices/dbus-fast/compare/v2.23.0...v2.24.0)

---
updated-dependencies:
- dependency-name: dbus-fast
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-27 08:49:24 +02:00
dependabot[bot]
f16a4ce3ef Bump pulsectl from 24.4.0 to 24.8.0 (#5273)
Bumps [pulsectl](https://github.com/mk-fg/python-pulse-control) from 24.4.0 to 24.8.0.
- [Changelog](https://github.com/mk-fg/python-pulse-control/blob/master/CHANGES.rst)
- [Commits](https://github.com/mk-fg/python-pulse-control/commits)

---
updated-dependencies:
- dependency-name: pulsectl
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-27 08:49:11 +02:00
dependabot[bot]
306f63c75b Bump ruff from 0.6.1 to 0.6.2 (#5269) 2024-08-24 06:54:34 +02:00
Stefan Agner
2a0312318d Use single quotes in f-strings (#5267)
Instead of using double quotes in f-strings use single quotes. This
works with Python 3.11 too. We don't use Python 3.11 anymore, but is
useful when running pytest on Debian bookworm natively, which comes
with Python 3.11.
2024-08-23 16:16:08 +02:00
Stefan Agner
695a23a454 Minimize D-Bus requirements for tests (#5265)
This PR minimizes the D-Bus requirements for tests. It does this by
using dbus-daemon directly instead of dbus-launch. The latter is meant
for graphical applications and therefor has X11 dependencies. It also
leaves the D-Bus daemon running after the tests are done. This will
accumulate dbus-daemon processes over time which is not ideal.

I've also considered using dbus-run-session since it is meant to launch
processes with a private D-Bus session. For Python tests one could
launch it like so:
dbus-run-session -- python3 -m pytest ...

Then `DBUS_SESSION_BUS_ADDRESS` would be used automatically by the
`MessageBus` class. However, to keep the current behavior of the tests,
launching the D-Bus daemon manually is the better option.
2024-08-22 19:04:34 +02:00
dependabot[bot]
7366673eea Bump sentry-sdk from 2.10.0 to 2.13.0 (#5246)
* Bump sentry-sdk from 2.10.0 to 2.13.0

Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.10.0 to 2.13.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.10.0...2.13.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Replace deprecated apis with new ones

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mike Degatano <michael.degatano@gmail.com>
2024-08-22 10:04:32 +02:00
dependabot[bot]
53fa0fe215 Bump dbus-fast from 2.22.1 to 2.23.0 (#5264)
Bumps [dbus-fast](https://github.com/bluetooth-devices/dbus-fast) from 2.22.1 to 2.23.0.
- [Release notes](https://github.com/bluetooth-devices/dbus-fast/releases)
- [Changelog](https://github.com/Bluetooth-Devices/dbus-fast/blob/main/CHANGELOG.md)
- [Commits](https://github.com/bluetooth-devices/dbus-fast/compare/v2.22.1...v2.23.0)

---
updated-dependencies:
- dependency-name: dbus-fast
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-22 10:00:50 +02:00
Stefan Agner
1ba621be60 Use separate data structure for IP configuration (#5262)
* Use separate data structure for IP configuration

So far we use the same IpConfig data structure to represent the users
IP setting and the currently applied IP configuration.

This commit separates the two in IpConfig (for the currently applied
IP configuration) and IpSetting (representing the user provided IP
setting).

* Use custom string constants for connection settings

Use separate string constants for all connection settings. This makes
it easier to search where a particular NetworkManager connection
setting is used.

* Use Python typing for IpAddress in IpProperties

* Address pytest issue
2024-08-22 08:08:55 +02:00
Stefan Agner
5117364625 Bump cosign to v2.4.0 (#5263)
Follow the builder bump of 2024.08.2 and use cosign v2.4.0 for
Supervisor too.
2024-08-21 14:30:12 -04:00
Mike Degatano
986b92aee4 Keep shared images on addon uninstall (#5259)
* Keep shared images on addon uninstall

* Add missing step for mocking new addon in store
2024-08-21 11:14:57 +02:00
dependabot[bot]
12d26b05af Bump setuptools from 73.0.0 to 73.0.1 (#5261)
Bumps [setuptools](https://github.com/pypa/setuptools) from 73.0.0 to 73.0.1.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v73.0.0...v73.0.1)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-21 09:50:02 +02:00
dependabot[bot]
e6c9704505 Bump home-assistant/builder from 2024.08.1 to 2024.08.2 (#5260)
Bumps [home-assistant/builder](https://github.com/home-assistant/builder) from 2024.08.1 to 2024.08.2.
- [Release notes](https://github.com/home-assistant/builder/releases)
- [Commits](https://github.com/home-assistant/builder/compare/2024.08.1...2024.08.2)

---
updated-dependencies:
- dependency-name: home-assistant/builder
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-21 09:38:59 +02:00
Stefan Agner
8ab396d77c Improve and extend error handling on D-Bus connect (#5245)
* Improve and extend error handling on D-Bus connect

Avoid initializing the Supervisor board since it does not support the
Properties interface (see https://github.com/home-assistant/os-agent/issues/206).

This prevents the following somewhat confusing warning:
  No OS-Agent support on the host. Some Host functions have been disabled.

The OS Agent is actually installed on the host, it is just a single
object which caused issues. No functionalty was actually lost, as the
Supervisor board object has no features currently, and all other
interfaces got properly initialized still (thanks to gather()).

Print warnings more fine graned so it is clear which object exactly
causes an issue. Also print a log message on the lowest layer when an
error occures on calling D-Bus. This allows to easier track the actual
D-Bus error source.

Fixes: #5241

* Fix tests

* Use local variable

* Avoid stack trace when board support fails to load

* Fix tests

* Use override mechanism to disable Properties support

Instead of disable loading of Supervised entirly override initialization
to prevent loading the Properties interface.

* Revert "Fix tests"

This reverts commit 1e3c491ace.
2024-08-20 17:55:53 +02:00
dependabot[bot]
8438448843 Bump aiohttp from 3.10.4 to 3.10.5 (#5255)
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.10.4 to 3.10.5.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.10.4...v3.10.5)

---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-20 11:23:27 +02:00
dependabot[bot]
362edb9a61 Bump setuptools from 72.2.0 to 73.0.0 (#5256)
Bumps [setuptools](https://github.com/pypa/setuptools) from 72.2.0 to 73.0.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v72.2.0...v73.0.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-20 11:22:42 +02:00
dependabot[bot]
1ff53e1853 Bump ruff from 0.6.0 to 0.6.1 (#5254)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.6.0 to 0.6.1.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.6.0...0.6.1)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 14:02:32 +02:00
dependabot[bot]
cfd28dbb5c Bump aiohttp from 3.10.3 to 3.10.4 (#5253)
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.10.3 to 3.10.4.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.10.3...v3.10.4)

---
updated-dependencies:
- dependency-name: aiohttp
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-19 13:38:08 +02:00
dependabot[bot]
cbec558289 Bump ruff from 0.5.7 to 0.6.0 (#5252)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.5.7 to 0.6.0.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.5.7...0.6.0)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-16 08:40:24 +02:00
dependabot[bot]
ca3a2937d0 Bump home-assistant/builder from 2024.03.5 to 2024.08.1 (#5250)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-15 09:31:33 +02:00
dependabot[bot]
3e67fc12c5 Bump setuptools from 72.1.0 to 72.2.0 (#5247)
Bumps [setuptools](https://github.com/pypa/setuptools) from 72.1.0 to 72.2.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v72.1.0...v72.2.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-14 11:01:30 +02:00
Stefan Agner
f6faa18409 Bump pre-commit ruff to 0.5.7 and reformat (#5242)
It seems that the codebase is not formatted with the latest ruff
version. This PR reformats the codebase with ruff 0.5.7.
2024-08-13 20:53:56 +02:00
dependabot[bot]
21ae2c2e54 Bump cpe from 1.2.1 to 1.3.0 (#5243)
Bumps [cpe](https://github.com/nilp0inter/cpe) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/nilp0inter/cpe/releases)
- [Changelog](https://github.com/nilp0inter/cpe/blob/develop/NEWS.txt)
- [Commits](https://github.com/nilp0inter/cpe/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: cpe
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-13 16:09:20 +02:00
Mike Degatano
eb3986bea2 Allow core to mark addons as system managed (#5145)
* Allow core to mark addons as system managed

* System managed options only settable by Home Assistant
2024-08-13 15:14:42 +02:00
dependabot[bot]
5d6738ced8 Bump aiohttp from 3.10.2 to 3.10.3 (#5240)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-12 09:05:42 +02:00
dependabot[bot]
2f2fecddf2 Bump pyyaml from 6.0.1 to 6.0.2 (#5230)
Bumps [pyyaml](https://github.com/yaml/pyyaml) from 6.0.1 to 6.0.2.
- [Release notes](https://github.com/yaml/pyyaml/releases)
- [Changelog](https://github.com/yaml/pyyaml/blob/main/CHANGES)
- [Commits](https://github.com/yaml/pyyaml/compare/6.0.1...6.0.2)

---
updated-dependencies:
- dependency-name: pyyaml
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 12:15:48 +02:00
dependabot[bot]
218ba3601e Bump orjson from 3.9.15 to 3.10.6 (#5169)
Bumps [orjson](https://github.com/ijl/orjson) from 3.9.15 to 3.10.6.
- [Release notes](https://github.com/ijl/orjson/releases)
- [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ijl/orjson/compare/3.9.15...3.10.6)

---
updated-dependencies:
- dependency-name: orjson
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 11:12:27 +02:00
J. Nick Koston
4c3f60c44b Bump aiohttp to 3.10.2, drop aiohttp-fast-url-dispatcher (#5236)
aiohttp-fast-url-dispatcher is not needed for 3.10.x

changelog: https://github.com/aio-libs/aiohttp/compare/v3.9.5...v3.10.2
2024-08-09 10:44:29 +02:00
dependabot[bot]
cb85e5e464 Bump ruff from 0.5.6 to 0.5.7 (#5237)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.5.6 to 0.5.7.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.5.6...0.5.7)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-09 10:41:30 +02:00
dependabot[bot]
5b46235872 Bump time-machine from 2.14.2 to 2.15.0 (#5229)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-08 09:05:56 +02:00
dependabot[bot]
70f675ac82 Bump sigstore/cosign-installer from 3.5.0 to 3.6.0 (#5234)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-08 08:53:54 +02:00
dependabot[bot]
bf0c714ea4 Bump attrs from 24.1.0 to 24.2.0 (#5231)
Bumps [attrs](https://github.com/sponsors/hynek) from 24.1.0 to 24.2.0.
- [Commits](https://github.com/sponsors/hynek/commits)

---
updated-dependencies:
- dependency-name: attrs
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 15:38:43 +02:00
Mike Degatano
c95df56e8d Suppress SyntaxWarning from CPE until fixed (#5227) 2024-08-07 15:37:30 +02:00
dependabot[bot]
5f3d851954 Bump actions/upload-artifact from 4.3.5 to 4.3.6 (#5232)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-07 09:05:38 +02:00
dependabot[bot]
10c69dcdae Bump ruff from 0.5.5 to 0.5.6 (#5221)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.5.5 to 0.5.6.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.5.5...0.5.6)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-06 09:10:52 +02:00
dependabot[bot]
bdd81ce3a9 Bump debugpy from 1.8.2 to 1.8.5 (#5225)
Bumps [debugpy](https://github.com/microsoft/debugpy) from 1.8.2 to 1.8.5.
- [Release notes](https://github.com/microsoft/debugpy/releases)
- [Commits](https://github.com/microsoft/debugpy/compare/v1.8.2...v1.8.5)

---
updated-dependencies:
- dependency-name: debugpy
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-06 08:38:52 +02:00
Mike Degatano
17ee234be4 Fix resp may be undefined end_backup issue (#5224) 2024-08-05 17:02:11 +02:00
dependabot[bot]
61034dfa7b Bump attrs from 23.2.0 to 24.1.0 (#5219)
Bumps [attrs](https://github.com/sponsors/hynek) from 23.2.0 to 24.1.0.
- [Commits](https://github.com/sponsors/hynek/commits)

---
updated-dependencies:
- dependency-name: attrs
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 09:41:21 +02:00
dependabot[bot]
185cd362fb Bump coverage from 7.6.0 to 7.6.1 (#5222)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.6.0 to 7.6.1.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.6.0...7.6.1)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 09:38:06 +02:00
dependabot[bot]
e2ca357774 Bump dirhash from 0.4.1 to 0.5.0 (#5223)
Bumps [dirhash](https://github.com/andhus/dirhash-python) from 0.4.1 to 0.5.0.
- [Release notes](https://github.com/andhus/dirhash-python/releases)
- [Changelog](https://github.com/andhus/dirhash-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/andhus/dirhash-python/compare/v0.4.1...v0.5.0)

---
updated-dependencies:
- dependency-name: dirhash
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-05 09:37:40 +02:00
dependabot[bot]
3dea7fc4e8 Bump actions/upload-artifact from 4.3.4 to 4.3.5 (#5217) 2024-08-05 08:36:00 +02:00
dependabot[bot]
01ba591bc9 Bump setuptools from 72.0.0 to 72.1.0 (#5212)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-30 10:12:58 +02:00
dependabot[bot]
640b7d46e3 Bump ruff from 0.5.4 to 0.5.5 (#5208)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 12:01:43 +02:00
dependabot[bot]
d6560c51ee Bump pre-commit from 3.7.1 to 3.8.0 (#5210)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 11:39:50 +02:00
dependabot[bot]
3e9b1938c6 Bump pytest from 8.3.1 to 8.3.2 (#5207)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.3.1 to 8.3.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/8.3.1...8.3.2)

---
updated-dependencies:
- dependency-name: pytest
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 11:26:14 +02:00
dependabot[bot]
44ce8de71f Bump setuptools from 71.1.0 to 72.0.0 (#5211)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-29 11:08:13 +02:00
Mike Degatano
0bbd15bfda Restrict stopping core during migrations with force option (#5205) 2024-07-25 17:14:45 +02:00
Mike Degatano
591b9a4d87 Stop backup if pre backup failed in Core (#5203)
* Stop backup if pre backup failed in Core

* Fix API tests

* Partial backup in ci since there's no Home assistant

* Add ssl folder to partial backup

* Allow backups when Home Assistant is not running

* Undo change to skip db test
2024-07-25 17:08:43 +02:00
Mike Degatano
5ee7d16687 Add hard-coded image fallback for plugins for offline start (#5204) 2024-07-25 13:45:38 +02:00
Erik Montnemery
4ab4350c58 Add support for offline DB migration (#5202)
* Add support for offline DB migration

* Format code
2024-07-23 15:27:16 -04:00
dependabot[bot]
4ea7133fa8 Bump docker/login-action from 3.2.0 to 3.3.0 (#5201)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-23 09:22:20 +02:00
dependabot[bot]
627d67f9d0 Bump cryptography from 42.0.8 to 43.0.0 (#5199)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 11:59:07 +02:00
dependabot[bot]
eb37655598 Bump pylint from 3.2.5 to 3.2.6 (#5198)
Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.2.5 to 3.2.6.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v3.2.5...v3.2.6)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 10:07:15 +02:00
dependabot[bot]
19b62dd0d4 Bump pytest from 8.2.2 to 8.3.1 (#5197)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 10:04:13 +02:00
dependabot[bot]
b2ad1ceea3 Bump sentry-sdk from 2.9.0 to 2.10.0 (#5188)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 10:03:25 +02:00
dependabot[bot]
c1545b5b78 Bump ruff from 0.5.3 to 0.5.4 (#5196)
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.5.3 to 0.5.4.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.5.3...0.5.4)

---
updated-dependencies:
- dependency-name: ruff
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 09:45:47 +02:00
dependabot[bot]
2c2f04ba85 Bump setuptools from 71.0.3 to 71.1.0 (#5200)
Bumps [setuptools](https://github.com/pypa/setuptools) from 71.0.3 to 71.1.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v71.0.3...v71.1.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-22 09:45:31 +02:00
Andrew Leech
77e7bf51b7 Only read wifi strength from active connections. (#5184) 2024-07-19 12:36:25 +02:00
Mike Degatano
a42d71dcef Small cleanup to pyproject.toml (#5191) 2024-07-19 09:09:13 +02:00
dependabot[bot]
1ff0432f4d Bump ruff from 0.5.2 to 0.5.3 (#5192)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-19 09:07:06 +02:00
dependabot[bot]
54afd6e1c8 Bump setuptools from 71.0.1 to 71.0.3 (#5193)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-19 09:06:43 +02:00
dependabot[bot]
458c493a74 Bump ruff from 0.5.1 to 0.5.2 (#5186)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-18 08:52:23 +02:00
dependabot[bot]
8ac8ecb17e Bump setuptools from 70.3.0 to 71.0.1 (#5190)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-18 08:51:36 +02:00
Mike Degatano
eac167067e Ignore false positive no-member error (#5189) 2024-07-18 08:43:59 +02:00
Mike Degatano
aa7f4aafeb Migrate supervisor devcontainer from pip to uv (#5170) 2024-07-12 10:26:45 +02:00
dependabot[bot]
d2183fa12b Bump coverage from 7.5.4 to 7.6.0 (#5185)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 7.5.4 to 7.6.0.
- [Release notes](https://github.com/nedbat/coveragepy/releases)
- [Changelog](https://github.com/nedbat/coveragepy/blob/master/CHANGES.rst)
- [Commits](https://github.com/nedbat/coveragepy/compare/7.5.4...7.6.0)

---
updated-dependencies:
- dependency-name: coverage
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-12 10:25:20 +02:00
dependabot[bot]
928f32bb4f Bump sentry-sdk from 2.8.0 to 2.9.0 (#5183)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-11 08:57:33 +02:00
dependabot[bot]
cbe21303c4 Bump actions/setup-python from 5.1.0 to 5.1.1 (#5182)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.1.0 to 5.1.1.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v5.1.0...v5.1.1)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-11 08:17:35 +02:00
dependabot[bot]
94987c04b8 Bump setuptools from 70.2.0 to 70.3.0 (#5181)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-10 08:37:23 +02:00
dependabot[bot]
d4ba46a846 Bump home-assistant/wheels from 2024.01.0 to 2024.07.1 (#5178)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-09 08:29:09 +02:00
dependabot[bot]
1a22d83895 Bump sentry-sdk from 2.7.1 to 2.8.0 (#5179)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-09 08:27:46 +02:00
dependabot[bot]
6b73bf5c28 Bump aiohttp-fast-url-dispatcher from 0.3.0 to 0.3.1 (#5175) 2024-07-08 08:41:48 +02:00
dependabot[bot]
c9c9451c36 Bump ruff from 0.5.0 to 0.5.1 (#5176) 2024-07-08 08:39:34 +02:00
dependabot[bot]
1882d448ea Bump actions/download-artifact from 4.1.7 to 4.1.8 (#5174) 2024-07-08 08:35:57 +02:00
dependabot[bot]
2f11c9c9e3 Bump actions/upload-artifact from 4.3.3 to 4.3.4 (#5173) 2024-07-08 08:34:07 +02:00
Mike Degatano
02bdc4b555 Use uv instead of pip in Supervisor (#5152)
* Migrate supervisor image from pip to uv

* Set python paths

* Put in i386 conditional to match core

* Semicolons within if statements
2024-07-03 11:51:16 -04:00
dependabot[bot]
1a1ee50d9d Bump voluptuous from 0.15.1 to 0.15.2 (#5168)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-03 09:57:11 +02:00
dependabot[bot]
50dc09d1a9 Bump setuptools from 70.1.1 to 70.2.0 (#5167)
Bumps [setuptools](https://github.com/pypa/setuptools) from 70.1.1 to 70.2.0.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/NEWS.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v70.1.1...v70.2.0)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-02 09:29:38 +02:00
dependabot[bot]
130efd340c Bump time-machine from 2.14.1 to 2.14.2 (#5165)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 08:47:00 +02:00
dependabot[bot]
00bc13c049 Bump pylint from 3.2.4 to 3.2.5 (#5166)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-01 08:43:39 +02:00
dependabot[bot]
3caad67f61 Bump sentry-sdk from 2.7.0 to 2.7.1 (#5164)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-30 15:27:42 +02:00
dependabot[bot]
13783f0d4a Bump ruff from 0.4.10 to 0.5.0 (#5163)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-28 08:39:34 +02:00
dependabot[bot]
eae97ba3f4 Bump pylint from 3.2.3 to 3.2.4 (#5160)
Bumps [pylint](https://github.com/pylint-dev/pylint) from 3.2.3 to 3.2.4.
- [Release notes](https://github.com/pylint-dev/pylint/releases)
- [Commits](https://github.com/pylint-dev/pylint/compare/v3.2.3...v3.2.4)

---
updated-dependencies:
- dependency-name: pylint
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-27 09:05:11 +02:00
dependabot[bot]
134dad7357 Bump sentry-sdk from 2.6.0 to 2.7.0 (#5161)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 2.6.0 to 2.7.0.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.6.0...2.7.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-27 09:04:42 +02:00
dependabot[bot]
1c4d2e8dec Bump voluptuous from 0.15.0 to 0.15.1 (#5162)
Bumps [voluptuous](https://github.com/alecthomas/voluptuous) from 0.15.0 to 0.15.1.
- [Release notes](https://github.com/alecthomas/voluptuous/releases)
- [Changelog](https://github.com/alecthomas/voluptuous/blob/master/CHANGELOG.md)
- [Commits](https://github.com/alecthomas/voluptuous/compare/0.15.0...0.15.1)

---
updated-dependencies:
- dependency-name: voluptuous
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-27 08:48:44 +02:00
dependabot[bot]
f2d7be3aac Bump dbus-fast from 2.21.3 to 2.22.1 (#5159)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-26 09:26:21 +02:00
dependabot[bot]
d06edb2dd6 Bump debugpy from 1.8.1 to 1.8.2 (#5158)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-26 08:50:33 +02:00
dependabot[bot]
7fa15b334a Bump setuptools from 70.1.0 to 70.1.1 (#5156)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-26 08:35:34 +02:00
Mike Degatano
ffb4e2d6d7 Bump Supervisor to Alpine 3.20 (#5151) 2024-06-25 08:37:10 +02:00
dependabot[bot]
bd8047ae9c Bump awesomeversion from 24.2.0 to 24.6.0 (#5153)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-25 08:25:24 +02:00
Mike Degatano
49bc0624af Ignore dns-data field in network settings update (#5147) 2024-06-24 15:47:58 -04:00
dependabot[bot]
5e1d764eb3 Bump coverage from 7.5.3 to 7.5.4 (#5150)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 08:41:30 +02:00
dependabot[bot]
0064d93d75 Bump dirhash from 0.4.0 to 0.4.1 (#5149)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 08:40:15 +02:00
dependabot[bot]
5a838ecfe7 Bump voluptuous from 0.14.2 to 0.15.0 (#5148)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 08:36:04 +02:00
358 changed files with 3491 additions and 1278 deletions

View File

@@ -4,8 +4,12 @@
"containerEnv": {
"WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}"
},
"remoteEnv": {
"PATH": "${containerEnv:VIRTUAL_ENV}/bin:${containerEnv:PATH}"
},
"appPort": ["9123:8123", "7357:4357"],
"postCreateCommand": "bash devcontainer_bootstrap",
"postCreateCommand": "bash devcontainer_setup",
"postStartCommand": "bash devcontainer_bootstrap",
"runArgs": ["-e", "GIT_EDITOR=code --wait", "--privileged"],
"customizations": {
"vscode": {
@@ -19,17 +23,21 @@
"GitHub.vscode-pull-request-github"
],
"settings": {
"python.defaultInterpreterPath": "/home/vscode/.local/ha-venv/bin/python",
"python.pythonPath": "/home/vscode/.local/ha-venv/bin/python",
"python.terminal.activateEnvInCurrentTerminal": true,
"python.testing.pytestArgs": ["--no-cov"],
"pylint.importStrategy": "fromEnvironment",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"terminal.integrated.profiles.linux": {
"zsh": {
"path": "/usr/bin/zsh"
}
},
"terminal.integrated.defaultProfile.linux": "zsh",
"editor.formatOnPaste": false,
"editor.formatOnSave": true,
"editor.formatOnType": true,
"files.trimTrailingWhitespace": true,
"python.pythonPath": "/usr/local/bin/python3",
"[python]": {
"editor.defaultFormatter": "charliermarsh.ruff"
}

View File

@@ -38,6 +38,7 @@
- This PR is related to issue:
- Link to documentation pull request:
- Link to cli pull request:
- Link to client library pull request:
## Checklist
@@ -55,9 +56,11 @@
- [ ] The code has been formatted using Ruff (`ruff format supervisor tests`)
- [ ] Tests have been added to verify that the new code works.
If API endpoints of add-on configuration are added/changed:
If API endpoints or add-on configuration are added/changed:
- [ ] Documentation added/updated for [developers.home-assistant.io][docs-repository]
- [ ] [CLI][cli-repository] updated (if necessary)
- [ ] [Client library][client-library-repository] updated (if necessary)
<!--
Thank you for contributing <3
@@ -67,3 +70,5 @@ If API endpoints of add-on configuration are added/changed:
[dev-checklist]: https://developers.home-assistant.io/docs/en/development_checklist.html
[docs-repository]: https://github.com/home-assistant/developers.home-assistant
[cli-repository]: https://github.com/home-assistant/cli
[client-library-repository]: https://github.com/home-assistant-libs/python-supervisor-client/

View File

@@ -53,7 +53,7 @@ jobs:
requirements: ${{ steps.requirements.outputs.changed }}
steps:
- name: Checkout the repository
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
with:
fetch-depth: 0
@@ -92,7 +92,7 @@ jobs:
arch: ${{ fromJson(needs.init.outputs.architectures) }}
steps:
- name: Checkout the repository
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
with:
fetch-depth: 0
@@ -106,7 +106,7 @@ jobs:
- name: Build wheels
if: needs.init.outputs.requirements == 'true'
uses: home-assistant/wheels@2024.01.0
uses: home-assistant/wheels@2024.07.1
with:
abi: cp312
tag: musllinux_1_2
@@ -125,15 +125,15 @@ jobs:
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
if: needs.init.outputs.publish == 'true'
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Install Cosign
if: needs.init.outputs.publish == 'true'
uses: sigstore/cosign-installer@v3.5.0
uses: sigstore/cosign-installer@v3.7.0
with:
cosign-release: "v2.2.3"
cosign-release: "v2.4.0"
- name: Install dirhash and calc hash
if: needs.init.outputs.publish == 'true'
@@ -149,7 +149,7 @@ jobs:
- name: Login to GitHub Container Registry
if: needs.init.outputs.publish == 'true'
uses: docker/login-action@v3.2.0
uses: docker/login-action@v3.3.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
@@ -160,7 +160,7 @@ jobs:
run: echo "BUILD_ARGS=--test" >> $GITHUB_ENV
- name: Build supervisor
uses: home-assistant/builder@2024.03.5
uses: home-assistant/builder@2024.08.2
with:
args: |
$BUILD_ARGS \
@@ -178,7 +178,7 @@ jobs:
steps:
- name: Checkout the repository
if: needs.init.outputs.publish == 'true'
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Initialize git
if: needs.init.outputs.publish == 'true'
@@ -203,11 +203,11 @@ jobs:
timeout-minutes: 60
steps:
- name: Checkout the repository
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Build the Supervisor
if: needs.init.outputs.publish != 'true'
uses: home-assistant/builder@2024.03.5
uses: home-assistant/builder@2024.08.2
with:
args: |
--test \

View File

@@ -25,15 +25,15 @@ jobs:
name: Prepare Python dependencies
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python
id: python
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -47,7 +47,7 @@ jobs:
pip install -r requirements.txt -r requirements_tests.txt
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: ${{ env.PRE_COMMIT_CACHE }}
lookup-only: true
@@ -67,15 +67,15 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ needs.prepare.outputs.python-version }}
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
id: python
with:
python-version: ${{ needs.prepare.outputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -87,7 +87,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: |
@@ -110,15 +110,15 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ needs.prepare.outputs.python-version }}
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
id: python
with:
python-version: ${{ needs.prepare.outputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -130,7 +130,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: |
@@ -153,7 +153,7 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Register hadolint problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/hadolint.json"
@@ -168,15 +168,15 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ needs.prepare.outputs.python-version }}
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
id: python
with:
python-version: ${{ needs.prepare.outputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -188,7 +188,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: |
@@ -212,15 +212,15 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ needs.prepare.outputs.python-version }}
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
id: python
with:
python-version: ${{ needs.prepare.outputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -232,7 +232,7 @@ jobs:
exit 1
- name: Restore pre-commit environment from cache
id: cache-precommit
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: ${{ env.PRE_COMMIT_CACHE }}
key: |
@@ -256,15 +256,15 @@ jobs:
needs: prepare
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ needs.prepare.outputs.python-version }}
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
id: python
with:
python-version: ${{ needs.prepare.outputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -288,19 +288,19 @@ jobs:
name: Run tests Python ${{ needs.prepare.outputs.python-version }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ needs.prepare.outputs.python-version }}
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
id: python
with:
python-version: ${{ needs.prepare.outputs.python-version }}
- name: Install Cosign
uses: sigstore/cosign-installer@v3.5.0
uses: sigstore/cosign-installer@v3.7.0
with:
cosign-release: "v2.2.3"
cosign-release: "v2.4.0"
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -313,7 +313,7 @@ jobs:
- name: Install additional system dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends libpulse0 libudev1 dbus dbus-x11
sudo apt-get install -y --no-install-recommends libpulse0 libudev1 dbus-daemon
- name: Register Python problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/python.json"
@@ -335,10 +335,11 @@ jobs:
-o console_output_style=count \
tests
- name: Upload coverage artifact
uses: actions/upload-artifact@v4.3.3
uses: actions/upload-artifact@v4.4.3
with:
name: coverage-${{ matrix.python-version }}
path: .coverage
include-hidden-files: true
coverage:
name: Process test coverage
@@ -346,15 +347,15 @@ jobs:
needs: ["pytest", "prepare"]
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Set up Python ${{ needs.prepare.outputs.python-version }}
uses: actions/setup-python@v5.1.0
uses: actions/setup-python@v5.2.0
id: python
with:
python-version: ${{ needs.prepare.outputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.0.2
uses: actions/cache@v4.1.1
with:
path: venv
key: |
@@ -365,7 +366,7 @@ jobs:
echo "Failed to restore Python virtual environment from cache"
exit 1
- name: Download all coverage artifacts
uses: actions/download-artifact@v4.1.7
uses: actions/download-artifact@v4.1.8
- name: Combine coverage results
run: |
. venv/bin/activate
@@ -373,4 +374,4 @@ jobs:
coverage report
coverage xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4.5.0
uses: codecov/codecov-action@v4.6.0

View File

@@ -11,7 +11,7 @@ jobs:
name: Release Drafter
steps:
- name: Checkout the repository
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
with:
fetch-depth: 0

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.1.7
uses: actions/checkout@v4.2.1
- name: Sentry Release
uses: getsentry/action-release@v1.7.0
env:

View File

@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.2.1
rev: v0.5.7
hooks:
- id: ruff
args:

View File

@@ -4,7 +4,8 @@ FROM ${BUILD_FROM}
ENV \
S6_SERVICES_GRACETIME=10000 \
SUPERVISOR_API=http://localhost \
CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1
CRYPTOGRAPHY_OPENSSL_NO_LEGACY=1 \
UV_SYSTEM_PYTHON=true
ARG \
COSIGN_VERSION \
@@ -26,14 +27,17 @@ RUN \
yaml \
\
&& curl -Lso /usr/bin/cosign "https://github.com/home-assistant/cosign/releases/download/${COSIGN_VERSION}/cosign_${BUILD_ARCH}" \
&& chmod a+x /usr/bin/cosign
&& chmod a+x /usr/bin/cosign \
&& pip3 install uv==0.2.21
# Install requirements
COPY requirements.txt .
RUN \
export MAKEFLAGS="-j$(nproc)" \
&& pip3 install --only-binary=:all: \
-r ./requirements.txt \
if [ "${BUILD_ARCH}" = "i386" ]; then \
linux32 uv pip install --no-build -r requirements.txt; \
else \
uv pip install --no-build -r requirements.txt; \
fi \
&& rm -f requirements.txt
# Install Home Assistant Supervisor

View File

@@ -30,3 +30,5 @@ Releases are done in 3 stages (channels) with this structure:
[development]: https://developers.home-assistant.io/docs/supervisor/development
[stable]: https://github.com/home-assistant/version/blob/master/stable.json
[![Home Assistant - A project from the Open Home Foundation](https://www.openhomefoundation.org/badges/home-assistant.png)](https://www.openhomefoundation.org/)

View File

@@ -1,10 +1,10 @@
image: ghcr.io/home-assistant/{arch}-hassio-supervisor
build_from:
aarch64: ghcr.io/home-assistant/aarch64-base-python:3.12-alpine3.19
armhf: ghcr.io/home-assistant/armhf-base-python:3.12-alpine3.19
armv7: ghcr.io/home-assistant/armv7-base-python:3.12-alpine3.19
amd64: ghcr.io/home-assistant/amd64-base-python:3.12-alpine3.19
i386: ghcr.io/home-assistant/i386-base-python:3.12-alpine3.19
aarch64: ghcr.io/home-assistant/aarch64-base-python:3.12-alpine3.20
armhf: ghcr.io/home-assistant/armhf-base-python:3.12-alpine3.20
armv7: ghcr.io/home-assistant/armv7-base-python:3.12-alpine3.20
amd64: ghcr.io/home-assistant/amd64-base-python:3.12-alpine3.20
i386: ghcr.io/home-assistant/i386-base-python:3.12-alpine3.20
codenotary:
signer: notary@home-assistant.io
base_image: notary@home-assistant.io
@@ -12,7 +12,7 @@ cosign:
base_identity: https://github.com/home-assistant/docker-base/.*
identity: https://github.com/home-assistant/supervisor/.*
args:
COSIGN_VERSION: 2.2.3
COSIGN_VERSION: 2.4.0
labels:
io.hass.type: supervisor
org.opencontainers.image.title: Home Assistant Supervisor

View File

@@ -31,7 +31,7 @@ include-package-data = true
include = ["supervisor*"]
[tool.pylint.MAIN]
py-version = "3.11"
py-version = "3.12"
# Use a conservative default here; 2 should speed up most setups and not hurt
# any too bad. Override on command line as appropriate.
jobs = 2
@@ -215,6 +215,9 @@ expected-line-ending-format = "LF"
[tool.pylint.EXCEPTIONS]
overgeneral-exceptions = ["builtins.BaseException", "builtins.Exception"]
[tool.pylint.DESIGN]
max-positional-arguments = 10
[tool.pytest.ini_options]
testpaths = ["tests"]
norecursedirs = [".git"]
@@ -228,12 +231,13 @@ filterwarnings = [
]
[tool.ruff]
select = [
lint.select = [
"B002", # Python does not support the unary prefix increment
"B007", # Loop control variable {name} not used within loop body
"B014", # Exception handler with duplicate exception
"B023", # Function definition does not bind loop variable {name}
"B026", # Star-arg unpacking after a keyword argument is strongly discouraged
"B904", # Use raise from to specify exception cause
"C", # complexity
"COM818", # Trailing comma on bare tuple prohibited
"D", # docstrings
@@ -247,7 +251,6 @@ select = [
"N804", # First argument of a class method should be named cls
"N805", # First argument of a method should be named self
"N815", # Variable {name} in class scope should not be mixedCase
"PGH001", # No builtin eval() allowed
"PGH004", # Use specific rule codes when using noqa
"PLC0414", # Useless import alias. Import alias does not rename original package.
"PLC", # pylint
@@ -286,13 +289,12 @@ select = [
"T20", # flake8-print
"TID251", # Banned imports
"TRY004", # Prefer TypeError exception for invalid type
"TRY200", # Use raise from to specify exception cause
"TRY302", # Remove exception handler; error is immediately re-raised
"UP", # pyupgrade
"W", # pycodestyle
]
ignore = [
lint.ignore = [
"D202", # No blank lines allowed after function docstring
"D203", # 1 blank line required before class docstring
"D213", # Multi-line docstring summary should start at the second line
@@ -339,16 +341,16 @@ ignore = [
"PLE0605",
]
[tool.ruff.flake8-import-conventions.extend-aliases]
[tool.ruff.lint.flake8-import-conventions.extend-aliases]
voluptuous = "vol"
[tool.ruff.flake8-pytest-style]
[tool.ruff.lint.flake8-pytest-style]
fixture-parentheses = false
[tool.ruff.flake8-tidy-imports.banned-api]
[tool.ruff.lint.flake8-tidy-imports.banned-api]
"pytz".msg = "use zoneinfo instead"
[tool.ruff.isort]
[tool.ruff.lint.isort]
force-sort-within-sections = true
section-order = [
"future",
@@ -362,10 +364,10 @@ known-first-party = ["supervisor", "tests"]
combine-as-imports = true
split-on-trailing-comma = false
[tool.ruff.per-file-ignores]
[tool.ruff.lint.per-file-ignores]
# DBus Service Mocks must use typing and names understood by dbus-fast
"tests/dbus_service_mocks/*.py" = ["F722", "F821", "N815"]
[tool.ruff.mccabe]
[tool.ruff.lint.mccabe]
max-complexity = 25

View File

@@ -1,30 +1,29 @@
aiodns==3.2.0
aiohttp==3.9.5
aiohttp-fast-url-dispatcher==0.3.0
aiohttp==3.10.10
atomicwrites-homeassistant==1.4.1
attrs==23.2.0
awesomeversion==24.2.0
attrs==24.2.0
awesomeversion==24.6.0
brotli==1.1.0
ciso8601==2.3.1
colorlog==6.8.2
cpe==1.2.1
cryptography==42.0.8
debugpy==1.8.1
deepmerge==1.1.1
dirhash==0.4.0
cpe==1.3.1
cryptography==43.0.1
debugpy==1.8.7
deepmerge==2.0
dirhash==0.5.0
docker==7.1.0
faust-cchardet==2.1.19
gitpython==3.1.43
jinja2==3.1.4
orjson==3.9.15
pulsectl==24.4.0
orjson==3.10.7
pulsectl==24.8.0
pyudev==0.24.3
PyYAML==6.0.1
PyYAML==6.0.2
requests==2.32.3
securetar==2024.2.1
sentry-sdk==2.6.0
setuptools==70.1.0
voluptuous==0.14.2
dbus-fast==2.21.3
sentry-sdk==2.16.0
setuptools==75.1.0
voluptuous==0.15.2
dbus-fast==2.24.3
typing_extensions==4.12.2
zlib-fast==0.2.0

View File

@@ -1,12 +1,12 @@
coverage==7.5.3
pre-commit==3.7.1
pylint==3.2.3
coverage==7.6.3
pre-commit==4.0.1
pylint==3.3.1
pytest-aiohttp==1.0.5
pytest-asyncio==0.23.6
pytest-cov==5.0.0
pytest-timeout==2.3.1
pytest==8.2.2
ruff==0.4.10
time-machine==2.14.1
pytest==8.3.3
ruff==0.6.9
time-machine==2.16.0
typing_extensions==4.12.2
urllib3==2.2.2
urllib3==2.2.3

View File

@@ -1,4 +1,5 @@
"""Home Assistant Supervisor setup."""
from pathlib import Path
import re

View File

@@ -1,4 +1,5 @@
"""Main file for Supervisor."""
import asyncio
from concurrent.futures import ThreadPoolExecutor
import logging

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor add-ons."""
import asyncio
from collections.abc import Awaitable
from contextlib import suppress
@@ -46,6 +47,8 @@ from ..const import (
ATTR_SLUG,
ATTR_STATE,
ATTR_SYSTEM,
ATTR_SYSTEM_MANAGED,
ATTR_SYSTEM_MANAGED_CONFIG_ENTRY,
ATTR_TYPE,
ATTR_USER,
ATTR_UUID,
@@ -54,6 +57,7 @@ from ..const import (
ATTR_WATCHDOG,
DNS_SUFFIX,
AddonBoot,
AddonBootConfig,
AddonStartup,
AddonState,
BusEvent,
@@ -308,7 +312,9 @@ class Addon(AddonModel):
@property
def boot(self) -> AddonBoot:
"""Return boot config with prio local settings."""
"""Return boot config with prio local settings unless config is forced."""
if self.boot_config == AddonBootConfig.MANUAL_ONLY:
return super().boot
return self.persist.get(ATTR_BOOT, super().boot)
@boot.setter
@@ -363,6 +369,37 @@ class Addon(AddonModel):
else:
self.persist[ATTR_WATCHDOG] = value
@property
def system_managed(self) -> bool:
"""Return True if addon is managed by Home Assistant."""
return self.persist[ATTR_SYSTEM_MANAGED]
@system_managed.setter
def system_managed(self, value: bool) -> None:
"""Set system managed enable/disable."""
if not value and self.system_managed_config_entry:
self.system_managed_config_entry = None
self.persist[ATTR_SYSTEM_MANAGED] = value
@property
def system_managed_config_entry(self) -> str | None:
"""Return id of config entry managing this addon (if any)."""
if not self.system_managed:
return None
return self.persist.get(ATTR_SYSTEM_MANAGED_CONFIG_ENTRY)
@system_managed_config_entry.setter
def system_managed_config_entry(self, value: str | None) -> None:
"""Set ID of config entry managing this addon."""
if not self.system_managed:
_LOGGER.warning(
"Ignoring system managed config entry for %s because it is not system managed",
self.slug,
)
else:
self.persist[ATTR_SYSTEM_MANAGED_CONFIG_ENTRY] = value
@property
def uuid(self) -> str:
"""Return an API token for this add-on."""
@@ -729,10 +766,12 @@ class Addon(AddonModel):
limit=JobExecutionLimit.GROUP_ONCE,
on_condition=AddonsJobError,
)
async def uninstall(self, *, remove_config: bool) -> None:
async def uninstall(
self, *, remove_config: bool, remove_image: bool = True
) -> None:
"""Uninstall and cleanup this addon."""
try:
await self.instance.remove()
await self.instance.remove(remove_image=remove_image)
except DockerError as err:
raise AddonsError() from err

View File

@@ -1,4 +1,5 @@
"""Supervisor add-on build environment."""
from __future__ import annotations
from functools import cached_property

View File

@@ -1,4 +1,5 @@
"""Add-on static data."""
from datetime import timedelta
from enum import StrEnum

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor add-on data."""
from copy import deepcopy
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Supervisor add-on manager."""
import asyncio
from collections.abc import Awaitable
from contextlib import suppress
@@ -184,7 +185,15 @@ class AddonManager(CoreSysAttributes):
_LOGGER.warning("Add-on %s is not installed", slug)
return
await self.local[slug].uninstall(remove_config=remove_config)
shared_image = any(
self.local[slug].image == addon.image
and self.local[slug].version == addon.version
for addon in self.installed
if addon.slug != slug
)
await self.local[slug].uninstall(
remove_config=remove_config, remove_image=not shared_image
)
_LOGGER.info("Add-on '%s' successfully removed", slug)

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor add-ons."""
from abc import ABC, abstractmethod
from collections import defaultdict
from collections.abc import Awaitable, Callable
@@ -82,6 +83,7 @@ from ..const import (
SECURITY_DISABLE,
SECURITY_PROFILE,
AddonBoot,
AddonBootConfig,
AddonStage,
AddonStartup,
)
@@ -149,10 +151,15 @@ class AddonModel(JobGroup, ABC):
return self.data[ATTR_OPTIONS]
@property
def boot(self) -> AddonBoot:
"""Return boot config with prio local settings."""
def boot_config(self) -> AddonBootConfig:
"""Return boot config."""
return self.data[ATTR_BOOT]
@property
def boot(self) -> AddonBoot:
"""Return boot config with prio local settings unless config is forced."""
return AddonBoot(self.data[ATTR_BOOT])
@property
def auto_update(self) -> bool | None:
"""Return if auto update is enable."""

View File

@@ -1,4 +1,5 @@
"""Add-on Options / UI rendering."""
import hashlib
import logging
from pathlib import Path

View File

@@ -1,4 +1,5 @@
"""Util add-ons functions."""
from __future__ import annotations
import asyncio

View File

@@ -1,4 +1,5 @@
"""Validate add-ons options schema."""
import logging
import re
import secrets
@@ -78,6 +79,8 @@ from ..const import (
ATTR_STATE,
ATTR_STDIN,
ATTR_SYSTEM,
ATTR_SYSTEM_MANAGED,
ATTR_SYSTEM_MANAGED_CONFIG_ENTRY,
ATTR_TIMEOUT,
ATTR_TMPFS,
ATTR_TRANSLATIONS,
@@ -95,6 +98,7 @@ from ..const import (
ROLE_ALL,
ROLE_DEFAULT,
AddonBoot,
AddonBootConfig,
AddonStage,
AddonStartup,
AddonState,
@@ -318,7 +322,9 @@ _SCHEMA_ADDON_CONFIG = vol.Schema(
vol.Optional(ATTR_STARTUP, default=AddonStartup.APPLICATION): vol.Coerce(
AddonStartup
),
vol.Optional(ATTR_BOOT, default=AddonBoot.AUTO): vol.Coerce(AddonBoot),
vol.Optional(ATTR_BOOT, default=AddonBootConfig.AUTO): vol.Coerce(
AddonBootConfig
),
vol.Optional(ATTR_INIT, default=True): vol.Boolean(),
vol.Optional(ATTR_ADVANCED, default=False): vol.Boolean(),
vol.Optional(ATTR_STAGE, default=AddonStage.STABLE): vol.Coerce(AddonStage),
@@ -467,6 +473,8 @@ SCHEMA_ADDON_USER = vol.Schema(
vol.Optional(ATTR_PROTECTED, default=True): vol.Boolean(),
vol.Optional(ATTR_INGRESS_PANEL, default=False): vol.Boolean(),
vol.Optional(ATTR_WATCHDOG, default=False): vol.Boolean(),
vol.Optional(ATTR_SYSTEM_MANAGED, default=False): vol.Boolean(),
vol.Optional(ATTR_SYSTEM_MANAGED_CONFIG_ENTRY, default=None): vol.Maybe(str),
},
extra=vol.REMOVE_EXTRA,
)

View File

@@ -1,11 +1,11 @@
"""Init file for Supervisor RESTful API."""
from functools import partial
import logging
from pathlib import Path
from typing import Any
from aiohttp import web
from aiohttp_fast_url_dispatcher import FastUrlDispatcher, attach_fast_url_dispatcher
from ..const import AddonState
from ..coresys import CoreSys, CoreSysAttributes
@@ -67,7 +67,6 @@ class RestAPI(CoreSysAttributes):
"max_field_size": MAX_LINE_SIZE,
},
)
attach_fast_url_dispatcher(self.webapp, FastUrlDispatcher())
# service stuff
self._runner: web.AppRunner = web.AppRunner(self.webapp, shutdown_timeout=5)
@@ -510,6 +509,7 @@ class RestAPI(CoreSysAttributes):
web.post("/addons/{addon}/stop", api_addons.stop),
web.post("/addons/{addon}/restart", api_addons.restart),
web.post("/addons/{addon}/options", api_addons.options),
web.post("/addons/{addon}/sys_options", api_addons.sys_options),
web.post(
"/addons/{addon}/options/validate", api_addons.options_validate
),

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Home Assistant RESTful API."""
import asyncio
from collections.abc import Awaitable
import logging
@@ -81,6 +82,8 @@ from ..const import (
ATTR_STARTUP,
ATTR_STATE,
ATTR_STDIN,
ATTR_SYSTEM_MANAGED,
ATTR_SYSTEM_MANAGED_CONFIG_ENTRY,
ATTR_TRANSLATIONS,
ATTR_UART,
ATTR_UDEV,
@@ -95,6 +98,7 @@ from ..const import (
ATTR_WEBUI,
REQUEST_FROM,
AddonBoot,
AddonBootConfig,
)
from ..coresys import CoreSysAttributes
from ..docker.stats import DockerStats
@@ -106,7 +110,7 @@ from ..exceptions import (
PwnedSecret,
)
from ..validate import docker_ports
from .const import ATTR_REMOVE_CONFIG, ATTR_SIGNED
from .const import ATTR_BOOT_CONFIG, ATTR_REMOVE_CONFIG, ATTR_SIGNED
from .utils import api_process, api_validate, json_loads
_LOGGER: logging.Logger = logging.getLogger(__name__)
@@ -126,6 +130,13 @@ SCHEMA_OPTIONS = vol.Schema(
}
)
SCHEMA_SYS_OPTIONS = vol.Schema(
{
vol.Optional(ATTR_SYSTEM_MANAGED): vol.Boolean(),
vol.Optional(ATTR_SYSTEM_MANAGED_CONFIG_ENTRY): vol.Maybe(str),
}
)
SCHEMA_SECURITY = vol.Schema({vol.Optional(ATTR_PROTECTED): vol.Boolean()})
SCHEMA_UNINSTALL = vol.Schema(
@@ -178,6 +189,7 @@ class APIAddons(CoreSysAttributes):
ATTR_URL: addon.url,
ATTR_ICON: addon.with_icon,
ATTR_LOGO: addon.with_logo,
ATTR_SYSTEM_MANAGED: addon.system_managed,
}
for addon in self.sys_addons.installed
]
@@ -206,6 +218,7 @@ class APIAddons(CoreSysAttributes):
ATTR_VERSION_LATEST: addon.latest_version,
ATTR_PROTECTED: addon.protected,
ATTR_RATING: rating_security(addon),
ATTR_BOOT_CONFIG: addon.boot_config,
ATTR_BOOT: addon.boot,
ATTR_OPTIONS: addon.options,
ATTR_SCHEMA: addon.schema_ui,
@@ -265,6 +278,8 @@ class APIAddons(CoreSysAttributes):
ATTR_WATCHDOG: addon.watchdog,
ATTR_DEVICES: addon.static_devices
+ [device.path for device in addon.devices],
ATTR_SYSTEM_MANAGED: addon.system_managed,
ATTR_SYSTEM_MANAGED_CONFIG_ENTRY: addon.system_managed_config_entry,
}
return data
@@ -287,6 +302,10 @@ class APIAddons(CoreSysAttributes):
if ATTR_OPTIONS in body:
addon.options = body[ATTR_OPTIONS]
if ATTR_BOOT in body:
if addon.boot_config == AddonBootConfig.MANUAL_ONLY:
raise APIError(
f"Addon {addon.slug} boot option is set to {addon.boot_config} so it cannot be changed"
)
addon.boot = body[ATTR_BOOT]
if ATTR_AUTO_UPDATE in body:
addon.auto_update = body[ATTR_AUTO_UPDATE]
@@ -304,6 +323,20 @@ class APIAddons(CoreSysAttributes):
addon.save_persist()
@api_process
async def sys_options(self, request: web.Request) -> None:
"""Store system options for an add-on."""
addon = self.get_addon_for_request(request)
# Validate/Process Body
body = await api_validate(SCHEMA_SYS_OPTIONS, request)
if ATTR_SYSTEM_MANAGED in body:
addon.system_managed = body[ATTR_SYSTEM_MANAGED]
if ATTR_SYSTEM_MANAGED_CONFIG_ENTRY in body:
addon.system_managed_config_entry = body[ATTR_SYSTEM_MANAGED_CONFIG_ENTRY]
addon.save_persist()
@api_process
async def options_validate(self, request: web.Request) -> None:
"""Validate user options for add-on."""

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Audio RESTful API."""
import asyncio
from collections.abc import Awaitable
from dataclasses import asdict

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor auth/SSO RESTful API."""
import asyncio
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Backups RESTful API."""
import asyncio
from collections.abc import Callable
import errno
@@ -342,9 +343,9 @@ class APIBackups(CoreSysAttributes):
_LOGGER.info("Downloading backup %s", backup.slug)
response = web.FileResponse(backup.tarfile)
response.content_type = CONTENT_TYPE_TAR
response.headers[
CONTENT_DISPOSITION
] = f"attachment; filename={RE_SLUGIFY_NAME.sub('_', backup.name)}.tar"
response.headers[CONTENT_DISPOSITION] = (
f"attachment; filename={RE_SLUGIFY_NAME.sub('_', backup.name)}.tar"
)
return response
@api_process

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor HA cli RESTful API."""
import asyncio
import logging
from typing import Any

View File

@@ -17,6 +17,7 @@ ATTR_APPARMOR_VERSION = "apparmor_version"
ATTR_ATTRIBUTES = "attributes"
ATTR_AVAILABLE_UPDATES = "available_updates"
ATTR_BACKGROUND = "background"
ATTR_BOOT_CONFIG = "boot_config"
ATTR_BOOT_SLOT = "boot_slot"
ATTR_BOOT_SLOTS = "boot_slots"
ATTR_BOOT_TIMESTAMP = "boot_timestamp"
@@ -36,6 +37,7 @@ ATTR_DT_UTC = "dt_utc"
ATTR_EJECTABLE = "ejectable"
ATTR_FALLBACK = "fallback"
ATTR_FILESYSTEMS = "filesystems"
ATTR_FORCE = "force"
ATTR_GROUP_IDS = "group_ids"
ATTR_IDENTIFIERS = "identifiers"
ATTR_IS_ACTIVE = "is_active"

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor network RESTful API."""
import logging
import voluptuous as vol

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor DNS RESTful API."""
import asyncio
from collections.abc import Awaitable
import logging

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Home Assistant RESTful API."""
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor hardware RESTful API."""
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Home Assistant RESTful API."""
import asyncio
from collections.abc import Awaitable
import logging
@@ -34,9 +35,9 @@ from ..const import (
ATTR_WATCHDOG,
)
from ..coresys import CoreSysAttributes
from ..exceptions import APIError
from ..exceptions import APIDBMigrationInProgress, APIError
from ..validate import docker_image, network_port, version_tag
from .const import ATTR_SAFE_MODE
from .const import ATTR_FORCE, ATTR_SAFE_MODE
from .utils import api_process, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__)
@@ -66,6 +67,13 @@ SCHEMA_UPDATE = vol.Schema(
SCHEMA_RESTART = vol.Schema(
{
vol.Optional(ATTR_SAFE_MODE, default=False): vol.Boolean(),
vol.Optional(ATTR_FORCE, default=False): vol.Boolean(),
}
)
SCHEMA_STOP = vol.Schema(
{
vol.Optional(ATTR_FORCE, default=False): vol.Boolean(),
}
)
@@ -73,6 +81,17 @@ SCHEMA_RESTART = vol.Schema(
class APIHomeAssistant(CoreSysAttributes):
"""Handle RESTful API for Home Assistant functions."""
async def _check_offline_migration(self, force: bool = False) -> None:
"""Check and raise if there's an offline DB migration in progress."""
if (
not force
and (state := await self.sys_homeassistant.api.get_api_state())
and state.offline_db_migration
):
raise APIDBMigrationInProgress(
"Offline database migration in progress, try again after it has completed"
)
@api_process
async def info(self, request: web.Request) -> dict[str, Any]:
"""Return host information."""
@@ -154,6 +173,7 @@ class APIHomeAssistant(CoreSysAttributes):
async def update(self, request: web.Request) -> None:
"""Update Home Assistant."""
body = await api_validate(SCHEMA_UPDATE, request)
await self._check_offline_migration()
await asyncio.shield(
self.sys_homeassistant.core.update(
@@ -163,9 +183,12 @@ class APIHomeAssistant(CoreSysAttributes):
)
@api_process
def stop(self, request: web.Request) -> Awaitable[None]:
async def stop(self, request: web.Request) -> Awaitable[None]:
"""Stop Home Assistant."""
return asyncio.shield(self.sys_homeassistant.core.stop())
body = await api_validate(SCHEMA_STOP, request)
await self._check_offline_migration(force=body[ATTR_FORCE])
return await asyncio.shield(self.sys_homeassistant.core.stop())
@api_process
def start(self, request: web.Request) -> Awaitable[None]:
@@ -176,6 +199,7 @@ class APIHomeAssistant(CoreSysAttributes):
async def restart(self, request: web.Request) -> None:
"""Restart Home Assistant."""
body = await api_validate(SCHEMA_RESTART, request)
await self._check_offline_migration(force=body[ATTR_FORCE])
await asyncio.shield(
self.sys_homeassistant.core.restart(safe_mode=body[ATTR_SAFE_MODE])
@@ -185,6 +209,7 @@ class APIHomeAssistant(CoreSysAttributes):
async def rebuild(self, request: web.Request) -> None:
"""Rebuild Home Assistant."""
body = await api_validate(SCHEMA_RESTART, request)
await self._check_offline_migration(force=body[ATTR_FORCE])
await asyncio.shield(
self.sys_homeassistant.core.rebuild(safe_mode=body[ATTR_SAFE_MODE])

View File

@@ -28,7 +28,7 @@ from ..const import (
ATTR_TIMEZONE,
)
from ..coresys import CoreSysAttributes
from ..exceptions import APIError, HostLogError
from ..exceptions import APIDBMigrationInProgress, APIError, HostLogError
from ..host.const import (
PARAM_BOOT_ID,
PARAM_FOLLOW,
@@ -46,6 +46,7 @@ from .const import (
ATTR_BROADCAST_MDNS,
ATTR_DT_SYNCHRONIZED,
ATTR_DT_UTC,
ATTR_FORCE,
ATTR_IDENTIFIERS,
ATTR_LLMNR_HOSTNAME,
ATTR_STARTUP_TIME,
@@ -60,14 +61,33 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
IDENTIFIER = "identifier"
BOOTID = "bootid"
DEFAULT_RANGE = 100
DEFAULT_LINES = 100
SCHEMA_OPTIONS = vol.Schema({vol.Optional(ATTR_HOSTNAME): str})
# pylint: disable=no-value-for-parameter
SCHEMA_SHUTDOWN = vol.Schema(
{
vol.Optional(ATTR_FORCE, default=False): vol.Boolean(),
}
)
# pylint: enable=no-value-for-parameter
class APIHost(CoreSysAttributes):
"""Handle RESTful API for host functions."""
async def _check_ha_offline_migration(self, force: bool) -> None:
"""Check if HA has an offline migration in progress and raise if not forced."""
if (
not force
and (state := await self.sys_homeassistant.api.get_api_state())
and state.offline_db_migration
):
raise APIDBMigrationInProgress(
"Home Assistant offline database migration in progress, please wait until complete before shutting down host"
)
@api_process
async def info(self, request):
"""Return host information."""
@@ -109,14 +129,20 @@ class APIHost(CoreSysAttributes):
)
@api_process
def reboot(self, request):
async def reboot(self, request):
"""Reboot host."""
return asyncio.shield(self.sys_host.control.reboot())
body = await api_validate(SCHEMA_SHUTDOWN, request)
await self._check_ha_offline_migration(force=body[ATTR_FORCE])
return await asyncio.shield(self.sys_host.control.reboot())
@api_process
def shutdown(self, request):
async def shutdown(self, request):
"""Poweroff host."""
return asyncio.shield(self.sys_host.control.shutdown())
body = await api_validate(SCHEMA_SHUTDOWN, request)
await self._check_ha_offline_migration(force=body[ATTR_FORCE])
return await asyncio.shield(self.sys_host.control.shutdown())
@api_process
def reload(self, request):
@@ -196,13 +222,30 @@ class APIHost(CoreSysAttributes):
"supported for now."
)
if request.headers[ACCEPT] == CONTENT_TYPE_X_LOG:
if "verbose" in request.query or request.headers[ACCEPT] == CONTENT_TYPE_X_LOG:
log_formatter = LogFormatter.VERBOSE
if RANGE in request.headers:
if "lines" in request.query:
lines = request.query.get("lines", DEFAULT_LINES)
try:
lines = int(lines)
except ValueError:
# If the user passed a non-integer value, just use the default instead of error.
lines = DEFAULT_LINES
finally:
# We can't use the entries= Range header syntax to refer to the last 1 line,
# and passing 1 to the calculation below would return the 1st line of the logs
# instead. Since this is really an edge case that doesn't matter much, we'll just
# return 2 lines at minimum.
lines = max(2, lines)
# entries=cursor[[:num_skip]:num_entries]
range_header = f"entries=:-{lines-1}:{'' if follow else lines}"
elif RANGE in request.headers:
range_header = request.headers.get(RANGE)
else:
range_header = f"entries=:-{DEFAULT_RANGE}:"
range_header = (
f"entries=:-{DEFAULT_LINES-1}:{'' if follow else DEFAULT_LINES}"
)
async with self.sys_host.logs.journald_logs(
params=params, range_header=range_header, accept=LogFormat.JOURNAL
@@ -210,8 +253,13 @@ class APIHost(CoreSysAttributes):
try:
response = web.StreamResponse()
response.content_type = CONTENT_TYPE_TEXT
headers_returned = False
async for cursor, line in journal_logs_reader(resp, log_formatter):
if not headers_returned:
if cursor:
response.headers["X-First-Cursor"] = cursor
await response.prepare(request)
async for line in journal_logs_reader(resp, log_formatter):
headers_returned = True
await response.write(line.encode("utf-8") + b"\n")
except ConnectionResetError as ex:
raise APIError(

View File

@@ -1,4 +1,5 @@
"""Supervisor Add-on ingress service."""
import asyncio
from ipaddress import ip_address
import logging

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Jobs RESTful API."""
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Handle security part of this API."""
import logging
import re
from typing import Final
@@ -8,6 +9,8 @@ from aiohttp.web import Request, RequestHandler, Response, middleware
from aiohttp.web_exceptions import HTTPBadRequest, HTTPForbidden, HTTPUnauthorized
from awesomeversion import AwesomeVersion
from supervisor.homeassistant.const import LANDINGPAGE
from ...addons.const import RE_SLUG
from ...const import (
REQUEST_FROM,
@@ -77,6 +80,13 @@ ADDONS_API_BYPASS: Final = re.compile(
r")$"
)
# Home Assistant only
CORE_ONLY_PATHS: Final = re.compile(
r"^(?:"
r"/addons/" + RE_SLUG + "/sys_options"
r")$"
)
# Policy role add-on API access
ADDONS_ROLE_ACCESS: dict[str, re.Pattern] = {
ROLE_DEFAULT: re.compile(
@@ -232,6 +242,9 @@ class SecurityMiddleware(CoreSysAttributes):
if supervisor_token == self.sys_homeassistant.supervisor_token:
_LOGGER.debug("%s access from Home Assistant", request.path)
request_from = self.sys_homeassistant
elif CORE_ONLY_PATHS.match(request.path):
_LOGGER.warning("Attempted access to %s from client besides Home Assistant")
raise HTTPForbidden()
# Host
if supervisor_token == self.sys_plugins.cli.supervisor_token:
@@ -277,8 +290,10 @@ class SecurityMiddleware(CoreSysAttributes):
@middleware
async def core_proxy(self, request: Request, handler: RequestHandler) -> Response:
"""Validate user from Core API proxy."""
if request[REQUEST_FROM] != self.sys_homeassistant or version_is_new_enough(
self.sys_homeassistant.version, _CORE_VERSION
if (
request[REQUEST_FROM] != self.sys_homeassistant
or self.sys_homeassistant.version == LANDINGPAGE
or version_is_new_enough(self.sys_homeassistant.version, _CORE_VERSION)
):
return await handler(request)

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Multicast RESTful API."""
import asyncio
from collections.abc import Awaitable
import logging

View File

@@ -1,8 +1,8 @@
"""REST API for network."""
import asyncio
from collections.abc import Awaitable
from dataclasses import replace
from ipaddress import ip_address, ip_interface
from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface
from typing import Any
from aiohttp import web
@@ -48,18 +48,28 @@ from ..host.configuration import (
Interface,
InterfaceMethod,
IpConfig,
IpSetting,
VlanConfig,
WifiConfig,
)
from ..host.const import AuthMethod, InterfaceType, WifiMode
from .utils import api_process, api_validate
_SCHEMA_IP_CONFIG = vol.Schema(
_SCHEMA_IPV4_CONFIG = vol.Schema(
{
vol.Optional(ATTR_ADDRESS): [vol.Coerce(ip_interface)],
vol.Optional(ATTR_ADDRESS): [vol.Coerce(IPv4Interface)],
vol.Optional(ATTR_METHOD): vol.Coerce(InterfaceMethod),
vol.Optional(ATTR_GATEWAY): vol.Coerce(ip_address),
vol.Optional(ATTR_NAMESERVERS): [vol.Coerce(ip_address)],
vol.Optional(ATTR_GATEWAY): vol.Coerce(IPv4Address),
vol.Optional(ATTR_NAMESERVERS): [vol.Coerce(IPv4Address)],
}
)
_SCHEMA_IPV6_CONFIG = vol.Schema(
{
vol.Optional(ATTR_ADDRESS): [vol.Coerce(IPv6Interface)],
vol.Optional(ATTR_METHOD): vol.Coerce(InterfaceMethod),
vol.Optional(ATTR_GATEWAY): vol.Coerce(IPv6Address),
vol.Optional(ATTR_NAMESERVERS): [vol.Coerce(IPv6Address)],
}
)
@@ -76,18 +86,18 @@ _SCHEMA_WIFI_CONFIG = vol.Schema(
# pylint: disable=no-value-for-parameter
SCHEMA_UPDATE = vol.Schema(
{
vol.Optional(ATTR_IPV4): _SCHEMA_IP_CONFIG,
vol.Optional(ATTR_IPV6): _SCHEMA_IP_CONFIG,
vol.Optional(ATTR_IPV4): _SCHEMA_IPV4_CONFIG,
vol.Optional(ATTR_IPV6): _SCHEMA_IPV6_CONFIG,
vol.Optional(ATTR_WIFI): _SCHEMA_WIFI_CONFIG,
vol.Optional(ATTR_ENABLED): vol.Boolean(),
}
)
def ipconfig_struct(config: IpConfig) -> dict[str, Any]:
def ipconfig_struct(config: IpConfig, setting: IpSetting) -> dict[str, Any]:
"""Return a dict with information about ip configuration."""
return {
ATTR_METHOD: config.method,
ATTR_METHOD: setting.method,
ATTR_ADDRESS: [address.with_prefixlen for address in config.address],
ATTR_NAMESERVERS: [str(address) for address in config.nameservers],
ATTR_GATEWAY: str(config.gateway) if config.gateway else None,
@@ -122,8 +132,8 @@ def interface_struct(interface: Interface) -> dict[str, Any]:
ATTR_CONNECTED: interface.connected,
ATTR_PRIMARY: interface.primary,
ATTR_MAC: interface.mac,
ATTR_IPV4: ipconfig_struct(interface.ipv4) if interface.ipv4 else None,
ATTR_IPV6: ipconfig_struct(interface.ipv6) if interface.ipv6 else None,
ATTR_IPV4: ipconfig_struct(interface.ipv4, interface.ipv4setting),
ATTR_IPV6: ipconfig_struct(interface.ipv6, interface.ipv6setting),
ATTR_WIFI: wifi_struct(interface.wifi) if interface.wifi else None,
ATTR_VLAN: vlan_struct(interface.vlan) if interface.vlan else None,
}
@@ -197,24 +207,26 @@ class APINetwork(CoreSysAttributes):
# Apply config
for key, config in body.items():
if key == ATTR_IPV4:
interface.ipv4 = replace(
interface.ipv4
or IpConfig(InterfaceMethod.STATIC, [], None, [], None),
**config,
interface.ipv4setting = IpSetting(
config.get(ATTR_METHOD, InterfaceMethod.STATIC),
config.get(ATTR_ADDRESS, []),
config.get(ATTR_GATEWAY),
config.get(ATTR_NAMESERVERS, []),
)
elif key == ATTR_IPV6:
interface.ipv6 = replace(
interface.ipv6
or IpConfig(InterfaceMethod.STATIC, [], None, [], None),
**config,
interface.ipv6setting = IpSetting(
config.get(ATTR_METHOD, InterfaceMethod.STATIC),
config.get(ATTR_ADDRESS, []),
config.get(ATTR_GATEWAY),
config.get(ATTR_NAMESERVERS, []),
)
elif key == ATTR_WIFI:
interface.wifi = replace(
interface.wifi
or WifiConfig(
WifiMode.INFRASTRUCTURE, "", AuthMethod.OPEN, None, None
),
**config,
interface.wifi = WifiConfig(
config.get(ATTR_MODE, WifiMode.INFRASTRUCTURE),
config.get(ATTR_SSID, ""),
config.get(ATTR_AUTH, AuthMethod.OPEN),
config.get(ATTR_PSK, None),
None,
)
elif key == ATTR_ENABLED:
interface.enabled = config
@@ -256,24 +268,22 @@ class APINetwork(CoreSysAttributes):
vlan_config = VlanConfig(vlan, interface.name)
ipv4_config = None
ipv4_setting = None
if ATTR_IPV4 in body:
ipv4_config = IpConfig(
ipv4_setting = IpSetting(
body[ATTR_IPV4].get(ATTR_METHOD, InterfaceMethod.AUTO),
body[ATTR_IPV4].get(ATTR_ADDRESS, []),
body[ATTR_IPV4].get(ATTR_GATEWAY, None),
body[ATTR_IPV4].get(ATTR_NAMESERVERS, []),
None,
)
ipv6_config = None
ipv6_setting = None
if ATTR_IPV6 in body:
ipv6_config = IpConfig(
ipv6_setting = IpSetting(
body[ATTR_IPV6].get(ATTR_METHOD, InterfaceMethod.AUTO),
body[ATTR_IPV6].get(ATTR_ADDRESS, []),
body[ATTR_IPV6].get(ATTR_GATEWAY, None),
body[ATTR_IPV6].get(ATTR_NAMESERVERS, []),
None,
)
vlan_interface = Interface(
@@ -284,8 +294,10 @@ class APINetwork(CoreSysAttributes):
True,
False,
InterfaceType.VLAN,
ipv4_config,
ipv6_config,
None,
ipv4_setting,
None,
ipv6_setting,
None,
vlan_config,
)

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Observer RESTful API."""
import asyncio
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor HassOS RESTful API."""
import asyncio
from collections.abc import Awaitable
import logging

View File

@@ -1,4 +1,5 @@
"""Utils for Home Assistant Proxy."""
import asyncio
from contextlib import asynccontextmanager
import logging

View File

@@ -1,4 +1,5 @@
"""Handle REST API for resoulution."""
import asyncio
from collections.abc import Awaitable
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Root RESTful API."""
import asyncio
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Security RESTful API."""
import asyncio
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Home Assistant RESTful API."""
import asyncio
from collections.abc import Awaitable
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Supervisor RESTful API."""
import asyncio
from collections.abc import Awaitable
import logging

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor util for RESTful API."""
import json
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Handle Arch for underlay maschine/platforms."""
import logging
from pathlib import Path
import platform

View File

@@ -1,4 +1,5 @@
"""Manage SSO for Add-ons with Home Assistant user."""
import asyncio
import hashlib
import logging

View File

@@ -1,4 +1,5 @@
"""Representation of a backup file."""
import asyncio
from base64 import b64decode, b64encode
from collections import defaultdict

View File

@@ -1,4 +1,5 @@
"""Backup consts."""
from enum import StrEnum
BUF_SIZE = 2**20 * 4 # 4MB

View File

@@ -1,4 +1,5 @@
"""Backup manager."""
from __future__ import annotations
import asyncio
@@ -9,7 +10,10 @@ from pathlib import Path
from ..addons.addon import Addon
from ..const import (
ATTR_DATA,
ATTR_DAYS_UNTIL_STALE,
ATTR_SLUG,
ATTR_TYPE,
FILE_HASSIO_BACKUPS,
FOLDER_HOMEASSISTANT,
CoreState,
@@ -20,7 +24,9 @@ from ..exceptions import (
BackupInvalidError,
BackupJobError,
BackupMountDownError,
HomeAssistantWSError,
)
from ..homeassistant.const import WSType
from ..jobs.const import JOB_GROUP_BACKUP_MANAGER, JobCondition, JobExecutionLimit
from ..jobs.decorator import Job
from ..jobs.job_group import JobGroup
@@ -259,11 +265,6 @@ class BackupManager(FileConfiguration, JobGroup):
self.sys_core.state = CoreState.FREEZE
async with backup:
# Backup add-ons
if addon_list:
self._change_stage(BackupJobStage.ADDONS, backup)
addon_start_tasks = await backup.store_addons(addon_list)
# HomeAssistant Folder is for v1
if homeassistant:
self._change_stage(BackupJobStage.HOME_ASSISTANT, backup)
@@ -273,6 +274,11 @@ class BackupManager(FileConfiguration, JobGroup):
else homeassistant_exclude_database
)
# Backup add-ons
if addon_list:
self._change_stage(BackupJobStage.ADDONS, backup)
addon_start_tasks = await backup.store_addons(addon_list)
# Backup folders
if folder_list:
self._change_stage(BackupJobStage.FOLDERS, backup)
@@ -298,6 +304,18 @@ class BackupManager(FileConfiguration, JobGroup):
# Ignore exceptions from waiting for addon startup, addon errors handled elsewhere
await asyncio.gather(*addon_start_tasks, return_exceptions=True)
try:
await self.sys_homeassistant.websocket.async_send_command(
{
ATTR_TYPE: WSType.BACKUP_SYNC,
ATTR_DATA: {
ATTR_SLUG: backup.slug,
},
},
)
except HomeAssistantWSError as err:
_LOGGER.error("Can't send backup sync to Home Assistant: %s", err)
return backup
finally:
self.sys_core.state = CoreState.RUNNING

View File

@@ -1,4 +1,5 @@
"""Util add-on functions."""
import hashlib
import re

View File

@@ -1,4 +1,5 @@
"""Validate some things around restore."""
from __future__ import annotations
from typing import Any

View File

@@ -1,4 +1,6 @@
"""Bootstrap Supervisor."""
# ruff: noqa: T100
import logging
import os
from pathlib import Path

View File

@@ -1,4 +1,5 @@
"""Bus event system."""
from __future__ import annotations
from collections.abc import Awaitable, Callable

View File

@@ -1,4 +1,5 @@
"""Bootstrap Supervisor."""
from datetime import UTC, datetime
import logging
import os

View File

@@ -1,4 +1,5 @@
"""Constants file for Supervisor."""
from dataclasses import dataclass
from enum import StrEnum
from ipaddress import ip_network
@@ -309,6 +310,8 @@ ATTR_SUPERVISOR_VERSION = "supervisor_version"
ATTR_SUPPORTED = "supported"
ATTR_SUPPORTED_ARCH = "supported_arch"
ATTR_SYSTEM = "system"
ATTR_SYSTEM_MANAGED = "system_managed"
ATTR_SYSTEM_MANAGED_CONFIG_ENTRY = "system_managed_config_entry"
ATTR_TIMEOUT = "timeout"
ATTR_TIMEZONE = "timezone"
ATTR_TITLE = "title"
@@ -379,12 +382,27 @@ ROLE_ADMIN = "admin"
ROLE_ALL = [ROLE_DEFAULT, ROLE_HOMEASSISTANT, ROLE_BACKUP, ROLE_MANAGER, ROLE_ADMIN]
class AddonBootConfig(StrEnum):
"""Boot mode config for the add-on."""
AUTO = "auto"
MANUAL = "manual"
MANUAL_ONLY = "manual_only"
class AddonBoot(StrEnum):
"""Boot mode for the add-on."""
AUTO = "auto"
MANUAL = "manual"
@classmethod
def _missing_(cls, value: str) -> Self | None:
"""Convert 'forced' config values to their counterpart."""
if value == AddonBootConfig.MANUAL_ONLY:
return AddonBoot.MANUAL
return None
class AddonStartup(StrEnum):
"""Startup types of Add-on."""

View File

@@ -1,4 +1,5 @@
"""Main file for Supervisor."""
import asyncio
from collections.abc import Awaitable
from contextlib import suppress

View File

@@ -1,4 +1,5 @@
"""Handle core shared data."""
from __future__ import annotations
import asyncio
@@ -62,7 +63,7 @@ class CoreSys:
# External objects
self._loop: asyncio.BaseEventLoop = asyncio.get_running_loop()
self._websession: aiohttp.ClientSession = aiohttp.ClientSession()
self._websession = None
# Global objects
self._config: CoreConfig = CoreConfig()
@@ -95,10 +96,8 @@ class CoreSys:
self._bus: Bus | None = None
self._mounts: MountManager | None = None
# Set default header for aiohttp
self._websession._default_headers = MappingProxyType(
{aiohttp.hdrs.USER_AGENT: SERVER_SOFTWARE}
)
# Setup aiohttp session
self.create_websession()
# Task factory attributes
self._set_task_context: list[Callable[[Context], Context]] = []
@@ -113,8 +112,11 @@ class CoreSys:
"""Return system timezone."""
if self.config.timezone:
return self.config.timezone
# pylint bug with python 3.12.4 (https://github.com/pylint-dev/pylint/issues/9811)
# pylint: disable=no-member
if self.host.info.timezone:
return self.host.info.timezone
# pylint: enable=no-member
return "UTC"
@property
@@ -544,6 +546,16 @@ class CoreSys:
return self.loop.run_in_executor(None, funct, *args)
def create_websession(self) -> None:
"""Create a new aiohttp session."""
if self._websession:
self.create_task(self._websession.close())
# Create session and set default header for aiohttp
self._websession: aiohttp.ClientSession = aiohttp.ClientSession(
headers=MappingProxyType({aiohttp.hdrs.USER_AGENT: SERVER_SOFTWARE})
)
def _create_context(self) -> Context:
"""Create a new context for a task."""
context = copy_context()

View File

@@ -1,4 +1,5 @@
"""OS-Agent implementation for DBUS."""
import asyncio
from collections.abc import Awaitable
import logging
@@ -7,7 +8,7 @@ from typing import Any
from awesomeversion import AwesomeVersion
from dbus_fast.aio.message_bus import MessageBus
from ...exceptions import DBusError, DBusInterfaceError, DBusServiceUnkownError
from ...exceptions import DBusInterfaceError, DBusServiceUnkownError
from ..const import (
DBUS_ATTR_DIAGNOSTICS,
DBUS_ATTR_VERSION,
@@ -95,13 +96,25 @@ class OSAgent(DBusInterfaceProxy):
_LOGGER.info("Load dbus interface %s", self.name)
try:
await super().connect(bus)
await asyncio.gather(*[dbus.connect(bus) for dbus in self.all])
except DBusError:
_LOGGER.warning("Can't connect to OS-Agent")
except (DBusServiceUnkownError, DBusInterfaceError):
_LOGGER.warning(
_LOGGER.error(
"No OS-Agent support on the host. Some Host functions have been disabled."
)
return
errors = await asyncio.gather(
*[dbus.connect(bus) for dbus in self.all], return_exceptions=True
)
for err in errors:
if err:
dbus = self.all[errors.index(err)]
_LOGGER.error(
"Can't load OS Agent dbus interface %s %s: %s",
dbus.bus_name,
dbus.object_path,
err,
)
@dbus_connected
async def update(self, changed: dict[str, Any] | None = None) -> None:

View File

@@ -1,4 +1,5 @@
"""AppArmor object for OS-Agent."""
from pathlib import Path
from awesomeversion import AwesomeVersion

View File

@@ -1,9 +1,10 @@
"""Board management for OS Agent."""
import logging
from dbus_fast.aio.message_bus import MessageBus
from ....exceptions import BoardInvalidError
from ....exceptions import BoardInvalidError, DBusInterfaceError, DBusServiceUnkownError
from ...const import (
DBUS_ATTR_BOARD,
DBUS_IFACE_HAOS_BOARDS,
@@ -74,6 +75,10 @@ class BoardManager(DBusInterfaceProxy):
self._board_proxy = Green()
elif self.board == BOARD_NAME_SUPERVISED:
self._board_proxy = Supervised()
else:
return
if self._board_proxy:
try:
await self._board_proxy.connect(bus)
except (DBusServiceUnkownError, DBusInterfaceError) as ex:
_LOGGER.warning("OS-Agent board support initialization failed: %s", ex)

View File

@@ -1,5 +1,9 @@
"""Supervised board management."""
from typing import Any
from supervisor.dbus.utils import dbus_connected
from .const import BOARD_NAME_SUPERVISED
from .interface import BoardProxy
@@ -11,3 +15,11 @@ class Supervised(BoardProxy):
"""Initialize properties."""
super().__init__(BOARD_NAME_SUPERVISED)
self.sync_properties: bool = False
@dbus_connected
async def update(self, changed: dict[str, Any] | None = None) -> None:
"""Do nothing as there are no properties.
Currently unused, avoid using the Properties interface to avoid a bug in
Go D-Bus, see: https://github.com/home-assistant/os-agent/issues/206
"""

View File

@@ -1,4 +1,5 @@
"""DataDisk object for OS-Agent."""
from pathlib import Path
from ..const import (

View File

@@ -1,4 +1,5 @@
"""Constants for DBUS."""
from enum import IntEnum, StrEnum
from socket import AF_INET, AF_INET6

View File

@@ -1,4 +1,5 @@
"""D-Bus interface for hostname."""
import logging
from dbus_fast.aio.message_bus import MessageBus

View File

@@ -1,4 +1,5 @@
"""Interface class for D-Bus wrappers."""
from abc import ABC
from collections.abc import Callable
from functools import wraps

View File

@@ -1,4 +1,5 @@
"""Interface to Logind over D-Bus."""
import logging
from dbus_fast.aio.message_bus import MessageBus

View File

@@ -1,4 +1,5 @@
"""D-Bus interface objects."""
import asyncio
import logging
@@ -128,9 +129,11 @@ class DBusManager(CoreSysAttributes):
for err in errors:
if err:
dbus = self.all[errors.index(err)]
_LOGGER.warning(
"Can't load dbus interface %s: %s",
self.all[errors.index(err)].name,
"Can't load dbus interface %s %s: %s",
dbus.name,
dbus.object_path,
err,
)

View File

@@ -1,4 +1,5 @@
"""Network Manager implementation for DBUS."""
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""NetworkConnection objects for Network Manager."""
from dataclasses import dataclass
from ipaddress import IPv4Address, IPv6Address
@@ -58,11 +59,22 @@ class VlanProperties:
parent: str | None
@dataclass(slots=True)
class IpAddress:
"""IP address object for Network Manager."""
address: str
prefix: int
@dataclass(slots=True)
class IpProperties:
"""IP properties object for Network Manager."""
method: str | None
address_data: list[IpAddress] | None
gateway: str | None
dns: list[bytes | int] | None
@dataclass(slots=True)

View File

@@ -1,4 +1,5 @@
"""Network Manager DNS Manager object."""
from ipaddress import ip_address
import logging
from typing import Any

View File

@@ -1,17 +1,18 @@
"""Connection object for Network Manager."""
import logging
from typing import Any
from dbus_fast import Variant
from dbus_fast.aio.message_bus import MessageBus
from ....const import ATTR_METHOD, ATTR_MODE, ATTR_PSK, ATTR_SSID
from ...const import DBUS_NAME_NM
from ...interface import DBusInterface
from ...utils import dbus_connected
from ..configuration import (
ConnectionProperties,
EthernetProperties,
IpAddress,
IpProperties,
MatchProperties,
VlanProperties,
@@ -20,30 +21,52 @@ from ..configuration import (
)
CONF_ATTR_CONNECTION = "connection"
CONF_ATTR_MATCH = "match"
CONF_ATTR_802_ETHERNET = "802-3-ethernet"
CONF_ATTR_802_WIRELESS = "802-11-wireless"
CONF_ATTR_802_WIRELESS_SECURITY = "802-11-wireless-security"
CONF_ATTR_VLAN = "vlan"
CONF_ATTR_IPV4 = "ipv4"
CONF_ATTR_IPV6 = "ipv6"
CONF_ATTR_MATCH = "match"
CONF_ATTR_PATH = "path"
ATTR_ID = "id"
ATTR_UUID = "uuid"
ATTR_TYPE = "type"
ATTR_PARENT = "parent"
ATTR_ASSIGNED_MAC = "assigned-mac-address"
ATTR_POWERSAVE = "powersave"
ATTR_AUTH_ALG = "auth-alg"
ATTR_KEY_MGMT = "key-mgmt"
ATTR_INTERFACE_NAME = "interface-name"
ATTR_PATH = "path"
CONF_ATTR_CONNECTION_ID = "id"
CONF_ATTR_CONNECTION_UUID = "uuid"
CONF_ATTR_CONNECTION_TYPE = "type"
CONF_ATTR_CONNECTION_LLMNR = "llmnr"
CONF_ATTR_CONNECTION_MDNS = "mdns"
CONF_ATTR_CONNECTION_AUTOCONNECT = "autoconnect"
CONF_ATTR_CONNECTION_INTERFACE_NAME = "interface-name"
CONF_ATTR_MATCH_PATH = "path"
CONF_ATTR_VLAN_ID = "id"
CONF_ATTR_VLAN_PARENT = "parent"
CONF_ATTR_802_ETHERNET_ASSIGNED_MAC = "assigned-mac-address"
CONF_ATTR_802_WIRELESS_MODE = "mode"
CONF_ATTR_802_WIRELESS_ASSIGNED_MAC = "assigned-mac-address"
CONF_ATTR_802_WIRELESS_SSID = "ssid"
CONF_ATTR_802_WIRELESS_POWERSAVE = "powersave"
CONF_ATTR_802_WIRELESS_SECURITY_AUTH_ALG = "auth-alg"
CONF_ATTR_802_WIRELESS_SECURITY_KEY_MGMT = "key-mgmt"
CONF_ATTR_802_WIRELESS_SECURITY_PSK = "psk"
CONF_ATTR_IPV4_METHOD = "method"
CONF_ATTR_IPV4_ADDRESS_DATA = "address-data"
CONF_ATTR_IPV4_GATEWAY = "gateway"
CONF_ATTR_IPV4_DNS = "dns"
CONF_ATTR_IPV6_METHOD = "method"
CONF_ATTR_IPV6_ADDRESS_DATA = "address-data"
CONF_ATTR_IPV6_GATEWAY = "gateway"
CONF_ATTR_IPV6_DNS = "dns"
IPV4_6_IGNORE_FIELDS = [
"addresses",
"address-data",
"dns",
"dns-data",
"gateway",
"method",
]
@@ -73,7 +96,7 @@ def _merge_settings_attribute(
class NetworkSetting(DBusInterface):
"""Network connection setting object for Network Manager.
https://developer.gnome.org/NetworkManager/stable/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html
https://networkmanager.dev/docs/api/1.48.0/gdbus-org.freedesktop.NetworkManager.Settings.Connection.html
"""
bus_name: str = DBUS_NAME_NM
@@ -147,7 +170,7 @@ class NetworkSetting(DBusInterface):
new_settings,
settings,
CONF_ATTR_CONNECTION,
ignore_current_value=[ATTR_INTERFACE_NAME],
ignore_current_value=[CONF_ATTR_CONNECTION_INTERFACE_NAME],
)
_merge_settings_attribute(new_settings, settings, CONF_ATTR_802_ETHERNET)
_merge_settings_attribute(new_settings, settings, CONF_ATTR_802_WIRELESS)
@@ -192,47 +215,69 @@ class NetworkSetting(DBusInterface):
# See: https://developer-old.gnome.org/NetworkManager/stable/ch01.html
if CONF_ATTR_CONNECTION in data:
self._connection = ConnectionProperties(
data[CONF_ATTR_CONNECTION].get(ATTR_ID),
data[CONF_ATTR_CONNECTION].get(ATTR_UUID),
data[CONF_ATTR_CONNECTION].get(ATTR_TYPE),
data[CONF_ATTR_CONNECTION].get(ATTR_INTERFACE_NAME),
data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_ID),
data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_UUID),
data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_TYPE),
data[CONF_ATTR_CONNECTION].get(CONF_ATTR_CONNECTION_INTERFACE_NAME),
)
if CONF_ATTR_802_ETHERNET in data:
self._ethernet = EthernetProperties(
data[CONF_ATTR_802_ETHERNET].get(ATTR_ASSIGNED_MAC),
data[CONF_ATTR_802_ETHERNET].get(CONF_ATTR_802_ETHERNET_ASSIGNED_MAC),
)
if CONF_ATTR_802_WIRELESS in data:
self._wireless = WirelessProperties(
bytes(data[CONF_ATTR_802_WIRELESS].get(ATTR_SSID, [])).decode(),
data[CONF_ATTR_802_WIRELESS].get(ATTR_ASSIGNED_MAC),
data[CONF_ATTR_802_WIRELESS].get(ATTR_MODE),
data[CONF_ATTR_802_WIRELESS].get(ATTR_POWERSAVE),
bytes(
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_SSID, [])
).decode(),
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_ASSIGNED_MAC),
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_MODE),
data[CONF_ATTR_802_WIRELESS].get(CONF_ATTR_802_WIRELESS_POWERSAVE),
)
if CONF_ATTR_802_WIRELESS_SECURITY in data:
self._wireless_security = WirelessSecurityProperties(
data[CONF_ATTR_802_WIRELESS_SECURITY].get(ATTR_AUTH_ALG),
data[CONF_ATTR_802_WIRELESS_SECURITY].get(ATTR_KEY_MGMT),
data[CONF_ATTR_802_WIRELESS_SECURITY].get(ATTR_PSK),
data[CONF_ATTR_802_WIRELESS_SECURITY].get(
CONF_ATTR_802_WIRELESS_SECURITY_AUTH_ALG
),
data[CONF_ATTR_802_WIRELESS_SECURITY].get(
CONF_ATTR_802_WIRELESS_SECURITY_KEY_MGMT
),
data[CONF_ATTR_802_WIRELESS_SECURITY].get(
CONF_ATTR_802_WIRELESS_SECURITY_PSK
),
)
if CONF_ATTR_VLAN in data:
self._vlan = VlanProperties(
data[CONF_ATTR_VLAN].get(ATTR_ID),
data[CONF_ATTR_VLAN].get(ATTR_PARENT),
data[CONF_ATTR_VLAN].get(CONF_ATTR_VLAN_ID),
data[CONF_ATTR_VLAN].get(CONF_ATTR_VLAN_PARENT),
)
if CONF_ATTR_IPV4 in data:
address_data = None
if ips := data[CONF_ATTR_IPV4].get(CONF_ATTR_IPV4_ADDRESS_DATA):
address_data = [IpAddress(ip["address"], ip["prefix"]) for ip in ips]
self._ipv4 = IpProperties(
data[CONF_ATTR_IPV4].get(ATTR_METHOD),
data[CONF_ATTR_IPV4].get(CONF_ATTR_IPV4_METHOD),
address_data,
data[CONF_ATTR_IPV4].get(CONF_ATTR_IPV4_GATEWAY),
data[CONF_ATTR_IPV4].get(CONF_ATTR_IPV4_DNS),
)
if CONF_ATTR_IPV6 in data:
address_data = None
if ips := data[CONF_ATTR_IPV6].get(CONF_ATTR_IPV6_ADDRESS_DATA):
address_data = [IpAddress(ip["address"], ip["prefix"]) for ip in ips]
self._ipv6 = IpProperties(
data[CONF_ATTR_IPV6].get(ATTR_METHOD),
data[CONF_ATTR_IPV6].get(CONF_ATTR_IPV6_METHOD),
address_data,
data[CONF_ATTR_IPV6].get(CONF_ATTR_IPV6_GATEWAY),
data[CONF_ATTR_IPV6].get(CONF_ATTR_IPV6_DNS),
)
if CONF_ATTR_MATCH in data:
self._match = MatchProperties(data[CONF_ATTR_MATCH].get(ATTR_PATH))
self._match = MatchProperties(
data[CONF_ATTR_MATCH].get(CONF_ATTR_MATCH_PATH)
)

View File

@@ -1,4 +1,5 @@
"""Payload generators for DBUS communication."""
from __future__ import annotations
import socket
@@ -10,22 +11,128 @@ from dbus_fast import Variant
from ....host.const import InterfaceMethod, InterfaceType
from .. import NetworkManager
from . import (
ATTR_ASSIGNED_MAC,
CONF_ATTR_802_ETHERNET,
CONF_ATTR_802_ETHERNET_ASSIGNED_MAC,
CONF_ATTR_802_WIRELESS,
CONF_ATTR_802_WIRELESS_ASSIGNED_MAC,
CONF_ATTR_802_WIRELESS_MODE,
CONF_ATTR_802_WIRELESS_POWERSAVE,
CONF_ATTR_802_WIRELESS_SECURITY,
CONF_ATTR_802_WIRELESS_SECURITY_AUTH_ALG,
CONF_ATTR_802_WIRELESS_SECURITY_KEY_MGMT,
CONF_ATTR_802_WIRELESS_SECURITY_PSK,
CONF_ATTR_802_WIRELESS_SSID,
CONF_ATTR_CONNECTION,
CONF_ATTR_CONNECTION_AUTOCONNECT,
CONF_ATTR_CONNECTION_ID,
CONF_ATTR_CONNECTION_LLMNR,
CONF_ATTR_CONNECTION_MDNS,
CONF_ATTR_CONNECTION_TYPE,
CONF_ATTR_CONNECTION_UUID,
CONF_ATTR_IPV4,
CONF_ATTR_IPV4_ADDRESS_DATA,
CONF_ATTR_IPV4_DNS,
CONF_ATTR_IPV4_GATEWAY,
CONF_ATTR_IPV4_METHOD,
CONF_ATTR_IPV6,
CONF_ATTR_IPV6_ADDRESS_DATA,
CONF_ATTR_IPV6_DNS,
CONF_ATTR_IPV6_GATEWAY,
CONF_ATTR_IPV6_METHOD,
CONF_ATTR_MATCH,
CONF_ATTR_PATH,
CONF_ATTR_MATCH_PATH,
CONF_ATTR_VLAN,
CONF_ATTR_VLAN_ID,
CONF_ATTR_VLAN_PARENT,
)
if TYPE_CHECKING:
from ....host.configuration import Interface
def _get_ipv4_connection_settings(ipv4setting) -> dict:
ipv4 = {}
if not ipv4setting or ipv4setting.method == InterfaceMethod.AUTO:
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "auto")
elif ipv4setting.method == InterfaceMethod.DISABLED:
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "disabled")
elif ipv4setting.method == InterfaceMethod.STATIC:
ipv4[CONF_ATTR_IPV4_METHOD] = Variant("s", "manual")
address_data = []
for address in ipv4setting.address:
address_data.append(
{
"address": Variant("s", str(address.ip)),
"prefix": Variant("u", int(address.with_prefixlen.split("/")[-1])),
}
)
ipv4[CONF_ATTR_IPV4_ADDRESS_DATA] = Variant("aa{sv}", address_data)
if ipv4setting.gateway:
ipv4[CONF_ATTR_IPV4_GATEWAY] = Variant("s", str(ipv4setting.gateway))
else:
raise RuntimeError("Invalid IPv4 InterfaceMethod")
if (
ipv4setting
and ipv4setting.nameservers
and ipv4setting.method
in (
InterfaceMethod.AUTO,
InterfaceMethod.STATIC,
)
):
nameservers = ipv4setting.nameservers if ipv4setting else []
ipv4[CONF_ATTR_IPV4_DNS] = Variant(
"au",
[socket.htonl(int(ip_address)) for ip_address in nameservers],
)
return ipv4
def _get_ipv6_connection_settings(ipv6setting) -> dict:
ipv6 = {}
if not ipv6setting or ipv6setting.method == InterfaceMethod.AUTO:
ipv6[CONF_ATTR_IPV6_METHOD] = Variant("s", "auto")
elif ipv6setting.method == InterfaceMethod.DISABLED:
ipv6[CONF_ATTR_IPV6_METHOD] = Variant("s", "link-local")
elif ipv6setting.method == InterfaceMethod.STATIC:
ipv6[CONF_ATTR_IPV6_METHOD] = Variant("s", "manual")
address_data = []
for address in ipv6setting.address:
address_data.append(
{
"address": Variant("s", str(address.ip)),
"prefix": Variant("u", int(address.with_prefixlen.split("/")[-1])),
}
)
ipv6[CONF_ATTR_IPV6_ADDRESS_DATA] = Variant("aa{sv}", address_data)
if ipv6setting.gateway:
ipv6[CONF_ATTR_IPV6_GATEWAY] = Variant("s", str(ipv6setting.gateway))
else:
raise RuntimeError("Invalid IPv6 InterfaceMethod")
if (
ipv6setting
and ipv6setting.nameservers
and ipv6setting.method
in (
InterfaceMethod.AUTO,
InterfaceMethod.STATIC,
)
):
nameservers = ipv6setting.nameservers if ipv6setting else []
ipv6[CONF_ATTR_IPV6_DNS] = Variant(
"aay",
[ip_address.packed for ip_address in nameservers],
)
return ipv6
def get_connection_from_interface(
interface: Interface,
network_manager: NetworkManager,
@@ -53,77 +160,31 @@ def get_connection_from_interface(
conn: dict[str, dict[str, Variant]] = {
CONF_ATTR_CONNECTION: {
"id": Variant("s", name),
"type": Variant("s", iftype),
"uuid": Variant("s", uuid),
"llmnr": Variant("i", 2),
"mdns": Variant("i", 2),
"autoconnect": Variant("b", True),
CONF_ATTR_CONNECTION_ID: Variant("s", name),
CONF_ATTR_CONNECTION_UUID: Variant("s", uuid),
CONF_ATTR_CONNECTION_TYPE: Variant("s", iftype),
CONF_ATTR_CONNECTION_LLMNR: Variant("i", 2),
CONF_ATTR_CONNECTION_MDNS: Variant("i", 2),
CONF_ATTR_CONNECTION_AUTOCONNECT: Variant("b", True),
},
}
if interface.type != InterfaceType.VLAN:
if interface.path:
conn[CONF_ATTR_MATCH] = {CONF_ATTR_PATH: Variant("as", [interface.path])}
conn[CONF_ATTR_MATCH] = {
CONF_ATTR_MATCH_PATH: Variant("as", [interface.path])
}
else:
conn[CONF_ATTR_CONNECTION]["interface-name"] = Variant("s", interface.name)
ipv4 = {}
if not interface.ipv4 or interface.ipv4.method == InterfaceMethod.AUTO:
ipv4["method"] = Variant("s", "auto")
elif interface.ipv4.method == InterfaceMethod.DISABLED:
ipv4["method"] = Variant("s", "disabled")
else:
ipv4["method"] = Variant("s", "manual")
ipv4["dns"] = Variant(
"au",
[
socket.htonl(int(ip_address))
for ip_address in interface.ipv4.nameservers
],
)
conn[CONF_ATTR_IPV4] = _get_ipv4_connection_settings(interface.ipv4setting)
adressdata = []
for address in interface.ipv4.address:
adressdata.append(
{
"address": Variant("s", str(address.ip)),
"prefix": Variant("u", int(address.with_prefixlen.split("/")[-1])),
}
)
ipv4["address-data"] = Variant("aa{sv}", adressdata)
ipv4["gateway"] = Variant("s", str(interface.ipv4.gateway))
conn[CONF_ATTR_IPV4] = ipv4
ipv6 = {}
if not interface.ipv6 or interface.ipv6.method == InterfaceMethod.AUTO:
ipv6["method"] = Variant("s", "auto")
elif interface.ipv6.method == InterfaceMethod.DISABLED:
ipv6["method"] = Variant("s", "link-local")
else:
ipv6["method"] = Variant("s", "manual")
ipv6["dns"] = Variant(
"aay", [ip_address.packed for ip_address in interface.ipv6.nameservers]
)
adressdata = []
for address in interface.ipv6.address:
adressdata.append(
{
"address": Variant("s", str(address.ip)),
"prefix": Variant("u", int(address.with_prefixlen.split("/")[-1])),
}
)
ipv6["address-data"] = Variant("aa{sv}", adressdata)
ipv6["gateway"] = Variant("s", str(interface.ipv6.gateway))
conn[CONF_ATTR_IPV6] = ipv6
conn[CONF_ATTR_IPV6] = _get_ipv6_connection_settings(interface.ipv6setting)
if interface.type == InterfaceType.ETHERNET:
conn[CONF_ATTR_802_ETHERNET] = {ATTR_ASSIGNED_MAC: Variant("s", "preserve")}
conn[CONF_ATTR_802_ETHERNET] = {
CONF_ATTR_802_ETHERNET_ASSIGNED_MAC: Variant("s", "preserve")
}
elif interface.type == "vlan":
parent = interface.vlan.interface
if parent in network_manager and (
@@ -132,30 +193,44 @@ def get_connection_from_interface(
parent = parent_connection.uuid
conn[CONF_ATTR_VLAN] = {
"id": Variant("u", interface.vlan.id),
"parent": Variant("s", parent),
CONF_ATTR_VLAN_ID: Variant("u", interface.vlan.id),
CONF_ATTR_VLAN_PARENT: Variant("s", parent),
}
elif interface.type == InterfaceType.WIRELESS:
wireless = {
ATTR_ASSIGNED_MAC: Variant("s", "preserve"),
"ssid": Variant("ay", interface.wifi.ssid.encode("UTF-8")),
"mode": Variant("s", "infrastructure"),
"powersave": Variant("i", 1),
CONF_ATTR_802_WIRELESS_ASSIGNED_MAC: Variant("s", "preserve"),
CONF_ATTR_802_WIRELESS_MODE: Variant("s", "infrastructure"),
CONF_ATTR_802_WIRELESS_POWERSAVE: Variant("i", 1),
}
if interface.wifi and interface.wifi.ssid:
wireless[CONF_ATTR_802_WIRELESS_SSID] = Variant(
"ay", interface.wifi.ssid.encode("UTF-8")
)
conn[CONF_ATTR_802_WIRELESS] = wireless
if interface.wifi.auth != "open":
if interface.wifi and interface.wifi.auth != "open":
wireless["security"] = Variant("s", CONF_ATTR_802_WIRELESS_SECURITY)
wireless_security = {}
if interface.wifi.auth == "wep":
wireless_security["auth-alg"] = Variant("s", "open")
wireless_security["key-mgmt"] = Variant("s", "none")
wireless_security[CONF_ATTR_802_WIRELESS_SECURITY_AUTH_ALG] = Variant(
"s", "open"
)
wireless_security[CONF_ATTR_802_WIRELESS_SECURITY_KEY_MGMT] = Variant(
"s", "none"
)
elif interface.wifi.auth == "wpa-psk":
wireless_security["auth-alg"] = Variant("s", "open")
wireless_security["key-mgmt"] = Variant("s", "wpa-psk")
wireless_security[CONF_ATTR_802_WIRELESS_SECURITY_AUTH_ALG] = Variant(
"s", "open"
)
wireless_security[CONF_ATTR_802_WIRELESS_SECURITY_KEY_MGMT] = Variant(
"s", "wpa-psk"
)
if interface.wifi.psk:
wireless_security["psk"] = Variant("s", interface.wifi.psk)
wireless_security[CONF_ATTR_802_WIRELESS_SECURITY_PSK] = Variant(
"s", interface.wifi.psk
)
conn[CONF_ATTR_802_WIRELESS_SECURITY] = wireless_security
return conn

View File

@@ -1,4 +1,5 @@
"""Network Manager implementation for DBUS."""
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Wireless object for Network Manager."""
import asyncio
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""D-Bus interface for systemd-resolved."""
from __future__ import annotations
import logging

View File

@@ -1,4 +1,5 @@
"""Interface to systemd-timedate over D-Bus."""
from datetime import datetime
import logging

View File

@@ -1,4 +1,5 @@
"""Interface to UDisks2 over D-Bus."""
import asyncio
import logging
from typing import Any

View File

@@ -1,4 +1,5 @@
"""Interface to UDisks2 Block Device over D-Bus."""
import asyncio
from collections.abc import Callable
from pathlib import Path

View File

@@ -1,4 +1,5 @@
"""Handle discover message for Home Assistant."""
from __future__ import annotations
from contextlib import suppress

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor add-on Docker object."""
from __future__ import annotations
from collections.abc import Awaitable
@@ -708,6 +709,28 @@ class DockerAddon(DockerInterface):
with suppress(DockerError):
await self.cleanup()
@Job(name="docker_addon_cleanup", limit=JobExecutionLimit.GROUP_WAIT)
async def cleanup(
self,
old_image: str | None = None,
image: str | None = None,
version: AwesomeVersion | None = None,
) -> None:
"""Check if old version exists and cleanup other versions of image not in use."""
await self.sys_run_in_executor(
self.sys_docker.cleanup_old_images,
(image := image or self.image),
version or self.version,
{old_image} if old_image else None,
keep_images={
f"{addon.image}:{addon.version}"
for addon in self.sys_addons.installed
if addon.slug != self.addon.slug
and addon.image
and addon.image in {old_image, image}
},
)
@Job(
name="docker_addon_write_stdin",
limit=JobExecutionLimit.GROUP_ONCE,

View File

@@ -1,4 +1,5 @@
"""Audio docker object."""
import logging
import docker

View File

@@ -1,4 +1,5 @@
"""HA Cli docker object."""
import logging
from ..coresys import CoreSysAttributes

View File

@@ -1,4 +1,5 @@
"""Docker constants."""
from enum import StrEnum
from docker.types import Mount

View File

@@ -1,4 +1,5 @@
"""DNS docker object."""
import logging
from docker.types import Mount

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Docker object."""
from collections.abc import Awaitable
from ipaddress import IPv4Address
import logging

View File

@@ -1,4 +1,5 @@
"""Interface class for Supervisor Docker object."""
from __future__ import annotations
from collections import defaultdict
@@ -428,15 +429,17 @@ class DockerInterface(JobGroup):
limit=JobExecutionLimit.GROUP_ONCE,
on_condition=DockerJobError,
)
async def remove(self) -> None:
async def remove(self, *, remove_image: bool = True) -> None:
"""Remove Docker images."""
# Cleanup container
with suppress(DockerError):
await self.stop()
if remove_image:
await self.sys_run_in_executor(
self.sys_docker.remove_image, self.image, self.version
)
self._meta = None
@Job(
@@ -509,14 +512,14 @@ class DockerInterface(JobGroup):
return b""
@Job(name="docker_interface_cleanup", limit=JobExecutionLimit.GROUP_WAIT)
def cleanup(
async def cleanup(
self,
old_image: str | None = None,
image: str | None = None,
version: AwesomeVersion | None = None,
) -> Awaitable[None]:
) -> None:
"""Check if old version exists and cleanup."""
return self.sys_run_in_executor(
await self.sys_run_in_executor(
self.sys_docker.cleanup_old_images,
image or self.image,
version or self.version,

View File

@@ -1,4 +1,5 @@
"""Manager for Supervisor Docker."""
from contextlib import suppress
from ipaddress import IPv4Address
import logging
@@ -547,10 +548,13 @@ class DockerAPI:
current_image: str,
current_version: AwesomeVersion,
old_images: set[str] | None = None,
*,
keep_images: set[str] | None = None,
) -> None:
"""Clean up old versions of an image."""
image = f"{current_image}:{current_version!s}"
try:
current: Image = self.images.get(f"{current_image}:{current_version!s}")
keep: set[str] = {self.images.get(image).id}
except ImageNotFound:
raise DockerNotFound(
f"{current_image} not found for cleanup", _LOGGER.warning
@@ -560,6 +564,19 @@ class DockerAPI:
f"Can't get {current_image} for cleanup", _LOGGER.warning
) from err
if keep_images:
keep_images -= {image}
try:
for image in keep_images:
# If its not found, no need to preserve it from getting removed
with suppress(ImageNotFound):
keep.add(self.images.get(image).id)
except (DockerException, requests.RequestException) as err:
raise DockerError(
f"Failed to get one or more images from {keep} during cleanup",
_LOGGER.warning,
) from err
# Cleanup old and current
image_names = list(
old_images | {current_image} if old_images else {current_image}
@@ -572,7 +589,7 @@ class DockerAPI:
) from err
for image in images_list:
if current.id == image.id:
if image.id in keep:
continue
with suppress(DockerException, requests.RequestException):

View File

@@ -1,4 +1,5 @@
"""HA Cli docker object."""
import logging
from ..coresys import CoreSysAttributes

View File

@@ -1,4 +1,5 @@
"""Internal network manager for Supervisor."""
from contextlib import suppress
from ipaddress import IPv4Address
import logging

View File

@@ -1,4 +1,5 @@
"""Observer docker object."""
import logging
from ..const import DOCKER_NETWORK_MASK

View File

@@ -1,4 +1,5 @@
"""Calc and represent docker stats data."""
from contextlib import suppress

View File

@@ -1,4 +1,5 @@
"""Init file for Supervisor Docker object."""
from collections.abc import Awaitable
from ipaddress import IPv4Address
import logging

View File

@@ -1,4 +1,5 @@
"""Core Exceptions."""
from collections.abc import Callable
@@ -339,6 +340,12 @@ class APIAddonNotInstalled(APIError):
"""Not installed addon requested at addons API."""
class APIDBMigrationInProgress(APIError):
"""Service is unavailable due to an offline DB migration is in progress."""
status = 503
# Service / Discovery

Some files were not shown because too many files have changed in this diff Show More