Compare commits

...

213 Commits

Author SHA1 Message Date
Pascal Vizeli
49ca923e51 Apply old udev handling like core container (#2511) 2021-02-03 12:56:25 +01:00
Pascal Vizeli
7ad22e0399 Make add-on file schema more future approved (#2510) 2021-02-03 12:06:22 +01:00
Pascal Vizeli
bb8acc6065 Fix add-on state was not fast reflected (#2509) 2021-02-03 12:02:09 +01:00
Joakim Sørensen
c0fa4a19e9 Change verbosity for hardware.trigger API (#2508) 2021-02-02 20:56:37 +01:00
Franck Nijhof
3f1741dd18 Typo: depircated -> deprecated (#2507) 2021-02-02 20:41:56 +01:00
Stefan Agner
9ef02e4110 Add eMMC life-time estimate support (#2413)
* Add eMMC life-time estimate support

Expose life time estimate as Host Info property "ssd_life_time"

* Fix pytest

* Fix path to helper

* Allow protected access in tests

* Apply suggestions from code review

Rename SSD to disk.

Co-authored-by: Pascal Vizeli <pascal.vizeli@syshack.ch>

* Rename functions as well

* Update host.py

Co-authored-by: Pascal Vizeli <pascal.vizeli@syshack.ch>
2021-02-02 10:31:02 +01:00
Pascal Vizeli
15a6f38ebb Make sure device is ready initialize on udev (#2504)
* Make sure device is ready initialize on udev

* fix style

* let's start with 2sec

* better logic

* style

* add change events back
2021-02-02 09:53:09 +01:00
dependabot[bot]
227f2e5a21 Bump pyupgrade from 2.8.0 to 2.9.0 (#2505)
Bumps [pyupgrade](https://github.com/asottile/pyupgrade) from 2.8.0 to 2.9.0.
- [Release notes](https://github.com/asottile/pyupgrade/releases)
- [Commits](https://github.com/asottile/pyupgrade/compare/v2.8.0...v2.9.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-02 09:52:51 +01:00
Pascal Vizeli
517d6ee981 Lookup udev device in monitor thread (#2503) 2021-02-01 18:29:05 +01:00
Pascal Vizeli
184eeb7f49 Udev - move away form depricated callback / increase buffer (#2502)
* Use new callback from udev / only forward

* minimize loop

* Udev - move away form depricated callback / increase buffer

* code cleanup
2021-02-01 17:33:53 +01:00
Joakim Sørensen
a3555c74e8 Bump awesomeversion from 21.1.8 to 21.2.0 (#2501) 2021-02-01 15:45:35 +01:00
Pascal Vizeli
657bafd458 Fix handling with shm and shared /dev (#2499)
* Fix handling with shm and shared /dev

* address commends

* let's share shm
2021-02-01 14:44:02 +01:00
Joakim Sørensen
2ad5df420c Rerun label check on synchronize (#2500) 2021-02-01 14:37:56 +01:00
Joakim Sørensen
b24d489ec5 Update frontend to a9192ae2 (#2498) 2021-02-01 13:26:54 +01:00
Franck Nijhof
6bb0210f1f Fix add-on is_valid check (#2497) 2021-02-01 11:27:34 +01:00
dependabot[bot]
c1de50266a Bump pytz from 2020.5 to 2021.1 (#2496)
Bumps [pytz](https://github.com/stub42/pytz) from 2020.5 to 2021.1.
- [Release notes](https://github.com/stub42/pytz/releases)
- [Commits](https://github.com/stub42/pytz/compare/release_2020.5...release_2021.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-01 11:27:17 +01:00
dependabot[bot]
562e02bc64 Bump pyupgrade from 2.7.4 to 2.8.0 (#2494)
Bumps [pyupgrade](https://github.com/asottile/pyupgrade) from 2.7.4 to 2.8.0.
- [Release notes](https://github.com/asottile/pyupgrade/releases)
- [Commits](https://github.com/asottile/pyupgrade/compare/v2.7.4...v2.8.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-01 11:27:04 +01:00
dependabot[bot]
f71ec7913a Bump awesomeversion from 21.1.5 to 21.1.8 (#2493)
Bumps [awesomeversion](https://github.com/ludeeus/awesomeversion) from 21.1.5 to 21.1.8.
- [Release notes](https://github.com/ludeeus/awesomeversion/releases)
- [Commits](https://github.com/ludeeus/awesomeversion/compare/21.1.5...21.1.8)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-01 11:26:51 +01:00
dependabot[bot]
d98baaf660 Bump jinja2 from 2.11.2 to 2.11.3 (#2495)
Bumps [jinja2](https://github.com/pallets/jinja) from 2.11.2 to 2.11.3.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/master/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/2.11.2...2.11.3)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-02-01 11:26:30 +01:00
Pascal Vizeli
72db591576 Validate build env before using it (#2492) 2021-02-01 09:46:48 +01:00
Wouter Schoot
509a37fc04 Typofix exsist -> exist (#2491)
* Typofix exsist -> exist

* Typofix exist -> exists
2021-02-01 09:34:17 +01:00
Pascal Vizeli
17f62b6e86 Handle corrupt store branch / ignore local reset on corruption (#2490)
* Handle corrupt store branch / ignore local reset on corruption

* Update data.py

* Update data.py
2021-01-31 22:55:43 +01:00
Pascal Vizeli
b09aee7644 Filter out virtual vcs devices (#2489)
* Filter out virtual vcs devices

* fix test
2021-01-31 14:40:14 +01:00
Pascal Vizeli
babcc0de0c Cleanup supervisor/udev device action / add GPIO (#2488)
* Cleanup supervisor/udev device action / add GPIO

* Apply francks comment
2021-01-31 14:24:22 +01:00
Franck Nijhof
5cc47c9222 Re-enable old template until form is resolved (#2486) 2021-01-30 19:47:45 +01:00
Franck Nijhof
833559a3b3 Add initial GitHub Issue Form (#2485)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2021-01-30 19:35:15 +01:00
Pascal Vizeli
b8a976b344 Change handling kernel udev events (#2484)
* Change handling kernel udev events / add USB events

* finish USB

* map dev ro

* fix bind
2021-01-30 14:19:53 +01:00
Joakim Sørensen
10b14132b9 Update frontend to 86847263 (#2483) 2021-01-29 18:23:58 +01:00
Pascal Vizeli
18953f0b7c plug & play devices (#2482)
* Add support for plug&play container & full udev passtrhough

* plug & play devices

* this hack is not needed anymore

* Fix GPIO issue

* Apply suggestions from code review

Co-authored-by: Franck Nijhof <git@frenck.dev>

Co-authored-by: Franck Nijhof <git@frenck.dev>
2021-01-29 17:17:41 +01:00
Joakim Sørensen
19f5fba3aa Bump awesomeversion from 21.1.4 to 21.1.5 (#2481) 2021-01-29 14:10:06 +01:00
Pascal Vizeli
636bc3e61a Handle GPIO / VIDEO map with subystem (#2478)
* Handle GPIO / VIDEO mapping with subystem

* fix tests

* add udev support

* init udev data

* fix
2021-01-29 11:28:16 +01:00
Pascal Vizeli
521037e1a6 Fix mknod creating of the device on runtime time (#2477) 2021-01-28 17:07:33 +01:00
Pascal Vizeli
e024c3e38d Improve device selection and show device by id if available (#2476) 2021-01-28 15:43:06 +01:00
Pascal Vizeli
6a0206c1e7 Next generation hardware handling (#2429)
* Next generation hardware handling

* need daemon for some details

* fix tests

* fix wrong coresys lookup

* test initial import

* test device lookup

* validate if device exists

* Add cgroups rules manager

* mapping udev from host

* Modify validation/options handling

* lookup devices

* add support for host udev mapping

* next

* Add policy support to add-ons

* Depricate hardware trigger call

* next cleanup round

* detect USB linking

* optimize

* readd udev utils for backwards compatibility

* fix tests

* Add more tests

* fix tests

* Make device explicit

* Add filter

* work on tests

* Add migration step

* clean out auto_uart

* Fix all tests

* Expose all device information

* small  improvment

* Fix loop over right devices

* Use migration for new device format

* Update rootfs/etc/cont-init.d/udev.sh

Co-authored-by: Franck Nijhof <git@frenck.dev>

* Fix old helper

* Fix API

* add helper for by-id

* fix tests

* Fix serial helper

* Fix hardware API schema

* Hide some virtual devices from tracking

* Apply suggestions from code review

Co-authored-by: Stefan Agner <stefan@agner.ch>

* Update supervisor/addons/validate.py

Co-authored-by: Stefan Agner <stefan@agner.ch>

* Update supervisor/addons/validate.py

Co-authored-by: Stefan Agner <stefan@agner.ch>

* fix lint

* Apply suggestions from code review

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

* Apply suggestions from code review

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

* fix black

* fix lint

Co-authored-by: Franck Nijhof <git@frenck.dev>
Co-authored-by: Stefan Agner <stefan@agner.ch>
Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2021-01-28 15:26:56 +01:00
Joakim Sørensen
69a8a83528 Limit label check (#2475) 2021-01-28 12:07:42 +01:00
Joakim Sørensen
0307d700fa Add TypeError guard for docker stats (#2474) 2021-01-28 11:58:04 +01:00
Joakim Sørensen
919c383b41 Bump awesomeversion from 21.1.3 to 21.1.4 (#2473) 2021-01-28 11:41:11 +01:00
dependabot[bot]
d331af4d5a Bump pre-commit from 2.9.3 to 2.10.0 (#2472)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.9.3 to 2.10.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.9.3...v2.10.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-28 08:46:29 +01:00
Joakim Sørensen
b5467d3c23 Update frontend to 5ee0250b (#2471) 2021-01-28 08:45:33 +01:00
dependabot[bot]
3ef0040d66 Bump coverage from 5.3.1 to 5.4 (#2470)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.3.1 to 5.4.
- [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/coverage-5.3.1...coverage-5.4)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-27 08:41:22 +01:00
Joakim Sørensen
ec4dfd2172 Add action to check PR labels (#2469)
* Check PR labels

* update

* update

* update

* only use lable events

* remove env stuff

* add back types
2021-01-26 14:21:05 +01:00
Pascal Vizeli
8f54d7c8e9 New version logic NM (#2466) 2021-01-26 10:33:35 +01:00
dependabot[bot]
b59e709dc0 Bump home-assistant/builder from 2020.11.0 to 2021.01.1 (#2468)
Bumps [home-assistant/builder](https://github.com/home-assistant/builder) from 2020.11.0 to 2021.01.1.
- [Release notes](https://github.com/home-assistant/builder/releases)
- [Commits](https://github.com/home-assistant/builder/compare/2020.11.0...e33ea8af3ad98e9ed7513cad92cc88fb303b42ff)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-26 10:17:50 +01:00
dependabot[bot]
b236e6c886 Bump pytest from 6.2.1 to 6.2.2 (#2467)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.1 to 6.2.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.2.1...6.2.2)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-26 09:47:45 +01:00
Pascal Vizeli
8acbb7d6f0 Fix API info calls access (#2464) 2021-01-25 10:45:08 +01:00
dependabot[bot]
49e4bc9381 Bump actions/stale from v3.0.14 to v3.0.15 (#2463)
Bumps [actions/stale](https://github.com/actions/stale) from v3.0.14 to v3.0.15.
- [Release notes](https://github.com/actions/stale/releases)
- [Commits](https://github.com/actions/stale/compare/v3.0.14...86561461b92875de77a8b2d2e75f004c826e8f45)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-25 09:59:20 +01:00
Philip Allgaier
36106cc08d Small README tweaks (#2460) 2021-01-24 21:18:06 +01:00
Pascal Vizeli
8f1763abe2 Fix OSError with custom component check (#2458) 2021-01-24 16:46:49 +01:00
Joakim Sørensen
480eebc6cb Update alert notification (#2457) 2021-01-23 21:06:55 +01:00
Pascal Vizeli
dccfffd979 Improve fixups with Job condition checks (#2451) 2021-01-21 16:48:25 +01:00
dependabot[bot]
1a978f4762 Bump pytest-cov from 2.11.0 to 2.11.1 (#2455)
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.11.0 to 2.11.1.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.11.0...v2.11.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-21 09:29:47 +01:00
Pascal Vizeli
1fbc8f4060 Add discovery support for zwave_js (#2454)
* Add discovery support for zwave_js

* New schema

* hmm

* address comments
2021-01-20 16:51:51 +01:00
Pascal Vizeli
db3fc1421c Fix: stable issue with corrupt git repository / submodule (#2452) 2021-01-19 14:21:27 +01:00
dependabot[bot]
9ecd03db0e Bump pytest-cov from 2.10.1 to 2.11.0 (#2446)
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.10.1 to 2.11.0.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.10.1...v2.11.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-18 13:54:22 +01:00
dependabot[bot]
f111ccb1b6 Bump awesomeversion from 21.1.2 to 21.1.3 (#2445)
Bumps [awesomeversion](https://github.com/ludeeus/awesomeversion) from 21.1.2 to 21.1.3.
- [Release notes](https://github.com/ludeeus/awesomeversion/releases)
- [Commits](https://github.com/ludeeus/awesomeversion/compare/21.1.2...21.1.3)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-18 13:54:07 +01:00
Joakim Sørensen
a32341cc5d Update frontend to 08c1b864 (#2444) 2021-01-17 17:54:42 +01:00
Pascal Vizeli
f73e277230 Fix issues with awesomeversion and representation (#2443) 2021-01-17 16:39:34 +01:00
Joakim Sørensen
8d8587ca29 Update wording in notification (#2438)
* Update wording in notification

* Update notify.py
2021-01-15 21:49:52 +01:00
Joakim Sørensen
88eb9511bf Add core version check (#2436)
* Add core version check

* Fix version handling, rename and use correct paths

* simplify check

* wrap approve check
2021-01-15 21:13:42 +01:00
Pascal Vizeli
e1068997ea Fix submodule update (#2434) 2021-01-15 14:28:31 +01:00
dependabot[bot]
560e04c64a Bump colorlog from 4.6.2 to 4.7.2 (#2432)
Bumps [colorlog](https://github.com/borntyping/python-colorlog) from 4.6.2 to 4.7.2.
- [Release notes](https://github.com/borntyping/python-colorlog/releases)
- [Commits](https://github.com/borntyping/python-colorlog/compare/v4.6.2...v4.7.2)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-15 14:24:40 +01:00
Joakim Sørensen
621ec03971 Ignore wheels on release (#2428)
* Fix wheels on publish

* ignore wheels for publish

* test

* revert test
2021-01-12 15:45:35 +01:00
Pascal Vizeli
d14a47d3f7 Auth: Improve authorisation (#2427) 2021-01-12 14:49:53 +01:00
Pascal Vizeli
3e9de0c210 Fix submodules - check if it is needed or not (#2426) 2021-01-12 13:53:04 +01:00
Joakim Sørensen
01a6e074a5 Adjust development tasks (#2425)
* Adjust development tasks

* add development
2021-01-12 13:50:11 +01:00
Joakim Sørensen
1434077f4e Update frontend panel to edcb7e87 (#2422) 2021-01-11 15:22:10 +01:00
Fredrik Erlandsson
3922175af1 Update git to support updates of submodules (#2378)
* Update git to support updates of submodules

* Remove unnecessary-comprehension

* prefix with **
2021-01-11 15:21:09 +01:00
Franck Nijhof
ec6852a8d7 Set a default for add-on options and schema config (#2421) 2021-01-11 12:36:19 +01:00
Pascal Vizeli
b0b908b4ae Fix missing repository (#2420) 2021-01-11 12:17:53 +01:00
Franck Nijhof
5a00336ef1 Set a default for add-on startup config (#2419) 2021-01-11 12:10:23 +01:00
Stefan Agner
d53f5e21f4 Increases core container timeout to match core shutdown time (#2417)
Align the core container timeout with what the core container
uses as grace period.
2021-01-11 11:24:54 +01:00
Stefan Agner
bd173fa333 Shutdown using systemd-logind if available (#2416)
The Reboot() and PowerOff() methods of the systemd D-Bus API are not
meant to be called directly when logind is in use. Make sure to use the
logind APIs if available.

Since OS release 5.1 systemd-logind is enabled.
2021-01-11 11:21:45 +01:00
Franck Nijhof
6b32fa31b6 Set a default for add-on boot config (#2418) 2021-01-11 11:17:23 +01:00
Joakim Sørensen
d1dba89e39 Add GitHub Action to build wheels (#2186)
* Make GitHub Action to build wheels

* try new

* fix branch

* fix typo

* test arch

* waitfor

* add ref

* fix wait

* fix name

* quote

* add complete step

* Update .github/workflows/wheels.yml

Co-authored-by: Franck Nijhof <git@frenck.dev>

* fix typo

* use name

* test

* merge them

* move

* test with requirement change

* add wheels-user

* revert version change

* use master

* bump awesomeversion

* set user

Co-authored-by: Franck Nijhof <git@frenck.dev>
2021-01-08 18:57:35 +01:00
dependabot[bot]
b2f2806465 Bump gitpython from 3.1.11 to 3.1.12 (#2404)
Bumps [gitpython](https://github.com/gitpython-developers/GitPython) from 3.1.11 to 3.1.12.
- [Release notes](https://github.com/gitpython-developers/GitPython/releases)
- [Changelog](https://github.com/gitpython-developers/GitPython/blob/master/CHANGES)
- [Commits](https://github.com/gitpython-developers/GitPython/compare/3.1.11...3.1.12)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-07 21:03:01 +01:00
Sergio Oller
3b70cd58a3 Allow GET method on /auth with BasicAuth (#2407)
* Allow GET on /auth with BasicAuth

* Accept GET without further validation

As suggested on https://github.com/home-assistant/supervisor/pull/2407#pullrequestreview-563712080
2021-01-07 21:02:36 +01:00
Joakim Sørensen
6769bfd824 Fix typo in reference (#2409) 2021-01-07 19:05:31 +01:00
dependabot[bot]
bff4af2534 Bump codecov/codecov-action from v1.2.0 to v1.2.1 (#2405)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from v1.2.0 to v1.2.1.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1.2.0...e156083f13aff6830c92fc5faa23505779fbf649)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-06 14:04:37 +01:00
dependabot[bot]
aabf575ac5 Bump actions/upload-artifact from v2.2.1 to v2.2.2 (#2400)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from v2.2.1 to v2.2.2.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2.2.1...e448a9b857ee2131e752b06002bf0e093c65e571)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-05 09:50:24 +01:00
dependabot[bot]
4aacaf6bd6 Bump codecov/codecov-action from v1.1.1 to v1.2.0 (#2401)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from v1.1.1 to v1.2.0.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1.1.1...a92c414703a4bba586f6df7fcc885c9d0bdff772)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-05 09:49:32 +01:00
dependabot[bot]
268070e89c Bump dessant/lock-threads from v2.0.1 to v2.0.3 (#2398)
Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from v2.0.1 to v2.0.3.
- [Release notes](https://github.com/dessant/lock-threads/releases)
- [Changelog](https://github.com/dessant/lock-threads/blob/master/CHANGELOG.md)
- [Commits](https://github.com/dessant/lock-threads/compare/v2.0.1...486f7380c15596f92b724e4260e4981c68d6bde6)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-04 09:37:26 +01:00
Joakim Sørensen
4fa2134cc6 Bump awesomeversion from 20.12.4 to 20.12.5 (#2394) 2021-01-02 22:13:35 +01:00
Pascal Vizeli
97c35de49a Refacture version handling with AwesomeVersion (#2392)
* Refacture version handling with AwesomeVersion

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* next

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* next

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* next

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* v20.12.3

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* next

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* next

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* fix exception

* fix schema

* cleanup plugins

* fix tests

* fix attach

* fix TypeError

* fix issue with compairing

* make lint happy

* Update supervisor/homeassistant/__init__.py

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

* Update tests/test_validate.py

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

* Update supervisor/docker/__init__.py

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

* Update supervisor/supervisor.py

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2020-12-31 17:09:33 +01:00
Joakim Sørensen
32fb550969 Bump docker to 4.4.1 (#2390) 2020-12-29 16:38:20 +01:00
dependabot[bot]
3457441929 Bump pytz from 2020.4 to 2020.5 (#2386)
Bumps [pytz](https://github.com/stub42/pytz) from 2020.4 to 2020.5.
- [Release notes](https://github.com/stub42/pytz/releases)
- [Commits](https://github.com/stub42/pytz/compare/release_2020.4...release_2020.5)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-28 16:26:50 +01:00
dependabot[bot]
32f0fc7a46 Bump codecov/codecov-action from v1.1.0 to v1.1.1 (#2381)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from v1.1.0 to v1.1.1.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1.1.0...1fc7722ded4708880a5aea49f2bfafb9336f0c8d)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-22 13:27:04 +01:00
dependabot[bot]
c891a8f164 Bump coverage from 5.3 to 5.3.1 (#2379)
Bumps [coverage](https://github.com/nedbat/coveragepy) from 5.3 to 5.3.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/coverage-5.3...coverage-5.3.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-21 15:18:02 +01:00
dependabot[bot]
991764af94 Bump actions/setup-python from v2.2.0 to v2.2.1 (#2380)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from v2.2.0 to v2.2.1.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v2.2.0...3105fb18c05ddd93efea5f9e0bef7a03a6e9e7df)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-21 15:17:25 +01:00
dependabot[bot]
1df447272e Bump codecov/codecov-action from v1.0.15 to v1.1.0 (#2375)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from v1.0.15 to v1.1.0.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Changelog](https://github.com/codecov/codecov-action/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-action/compare/v1.0.15...7de43a7373de21874ae196a78f8eb633fcf7f0c4)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-18 21:42:42 +01:00
dependabot[bot]
f032ae757b Bump actions/setup-python from v2.1.4 to v2.2.0 (#2376)
Bumps [actions/setup-python](https://github.com/actions/setup-python) from v2.1.4 to v2.2.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](https://github.com/actions/setup-python/compare/v2.1.4...8c5ea631b2b2d5d8840cf4a2b183a8a0edc1e40d)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-18 21:42:10 +01:00
dependabot[bot]
e529b2859e Bump codecov from 2.1.10 to 2.1.11 (#2377)
Bumps [codecov](https://github.com/codecov/codecov-python) from 2.1.10 to 2.1.11.
- [Release notes](https://github.com/codecov/codecov-python/releases)
- [Changelog](https://github.com/codecov/codecov-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/codecov/codecov-python/compare/v2.1.10...v2.1.11)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-18 21:40:42 +01:00
Casper
d1cb2368fa fix typo (#2372) 2020-12-16 10:13:20 +01:00
dependabot[bot]
7b812184d1 Bump pytest from 6.2.0 to 6.2.1 (#2373)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.0 to 6.2.1.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.2.0...6.2.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-16 10:12:57 +01:00
dependabot[bot]
4f7ce1c6ee Bump cryptography from 3.2.1 to 3.3.1 (#2360)
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.2.1 to 3.3.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/3.2.1...3.3.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 12:52:47 +01:00
dependabot[bot]
44a5ac63db Bump pytest from 6.1.2 to 6.2.0 (#2365)
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.1.2 to 6.2.0.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/6.1.2...6.2.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 12:52:22 +01:00
Joakim Sørensen
0989ee88cc Pin docker-py to commit (#2371)
Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
2020-12-15 12:48:50 +01:00
dependabot[bot]
ba8b72c2c8 Bump sentry-sdk from 0.19.4 to 0.19.5 (#2362)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.19.4 to 0.19.5.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.19.4...0.19.5)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 12:28:11 +01:00
dependabot[bot]
2dbb4583f4 Bump debugpy from 1.2.0 to 1.2.1 (#2370)
Bumps [debugpy](https://github.com/microsoft/debugpy) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/microsoft/debugpy/releases)
- [Commits](https://github.com/microsoft/debugpy/compare/v1.2.0...v1.2.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 12:26:45 +01:00
Robin
81ad42e029 Fix typo in log message when completing snapshot (#2367) 2020-12-15 10:49:40 +01:00
dependabot[bot]
5d3695f8ba Bump pre-commit from 2.9.2 to 2.9.3 (#2356)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.9.2 to 2.9.3.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.9.2...v2.9.3)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-08 08:35:18 +01:00
Pascal Vizeli
c771694aa0 Show link for help user with unsupported systems (#2354)
* Show link for help user with unsupported systems

* Update .github/ISSUE_TEMPLATE/config.yml

Co-authored-by: Franck Nijhof <git@frenck.dev>

Co-authored-by: Franck Nijhof <git@frenck.dev>
2020-12-07 11:45:46 +01:00
Pascal Vizeli
1ac0fd4c10 Add note for unsupported system (#2353) 2020-12-07 11:00:27 +01:00
dependabot[bot]
631ff8caef Bump voluptuous from 0.12.0 to 0.12.1 (#2352)
Bumps [voluptuous](https://github.com/alecthomas/voluptuous) from 0.12.0 to 0.12.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.12.0...0.12.1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-07 10:39:49 +01:00
Joakim Sørensen
7382182132 Add changes to release drafter (#2349)
* Add changes to release drafter

* remove duplicate

* Add more labels

* add CI

* remove enhacement
2020-12-06 13:24:09 +01:00
Joakim Sørensen
4ff9da68ef Actually use the vlan_struct (#2347) 2020-12-05 13:04:37 +01:00
Pascal Vizeli
dee2998ee3 Fix issue with mark system wrong as rollback (#2345) 2020-12-05 11:19:27 +01:00
Pascal Vizeli
1d43236211 Upgrade json config handler logging to critical (#2344) 2020-12-05 10:57:20 +01:00
Pascal Vizeli
792bc610a3 Fix NM byte switch for ipv6 nameserver (#2342)
* Fix NM byte switch for ipv6 nameserver

* remove not needed code
2020-12-04 17:55:26 +01:00
Pascal Vizeli
7a51c828c2 Fix wrong exception handler 2020-12-04 15:26:13 +00:00
Pascal Vizeli
fab6fcd5ac Check NetworkManager Version if it is supported (#2340)
Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2020-12-04 12:38:12 +01:00
Joakim Sørensen
c8e00ba160 Adds vlan_struct (#2337)
* Return VLAN ID instead of wifistruct for VLAN

* Use vlan_struct

* fix typing

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
2020-12-04 11:37:55 +01:00
Joakim Sørensen
6245b6d823 Fix KeyError in connectivity_enabled (#2336) 2020-12-03 21:40:34 +01:00
Pascal Vizeli
0c55bf20fc Fix issue on store git clone (#2331) 2020-12-03 21:06:48 +01:00
Pascal Vizeli
f8fd7b5933 Improve error handling with job condition (#2322)
* Improve error handling with job condition

* fix

* first patch

* last patch

* Address comments

* Revert strange replace
2020-12-03 12:24:32 +01:00
Pascal Vizeli
6462eea2ef Fix sentry stdlib spam (#2326) 2020-12-02 17:24:40 +01:00
Pascal Vizeli
3d79891249 Make dbus connection more robust (#2325)
* Make dbus connection more robust

* move rauc down
2020-12-02 17:22:28 +01:00
Pascal Vizeli
80763c4bbf Support OTA url over version files (#2324)
* Support OTA url over version files

* Fix new schema
2020-12-02 14:59:42 +01:00
Pascal Vizeli
59102afd45 Fix sentry with sets (#2323) 2020-12-02 12:43:38 +01:00
Pascal Vizeli
0b085354db Send list of images to sentry (#2321) 2020-12-01 14:29:37 +01:00
Pascal Vizeli
e2a473baa3 Add network reload to api (#2319) 2020-12-01 14:03:59 +01:00
Pascal Vizeli
06e10fdd3c Fix NM naming schema (#2318)
* Fix NM naming schema

* Address comments

* Add test
2020-12-01 12:11:20 +01:00
Pascal Vizeli
fb4386a7ad Use persistent MAC address instead clone / don't touch default (#2317) 2020-12-01 09:27:49 +01:00
Pascal Vizeli
2d294f6841 Make evaluation of container better (#2316) 2020-11-30 18:00:12 +01:00
Pascal Vizeli
e09a839148 Fix byte order for network DNS settings (#2315) 2020-11-30 15:22:02 +01:00
Pascal Vizeli
d9c4dae739 Send error to sentry from update 2020-11-30 10:28:05 +00:00
Pascal Vizeli
49853e92a4 Fix sentry spam (#2313) 2020-11-30 11:01:10 +01:00
Pascal Vizeli
19620d6808 Fix: cleanup repository from list (#2310)
* Fix: cleanup repository from list

* Add repr

* Avoid not exists error message
2020-11-29 14:00:29 +01:00
Pascal Vizeli
f6bf44de1c Add tests for remove function (#2309) 2020-11-29 12:34:33 +01:00
Pascal Vizeli
06fae59fc8 Remove corrupt FS on store sentry report (#2308) 2020-11-28 18:11:56 +01:00
Pascal Vizeli
5c25fcd84c Reset on invalid filesystem (#2307) 2020-11-28 15:57:00 +01:00
Pascal Vizeli
aa5297026f Handle Store suggestion (#2306)
* Handle Store suggestion

* Add fixup

* Add more fixup & list

* Enable fixups

* Add tests

* fix index

* fix break

* fix import

* Load it anyway

* Run suFix ccestion on load too

* fix error message

* fix error message

* Fix remove

* Finishing

* Add tests

* Fix error

* fix cleanup stale stuff

* Fix source

* use source as url

* add test for url

* Apply suggestions from code review

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2020-11-28 15:03:44 +01:00
Joakim Sørensen
841520b75e Strip device names (#2303) 2020-11-26 22:40:54 +01:00
Pascal Vizeli
d9e20307de Allow check to cleanup issues (#2302) 2020-11-26 22:38:33 +01:00
Pascal Vizeli
fda1b523ba Extend resolution center (#2297)
* Extend resolution center

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* move forward

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* Rename it to fixups

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* Finish p1

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* Finish p1 - add files

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* Finishup

* Add more tests

* Add test for suggestion

* Add more tests

* fix tests & isort

* address comments

* address comments v2

* fix isort

* Change reference handling
2020-11-26 17:16:36 +01:00
dependabot[bot]
7cccbc682c Bump pre-commit from 2.9.0 to 2.9.2 (#2300)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.9.0 to 2.9.2.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.9.0...v2.9.2)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-26 08:30:35 +01:00
Pascal Vizeli
621eb4c4c0 Don't send DBusProgramError to sentry (#2294)
* Don't send DBusProgramError to sentry

* Add message
2020-11-24 14:18:00 +01:00
Pascal Vizeli
056926242f Fix sentry resoluton messages (#2295) 2020-11-24 14:17:47 +01:00
Pascal Vizeli
84294f286f Add unhealthy if update fails on startup 2020-11-24 12:51:16 +00:00
Joakim Sørensen
b6bc6b8498 Update frontend panel to 1d367eca (#2293) 2020-11-24 11:56:35 +01:00
Pascal Vizeli
845c935b39 Add JobManager API ignore (#2290)
* Disable job condition for unhealth & unsupported systems

* Add JobManager API ignore

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* Update tests/resolution/evaluation/test_evaluate_job_conditions.py

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>

* fix names

* address comments

* Update decorator.py

* adjust security

* add reset

* Apply suggestions from code review

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2020-11-24 10:54:57 +01:00
dependabot[bot]
19d8de89df Bump docker from 4.3.1 to 4.4.0 (#2292)
Bumps [docker](https://github.com/docker/docker-py) from 4.3.1 to 4.4.0.
- [Release notes](https://github.com/docker/docker-py/releases)
- [Commits](https://github.com/docker/docker-py/compare/4.3.1...4.4.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-24 08:49:22 +01:00
Joakim Sørensen
cfae20a3ec Change snapshot create conditions (#2289) 2020-11-23 22:57:41 +01:00
Joakim Sørensen
6db6ab96e6 Update frontend panel to 0ef88816 (#2291) 2020-11-23 22:57:11 +01:00
dependabot[bot]
48695c6805 Bump actions/stale from v3.0.13 to v3.0.14 (#2286)
Bumps [actions/stale](https://github.com/actions/stale) from v3.0.13 to v3.0.14.
- [Release notes](https://github.com/actions/stale/releases)
- [Commits](https://github.com/actions/stale/compare/v3.0.13...87c2b794b9b47a9bec68ae03c01aeb572ffebdb1)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-23 09:36:20 +01:00
dependabot[bot]
d74908e3b5 Bump pre-commit from 2.8.2 to 2.9.0 (#2287)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.8.2 to 2.9.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.8.2...v2.9.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-23 09:30:41 +01:00
Pascal Vizeli
7e94537e36 Soft restart supervisor (#2281)
* Add softrestart to supervisor

* decouble

* adjust logger

* make sure it need run

* Use job condition

* add more job running
2020-11-21 12:48:16 +01:00
Pascal Vizeli
1427e0ae96 Add jobs decorator to add-ons/snapshot/core and remove 404 hack (#2280)
* Add jobs decorator to add-ons/snapshot/core and remove 404 hack

* add to repair
2020-11-21 10:47:15 +01:00
Pascal Vizeli
01e27dfa2f Wifi mode old NM (#2279) 2020-11-21 10:20:31 +01:00
Joakim Sørensen
f48249c9d1 Remove HEALTHY from update_repositories (#2277) 2020-11-21 10:07:44 +01:00
Joakim Sørensen
e607d4feeb Fix missing primary interface after change (#2274)
* Fix missing primary interface after change

* Fix test
2020-11-20 12:01:59 +01:00
Joakim Sørensen
5367ac257e Update frontend panel to 46f55895 (#2275) 2020-11-20 11:51:43 +01:00
Joakim Sørensen
46dc6dc63b Add log about ratelimit (#2271)
* Add log about ratelimit

* Update wording

* create issue
2020-11-20 10:50:26 +01:00
dependabot[bot]
a59ea72c66 Bump sentry-sdk from 0.19.3 to 0.19.4 (#2273)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.19.3 to 0.19.4.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.19.3...0.19.4)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-20 09:44:28 +01:00
Pascal Vizeli
2daf46c444 Rename add-ons repository (#2272) 2020-11-19 21:10:37 +01:00
Pascal Vizeli
1bf38bdc99 Use Brotli instead of brotlipy (#2270) 2020-11-19 09:24:40 +01:00
dependabot[bot]
131909973c Bump aiohttp from 3.7.2 to 3.7.3 (#2269)
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.7.2 to 3.7.3.
- [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.7.2...v3.7.3)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-19 08:35:04 +01:00
Pascal Vizeli
ecdf4e53b8 Use atomic writes to make it more stable again full disk (#2267) 2020-11-18 17:08:57 +01:00
Pascal Vizeli
7aa039d162 Missing log what going on (#2268) 2020-11-18 17:08:28 +01:00
Pascal Vizeli
3dd3340e35 Make host feature cheaper to call and relay on it (#2266) 2020-11-18 14:13:49 +01:00
Pascal Vizeli
2f9fc39b72 Check if connectivity check if available on host (#2265)
* Check if connectivity check if available on host

* fix get

* not needed

* Update const.py

* Use enabled
2020-11-18 12:40:55 +01:00
Pascal Vizeli
80f4309799 Enforce internet host/system (#2263) 2020-11-18 11:29:23 +01:00
Pascal Vizeli
550fca4bcd Remove coroutine from job update (#2264) 2020-11-18 11:25:04 +01:00
Pascal Vizeli
4b500ef873 JobManager should not touch our exceptions (#2261)
* JobManager should not touch our exceptions

* Add tests

* temporary allow su update all time

* Update supervisor/jobs/decorator.py

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2020-11-17 18:46:02 +01:00
dependabot[bot]
476f021fbf Bump debugpy from 1.1.0 to 1.2.0 (#2260)
Bumps [debugpy](https://github.com/microsoft/debugpy) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/microsoft/debugpy/releases)
- [Commits](https://github.com/microsoft/debugpy/compare/v1.1.0...v1.2.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-17 18:38:00 +01:00
dependabot[bot]
8393ca5b23 Bump codecov/codecov-action from v1.0.14 to v1.0.15 (#2259)
Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from v1.0.14 to v1.0.15.
- [Release notes](https://github.com/codecov/codecov-action/releases)
- [Commits](https://github.com/codecov/codecov-action/compare/v1.0.14...239febf655bba88b16ff5dea1d3135ea8663a1f9)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-17 08:56:32 +01:00
dependabot[bot]
4eb7a60b88 Bump actions/upload-artifact from v2.2.0 to v2.2.1 (#2257)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from v2.2.0 to v2.2.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v2.2.0...726a6dcd0199f578459862705eed35cda05af50b)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-16 12:34:50 +01:00
Pascal Vizeli
2040102e21 Handle Unhealthy like Unsupported (#2255)
* Handle Unhealthy like Unsupported

* Add tests

* Add unhealthy to sentry

* Add test
2020-11-14 16:16:00 +01:00
Joakim Sørensen
7ee5737f75 Activate new network settings after update (#2253) 2020-11-13 18:15:46 +01:00
Pascal Vizeli
8d499753a0 Fix auto interface method (#2252) 2020-11-13 16:58:28 +01:00
Pascal Vizeli
028ec277eb Enable support for mdns & llmnr for host (#2251) 2020-11-13 16:47:56 +01:00
Pascal Vizeli
5552b1da49 Optimize flow / reduce call time (#2250)
* Optimize flow / reduce call time

* rename

* freeze too

* add connectivity task

* use newstyle timeout

* Fix tests

Co-authored-by: Ludeeus <ludeeus@ludeeus.dev>
2020-11-13 12:19:10 +01:00
Joakim Sørensen
06ab7e904f Split check for internet connection to help troubleshooting (#2248)
* Split check for internet connection to help troubleshooting

* Siplify

* revert

* cleanup

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
2020-11-13 08:58:07 +01:00
Pascal Vizeli
e4bf820038 Check & fix git repository integrity (#2245)
* Check & fix git repository integrity

* fix typing

* New style error handling

* Fix return

* tag more issue

* Fix black
2020-11-13 08:35:45 +01:00
dependabot[bot]
c209d2fa8d Bump sentry-sdk from 0.19.2 to 0.19.3 (#2249)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.19.2 to 0.19.3.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.19.2...0.19.3)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-13 08:27:31 +01:00
Joakim Sørensen
784c5d3b7c Use bool for host internet (#2247)
* Use bool for host internet

* Ignore host check if no network manager

* Update supervisor/host/network.py

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>

* Check dbus connection isntead of supported features

Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
2020-11-13 00:07:05 +01:00
Joakim Sørensen
a18b706f99 Add JobManager and Job decorator (#2225)
* Adds condition decorator to block execution that require internet

* Fix exsisting tests

* Add internet state to network info

* Add healthy condition

* Add tests

* It's all changed

* rename
2020-11-12 22:57:28 +01:00
Pascal Vizeli
cd34a40dd8 Send issues with sentry report (#2246) 2020-11-12 14:57:04 +01:00
Pascal Vizeli
ced72e1273 Fix show update if version is None (#2244) 2020-11-12 10:11:38 +01:00
Pascal Vizeli
5416eda1d6 Improve the error logging with new DBusProgramError (#2243) 2020-11-12 09:34:43 +01:00
Pascal Vizeli
c76a4ff422 Revert: psk is not readable and only exists on initial (#2242)
* Revert: psk is not readable and only exists on initial

* fix tests
2020-11-11 21:07:28 +01:00
Stefan Agner
d558ad2d76 Use technology neutral "auto" instead of "dhcp" for autoconfiguration (#2241)
* Use technology neutral "auto"  instead of "dhcp" for autoconfiguration

IPv6 is often run with SLAAC which does not use a DHCP server but still
does automatic address configuration. Follow wording of NetworkManager
and use "auto" instead.

* Use "auto" also in interface_update.tmpl

* Update interface_update.tmpl

* remove newline

Co-authored-by: Pascal Vizeli <pascal.vizeli@syshack.ch>
Co-authored-by: Pascal Vizeli <pvizeli@syshack.ch>
2020-11-11 18:23:04 +01:00
Pascal Vizeli
5f2d183b1d Fix wifi conversation (#2240)
* Fix wifi conversation

* Fix naming

* simple
2020-11-11 17:09:48 +01:00
Pascal Vizeli
46e92036ec Fix handling with open or wpa-psk (#2239) 2020-11-11 16:33:46 +01:00
Pascal Vizeli
280d423bfe Fix error if a wlan scan is allready running (#2238)
* Fix error if a wlan scan is allready running

* fix other messages too
2020-11-11 13:48:50 +01:00
Pascal Vizeli
c4847ad10d Handle dbus single byte (#2237) 2020-11-11 13:09:13 +01:00
dependabot[bot]
0a7c75830b Bump pyupgrade from 2.7.3 to 2.7.4 (#2236)
Bumps [pyupgrade](https://github.com/asottile/pyupgrade) from 2.7.3 to 2.7.4.
- [Release notes](https://github.com/asottile/pyupgrade/releases)
- [Commits](https://github.com/asottile/pyupgrade/compare/v2.7.3...v2.7.4)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-11 08:45:07 +01:00
Pascal Vizeli
7aceb21123 Fix auth mode WEP (#2235)
* Fix auth mode WEP

* fix mapping
2020-11-10 18:07:20 +01:00
Pascal Vizeli
9264d437b1 Fix network API default value & tests (#2234) 2020-11-10 15:08:35 +01:00
Franck Nijhof
edc8d8960f Replace stale bot with GitHub Action (#2232) 2020-11-10 09:15:34 +01:00
dependabot[bot]
0f4f196dc9 Bump colorlog from 4.5.0 to 4.6.2 (#2233)
Bumps [colorlog](https://github.com/borntyping/python-colorlog) from 4.5.0 to 4.6.2.
- [Release notes](https://github.com/borntyping/python-colorlog/releases)
- [Commits](https://github.com/borntyping/python-colorlog/compare/v4.5.0...v4.6.2)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-10 09:15:01 +01:00
Pascal Vizeli
a027f4b5fc Revert info back to debug 2020-11-09 15:11:57 +00:00
Franck Nijhof
f025d1df05 Replace lock bot with GitHub Action (#2231) 2020-11-09 13:07:23 +01:00
Pascal Vizeli
4c560d7c54 Fix gateway None on API (#2230)
* Fix gateway None on API

* fix tests
2020-11-09 10:00:39 +01:00
Pascal Vizeli
a976ef6e67 Cleanup some logger (#2229) 2020-11-09 09:56:01 +01:00
Pascal Vizeli
e1b9d754af Fix all interface are primary (#2228) 2020-11-09 09:27:16 +01:00
Pascal Vizeli
ee49935b7d Odroid-C4 (#2226)
* Add Odroid-C4

* add machine
2020-11-09 08:57:18 +01:00
dependabot[bot]
36694c9ef0 Bump colorlog from 4.4.0 to 4.5.0 (#2227)
Bumps [colorlog](https://github.com/borntyping/python-colorlog) from 4.4.0 to 4.5.0.
- [Release notes](https://github.com/borntyping/python-colorlog/releases)
- [Commits](https://github.com/borntyping/python-colorlog/compare/v4.4.0...v4.5.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-09 08:57:08 +01:00
Pascal Vizeli
bd786811a3 Network: abstract dbus and supervisor - ipv6/wifi/vlan (#2217)
* Abstract code between dbus - supervisor

* cleanup v2

* fix address vs interface

* fix API calls

* Fix methodnames

* add vlan type

* add vlan support

* Fix tests

* Add wifi support

* more OOO

* fix typing import

* typing part 2

* Fix profile

* fix test payload

* ignore powersafe

* support privancy

* fix property

* Fix tests

* full support all API

* Fix all

* more robust

* Update supervisor/dbus/network/connection.py

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

* Fix gateway

* fix empty gateway

* Allow no ipv6 or ipv4 kernel support

* Exclude device drivers

* Add wifi

* Use loop on api

* refactory p1

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* refactory p2

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* refactory p3

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* refactory p4

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* refactory p5

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* refactory p6

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* refactory p7

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* refactory p8

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* Fix lint

* update sup p1

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* update sup p2

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* fix tests

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* fix logging

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* improve mock handling

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* add fixtures

Signed-off-by: Pascal Vizeli <pvizeli@syshack.ch>

* fix tests

* better testing

* Add more tests

* Fix API test

* Add test for vlan payload

* Support variation

* Fix doc string

* support remove & wifi scan

* make sure we ignore local-link on ipv6

* remove privancy - add vlan

* Fix tests

* fix isort

* Fixture dbus by commands

* Add dnsmanager fixture

* expose commands called by dbus

* Add wifi tests

* Update supervisor/plugins/dns.py

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>

* Address comments & fix tests

* change url to be closer on others

Co-authored-by: Joakim Sørensen <joasoe@gmail.com>
2020-11-09 08:56:42 +01:00
Paulus Schoutsen
ffaeb2b96d Add validate session API (#2223) 2020-11-06 11:52:11 +01:00
dependabot[bot]
517e6cb437 Bump attrs from 20.2.0 to 20.3.0 (#2222)
Bumps [attrs](https://github.com/python-attrs/attrs) from 20.2.0 to 20.3.0.
- [Release notes](https://github.com/python-attrs/attrs/releases)
- [Changelog](https://github.com/python-attrs/attrs/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/python-attrs/attrs/compare/20.2.0...20.3.0)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-06 11:45:42 +01:00
Joakim Sørensen
9479672b88 Create evaluation modules (#2220)
* Create evaluation modules

* Use sys_core
2020-11-05 17:36:02 +01:00
Joakim Sørensen
934e59596a Adds more logs to session validation (#2219)
* Adds more logs to session validation

* It's not there

* Use debug

* format

* Create new timestamp if OverflowError
2020-11-05 10:40:56 +01:00
Joakim Sørensen
8f4ac10361 Add login support for dockerhub (#2218)
* Add login support for dockerhub

* Remove registry
2020-11-05 10:39:53 +01:00
Pascal Vizeli
50e0fd159f Add process lock for update + fix timeout (#2215) 2020-11-03 18:12:57 +01:00
Pascal Vizeli
28344ff5f3 Supervisor container startup health function (#2214)
* Supervisor container startup health function

* better struct

* add test

* address comment

* rename file

* Update tests/test_main.py

Co-authored-by: Stefan Agner <stefan@agner.ch>

Co-authored-by: Stefan Agner <stefan@agner.ch>
2020-11-03 16:36:10 +01:00
dependabot[bot]
608ae14246 Bump sentry-sdk from 0.19.1 to 0.19.2 (#2211)
Bumps [sentry-sdk](https://github.com/getsentry/sentry-python) from 0.19.1 to 0.19.2.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGES.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/0.19.1...0.19.2)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-03 09:58:43 +01:00
dependabot[bot]
c0c0d44c2d Bump home-assistant/builder from 2020.10.0 to 2020.11.0 (#2210)
Bumps [home-assistant/builder](https://github.com/home-assistant/builder) from 2020.10.0 to 2020.11.0.
- [Release notes](https://github.com/home-assistant/builder/releases)
- [Commits](https://github.com/home-assistant/builder/compare/2020.10.0...c60c59d1300ac720519bbf35026f6b6904214d71)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-03 09:58:12 +01:00
Pascal Vizeli
5e947348ae Fix pulse cookie error (#2212) 2020-11-03 09:54:31 +01:00
Joakim Sørensen
1f4032f56f Add the log stream from docker if build fails (#2207)
* Add the log stream from docker if build fails

* Check if dict
2020-11-02 11:44:11 +01:00
dependabot[bot]
336ab0d2b1 Bump pre-commit from 2.8.1 to 2.8.2 (#2206)
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.8.1 to 2.8.2.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v2.8.1...v2.8.2)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-02 09:58:55 +01:00
dependabot[bot]
0f9d80dde4 Bump pytz from 2020.1 to 2020.4 (#2205)
Bumps [pytz](https://github.com/stub42/pytz) from 2020.1 to 2020.4.
- [Release notes](https://github.com/stub42/pytz/releases)
- [Commits](https://github.com/stub42/pytz/compare/release_2020.1...release_2020.4)

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

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-11-02 09:58:36 +01:00
Joakim Sørensen
0fcab4d92b Fix missing metadata in the issue template (#2200) 2020-10-30 17:18:37 +01:00
Joakim Sørensen
abd35b62c8 Update issue template (#2199) 2020-10-30 17:11:51 +01:00
397 changed files with 17268 additions and 8896 deletions

View File

@@ -2,6 +2,11 @@ FROM mcr.microsoft.com/vscode/devcontainers/python:0-3.8
WORKDIR /workspaces
# Set Docker daemon config
RUN \
mkdir -p /etc/docker \
&& echo '{"storage-driver": "vfs"}' > /etc/docker/daemon.json
# Install Node/Yarn for Frontent
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \

View File

@@ -5,6 +5,7 @@
"appPort": "9123:8123",
"postCreateCommand": "pre-commit install",
"runArgs": ["-e", "GIT_EDITOR=code --wait", "--privileged"],
"containerEnv": {"NVM_DIR":"/usr/local/share/nvm"},
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",

View File

@@ -1,28 +0,0 @@
<!-- READ THIS FIRST:
- If you need additional help with this template please refer to https://www.home-assistant.io/help/reporting_issues/
- Make sure you are running the latest version of Home Assistant before reporting an issue: https://github.com/home-assistant/core/releases
- Do not report issues for integrations here, please refer to https://github.com/home-assistant/core/issues
- This is for bugs only. Feature and enhancement requests should go in our community forum: https://community.home-assistant.io/c/feature-requests
- Provide as many details as possible. Paste logs, configuration sample and code into the backticks. Do not delete any text from this template!
- If you have a problem with an add-on, make an issue in its repository.
-->
**Home Assistant release with the issue:**
<!--
- Frontend -> Configuration -> Info
- Or use this command: hass --version
-->
**Operating environment (HassOS/Generic):**
<!--
Please provide details about your environment.
-->
**Supervisor logs:**
<!--
- Frontend -> Supervisor -> System
- Or use this command: ha supervisor logs
-->
**Description of problem:**

69
.github/ISSUE_TEMPLATE/BUG_REPORT.md vendored Normal file
View File

@@ -0,0 +1,69 @@
---
name: Report a bug with the Supervisor on a supported System
about: Report an issue related to the Home Assistant Supervisor.
labels: bug
---
<!-- READ THIS FIRST:
- If you need additional help with this template please refer to https://www.home-assistant.io/help/reporting_issues/
- This is for bugs only. Feature and enhancement requests should go in our community forum: https://community.home-assistant.io/c/feature-requests
- Provide as many details as possible. Paste logs, configuration sample and code into the backticks. Do not delete any text from this template!
- If you have a problem with an add-on, make an issue in it's repository.
-->
<!--
Important: You can only fill a bug repport for an supported system! If you run an unsupported installation. This report would be closed without comment.
-->
### Describe the issue
<!-- Provide as many details as possible. -->
### Steps to reproduce
<!-- What do you do to encounter the issue. -->
1. ...
2. ...
3. ...
### Enviroment details
<!-- You can find these details in the system tab of the supervisor panel, or by using the `ha` CLI. -->
- **Operating System:**: xxx
- **Supervisor version:**: xxx
- **Home Assistant version**: xxx
### Supervisor logs
<details>
<summary>Supervisor logs</summary>
<!--
- Frontend -> Supervisor -> System
- Or use this command: ha supervisor logs
- Logs are more than just errors, even if you don't think it's important, it is.
-->
```
Paste supervisor logs here
```
</details>
### System Information
<details>
<summary>System Information</summary>
<!--
- Use this command: ha info
-->
```
Paste system info here
```
</details>

25
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
blank_issues_enabled: false
contact_links:
- name: Report a bug/issues with an unsupported Supervisor
url: https://community.home-assistant.io
about: The Community guide can help or was updated to solve your issue
- name: Report a bug for the Supervisor panel
url: https://github.com/home-assistant/frontend/issues
about: The Supervisor panel is a part of the Home Assistant frontend
- name: Report incorrect or missing information on our developer documentation
url: https://github.com/home-assistant/developers.home-assistant.io/issues
about: Our documentation has its own issue tracker. Please report issues with the website there.
- name: Request a feature for the Supervisor
url: https://community.home-assistant.io/c/feature-requests
about: Request an new feature for the Supervisor.
- name: I have a question or need support
url: https://www.home-assistant.io/help
about: We use GitHub for tracking bugs, check our website for resources on getting help.
- name: I'm unsure where to go?
url: https://www.home-assistant.io/join-chat
about: If you are unsure where to go, then joining our chat is recommended; Just ask!

View File

@@ -0,0 +1,80 @@
name: Bug Report Form
about: Report an issue related to the Home Assistant Supervisor.
labels: bug
title: ""
issue_body: true
inputs:
- type: description
attributes:
value: |
This issue form is for reporting bugs with **supported** setups only!
If you have a feature or enhancement request, please use the [feature request][fr] section of our [Community Forum][fr].
[fr]: https://community.home-assistant.io/c/feature-requests
- type: input
attributes:
label: What is the version of the Supervisor used?
required: true
placeholder: supervisor-
description: >
Can be found in the Supervisor panel -> System tab. Starts with
`supervisor-....`.
- type: dropdown
attributes:
label: What type of installation are you running?
required: true
description: >
If you don't know, you can find it in: Configuration panel -> Info.
choices:
- Home Assistant OS
- Home Assistant Supervised
- type: dropdown
attributes:
label: Which operating system are you running on?
required: true
choices:
- Home Assistant Operating System
- Debian
- Other (e.g., Raspbian/Raspberry Pi OS/Fedora)
- type: input
attributes:
label: What is the version of your installed operating system?
required: true
placeholder: 5.10
description: Can be found in the Supervisor panel -> System tab.
- type: input
attributes:
label: What version of Home Assistant Core is installed?
required: true
placeholder: core-
description: >
Can be found in the Supervisor panel -> System tab. Starts with
`core-....`.
- type: textarea
attributes:
label: Describe the issue you are experiencing
required: true
description: Provide a clear and concise description of what the bug is.
- type: textarea
attributes:
label: Steps to reproduce the issue
required: true
description: |
Please tell us exactly how to reproduce your issue.
Provide clear and concise step by step instructions and add code snippets if needed.
value: |
1.
2.
3.
...
- type: textarea
attributes:
label: Anything in the Supervisor logs that might be useful for us?
required: false
description: >
The Supervisor logs can be found in the Supervisor panel -> System tab.
- type: description
attributes:
value: |
If you have any additional information for us, use the field below.
Please note, you can attach screenshots or screen recordings here.

27
.github/lock.yml vendored
View File

@@ -1,27 +0,0 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 1
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: 2020-01-01
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: false
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: false
# Limit to only `issues` or `pulls`
only: pulls
# Optionally, specify configuration settings just for `issues` or `pulls`
issues:
daysUntilLock: 30

View File

@@ -1,4 +1,49 @@
change-template: "- #$NUMBER $TITLE @$AUTHOR"
sort-direction: ascending
categories:
- title: ":boom: Breaking Changes"
label: "breaking-change"
- title: ":wrench: Build"
label: "build"
- title: ":boar: Chore"
label: "chore"
- title: ":sparkles: New Features"
label: "new-feature"
- title: ":zap: Performance"
label: "performance"
- title: ":recycle: Refactor"
label: "refactor"
- title: ":green_heart: CI"
label: "ci"
- title: ":bug: Bug Fixes"
label: "bugfix"
- title: ":white_check_mark: Test"
label: "test"
- title: ":arrow_up: Dependency Updates"
label: "dependencies"
include-labels:
- "breaking-change"
- "build"
- "chore"
- "performance"
- "refactor"
- "new-feature"
- "bugfix"
- "dependencies"
- "test"
- "ci"
template: |
## What's Changed
$CHANGES

18
.github/stale.yml vendored
View File

@@ -1,18 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- rfc
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@@ -35,6 +35,7 @@ on:
env:
BUILD_NAME: supervisor
BUILD_TYPE: supervisor
WHEELS_TAG: 3.8-alpine3.12
jobs:
init:
@@ -45,6 +46,7 @@ jobs:
version: ${{ steps.version.outputs.version }}
channel: ${{ steps.version.outputs.channel }}
publish: ${{ steps.version.outputs.publish }}
requirements: ${{ steps.requirements.outputs.changed }}
steps:
- name: Checkout the repository
uses: actions/checkout@v2
@@ -61,6 +63,18 @@ jobs:
with:
type: ${{ env.BUILD_TYPE }}
- name: Get changed files
id: changed_files
if: steps.version.outputs.publish == 'false'
uses: jitterbit/get-changed-files@v1
- name: Check if requirements files changed
id: requirements
run: |
if [[ "${{ steps.changed_files.outputs.all }}" =~ requirements.txt ]]; then
echo "::set-output name=changed::true"
fi
build:
name: Build ${{ matrix.arch }} supervisor
needs: init
@@ -74,6 +88,19 @@ jobs:
with:
fetch-depth: 0
- name: Build wheels
if: needs.init.outputs.requirements == 'true'
uses: home-assistant/wheels@master
with:
tag: ${{ env.WHEELS_TAG }}
arch: ${{ matrix.arch }}
wheels-host: ${{ secrets.WHEELS_HOST }}
wheels-key: ${{ secrets.WHEELS_KEY }}
wheels-user: wheels
apk: "build-base;libffi-dev;openssl-dev"
skip-binary: aiohttp
requirements: "requirements.txt"
- name: Set version
if: needs.init.outputs.publish == 'true'
uses: home-assistant/actions/helpers/version@master
@@ -92,7 +119,7 @@ jobs:
run: echo "BUILD_ARGS=--test" >> $GITHUB_ENV
- name: Build supervisor
uses: home-assistant/builder@2020.10.0
uses: home-assistant/builder@2021.01.1
with:
args: |
$BUILD_ARGS \
@@ -134,7 +161,7 @@ jobs:
uses: actions/checkout@v2
- name: Build the Supervisor
uses: home-assistant/builder@2020.10.0
uses: home-assistant/builder@2021.01.1
with:
args: |
--test \

19
.github/workflows/check_pr_labels.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Check PR
on:
pull_request:
branches: ["main"]
types: [labeled, unlabeled, synchronize]
jobs:
init:
name: Check labels
runs-on: ubuntu-latest
steps:
- name: Check labels
run: |
labels=$(jq -r '.pull_request.labels[] | .name' ${{github.event_path }})
echo "$labels"
if [ "$labels" == "cla-signed" ]; then
exit 1
fi

View File

@@ -25,7 +25,7 @@ jobs:
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
id: python
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
with:
python-version: ${{ matrix.python-version }}
- name: Restore Python virtual environment
@@ -68,7 +68,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -112,7 +112,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -156,7 +156,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -188,7 +188,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -229,7 +229,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -273,7 +273,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -305,7 +305,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -349,7 +349,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ matrix.python-version }}
@@ -390,7 +390,7 @@ jobs:
-o console_output_style=count \
tests
- name: Upload coverage artifact
uses: actions/upload-artifact@v2.2.0
uses: actions/upload-artifact@v2.2.2
with:
name: coverage-${{ matrix.python-version }}
path: .coverage
@@ -403,7 +403,7 @@ jobs:
- name: Check out code from GitHub
uses: actions/checkout@v2
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
uses: actions/setup-python@v2.1.4
uses: actions/setup-python@v2.2.1
id: python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
@@ -428,4 +428,4 @@ jobs:
coverage report
coverage xml
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1.0.14
uses: codecov/codecov-action@v1.2.1

20
.github/workflows/lock.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Lock
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "0 0 * * *"
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2.0.3
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: "30"
issue-exclude-created-before: "2020-10-01T00:00:00Z"
issue-lock-reason: ""
pr-lock-inactive-days: "1"
pr-exclude-created-before: "2020-11-01T00:00:00Z"
pr-lock-reason: ""

View File

@@ -2,14 +2,43 @@ name: Release Drafter
on:
push:
# branches to consider in the event; optional, defaults to all
branches:
- main
jobs:
update_release_draft:
runs-on: ubuntu-latest
name: Release Drafter
steps:
- uses: release-drafter/release-drafter@v5
- name: Checkout the repository
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Find Next Version
id: version
run: |
declare -i newpost
latest=$(git describe --tags $(git rev-list --tags --max-count=1))
latestpre=$(echo "$latest" | awk '{split($0,a,"."); print a[1] "." a[2]}')
datepre=$(date --utc '+%Y.%m')
if [[ "$latestpre" == "$datepre" ]]; then
latestpost=$(echo "$latest" | awk '{split($0,a,"."); print a[3]}')
newpost=$latestpost+1
else
newpost=0
fi
echo Current version: $latest
echo New target version: $datepre.$newpost
echo "::set-output name=version::$datepre.$newpost"
- name: Run Release Drafter
uses: release-drafter/release-drafter@v5
with:
tag: ${{ steps.version.outputs.version }}
name: ${{ steps.version.outputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

39
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
name: Stale
# yamllint disable-line rule:truthy
on:
schedule:
- cron: "0 * * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3.0.15
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 60
days-before-close: 7
stale-issue-label: "stale"
exempt-issue-labels: "no-stale,Help%20wanted,help-wanted,pinned,rfc,security"
stale-issue-message: >
There hasn't been any activity on this issue recently. Due to the
high number of incoming GitHub notifications, we have to clean some
of the old issues, as many of them have already been resolved with
the latest updates.
Please make sure to update to the latest version and check if that
solves the issue. Let us know if that works for you by
adding a comment 👍
This issue has now been marked as stale and will be closed if no
further activity occurs. Thank you for your contributions.
stale-pr-label: "stale"
exempt-pr-labels: "no-stale,pinned,rfc,security"
stale-pr-message: >
There hasn't been any activity on this pull request recently. This
pull request has been automatically marked as stale because of that
and will be closed if no further activity occurs within 7 days.
Thank you for your contributions.

22
.vscode/tasks.json vendored
View File

@@ -2,9 +2,9 @@
"version": "2.0.0",
"tasks": [
{
"label": "Run Testenv",
"label": "Run Supervisor",
"type": "shell",
"command": "./scripts/test_env.sh",
"command": "./scripts/run-supervisor.sh",
"group": {
"kind": "test",
"isDefault": true
@@ -16,7 +16,21 @@
"problemMatcher": []
},
{
"label": "Run Testenv CLI",
"label": "Build Supervisor",
"type": "shell",
"command": "./scripts/build-supervisor.sh",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "new"
},
"problemMatcher": []
},
{
"label": "Run Supervisor CLI",
"type": "shell",
"command": "docker exec -ti hassio_cli /usr/bin/cli.sh",
"group": {
@@ -30,7 +44,7 @@
"problemMatcher": []
},
{
"label": "Update UI",
"label": "Update Supervisor Panel",
"type": "shell",
"command": "./scripts/update-frontend.sh",
"group": {

View File

@@ -10,26 +10,23 @@ network settings or installing and updating software.
## Installation
Installation instructions can be found at https://home-assistant.io/hassio.
Installation instructions can be found at https://home-assistant.io/getting-started.
## Development
The development of the Supervisor is not difficult but tricky.
- You can use the builder to create your Supervisor: https://github.com/home-assistant/hassio-builder
- Access a HassOS device or VM and pull your Supervisor.
- Set the developer modus with the CLI tool: `ha supervisor options --channel=dev`
- Tag it as `homeassistant/xy-hassio-supervisor:latest`
- Restart the service with `systemctl restart hassos-supervisor | journalctl -fu hassos-supervisor`
- Test your changes
For small bugfixes or improvements, make a PR. For significant changes open a RFC first, please. Thanks.
For small changes and bugfixes you can just follow this, but for significant changes open a RFC first.
Development instructions can be found [here][development].
## Release
Follow is the relase circle process:
Releases are done in 3 stages (channels) with this structure:
1. Merge master into dev / make sure version stay on dev
2. Merge dev into master
3. Bump the release on master
4. Create a GitHub Release from master with the right version tag
1. Pull requests are merged to the `main` branch.
2. A new build is pushed to the `dev` stage.
3. Releases are published.
4. A new build is pushed to the `beta` stage.
5. The [`stable.json`][stable] file is updated.
6. The build that was pushed to `beta` will now be pushed to `stable`.
[development]: https://developers.home-assistant.io/docs/supervisor/development
[stable]: https://github.com/home-assistant/version/blob/master/stable.json

View File

@@ -1,26 +0,0 @@
# https://dev.azure.com/home-assistant
trigger:
batch: true
branches:
include:
- main
pr: none
variables:
- name: versionWheels
value: "1.13.0-3.8-alpine3.12"
resources:
repositories:
- repository: azure
type: github
name: "home-assistant/ci-azure"
endpoint: "home-assistant"
jobs:
- template: templates/azp-job-wheels.yaml@azure
parameters:
builderVersion: "$(versionWheels)"
builderApk: "build-base;libffi-dev;openssl-dev"
builderPip: "Cython"
skipBinary: "aiohttp"
wheelsRequirement: "requirements.txt"

View File

@@ -1,19 +1,20 @@
aiohttp==3.7.2
aiohttp==3.7.3
async_timeout==3.0.1
attrs==20.2.0
brotlipy==0.7.0
atomicwrites==1.4.0
attrs==20.3.0
awesomeversion==21.2.0
brotli==1.0.9
cchardet==2.1.7
colorlog==4.4.0
colorlog==4.7.2
cpe==1.2.1
cryptography==3.2.1
debugpy==1.1.0
docker==4.3.1
gitpython==3.1.11
jinja2==2.11.2
packaging==20.4
cryptography==3.3.1
debugpy==1.2.1
docker==4.4.1
gitpython==3.1.12
jinja2==2.11.3
pulsectl==20.5.1
pytz==2020.1
pytz==2021.1
pyudev==0.22.0
ruamel.yaml==0.15.100
sentry-sdk==0.19.1
voluptuous==0.12.0
sentry-sdk==0.19.5
voluptuous==0.12.1

View File

@@ -1,14 +1,14 @@
black==20.8b1
codecov==2.1.10
coverage==5.3
codecov==2.1.11
coverage==5.4
flake8-docstrings==1.5.0
flake8==3.8.4
pre-commit==2.8.1
pre-commit==2.10.0
pydocstyle==5.1.1
pylint==2.6.0
pytest-aiohttp==0.3.0
pytest-asyncio==0.12.0 # NB!: Versions over 0.12.0 breaks pytest-aiohttp (https://github.com/aio-libs/pytest-aiohttp/issues/16)
pytest-cov==2.10.1
pytest-cov==2.11.1
pytest-timeout==1.4.2
pytest==6.1.2
pyupgrade==2.7.3
pytest==6.2.2
pyupgrade==2.9.0

View File

@@ -2,9 +2,17 @@
# ==============================================================================
# Start udev service
# ==============================================================================
if bashio::fs.directory_exists /run/udev && ! bashio::fs.file_exists /run/.old_udev; then
bashio::log.info "Using udev information from host"
bashio::exit.ok
fi
bashio::log.info "Setup udev backend inside container"
udevd --daemon
bashio::log.info "Update udev information"
touch /run/.old_udev
if udevadm trigger; then
udevadm settle || true
else

View File

@@ -26,7 +26,7 @@ autospawn = no
; daemon-binary = /usr/bin/pulseaudio
; extra-arguments = --log-target=syslog
; cookie-file =
cookie-file = /run/pulse-cookie
; enable-shm = yes
; shm-size-bytes = 0 # setting this 0 will use the system-default, usually 64 MiB

View File

@@ -1,5 +1,8 @@
#!/usr/bin/execlineb -S0
#!/usr/bin/execlineb -S1
# ==============================================================================
# Take down the S6 supervision tree when Supervisor fails
# ==============================================================================
if { s6-test ${1} -ne 100 }
if { s6-test ${1} -ne 256 }
redirfd -w 2 /dev/null s6-svscanctl -t /var/run/s6/services

28
scripts/build-supervisor.sh Executable file
View File

@@ -0,0 +1,28 @@
#!/bin/bash
source "${BASH_SOURCE[0]%/*}/common.sh"
set -eE
DOCKER_TIMEOUT=30
DOCKER_PID=0
function build_supervisor() {
docker pull homeassistant/amd64-builder:dev
docker run --rm \
--privileged \
-v /run/docker.sock:/run/docker.sock \
-v "$(pwd):/data" \
homeassistant/amd64-builder:dev \
--generic latest \
--target /data \
--test \
--amd64 \
--no-cache
}
echo "Build Supervisor"
start_docker
trap "stop_docker" ERR
build_supervisor

75
scripts/test_env.sh → scripts/common.sh Executable file → Normal file
View File

@@ -1,9 +1,4 @@
#!/bin/bash
set -eE
DOCKER_TIMEOUT=30
DOCKER_PID=0
function start_docker() {
local starttime
@@ -28,7 +23,6 @@ function start_docker() {
echo "Docker was initialized"
}
function stop_docker() {
local starttime
local endtime
@@ -54,17 +48,6 @@ function stop_docker() {
fi
}
function build_supervisor() {
docker pull homeassistant/amd64-builder:dev
docker run --rm --privileged \
-v /run/docker.sock:/run/docker.sock -v "$(pwd):/data" \
homeassistant/amd64-builder:dev \
--generic dev -t /data --test --amd64 --no-cache
}
function cleanup_lastboot() {
if [[ -f /workspaces/test_supervisor/config.json ]]; then
echo "Cleaning up last boot"
@@ -73,61 +56,3 @@ function cleanup_lastboot() {
rm /tmp/config.json
fi
}
function cleanup_docker() {
echo "Cleaning up stopped containers..."
docker rm $(docker ps -a -q) || true
}
function setup_test_env() {
mkdir -p /workspaces/test_supervisor
echo "Start Supervisor"
docker run --rm --privileged \
--name hassio_supervisor \
--security-opt seccomp=unconfined \
--security-opt apparmor:unconfined \
-v /run/docker.sock:/run/docker.sock \
-v /run/dbus:/run/dbus \
-v "/workspaces/test_supervisor":/data \
-v /etc/machine-id:/etc/machine-id:ro \
-e SUPERVISOR_SHARE="/workspaces/test_supervisor" \
-e SUPERVISOR_NAME=hassio_supervisor \
-e SUPERVISOR_DEV=1 \
-e SUPERVISOR_MACHINE="qemux86-64" \
homeassistant/amd64-hassio-supervisor:latest
}
function init_dbus() {
if pgrep dbus-daemon; then
echo "Dbus is running"
return 0
fi
echo "Startup dbus"
mkdir -p /var/lib/dbus
cp -f /etc/machine-id /var/lib/dbus/machine-id
# cleanups
mkdir -p /run/dbus
rm -f /run/dbus/pid
# run
dbus-daemon --system --print-address
}
echo "Start Test-Env"
start_docker
trap "stop_docker" ERR
build_supervisor
cleanup_lastboot
cleanup_docker
init_dbus
setup_test_env
stop_docker

102
scripts/run-supervisor.sh Executable file
View File

@@ -0,0 +1,102 @@
#!/bin/bash
source "${BASH_SOURCE[0]%/*}/common.sh"
source "${BASH_SOURCE[0]%/*}/build-supervisor.sh"
set -eE
DOCKER_TIMEOUT=30
DOCKER_PID=0
function cleanup_docker() {
echo "Cleaning up stopped containers..."
docker rm $(docker ps -a -q) || true
}
function run_supervisor() {
mkdir -p /workspaces/test_supervisor
echo "Start Supervisor"
docker run --rm --privileged \
--name hassio_supervisor \
--privileged \
--security-opt seccomp=unconfined \
--security-opt apparmor:unconfined \
-v /run/docker.sock:/run/docker.sock:rw \
-v /run/dbus:/run/dbus:ro \
-v /run/udev:/run/udev:ro \
-v "/workspaces/test_supervisor":/data:rw \
-v /etc/machine-id:/etc/machine-id:ro \
-v /workspaces/supervisor:/usr/src/supervisor \
-e SUPERVISOR_SHARE="/workspaces/test_supervisor" \
-e SUPERVISOR_NAME=hassio_supervisor \
-e SUPERVISOR_DEV=1 \
-e SUPERVISOR_MACHINE="qemux86-64" \
homeassistant/amd64-hassio-supervisor:latest
}
function init_dbus() {
if pgrep dbus-daemon; then
echo "Dbus is running"
return 0
fi
echo "Startup dbus"
mkdir -p /var/lib/dbus
cp -f /etc/machine-id /var/lib/dbus/machine-id
# cleanups
mkdir -p /run/dbus
rm -f /run/dbus/pid
# run
dbus-daemon --system --print-address
}
function init_udev() {
if pgrep systemd-udevd; then
echo "udev is running"
return 0
fi
echo "Startup udev"
# cleanups
mkdir -p /run/udev
# run
/lib/systemd/systemd-udevd --daemon
sleep 3
udevadm trigger && udevadm settle
}
echo "Run Supervisor"
start_docker
trap "stop_docker" ERR
if [ "$( docker container inspect -f '{{.State.Status}}' hassio_supervisor )" == "running" ]; then
echo "Restarting Supervisor"
docker rm -f hassio_supervisor
init_dbus
init_udev
cleanup_lastboot
run_supervisor
stop_docker
else
echo "Starting Supervisor"
docker system prune -f
build_supervisor
cleanup_lastboot
cleanup_docker
init_dbus
init_udev
run_supervisor
stop_docker
fi

View File

@@ -31,24 +31,27 @@ setup(
zip_safe=False,
platforms="any",
packages=[
"supervisor",
"supervisor.docker",
"supervisor.addons",
"supervisor.api",
"supervisor.dbus",
"supervisor.dbus.payloads",
"supervisor.dbus.network",
"supervisor.discovery",
"supervisor.dbus.payloads",
"supervisor.dbus",
"supervisor.discovery.services",
"supervisor.services",
"supervisor.services.modules",
"supervisor.discovery",
"supervisor.docker",
"supervisor.homeassistant",
"supervisor.host",
"supervisor.jobs",
"supervisor.misc",
"supervisor.utils",
"supervisor.plugins",
"supervisor.resolution.evaluations",
"supervisor.resolution",
"supervisor.services.modules",
"supervisor.services",
"supervisor.snapshots",
"supervisor.store",
"supervisor.utils",
"supervisor",
],
include_package_data=True,
)

View File

@@ -2,12 +2,26 @@
import asyncio
from concurrent.futures import ThreadPoolExecutor
import logging
from pathlib import Path
import sys
from supervisor import bootstrap
_LOGGER: logging.Logger = logging.getLogger(__name__)
CONTAINER_OS_STARTUP_CHECK = Path("/run/os/startup-marker")
def run_os_startup_check_cleanup() -> None:
"""Cleanup OS startup check."""
if not CONTAINER_OS_STARTUP_CHECK.exists():
return
try:
CONTAINER_OS_STARTUP_CHECK.unlink()
except OSError as err:
_LOGGER.warning("Not able to remove the startup health file: %s", err)
# pylint: disable=invalid-name
if __name__ == "__main__":
@@ -30,6 +44,9 @@ if __name__ == "__main__":
bootstrap.supervisor_debugger(coresys)
bootstrap.migrate_system_env(coresys)
# Signal health startup for container
run_os_startup_check_cleanup()
_LOGGER.info("Setting up Supervisor")
loop.run_until_complete(coresys.core.setup())
@@ -43,4 +60,4 @@ if __name__ == "__main__":
loop.close()
_LOGGER.info("Closing Supervisor")
sys.exit(0)
sys.exit(coresys.core.exit_code)

View File

@@ -10,6 +10,7 @@ from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import (
AddonConfigurationError,
AddonsError,
AddonsJobError,
AddonsNotSupportedError,
CoreDNSError,
DockerAPIError,
@@ -18,6 +19,8 @@ from ..exceptions import (
HomeAssistantAPIError,
HostAppArmorError,
)
from ..jobs.decorator import Job, JobCondition
from ..resolution.const import ContextType, IssueType, SuggestionType
from ..store.addon import AddonStore
from ..utils import check_exception_chain
from .addon import Addon
@@ -140,6 +143,14 @@ class AddonManager(CoreSysAttributes):
_LOGGER.warning("Can't stop Add-on %s: %s", addon.slug, err)
self.sys_capture_exception(err)
@Job(
conditions=[
JobCondition.FREE_SPACE,
JobCondition.INTERNET_HOST,
JobCondition.HEALTHY,
],
on_condition=AddonsJobError,
)
async def install(self, slug: str) -> None:
"""Install an add-on."""
if slug in self.local:
@@ -234,6 +245,14 @@ class AddonManager(CoreSysAttributes):
_LOGGER.info("Add-on '%s' successfully removed", slug)
@Job(
conditions=[
JobCondition.FREE_SPACE,
JobCondition.INTERNET_HOST,
JobCondition.HEALTHY,
],
on_condition=AddonsJobError,
)
async def update(self, slug: str) -> None:
"""Update add-on."""
if slug not in self.local:
@@ -276,6 +295,14 @@ class AddonManager(CoreSysAttributes):
if last_state == AddonState.STARTED:
await addon.start()
@Job(
conditions=[
JobCondition.FREE_SPACE,
JobCondition.INTERNET_HOST,
JobCondition.HEALTHY,
],
on_condition=AddonsJobError,
)
async def rebuild(self, slug: str) -> None:
"""Perform a rebuild of local build add-on."""
if slug not in self.local:
@@ -311,6 +338,14 @@ class AddonManager(CoreSysAttributes):
if last_state == AddonState.STARTED:
await addon.start()
@Job(
conditions=[
JobCondition.FREE_SPACE,
JobCondition.INTERNET_HOST,
JobCondition.HEALTHY,
],
on_condition=AddonsJobError,
)
async def restore(self, slug: str, tar_file: tarfile.TarFile) -> None:
"""Restore state of an add-on."""
if slug not in self.local:
@@ -333,6 +368,7 @@ class AddonManager(CoreSysAttributes):
with suppress(HomeAssistantAPIError):
await self.sys_ingress.update_hass_panel(addon)
@Job(conditions=[JobCondition.FREE_SPACE, JobCondition.INTERNET_HOST])
async def repair(self) -> None:
"""Repair local add-ons."""
needs_repair: List[Addon] = []
@@ -376,7 +412,12 @@ class AddonManager(CoreSysAttributes):
continue
except DockerError as err:
_LOGGER.warning("Add-on %s is corrupt: %s", addon.slug, err)
self.sys_core.healthy = False
self.sys_resolution.create_issue(
IssueType.CORRUPT_DOCKER,
ContextType.ADDON,
reference=addon.slug,
suggestions=[SuggestionType.EXECUTE_REPAIR],
)
self.sys_capture_exception(err)
else:
self.sys_plugins.dns.add_host(

View File

@@ -10,7 +10,7 @@ import secrets
import shutil
import tarfile
from tempfile import TemporaryDirectory
from typing import Any, Awaitable, Dict, List, Optional
from typing import Any, Awaitable, Dict, List, Optional, Set
import aiohttp
import voluptuous as vol
@@ -55,13 +55,15 @@ from ..exceptions import (
HostAppArmorError,
JsonFileError,
)
from ..hardware.data import Device
from ..utils import check_port
from ..utils.apparmor import adjust_profile
from ..utils.json import read_json_file, write_json_file
from ..utils.tar import atomic_contents_add, secure_path
from .model import AddonModel, Data
from .options import AddonOptions
from .utils import remove_data
from .validate import SCHEMA_ADDON_SNAPSHOT, validate_options
from .validate import SCHEMA_ADDON_SNAPSHOT
_LOGGER: logging.Logger = logging.getLogger(__name__)
@@ -101,7 +103,7 @@ class Addon(AddonModel):
async def load(self) -> None:
"""Async initialize of object."""
with suppress(DockerError):
await self.instance.attach(tag=self.version)
await self.instance.attach(version=self.version)
# Evaluate state
if await self.instance.is_running():
@@ -394,6 +396,20 @@ class Addon(AddonModel):
"""Return path to asound config for Docker."""
return Path(self.sys_config.path_extern_tmp, f"{self.slug}_pulse")
@property
def devices(self) -> Set[Device]:
"""Create a schema for add-on options."""
raw_schema = self.data[ATTR_SCHEMA]
if isinstance(raw_schema, bool) or not raw_schema:
return set()
# Validate devices
options_validator = AddonOptions(self.coresys, raw_schema)
with suppress(vol.Invalid):
options_validator(self.options)
return options_validator.devices
def save_persist(self) -> None:
"""Save data of add-on."""
self.sys_addons.data.save_data()
@@ -442,20 +458,17 @@ class Addon(AddonModel):
async def write_options(self) -> None:
"""Return True if add-on options is written to data."""
schema = self.schema
options = self.options
# Update secrets for validation
await self.sys_homeassistant.secrets.reload()
try:
options = schema(options)
options = self.schema(self.options)
write_json_file(self.path_options, options)
except vol.Invalid as ex:
_LOGGER.error(
"Add-on %s has invalid options: %s",
self.slug,
humanize_error(options, ex),
humanize_error(self.options, ex),
)
except JsonFileError:
_LOGGER.error("Add-on %s can't write options", self.slug)
@@ -538,7 +551,7 @@ class Addon(AddonModel):
# create voluptuous
new_schema = vol.Schema(
vol.All(dict, validate_options(self.coresys, new_raw_schema))
vol.All(dict, AddonOptions(self.coresys, new_raw_schema))
)
# validate
@@ -581,7 +594,7 @@ class Addon(AddonModel):
async def stop(self) -> None:
"""Stop add-on."""
try:
return await self.instance.stop()
await self.instance.stop()
except DockerRequestError as err:
raise AddonsError() from err
except DockerError as err:

View File

@@ -4,6 +4,8 @@ from __future__ import annotations
from pathlib import Path
from typing import TYPE_CHECKING, Dict
from awesomeversion import AwesomeVersion
from ..const import ATTR_ARGS, ATTR_BUILD_FROM, ATTR_SQUASH, META_ADDON
from ..coresys import CoreSys, CoreSysAttributes
from ..utils.json import JsonConfig
@@ -46,11 +48,21 @@ class AddonBuild(JsonConfig, CoreSysAttributes):
"""Return additional Docker build arguments."""
return self._data[ATTR_ARGS]
def get_docker_args(self, version):
@property
def is_valid(self) -> bool:
"""Return true if the build env is valid."""
return all(
[
self.addon.path_location.is_dir(),
Path(self.addon.path_location, "Dockerfile").is_file(),
]
)
def get_docker_args(self, version: AwesomeVersion):
"""Create a dict with Docker build arguments."""
args = {
"path": str(self.addon.path_location),
"tag": f"{self.addon.image}:{version}",
"tag": f"{self.addon.image}:{version!s}",
"pull": True,
"forcerm": True,
"squash": self.squash,

View File

@@ -3,7 +3,7 @@ from abc import ABC, abstractmethod
from pathlib import Path
from typing import Any, Awaitable, Dict, List, Optional
from packaging import version as pkg_version
from awesomeversion import AwesomeVersion, AwesomeVersionException
import voluptuous as vol
from ..const import (
@@ -12,7 +12,6 @@ from ..const import (
ATTR_ARCH,
ATTR_AUDIO,
ATTR_AUTH_API,
ATTR_AUTO_UART,
ATTR_BOOT,
ATTR_DESCRIPTON,
ATTR_DEVICES,
@@ -56,6 +55,7 @@ from ..const import (
ATTR_STDIN,
ATTR_TIMEOUT,
ATTR_TMPFS,
ATTR_UART,
ATTR_UDEV,
ATTR_URL,
ATTR_USB,
@@ -71,7 +71,8 @@ from ..const import (
AddonStartup,
)
from ..coresys import CoreSys, CoreSysAttributes
from .validate import RE_SERVICE, RE_VOLUME, schema_ui_options, validate_options
from .options import AddonOptions, UiOptions
from .validate import RE_SERVICE, RE_VOLUME
Data = Dict[str, Any]
@@ -183,12 +184,12 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_REPOSITORY]
@property
def latest_version(self) -> str:
def latest_version(self) -> AwesomeVersion:
"""Return latest version of add-on."""
return self.data[ATTR_VERSION]
@property
def version(self) -> Optional[str]:
def version(self) -> AwesomeVersion:
"""Return version of add-on."""
return self.data[ATTR_VERSION]
@@ -296,14 +297,9 @@ class AddonModel(CoreSysAttributes, ABC):
return self.data[ATTR_HOST_DBUS]
@property
def devices(self) -> List[str]:
"""Return devices of add-on."""
return self.data.get(ATTR_DEVICES, [])
@property
def tmpfs(self) -> Optional[str]:
"""Return tmpfs of add-on."""
return self.data.get(ATTR_TMPFS)
def static_devices(self) -> List[Path]:
"""Return static devices of add-on."""
return [Path(node) for node in self.data.get(ATTR_DEVICES, [])]
@property
def environment(self) -> Optional[Dict[str, str]]:
@@ -387,7 +383,7 @@ class AddonModel(CoreSysAttributes, ABC):
@property
def with_uart(self) -> bool:
"""Return True if we should map all UART device."""
return self.data[ATTR_AUTO_UART]
return self.data[ATTR_UART]
@property
def with_udev(self) -> bool:
@@ -409,6 +405,11 @@ class AddonModel(CoreSysAttributes, ABC):
"""Return True if the add-on read access to devicetree."""
return self.data[ATTR_DEVICETREE]
@property
def with_tmpfs(self) -> Optional[str]:
"""Return if tmp is in memory of add-on."""
return self.data[ATTR_TMPFS]
@property
def access_auth_api(self) -> bool:
"""Return True if the add-on access to login/auth backend."""
@@ -522,8 +523,8 @@ class AddonModel(CoreSysAttributes, ABC):
raw_schema = self.data[ATTR_SCHEMA]
if isinstance(raw_schema, bool):
return vol.Schema(dict)
return vol.Schema(vol.All(dict, validate_options(self.coresys, raw_schema)))
raw_schema = {}
return vol.Schema(vol.All(dict, AddonOptions(self.coresys, raw_schema)))
@property
def schema_ui(self) -> Optional[List[Dict[str, Any]]]:
@@ -532,7 +533,7 @@ class AddonModel(CoreSysAttributes, ABC):
if isinstance(raw_schema, bool):
return None
return schema_ui_options(raw_schema)
return UiOptions(self.coresys)(raw_schema)
def __eq__(self, other):
"""Compaired add-on objects."""
@@ -554,15 +555,10 @@ class AddonModel(CoreSysAttributes, ABC):
return False
# Home Assistant
version = config.get(ATTR_HOMEASSISTANT)
if version is None or self.sys_homeassistant.version is None:
return True
version: Optional[AwesomeVersion] = config.get(ATTR_HOMEASSISTANT)
try:
return pkg_version.parse(
self.sys_homeassistant.version
) >= pkg_version.parse(version)
except pkg_version.InvalidVersion:
return self.sys_homeassistant.version >= version
except (AwesomeVersionException, TypeError):
return True
def _image(self, config) -> str:

View File

@@ -0,0 +1,381 @@
"""Add-on Options / UI rendering."""
import logging
from pathlib import Path
import re
from typing import Any, Dict, List, Set, Union
import voluptuous as vol
from ..coresys import CoreSys, CoreSysAttributes
from ..exceptions import HardwareNotFound
from ..hardware.const import UdevSubsystem
from ..hardware.data import Device
from ..validate import network_port
_LOGGER: logging.Logger = logging.getLogger(__name__)
_STR = "str"
_INT = "int"
_FLOAT = "float"
_BOOL = "bool"
_PASSWORD = "password"
_EMAIL = "email"
_URL = "url"
_PORT = "port"
_MATCH = "match"
_LIST = "list"
_DEVICE = "device"
RE_SCHEMA_ELEMENT = re.compile(
r"^(?:"
r"|bool"
r"|email"
r"|url"
r"|port"
r"|device(?:\((?P<filter>subsystem=[a-z]+)\))?"
r"|str(?:\((?P<s_min>\d+)?,(?P<s_max>\d+)?\))?"
r"|password(?:\((?P<p_min>\d+)?,(?P<p_max>\d+)?\))?"
r"|int(?:\((?P<i_min>\d+)?,(?P<i_max>\d+)?\))?"
r"|float(?:\((?P<f_min>[\d\.]+)?,(?P<f_max>[\d\.]+)?\))?"
r"|match\((?P<match>.*)\)"
r"|list\((?P<list>.+)\)"
r")\??$"
)
_SCHEMA_LENGTH_PARTS = (
"i_min",
"i_max",
"f_min",
"f_max",
"s_min",
"s_max",
"p_min",
"p_max",
)
class AddonOptions(CoreSysAttributes):
"""Validate Add-ons Options."""
def __init__(
self,
coresys: CoreSys,
raw_schema: Dict[str, Any],
):
"""Validate schema."""
self.coresys: CoreSys = coresys
self.raw_schema: Dict[str, Any] = raw_schema
self.devices: Set[Device] = set()
def __call__(self, struct):
"""Create schema validator for add-ons options."""
options = {}
# read options
for key, value in struct.items():
# Ignore unknown options / remove from list
if key not in self.raw_schema:
_LOGGER.warning("Unknown options %s", key)
continue
typ = self.raw_schema[key]
try:
if isinstance(typ, list):
# nested value list
options[key] = self._nested_validate_list(typ[0], value, key)
elif isinstance(typ, dict):
# nested value dict
options[key] = self._nested_validate_dict(typ, value, key)
else:
# normal value
options[key] = self._single_validate(typ, value, key)
except (IndexError, KeyError):
raise vol.Invalid(f"Type error for {key}") from None
self._check_missing_options(self.raw_schema, options, "root")
return options
# pylint: disable=no-value-for-parameter
def _single_validate(self, typ: str, value: Any, key: str):
"""Validate a single element."""
# if required argument
if value is None:
raise vol.Invalid(f"Missing required option '{key}'") from None
# Lookup secret
if str(value).startswith("!secret "):
secret: str = value.partition(" ")[2]
value = self.sys_homeassistant.secrets.get(secret)
if value is None:
raise vol.Invalid(f"Unknown secret {secret}") from None
# parse extend data from type
match = RE_SCHEMA_ELEMENT.match(typ)
if not match:
raise vol.Invalid(f"Unknown type {typ}") from None
# prepare range
range_args = {}
for group_name in _SCHEMA_LENGTH_PARTS:
group_value = match.group(group_name)
if group_value:
range_args[group_name[2:]] = float(group_value)
if typ.startswith(_STR) or typ.startswith(_PASSWORD):
return vol.All(str(value), vol.Range(**range_args))(value)
elif typ.startswith(_INT):
return vol.All(vol.Coerce(int), vol.Range(**range_args))(value)
elif typ.startswith(_FLOAT):
return vol.All(vol.Coerce(float), vol.Range(**range_args))(value)
elif typ.startswith(_BOOL):
return vol.Boolean()(value)
elif typ.startswith(_EMAIL):
return vol.Email()(value)
elif typ.startswith(_URL):
return vol.Url()(value)
elif typ.startswith(_PORT):
return network_port(value)
elif typ.startswith(_MATCH):
return vol.Match(match.group("match"))(str(value))
elif typ.startswith(_LIST):
return vol.In(match.group("list").split("|"))(str(value))
elif typ.startswith(_DEVICE):
try:
device = self.sys_hardware.get_by_path(Path(value))
except HardwareNotFound:
raise vol.Invalid(f"Device {value} does not exists!") from None
# Have filter
if match.group("filter"):
str_filter = match.group("filter")
device_filter = _create_device_filter(str_filter)
if device not in self.sys_hardware.filter_devices(**device_filter):
raise vol.Invalid(
f"Device {value} don't match the filter {str_filter}!"
)
# Device valid
self.devices.add(device)
return str(device.path)
raise vol.Invalid(f"Fatal error for {key} type {typ}") from None
def _nested_validate_list(self, typ: Any, data_list: List[Any], key: str):
"""Validate nested items."""
options = []
# Make sure it is a list
if not isinstance(data_list, list):
raise vol.Invalid(f"Invalid list for {key}") from None
# Process list
for element in data_list:
# Nested?
if isinstance(typ, dict):
c_options = self._nested_validate_dict(typ, element, key)
options.append(c_options)
else:
options.append(self._single_validate(typ, element, key))
return options
def _nested_validate_dict(
self, typ: Dict[Any, Any], data_dict: Dict[Any, Any], key: str
):
"""Validate nested items."""
options = {}
# Make sure it is a dict
if not isinstance(data_dict, dict):
raise vol.Invalid(f"Invalid dict for {key}") from None
# Process dict
for c_key, c_value in data_dict.items():
# Ignore unknown options / remove from list
if c_key not in typ:
_LOGGER.warning("Unknown options %s", c_key)
continue
# Nested?
if isinstance(typ[c_key], list):
options[c_key] = self._nested_validate_list(
typ[c_key][0], c_value, c_key
)
else:
options[c_key] = self._single_validate(typ[c_key], c_value, c_key)
self._check_missing_options(typ, options, key)
return options
def _check_missing_options(
self, origin: Dict[Any, Any], exists: Dict[Any, Any], root: str
) -> None:
"""Check if all options are exists."""
missing = set(origin) - set(exists)
for miss_opt in missing:
if isinstance(origin[miss_opt], str) and origin[miss_opt].endswith("?"):
continue
raise vol.Invalid(f"Missing option {miss_opt} in {root}") from None
class UiOptions(CoreSysAttributes):
"""Render UI Add-ons Options."""
def __init__(self, coresys: CoreSys) -> None:
"""Initialize UI option render."""
self.coresys = coresys
def __call__(self, raw_schema: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Generate UI schema."""
ui_schema: List[Dict[str, Any]] = []
# read options
for key, value in raw_schema.items():
if isinstance(value, list):
# nested value list
self._nested_ui_list(ui_schema, value, key)
elif isinstance(value, dict):
# nested value dict
self._nested_ui_dict(ui_schema, value, key)
else:
# normal value
self._single_ui_option(ui_schema, value, key)
return ui_schema
def _single_ui_option(
self,
ui_schema: List[Dict[str, Any]],
value: str,
key: str,
multiple: bool = False,
) -> None:
"""Validate a single element."""
ui_node: Dict[str, Union[str, bool, float, List[str]]] = {"name": key}
# If multiple
if multiple:
ui_node["multiple"] = True
# Parse extend data from type
match = RE_SCHEMA_ELEMENT.match(value)
if not match:
return
# Prepare range
for group_name in _SCHEMA_LENGTH_PARTS:
group_value = match.group(group_name)
if not group_value:
continue
if group_name[2:] == "min":
ui_node["lengthMin"] = float(group_value)
elif group_name[2:] == "max":
ui_node["lengthMax"] = float(group_value)
# If required
if value.endswith("?"):
ui_node["optional"] = True
else:
ui_node["required"] = True
# Data types
if value.startswith(_STR):
ui_node["type"] = "string"
elif value.startswith(_PASSWORD):
ui_node["type"] = "string"
ui_node["format"] = "password"
elif value.startswith(_INT):
ui_node["type"] = "integer"
elif value.startswith(_FLOAT):
ui_node["type"] = "float"
elif value.startswith(_BOOL):
ui_node["type"] = "boolean"
elif value.startswith(_EMAIL):
ui_node["type"] = "string"
ui_node["format"] = "email"
elif value.startswith(_URL):
ui_node["type"] = "string"
ui_node["format"] = "url"
elif value.startswith(_PORT):
ui_node["type"] = "integer"
elif value.startswith(_MATCH):
ui_node["type"] = "string"
elif value.startswith(_LIST):
ui_node["type"] = "select"
ui_node["options"] = match.group("list").split("|")
elif value.startswith(_DEVICE):
ui_node["type"] = "select"
# Have filter
if match.group("filter"):
device_filter = _create_device_filter(match.group("filter"))
ui_node["options"] = [
(device.by_id or device.path).as_posix()
for device in self.sys_hardware.filter_devices(**device_filter)
]
else:
ui_node["options"] = [
(device.by_id or device.path).as_posix()
for device in self.sys_hardware.devices()
]
ui_schema.append(ui_node)
def _nested_ui_list(
self,
ui_schema: List[Dict[str, Any]],
option_list: List[Any],
key: str,
) -> None:
"""UI nested list items."""
try:
element = option_list[0]
except IndexError:
_LOGGER.error("Invalid schema %s", key)
return
if isinstance(element, dict):
self._nested_ui_dict(ui_schema, element, key, multiple=True)
else:
self._single_ui_option(ui_schema, element, key, multiple=True)
def _nested_ui_dict(
self,
ui_schema: List[Dict[str, Any]],
option_dict: Dict[str, Any],
key: str,
multiple: bool = False,
) -> None:
"""UI nested dict items."""
ui_node = {
"name": key,
"type": "schema",
"optional": True,
"multiple": multiple,
}
nested_schema = []
for c_key, c_value in option_dict.items():
# Nested?
if isinstance(c_value, list):
self._nested_ui_list(nested_schema, c_value, c_key)
else:
self._single_ui_option(nested_schema, c_value, c_key)
ui_node["schema"] = nested_schema
ui_schema.append(ui_node)
def _create_device_filter(str_filter: str) -> Dict[str, Any]:
"""Generate device Filter."""
raw_filter = dict(value.split("=") for value in str_filter.split(";"))
clean_filter = {}
for key, value in raw_filter.items():
if key == "subsystem":
clean_filter[key] = UdevSubsystem(value)
else:
clean_filter[key] = value
return clean_filter

View File

@@ -2,7 +2,7 @@
import logging
import re
import secrets
from typing import Any, Dict, List, Union
from typing import Any, Dict
import uuid
import voluptuous as vol
@@ -18,7 +18,6 @@ from ..const import (
ATTR_AUDIO_INPUT,
ATTR_AUDIO_OUTPUT,
ATTR_AUTH_API,
ATTR_AUTO_UART,
ATTR_AUTO_UPDATE,
ATTR_BOOT,
ATTR_BUILD_FROM,
@@ -73,6 +72,7 @@ from ..const import (
ATTR_SYSTEM,
ATTR_TIMEOUT,
ATTR_TMPFS,
ATTR_UART,
ATTR_UDEV,
ATTR_URL,
ATTR_USB,
@@ -90,9 +90,9 @@ from ..const import (
AddonStartup,
AddonState,
)
from ..coresys import CoreSys
from ..discovery.validate import valid_discovery_service
from ..validate import (
docker_image,
docker_ports,
docker_ports_description,
network_port,
@@ -100,51 +100,14 @@ from ..validate import (
uuid_match,
version_tag,
)
from .options import RE_SCHEMA_ELEMENT
_LOGGER: logging.Logger = logging.getLogger(__name__)
RE_VOLUME = re.compile(r"^(config|ssl|addons|backup|share|media)(?::(rw|ro))?$")
RE_SERVICE = re.compile(r"^(?P<service>mqtt|mysql):(?P<rights>provide|want|need)$")
V_STR = "str"
V_INT = "int"
V_FLOAT = "float"
V_BOOL = "bool"
V_PASSWORD = "password"
V_EMAIL = "email"
V_URL = "url"
V_PORT = "port"
V_MATCH = "match"
V_LIST = "list"
RE_SCHEMA_ELEMENT = re.compile(
r"^(?:"
r"|bool"
r"|email"
r"|url"
r"|port"
r"|str(?:\((?P<s_min>\d+)?,(?P<s_max>\d+)?\))?"
r"|password(?:\((?P<p_min>\d+)?,(?P<p_max>\d+)?\))?"
r"|int(?:\((?P<i_min>\d+)?,(?P<i_max>\d+)?\))?"
r"|float(?:\((?P<f_min>[\d\.]+)?,(?P<f_max>[\d\.]+)?\))?"
r"|match\((?P<match>.*)\)"
r"|list\((?P<list>.+)\)"
r")\??$"
)
_SCHEMA_LENGTH_PARTS = (
"i_min",
"i_max",
"f_min",
"f_max",
"s_min",
"s_max",
"p_min",
"p_max",
)
RE_DOCKER_IMAGE = re.compile(r"^([a-zA-Z\-\.:\d{}]+/)*?([\-\w{}]+)/([\-\w{}]+)$")
RE_DOCKER_IMAGE_BUILD = re.compile(
r"^([a-zA-Z\-\.:\d{}]+/)*?([\-\w{}]+)/([\-\w{}]+)(:[\.\-\w{}]+)?$"
)
@@ -155,6 +118,7 @@ RE_MACHINE = re.compile(
r"^!?(?:"
r"|intel-nuc"
r"|odroid-c2"
r"|odroid-c4"
r"|odroid-n2"
r"|odroid-xu"
r"|qemuarm-64"
@@ -172,27 +136,74 @@ RE_MACHINE = re.compile(
)
def _simple_startup(value) -> str:
"""Define startup schema."""
if value == "before":
return AddonStartup.SERVICES.value
if value == "after":
return AddonStartup.APPLICATION.value
return value
def _migrate_addon_config(protocol=False):
"""Migrate addon config."""
def _migrate(config: Dict[str, Any]):
name = config.get(ATTR_NAME)
if not name:
raise vol.Invalid("Invalid Add-on config!")
# Startup 2018-03-30
if config.get(ATTR_STARTUP) in ("before", "after"):
value = config[ATTR_STARTUP]
if protocol:
_LOGGER.warning(
"Add-on config 'startup' with '%s' is deprecated. Please report this to the maintainer of %s",
value,
name,
)
if value == "before":
config[ATTR_STARTUP] = AddonStartup.SERVICES.value
elif value == "after":
config[ATTR_STARTUP] = AddonStartup.APPLICATION.value
# UART 2021-01-20
if "auto_uart" in config:
if protocol:
_LOGGER.warning(
"Add-on config 'auto_uart' is deprecated, use 'uart'. Please report this to the maintainer of %s",
name,
)
config[ATTR_UART] = config.pop("auto_uart")
# Device 2021-01-20
if ATTR_DEVICES in config and any(":" in line for line in config[ATTR_DEVICES]):
if protocol:
_LOGGER.warning(
"Add-on config 'devices' use a deprecated format, the new format uses a list of paths only. Please report this to the maintainer of %s",
name,
)
config[ATTR_DEVICES] = [line.split(":")[0] for line in config[ATTR_DEVICES]]
# TMPFS 2021-02-01
if ATTR_TMPFS in config and not isinstance(config[ATTR_TMPFS], bool):
if protocol:
_LOGGER.warning(
"Add-on config 'tmpfs' use a deprecated format, new it's only a boolean. Please report this to the maintainer of %s",
name,
)
config[ATTR_TMPFS] = True
return config
return _migrate
# pylint: disable=no-value-for-parameter
SCHEMA_ADDON_CONFIG = vol.Schema(
_SCHEMA_ADDON_CONFIG = vol.Schema(
{
vol.Required(ATTR_NAME): vol.Coerce(str),
vol.Required(ATTR_VERSION): vol.All(version_tag, str),
vol.Required(ATTR_SLUG): vol.Coerce(str),
vol.Required(ATTR_DESCRIPTON): vol.Coerce(str),
vol.Required(ATTR_NAME): str,
vol.Required(ATTR_VERSION): version_tag,
vol.Required(ATTR_SLUG): str,
vol.Required(ATTR_DESCRIPTON): str,
vol.Required(ATTR_ARCH): [vol.In(ARCH_ALL)],
vol.Optional(ATTR_MACHINE): vol.All([vol.Match(RE_MACHINE)], vol.Unique()),
vol.Optional(ATTR_URL): vol.Url(),
vol.Required(ATTR_STARTUP): vol.All(_simple_startup, vol.Coerce(AddonStartup)),
vol.Required(ATTR_BOOT): vol.Coerce(AddonBoot),
vol.Optional(ATTR_STARTUP, default=AddonStartup.APPLICATION): vol.Coerce(
AddonStartup
),
vol.Optional(ATTR_BOOT, default=AddonBoot.AUTO): vol.Coerce(AddonBoot),
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),
@@ -208,21 +219,20 @@ SCHEMA_ADDON_CONFIG = vol.Schema(
vol.Optional(ATTR_INGRESS_PORT, default=8099): vol.Any(
network_port, vol.Equal(0)
),
vol.Optional(ATTR_INGRESS_ENTRY): vol.Coerce(str),
vol.Optional(ATTR_PANEL_ICON, default="mdi:puzzle"): vol.Coerce(str),
vol.Optional(ATTR_PANEL_TITLE): vol.Coerce(str),
vol.Optional(ATTR_INGRESS_ENTRY): str,
vol.Optional(ATTR_PANEL_ICON, default="mdi:puzzle"): str,
vol.Optional(ATTR_PANEL_TITLE): str,
vol.Optional(ATTR_PANEL_ADMIN, default=True): vol.Boolean(),
vol.Optional(ATTR_HOMEASSISTANT): vol.Maybe(vol.Coerce(str)),
vol.Optional(ATTR_HOMEASSISTANT): vol.Maybe(version_tag),
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
vol.Optional(ATTR_HOST_PID, default=False): vol.Boolean(),
vol.Optional(ATTR_HOST_IPC, default=False): vol.Boolean(),
vol.Optional(ATTR_HOST_DBUS, default=False): vol.Boolean(),
vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")],
vol.Optional(ATTR_AUTO_UART, default=False): vol.Boolean(),
vol.Optional(ATTR_DEVICES): [str],
vol.Optional(ATTR_UDEV, default=False): vol.Boolean(),
vol.Optional(ATTR_TMPFS): vol.Match(r"^size=(\d)*[kmg](,uid=\d{1,4})?(,rw)?$"),
vol.Optional(ATTR_TMPFS, default=False): vol.Boolean(),
vol.Optional(ATTR_MAP, default=list): [vol.Match(RE_VOLUME)],
vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)},
vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): str},
vol.Optional(ATTR_PRIVILEGED): [vol.In(PRIVILEGED_ALL)],
vol.Optional(ATTR_APPARMOR, default=True): vol.Boolean(),
vol.Optional(ATTR_FULL_ACCESS, default=False): vol.Boolean(),
@@ -230,6 +240,7 @@ SCHEMA_ADDON_CONFIG = vol.Schema(
vol.Optional(ATTR_VIDEO, default=False): vol.Boolean(),
vol.Optional(ATTR_GPIO, default=False): vol.Boolean(),
vol.Optional(ATTR_USB, default=False): vol.Boolean(),
vol.Optional(ATTR_UART, default=False): vol.Boolean(),
vol.Optional(ATTR_DEVICETREE, default=False): vol.Boolean(),
vol.Optional(ATTR_KERNEL_MODULES, default=False): vol.Boolean(),
vol.Optional(ATTR_HASSIO_API, default=False): vol.Boolean(),
@@ -241,32 +252,26 @@ SCHEMA_ADDON_CONFIG = vol.Schema(
vol.Optional(ATTR_AUTH_API, default=False): vol.Boolean(),
vol.Optional(ATTR_SERVICES): [vol.Match(RE_SERVICE)],
vol.Optional(ATTR_DISCOVERY): [valid_discovery_service],
vol.Optional(ATTR_SNAPSHOT_EXCLUDE): [vol.Coerce(str)],
vol.Required(ATTR_OPTIONS): dict,
vol.Required(ATTR_SCHEMA): vol.Any(
vol.Optional(ATTR_SNAPSHOT_EXCLUDE): [str],
vol.Optional(ATTR_OPTIONS, default={}): dict,
vol.Optional(ATTR_SCHEMA, default={}): vol.Any(
vol.Schema(
{
vol.Coerce(str): vol.Any(
str: vol.Any(
SCHEMA_ELEMENT,
[
vol.Any(
SCHEMA_ELEMENT,
{
vol.Coerce(str): vol.Any(
SCHEMA_ELEMENT, [SCHEMA_ELEMENT]
)
},
{str: vol.Any(SCHEMA_ELEMENT, [SCHEMA_ELEMENT])},
)
],
vol.Schema(
{vol.Coerce(str): vol.Any(SCHEMA_ELEMENT, [SCHEMA_ELEMENT])}
),
vol.Schema({str: vol.Any(SCHEMA_ELEMENT, [SCHEMA_ELEMENT])}),
)
}
),
False,
),
vol.Optional(ATTR_IMAGE): vol.Match(RE_DOCKER_IMAGE),
vol.Optional(ATTR_IMAGE): docker_image,
vol.Optional(ATTR_TIMEOUT, default=10): vol.All(
vol.Coerce(int), vol.Range(min=10, max=300)
),
@@ -274,6 +279,8 @@ SCHEMA_ADDON_CONFIG = vol.Schema(
extra=vol.REMOVE_EXTRA,
)
SCHEMA_ADDON_CONFIG = vol.All(_migrate_addon_config(True), _SCHEMA_ADDON_CONFIG)
# pylint: disable=no-value-for-parameter
SCHEMA_BUILD_CONFIG = vol.Schema(
@@ -293,19 +300,17 @@ SCHEMA_BUILD_CONFIG = vol.Schema(
# pylint: disable=no-value-for-parameter
SCHEMA_ADDON_USER = vol.Schema(
{
vol.Required(ATTR_VERSION): vol.Coerce(str),
vol.Optional(ATTR_IMAGE): vol.Coerce(str),
vol.Required(ATTR_VERSION): version_tag,
vol.Optional(ATTR_IMAGE): docker_image,
vol.Optional(ATTR_UUID, default=lambda: uuid.uuid4().hex): uuid_match,
vol.Optional(ATTR_ACCESS_TOKEN): token,
vol.Optional(ATTR_INGRESS_TOKEN, default=secrets.token_urlsafe): vol.Coerce(
str
),
vol.Optional(ATTR_INGRESS_TOKEN, default=secrets.token_urlsafe): str,
vol.Optional(ATTR_OPTIONS, default=dict): dict,
vol.Optional(ATTR_AUTO_UPDATE, default=False): vol.Boolean(),
vol.Optional(ATTR_BOOT): vol.Coerce(AddonBoot),
vol.Optional(ATTR_NETWORK): docker_ports,
vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(vol.Coerce(str)),
vol.Optional(ATTR_AUDIO_INPUT): vol.Maybe(vol.Coerce(str)),
vol.Optional(ATTR_AUDIO_OUTPUT): vol.Maybe(str),
vol.Optional(ATTR_AUDIO_INPUT): vol.Maybe(str),
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(),
@@ -314,19 +319,23 @@ SCHEMA_ADDON_USER = vol.Schema(
)
SCHEMA_ADDON_SYSTEM = SCHEMA_ADDON_CONFIG.extend(
{
vol.Required(ATTR_LOCATON): vol.Coerce(str),
vol.Required(ATTR_REPOSITORY): vol.Coerce(str),
}
SCHEMA_ADDON_SYSTEM = vol.All(
_migrate_addon_config(),
_SCHEMA_ADDON_CONFIG.extend(
{
vol.Required(ATTR_LOCATON): str,
vol.Required(ATTR_REPOSITORY): str,
}
),
)
SCHEMA_ADDONS_FILE = vol.Schema(
{
vol.Optional(ATTR_USER, default=dict): {vol.Coerce(str): SCHEMA_ADDON_USER},
vol.Optional(ATTR_SYSTEM, default=dict): {vol.Coerce(str): SCHEMA_ADDON_SYSTEM},
}
vol.Optional(ATTR_USER, default=dict): {str: SCHEMA_ADDON_USER},
vol.Optional(ATTR_SYSTEM, default=dict): {str: SCHEMA_ADDON_SYSTEM},
},
extra=vol.REMOVE_EXTRA,
)
@@ -335,263 +344,7 @@ SCHEMA_ADDON_SNAPSHOT = vol.Schema(
vol.Required(ATTR_USER): SCHEMA_ADDON_USER,
vol.Required(ATTR_SYSTEM): SCHEMA_ADDON_SYSTEM,
vol.Required(ATTR_STATE): vol.Coerce(AddonState),
vol.Required(ATTR_VERSION): vol.Coerce(str),
vol.Required(ATTR_VERSION): version_tag,
},
extra=vol.REMOVE_EXTRA,
)
def validate_options(coresys: CoreSys, raw_schema: Dict[str, Any]):
"""Validate schema."""
def validate(struct):
"""Create schema validator for add-ons options."""
options = {}
# read options
for key, value in struct.items():
# Ignore unknown options / remove from list
if key not in raw_schema:
_LOGGER.warning("Unknown options %s", key)
continue
typ = raw_schema[key]
try:
if isinstance(typ, list):
# nested value list
options[key] = _nested_validate_list(coresys, typ[0], value, key)
elif isinstance(typ, dict):
# nested value dict
options[key] = _nested_validate_dict(coresys, typ, value, key)
else:
# normal value
options[key] = _single_validate(coresys, typ, value, key)
except (IndexError, KeyError):
raise vol.Invalid(f"Type error for {key}") from None
_check_missing_options(raw_schema, options, "root")
return options
return validate
# pylint: disable=no-value-for-parameter
# pylint: disable=inconsistent-return-statements
def _single_validate(coresys: CoreSys, typ: str, value: Any, key: str):
"""Validate a single element."""
# if required argument
if value is None:
raise vol.Invalid(f"Missing required option '{key}'") from None
# Lookup secret
if str(value).startswith("!secret "):
secret: str = value.partition(" ")[2]
value = coresys.homeassistant.secrets.get(secret)
if value is None:
raise vol.Invalid(f"Unknown secret {secret}") from None
# parse extend data from type
match = RE_SCHEMA_ELEMENT.match(typ)
if not match:
raise vol.Invalid(f"Unknown type {typ}") from None
# prepare range
range_args = {}
for group_name in _SCHEMA_LENGTH_PARTS:
group_value = match.group(group_name)
if group_value:
range_args[group_name[2:]] = float(group_value)
if typ.startswith(V_STR) or typ.startswith(V_PASSWORD):
return vol.All(str(value), vol.Range(**range_args))(value)
elif typ.startswith(V_INT):
return vol.All(vol.Coerce(int), vol.Range(**range_args))(value)
elif typ.startswith(V_FLOAT):
return vol.All(vol.Coerce(float), vol.Range(**range_args))(value)
elif typ.startswith(V_BOOL):
return vol.Boolean()(value)
elif typ.startswith(V_EMAIL):
return vol.Email()(value)
elif typ.startswith(V_URL):
return vol.Url()(value)
elif typ.startswith(V_PORT):
return network_port(value)
elif typ.startswith(V_MATCH):
return vol.Match(match.group("match"))(str(value))
elif typ.startswith(V_LIST):
return vol.In(match.group("list").split("|"))(str(value))
raise vol.Invalid(f"Fatal error for {key} type {typ}") from None
def _nested_validate_list(coresys, typ, data_list, key):
"""Validate nested items."""
options = []
# Make sure it is a list
if not isinstance(data_list, list):
raise vol.Invalid(f"Invalid list for {key}") from None
# Process list
for element in data_list:
# Nested?
if isinstance(typ, dict):
c_options = _nested_validate_dict(coresys, typ, element, key)
options.append(c_options)
else:
options.append(_single_validate(coresys, typ, element, key))
return options
def _nested_validate_dict(coresys, typ, data_dict, key):
"""Validate nested items."""
options = {}
# Make sure it is a dict
if not isinstance(data_dict, dict):
raise vol.Invalid(f"Invalid dict for {key}") from None
# Process dict
for c_key, c_value in data_dict.items():
# Ignore unknown options / remove from list
if c_key not in typ:
_LOGGER.warning("Unknown options %s", c_key)
continue
# Nested?
if isinstance(typ[c_key], list):
options[c_key] = _nested_validate_list(
coresys, typ[c_key][0], c_value, c_key
)
else:
options[c_key] = _single_validate(coresys, typ[c_key], c_value, c_key)
_check_missing_options(typ, options, key)
return options
def _check_missing_options(origin, exists, root):
"""Check if all options are exists."""
missing = set(origin) - set(exists)
for miss_opt in missing:
if isinstance(origin[miss_opt], str) and origin[miss_opt].endswith("?"):
continue
raise vol.Invalid(f"Missing option {miss_opt} in {root}") from None
def schema_ui_options(raw_schema: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Generate UI schema."""
ui_schema: List[Dict[str, Any]] = []
# read options
for key, value in raw_schema.items():
if isinstance(value, list):
# nested value list
_nested_ui_list(ui_schema, value, key)
elif isinstance(value, dict):
# nested value dict
_nested_ui_dict(ui_schema, value, key)
else:
# normal value
_single_ui_option(ui_schema, value, key)
return ui_schema
def _single_ui_option(
ui_schema: List[Dict[str, Any]], value: str, key: str, multiple: bool = False
) -> None:
"""Validate a single element."""
ui_node: Dict[str, Union[str, bool, float, List[str]]] = {"name": key}
# If multiple
if multiple:
ui_node["multiple"] = True
# Parse extend data from type
match = RE_SCHEMA_ELEMENT.match(value)
if not match:
return
# Prepare range
for group_name in _SCHEMA_LENGTH_PARTS:
group_value = match.group(group_name)
if not group_value:
continue
if group_name[2:] == "min":
ui_node["lengthMin"] = float(group_value)
elif group_name[2:] == "max":
ui_node["lengthMax"] = float(group_value)
# If required
if value.endswith("?"):
ui_node["optional"] = True
else:
ui_node["required"] = True
# Data types
if value.startswith(V_STR):
ui_node["type"] = "string"
elif value.startswith(V_PASSWORD):
ui_node["type"] = "string"
ui_node["format"] = "password"
elif value.startswith(V_INT):
ui_node["type"] = "integer"
elif value.startswith(V_FLOAT):
ui_node["type"] = "float"
elif value.startswith(V_BOOL):
ui_node["type"] = "boolean"
elif value.startswith(V_EMAIL):
ui_node["type"] = "string"
ui_node["format"] = "email"
elif value.startswith(V_URL):
ui_node["type"] = "string"
ui_node["format"] = "url"
elif value.startswith(V_PORT):
ui_node["type"] = "integer"
elif value.startswith(V_MATCH):
ui_node["type"] = "string"
elif value.startswith(V_LIST):
ui_node["type"] = "select"
ui_node["options"] = match.group("list").split("|")
ui_schema.append(ui_node)
def _nested_ui_list(
ui_schema: List[Dict[str, Any]], option_list: List[Any], key: str
) -> None:
"""UI nested list items."""
try:
element = option_list[0]
except IndexError:
_LOGGER.error("Invalid schema %s", key)
return
if isinstance(element, dict):
_nested_ui_dict(ui_schema, element, key, multiple=True)
else:
_single_ui_option(ui_schema, element, key, multiple=True)
def _nested_ui_dict(
ui_schema: List[Dict[str, Any]],
option_dict: Dict[str, Any],
key: str,
multiple: bool = False,
) -> None:
"""UI nested dict items."""
ui_node = {"name": key, "type": "schema", "optional": True, "multiple": multiple}
nested_schema = []
for c_key, c_value in option_dict.items():
# Nested?
if isinstance(c_value, list):
_nested_ui_list(nested_schema, c_value, c_key)
else:
_single_ui_option(nested_schema, c_value, c_key)
ui_node["schema"] = nested_schema
ui_schema.append(ui_node)

View File

@@ -18,6 +18,7 @@ from .homeassistant import APIHomeAssistant
from .host import APIHost
from .info import APIInfo
from .ingress import APIIngress
from .jobs import APIJobs
from .multicast import APIMulticast
from .network import APINetwork
from .observer import APIObserver
@@ -72,6 +73,7 @@ class RestAPI(CoreSysAttributes):
self._register_network()
self._register_observer()
self._register_os()
self._register_jobs()
self._register_panel()
self._register_proxy()
self._register_resolution()
@@ -110,6 +112,7 @@ class RestAPI(CoreSysAttributes):
self.webapp.add_routes(
[
web.get("/network/info", api_network.info),
web.post("/network/reload", api_network.reload),
web.get(
"/network/interface/{interface}/info", api_network.interface_info
),
@@ -117,6 +120,14 @@ class RestAPI(CoreSysAttributes):
"/network/interface/{interface}/update",
api_network.interface_update,
),
web.get(
"/network/interface/{interface}/accesspoints",
api_network.scan_accesspoints,
),
web.post(
"/network/interface/{interface}/vlan/{vlan}",
api_network.create_vlan,
),
]
)
@@ -133,6 +144,19 @@ class RestAPI(CoreSysAttributes):
]
)
def _register_jobs(self) -> None:
"""Register Jobs functions."""
api_jobs = APIJobs()
api_jobs.coresys = self.coresys
self.webapp.add_routes(
[
web.get("/jobs/info", api_jobs.info),
web.post("/jobs/options", api_jobs.options),
web.post("/jobs/reset", api_jobs.reset),
]
)
def _register_cli(self) -> None:
"""Register HA cli functions."""
api_cli = APICli()
@@ -224,6 +248,7 @@ class RestAPI(CoreSysAttributes):
self.webapp.add_routes(
[
web.get("/auth", api_auth.auth),
web.post("/auth", api_auth.auth),
web.post("/auth/reset", api_auth.reset),
web.delete("/auth/cache", api_auth.cache),
@@ -243,6 +268,7 @@ class RestAPI(CoreSysAttributes):
web.get("/supervisor/logs", api_supervisor.logs),
web.post("/supervisor/update", api_supervisor.update),
web.post("/supervisor/reload", api_supervisor.reload),
web.post("/supervisor/restart", api_supervisor.restart),
web.post("/supervisor/options", api_supervisor.options),
web.post("/supervisor/repair", api_supervisor.repair),
]
@@ -342,6 +368,7 @@ class RestAPI(CoreSysAttributes):
self.webapp.add_routes(
[
web.post("/ingress/session", api_ingress.create_session),
web.post("/ingress/validate_session", api_ingress.validate_session),
web.get("/ingress/panels", api_ingress.panels),
web.view("/ingress/{token}/{path:.*}", api_ingress.handler),
]

View File

@@ -82,6 +82,7 @@ from ..const import (
ATTR_STARTUP,
ATTR_STATE,
ATTR_STDIN,
ATTR_UART,
ATTR_UDEV,
ATTR_UPDATE_AVAILABLE,
ATTR_URL,
@@ -237,7 +238,7 @@ class APIAddons(CoreSysAttributes):
ATTR_PRIVILEGED: addon.privileged,
ATTR_FULL_ACCESS: addon.with_full_access,
ATTR_APPARMOR: addon.apparmor,
ATTR_DEVICES: _pretty_devices(addon),
ATTR_DEVICES: addon.static_devices,
ATTR_ICON: addon.with_icon,
ATTR_LOGO: addon.with_logo,
ATTR_CHANGELOG: addon.with_changelog,
@@ -250,6 +251,7 @@ class APIAddons(CoreSysAttributes):
ATTR_HOMEASSISTANT_API: addon.access_homeassistant_api,
ATTR_GPIO: addon.with_gpio,
ATTR_USB: addon.with_usb,
ATTR_UART: addon.with_uart,
ATTR_KERNEL_MODULES: addon.with_kernel_modules,
ATTR_DEVICETREE: addon.with_devicetree,
ATTR_UDEV: addon.with_udev,
@@ -286,6 +288,8 @@ class APIAddons(CoreSysAttributes):
ATTR_VERSION: addon.version,
ATTR_UPDATE_AVAILABLE: addon.need_update,
ATTR_WATCHDOG: addon.watchdog,
ATTR_DEVICES: addon.static_devices
+ [device.path for device in addon.devices],
}
)

View File

@@ -29,6 +29,10 @@ SCHEMA_PASSWORD_RESET = vol.Schema(
}
)
REALM_HEADER: Dict[str, str] = {
WWW_AUTHENTICATE: 'Basic realm="Home Assistant Authentication"'
}
class APIAuth(CoreSysAttributes):
"""Handle RESTful API for auth functions."""
@@ -63,7 +67,9 @@ class APIAuth(CoreSysAttributes):
# BasicAuth
if AUTHORIZATION in request.headers:
return await self._process_basic(request, addon)
if not await self._process_basic(request, addon):
raise HTTPUnauthorized(headers=REALM_HEADER)
return True
# Json
if request.headers.get(CONTENT_TYPE) == CONTENT_TYPE_JSON:
@@ -75,9 +81,7 @@ class APIAuth(CoreSysAttributes):
data = await request.post()
return await self._process_dict(request, addon, data)
raise HTTPUnauthorized(
headers={WWW_AUTHENTICATE: 'Basic realm="Home Assistant Authentication"'}
)
raise HTTPUnauthorized(headers=REALM_HEADER)
@api_process
async def reset(self, request: web.Request) -> None:

View File

@@ -1,50 +1,46 @@
"""Init file for Supervisor hardware RESTful API."""
import asyncio
import logging
from typing import Any, Awaitable, Dict, List
from typing import Any, Awaitable, Dict
from aiohttp import web
from ..const import (
ATTR_AUDIO,
ATTR_DISK,
ATTR_GPIO,
ATTR_INPUT,
ATTR_OUTPUT,
ATTR_SERIAL,
ATTR_USB,
)
from ..const import ATTR_AUDIO, ATTR_DEVICES, ATTR_INPUT, ATTR_NAME, ATTR_OUTPUT
from ..coresys import CoreSysAttributes
from ..hardware.const import (
ATTR_ATTRIBUTES,
ATTR_BY_ID,
ATTR_DEV_PATH,
ATTR_SUBSYSTEM,
ATTR_SYSFS,
)
from ..hardware.data import Device
from .utils import api_process
_LOGGER: logging.Logger = logging.getLogger(__name__)
def device_struct(device: Device) -> Dict[str, Any]:
"""Return a dict with information of a interface to be used in th API."""
return {
ATTR_NAME: device.name,
ATTR_SYSFS: device.sysfs,
ATTR_DEV_PATH: device.path,
ATTR_SUBSYSTEM: device.subsystem,
ATTR_BY_ID: device.by_id,
ATTR_ATTRIBUTES: device.attributes,
}
class APIHardware(CoreSysAttributes):
"""Handle RESTful API for hardware functions."""
@api_process
async def info(self, request: web.Request) -> Dict[str, Any]:
"""Show hardware info."""
serial: List[str] = []
# Create Serial list with device links
for device in self.sys_hardware.serial_devices:
serial.append(device.path.as_posix())
for link in device.links:
serial.append(link.as_posix())
return {
ATTR_SERIAL: serial,
ATTR_INPUT: list(self.sys_hardware.input_devices),
ATTR_DISK: [
device.path.as_posix() for device in self.sys_hardware.disk_devices
],
ATTR_GPIO: list(self.sys_hardware.gpio_devices),
ATTR_USB: [
device.path.as_posix() for device in self.sys_hardware.usb_devices
],
ATTR_AUDIO: self.sys_hardware.audio_devices,
ATTR_DEVICES: [
device_struct(device) for device in self.sys_hardware.devices
]
}
@api_process
@@ -64,6 +60,6 @@ class APIHardware(CoreSysAttributes):
}
@api_process
def trigger(self, request: web.Request) -> Awaitable[None]:
async def trigger(self, request: web.Request) -> Awaitable[None]:
"""Trigger a udev device reload."""
return asyncio.shield(self.sys_hardware.udev_trigger())
_LOGGER.debug("Ignoring DEPRECATED hardware trigger function call.")

View File

@@ -11,6 +11,7 @@ from ..const import (
ATTR_DEPLOYMENT,
ATTR_DESCRIPTON,
ATTR_DISK_FREE,
ATTR_DISK_LIFE_TIME,
ATTR_DISK_TOTAL,
ATTR_DISK_USED,
ATTR_FEATURES,
@@ -43,7 +44,8 @@ class APIHost(CoreSysAttributes):
ATTR_DISK_FREE: self.sys_host.info.free_space,
ATTR_DISK_TOTAL: self.sys_host.info.total_space,
ATTR_DISK_USED: self.sys_host.info.used_space,
ATTR_FEATURES: self.sys_host.supported_features,
ATTR_DISK_LIFE_TIME: self.sys_host.info.disk_life_time,
ATTR_FEATURES: self.sys_host.features,
ATTR_HOSTNAME: self.sys_host.info.hostname,
ATTR_KERNEL: self.sys_host.info.kernel,
ATTR_OPERATING_SYSTEM: self.sys_host.info.operating_system,
@@ -73,7 +75,11 @@ class APIHost(CoreSysAttributes):
@api_process
def reload(self, request):
"""Reload host data."""
return asyncio.shield(self.sys_host.reload())
return asyncio.shield(
asyncio.wait(
[self.sys_host.reload(), self.sys_resolution.evaluate.evaluate_system()]
)
)
@api_process
async def services(self, request):

View File

@@ -39,7 +39,7 @@ class APIInfo(CoreSysAttributes):
ATTR_DOCKER: self.sys_docker.info.version,
ATTR_HOSTNAME: self.sys_host.info.hostname,
ATTR_OPERATING_SYSTEM: self.sys_host.info.operating_system,
ATTR_FEATURES: self.sys_host.supported_features,
ATTR_FEATURES: self.sys_host.features,
ATTR_MACHINE: self.sys_machine,
ATTR_ARCH: self.sys_arch.default,
ATTR_SUPPORTED_ARCH: self.sys_arch.supported,

View File

@@ -12,6 +12,7 @@ from aiohttp.web_exceptions import (
HTTPUnauthorized,
)
from multidict import CIMultiDict, istr
import voluptuous as vol
from ..addons.addon import Addon
from ..const import (
@@ -27,10 +28,12 @@ from ..const import (
REQUEST_FROM,
)
from ..coresys import CoreSysAttributes
from .utils import api_process
from .utils import api_process, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__)
VALIDATE_SESSION_DATA = vol.Schema({ATTR_SESSION: str})
class APIIngress(CoreSysAttributes):
"""Ingress view to handle add-on webui routing."""
@@ -78,6 +81,18 @@ class APIIngress(CoreSysAttributes):
session = self.sys_ingress.create_session()
return {ATTR_SESSION: session}
@api_process
async def validate_session(self, request: web.Request) -> Dict[str, Any]:
"""Validate session and extending how long it's valid for."""
self._check_ha_access(request)
data = await api_validate(VALIDATE_SESSION_DATA, request)
# Check Ingress Session
if not self.sys_ingress.validate_session(data[ATTR_SESSION]):
_LOGGER.warning("No valid ingress session %s", data[ATTR_SESSION])
raise HTTPUnauthorized()
async def handler(
self, request: web.Request
) -> Union[web.Response, web.StreamResponse, web.WebSocketResponse]:

42
supervisor/api/jobs.py Normal file
View File

@@ -0,0 +1,42 @@
"""Init file for Supervisor Jobs RESTful API."""
import logging
from typing import Any, Dict
from aiohttp import web
import voluptuous as vol
from ..coresys import CoreSysAttributes
from ..jobs.const import ATTR_IGNORE_CONDITIONS, JobCondition
from .utils import api_process, api_validate
_LOGGER: logging.Logger = logging.getLogger(__name__)
SCHEMA_OPTIONS = vol.Schema(
{vol.Optional(ATTR_IGNORE_CONDITIONS): [vol.Coerce(JobCondition)]}
)
class APIJobs(CoreSysAttributes):
"""Handle RESTful API for OS functions."""
@api_process
async def info(self, request: web.Request) -> Dict[str, Any]:
"""Return JobManager information."""
return {
ATTR_IGNORE_CONDITIONS: self.sys_jobs.ignore_conditions,
}
@api_process
async def options(self, request: web.Request) -> None:
"""Set options for JobManager."""
body = await api_validate(SCHEMA_OPTIONS, request)
if ATTR_IGNORE_CONDITIONS in body:
self.sys_jobs.ignore_conditions = body[ATTR_IGNORE_CONDITIONS]
self.sys_jobs.save_data()
@api_process
async def reset(self, request: web.Request) -> None:
"""Reset options for JobManager."""
self.sys_jobs.reset_data()

View File

@@ -1,121 +1,282 @@
"""REST API for network."""
import asyncio
from typing import Any, Dict
from ipaddress import ip_address, ip_interface
from typing import Any, Awaitable, Dict
from aiohttp import web
import attr
import voluptuous as vol
from ..const import (
ATTR_ACCESSPOINTS,
ATTR_ADDRESS,
ATTR_AUTH,
ATTR_CONNECTED,
ATTR_DNS,
ATTR_DOCKER,
ATTR_ENABLED,
ATTR_FREQUENCY,
ATTR_GATEWAY,
ATTR_HOST_INTERNET,
ATTR_ID,
ATTR_INTERFACE,
ATTR_INTERFACES,
ATTR_IP_ADDRESS,
ATTR_IPV4,
ATTR_IPV6,
ATTR_MAC,
ATTR_METHOD,
ATTR_METHODS,
ATTR_MODE,
ATTR_NAMESERVERS,
ATTR_PARENT,
ATTR_PRIMARY,
ATTR_PSK,
ATTR_SIGNAL,
ATTR_SSID,
ATTR_SUPERVISOR_INTERNET,
ATTR_TYPE,
ATTR_VLAN,
ATTR_WIFI,
DOCKER_NETWORK,
DOCKER_NETWORK_MASK,
)
from ..coresys import CoreSysAttributes
from ..dbus.const import InterfaceMethodSimple
from ..dbus.network.interface import NetworkInterface
from ..dbus.network.utils import int2ip
from ..exceptions import APIError
from ..exceptions import APIError, HostNetworkNotFound
from ..host.const import AuthMethod, InterfaceType, WifiMode
from ..host.network import (
AccessPoint,
Interface,
InterfaceMethod,
IpConfig,
VlanConfig,
WifiConfig,
)
from .utils import api_process, api_validate
SCHEMA_UPDATE = vol.Schema(
_SCHEMA_IP_CONFIG = vol.Schema(
{
vol.Optional(ATTR_ADDRESS): vol.Coerce(str),
vol.Optional(ATTR_METHOD): vol.In(ATTR_METHODS),
vol.Optional(ATTR_GATEWAY): vol.Coerce(str),
vol.Optional(ATTR_DNS): [str],
vol.Optional(ATTR_ADDRESS): [vol.Coerce(ip_interface)],
vol.Optional(ATTR_METHOD): vol.Coerce(InterfaceMethod),
vol.Optional(ATTR_GATEWAY): vol.Coerce(ip_address),
vol.Optional(ATTR_NAMESERVERS): [vol.Coerce(ip_address)],
}
)
_SCHEMA_WIFI_CONFIG = vol.Schema(
{
vol.Optional(ATTR_MODE): vol.Coerce(WifiMode),
vol.Optional(ATTR_AUTH): vol.Coerce(AuthMethod),
vol.Optional(ATTR_SSID): str,
vol.Optional(ATTR_PSK): str,
}
)
def interface_information(interface: NetworkInterface) -> dict:
# 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_WIFI): _SCHEMA_WIFI_CONFIG,
vol.Optional(ATTR_ENABLED): vol.Boolean(),
}
)
def ipconfig_struct(config: IpConfig) -> Dict[str, Any]:
"""Return a dict with information about ip configuration."""
return {
ATTR_METHOD: config.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,
}
def wifi_struct(config: WifiConfig) -> Dict[str, Any]:
"""Return a dict with information about wifi configuration."""
return {
ATTR_MODE: config.mode,
ATTR_AUTH: config.auth,
ATTR_SSID: config.ssid,
ATTR_SIGNAL: config.signal,
}
def vlan_struct(config: VlanConfig) -> Dict[str, Any]:
"""Return a dict with information about VLAN configuration."""
return {
ATTR_ID: config.id,
ATTR_PARENT: config.interface,
}
def interface_struct(interface: Interface) -> Dict[str, Any]:
"""Return a dict with information of a interface to be used in th API."""
return {
ATTR_INTERFACE: interface.name,
ATTR_IP_ADDRESS: f"{interface.ip_address}/{interface.prefix}",
ATTR_GATEWAY: interface.gateway,
ATTR_ID: interface.id,
ATTR_TYPE: interface.type,
ATTR_NAMESERVERS: [int2ip(x) for x in interface.nameservers],
ATTR_METHOD: InterfaceMethodSimple.DHCP
if interface.method == "auto"
else InterfaceMethodSimple.STATIC,
ATTR_ENABLED: interface.enabled,
ATTR_CONNECTED: interface.connected,
ATTR_PRIMARY: interface.primary,
ATTR_IPV4: ipconfig_struct(interface.ipv4) if interface.ipv4 else None,
ATTR_IPV6: ipconfig_struct(interface.ipv6) if interface.ipv6 else None,
ATTR_WIFI: wifi_struct(interface.wifi) if interface.wifi else None,
ATTR_VLAN: vlan_struct(interface.vlan) if interface.vlan else None,
}
def accesspoint_struct(accesspoint: AccessPoint) -> Dict[str, Any]:
"""Return a dict for AccessPoint."""
return {
ATTR_MODE: accesspoint.mode,
ATTR_SSID: accesspoint.ssid,
ATTR_FREQUENCY: accesspoint.frequency,
ATTR_SIGNAL: accesspoint.signal,
ATTR_MAC: accesspoint.mac,
}
class APINetwork(CoreSysAttributes):
"""Handle REST API for network."""
def _get_interface(self, name: str) -> Interface:
"""Get Interface by name or default."""
name = name.lower()
if name == "default":
for interface in self.sys_host.network.interfaces:
if not interface.primary:
continue
return interface
else:
try:
return self.sys_host.network.get(name)
except HostNetworkNotFound:
pass
raise APIError(f"Interface {name} does not exist") from None
@api_process
async def info(self, request: web.Request) -> Dict[str, Any]:
"""Return network information."""
interfaces = {}
for interface in self.sys_host.network.interfaces:
interfaces[
self.sys_host.network.interfaces[interface].name
] = interface_information(self.sys_host.network.interfaces[interface])
return {
ATTR_INTERFACES: interfaces,
ATTR_INTERFACES: [
interface_struct(interface)
for interface in self.sys_host.network.interfaces
],
ATTR_DOCKER: {
ATTR_INTERFACE: DOCKER_NETWORK,
ATTR_ADDRESS: str(DOCKER_NETWORK_MASK),
ATTR_GATEWAY: str(self.sys_docker.network.gateway),
ATTR_DNS: str(self.sys_docker.network.dns),
},
ATTR_HOST_INTERNET: self.sys_host.network.connectivity,
ATTR_SUPERVISOR_INTERNET: self.sys_supervisor.connectivity,
}
@api_process
async def interface_info(self, request: web.Request) -> Dict[str, Any]:
"""Return network information for a interface."""
req_interface = request.match_info.get(ATTR_INTERFACE)
interface = self._get_interface(request.match_info.get(ATTR_INTERFACE))
if req_interface.lower() == "default":
for interface in self.sys_host.network.interfaces:
if not self.sys_host.network.interfaces[interface].primary:
continue
return interface_information(
self.sys_host.network.interfaces[interface]
)
else:
for interface in self.sys_host.network.interfaces:
if req_interface != self.sys_host.network.interfaces[interface].name:
continue
return interface_information(
self.sys_host.network.interfaces[interface]
)
return {}
return interface_struct(interface)
@api_process
async def interface_update(self, request: web.Request) -> Dict[str, Any]:
async def interface_update(self, request: web.Request) -> None:
"""Update the configuration of an interface."""
req_interface = request.match_info.get(ATTR_INTERFACE)
interface = self._get_interface(request.match_info.get(ATTR_INTERFACE))
if not self.sys_host.network.interfaces.get(req_interface):
raise APIError(f"Interface {req_interface} does not exsist")
args = await api_validate(SCHEMA_UPDATE, request)
if not args:
# Validate data
body = await api_validate(SCHEMA_UPDATE, request)
if not body:
raise APIError("You need to supply at least one option to update")
await asyncio.shield(
self.sys_host.network.interfaces[req_interface].update_settings(**args)
# Apply config
for key, config in body.items():
if key == ATTR_IPV4:
interface.ipv4 = attr.evolve(
interface.ipv4 or IpConfig(InterfaceMethod.STATIC, [], None, []),
**config,
)
elif key == ATTR_IPV6:
interface.ipv6 = attr.evolve(
interface.ipv6 or IpConfig(InterfaceMethod.STATIC, [], None, []),
**config,
)
elif key == ATTR_WIFI:
interface.wifi = attr.evolve(
interface.wifi
or WifiConfig(
WifiMode.INFRASTRUCTURE, "", AuthMethod.OPEN, None, None
),
**config,
)
elif key == ATTR_ENABLED:
interface.enabled = config
await asyncio.shield(self.sys_host.network.apply_changes(interface))
@api_process
def reload(self, request: web.Request) -> Awaitable[None]:
"""Reload network data."""
return asyncio.shield(self.sys_host.network.update())
@api_process
async def scan_accesspoints(self, request: web.Request) -> Dict[str, Any]:
"""Scan and return a list of available networks."""
interface = self._get_interface(request.match_info.get(ATTR_INTERFACE))
# Only wlan is supported
if interface.type != InterfaceType.WIRELESS:
raise APIError(f"Interface {interface.name} is not a valid wireless card!")
ap_list = await self.sys_host.network.scan_wifi(interface)
return {ATTR_ACCESSPOINTS: [accesspoint_struct(ap) for ap in ap_list]}
@api_process
async def create_vlan(self, request: web.Request) -> None:
"""Create a new vlan."""
interface = self._get_interface(request.match_info.get(ATTR_INTERFACE))
vlan = int(request.match_info.get(ATTR_VLAN))
# Only ethernet is supported
if interface.type != InterfaceType.ETHERNET:
raise APIError(
f"Interface {interface.name} is not a valid ethernet card for vlan!"
)
body = await api_validate(SCHEMA_UPDATE, request)
vlan_config = VlanConfig(vlan, interface.name)
ipv4_config = None
if ATTR_IPV4 in body:
ipv4_config = IpConfig(
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, []),
)
ipv6_config = None
if ATTR_IPV6 in body:
ipv6_config = IpConfig(
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, []),
)
vlan_interface = Interface(
"",
True,
True,
False,
InterfaceType.VLAN,
ipv4_config,
ipv6_config,
None,
vlan_config,
)
await asyncio.shield(self.sys_host.reload())
return await asyncio.shield(self.interface_info(request))
await asyncio.shield(self.sys_host.network.apply_changes(vlan_interface))

View File

@@ -1,9 +1,9 @@
try {
new Function("import('/api/hassio/app/frontend_latest/entrypoint.6bc241a4.js')")();
new Function("import('/api/hassio/app/frontend_latest/entrypoint.cf81f6d9.js')")();
} catch (err) {
var el = document.createElement('script');
el.src = '/api/hassio/app/frontend_es5/entrypoint.b71bd2af.js';
el.src = '/api/hassio/app/frontend_es5/entrypoint.c258a457.js';
document.body.appendChild(el);
}

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.0aeb318c1dfa0b946242.js","sources":["webpack://home-assistant-frontend/chunk.0aeb318c1dfa0b946242.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.0ca880f618245e0de2ab.js","sources":["webpack://home-assistant-frontend/chunk.0ca880f618245e0de2ab.js"],"mappings":"AAAA","sourceRoot":""}

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.0f03f80679461cebc400.js","sources":["webpack://home-assistant-frontend/chunk.0f03f80679461cebc400.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.1da2af7a753728051dc0.js","sources":["webpack://home-assistant-frontend/chunk.1da2af7a753728051dc0.js"],"mappings":";AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.36fd5e024cde0b68de37.js","sources":["webpack://home-assistant-frontend/chunk.36fd5e024cde0b68de37.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.42b19ffa1fa277adc9cd.js","sources":["webpack://home-assistant-frontend/chunk.42b19ffa1fa277adc9cd.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.54f9c95d940bc3a71084.js","sources":["webpack://home-assistant-frontend/chunk.54f9c95d940bc3a71084.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.63747632f287a94ecaa7.js","sources":["webpack://home-assistant-frontend/chunk.63747632f287a94ecaa7.js"],"mappings":"AAAA","sourceRoot":""}

View File

@@ -0,0 +1,2 @@
!function(){"use strict";var n,t={14971:function(n,t,e){var r,o,i=e(91107),u=e(9902),a=e.n(u),s=(e(58556),e(62173)),f={renderMarkdown:function(n,t){var e,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return r||(r=Object.assign({},(0,s.getDefaultWhiteList)(),{"ha-icon":["icon"],"ha-svg-icon":["path"]})),i.allowSvg?(o||(o=Object.assign({},r,{svg:["xmlns","height","width"],path:["transform","stroke","d"],img:["src"]})),e=o):e=r,(0,s.filterXSS)(a()(n,t),{whiteList:e})}};(0,i.Jj)(f)}},e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={exports:{}};return t[n].call(o.exports,o,o.exports,r),o.exports}r.m=t,r.x=function(){r(14971)},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,{a:t}),t},r.d=function(n,t){for(var e in t)r.o(t,e)&&!r.o(n,e)&&Object.defineProperty(n,e,{enumerable:!0,get:t[e]})},r.f={},r.e=function(n){return Promise.all(Object.keys(r.f).reduce((function(t,e){return r.f[e](n,t),t}),[]))},r.u=function(n){return"chunk.d93e72d29a82b1218f4a.js"},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},n=r.x,r.x=function(){return r.e(474).then(n)},r.p="/api/hassio/app/frontend_es5/",function(){var n={971:1};r.f.i=function(t,e){n[t]||importScripts(""+r.u(t))};var t=self.webpackChunkhome_assistant_frontend=self.webpackChunkhome_assistant_frontend||[],e=t.push.bind(t);t.push=function(t){var o=t[0],i=t[1],u=t[2];for(var a in i)r.o(i,a)&&(r.m[a]=i[a]);for(u&&u(r);o.length;)n[o.pop()]=1;e(t)}}(),r.x()}();
//# sourceMappingURL=chunk.67e3627d3c04d75f6f9d.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.67e3627d3c04d75f6f9d.js","sources":["webpack://home-assistant-frontend/chunk.67e3627d3c04d75f6f9d.js"],"mappings":"AAAA","sourceRoot":""}

View File

@@ -1,2 +0,0 @@
!function(){"use strict";var n,t={14971:function(n,t,e){e(58556);var r,o,i=e(91107),u=e(9902),s=e.n(u),f=e(62173),a={renderMarkdown:function(n,t){var e,i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};return r||(r=Object.assign({},(0,f.getDefaultWhiteList)(),{"ha-icon":["icon"],"ha-svg-icon":["path"]})),i.allowSvg?(o||(o=Object.assign({},r,{svg:["xmlns","height","width"],path:["transform","stroke","d"],img:["src"]})),e=o):e=r,(0,f.filterXSS)(s()(n,t),{whiteList:e})}};(0,i.Jj)(a)}},e={};function r(n){if(e[n])return e[n].exports;var o=e[n]={exports:{}};return t[n].call(o.exports,o,o.exports,r),o.exports}r.m=t,r.x=function(){r(14971)},r.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return r.d(t,{a:t}),t},r.d=function(n,t){for(var e in t)r.o(t,e)&&!r.o(n,e)&&Object.defineProperty(n,e,{enumerable:!0,get:t[e]})},r.f={},r.e=function(n){return Promise.all(Object.keys(r.f).reduce((function(t,e){return r.f[e](n,t),t}),[]))},r.u=function(n){return"chunk.bb85ff337912276d8e9b.js"},r.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},n=r.x,r.x=function(){return r.e(474).then(n)},r.p="/api/hassio/app/frontend_es5/",function(){var n={971:1};r.f.i=function(t,e){n[t]||importScripts(""+r.u(t))};var t=self.webpackChunkhome_assistant_frontend=self.webpackChunkhome_assistant_frontend||[],e=t.push.bind(t);t.push=function(t){var o=t[0],i=t[1],u=t[2];for(var s in i)r.o(i,s)&&(r.m[s]=i[s]);for(u&&u(r);o.length;)n[o.pop()]=1;e(t)}}(),r.x()}();
//# sourceMappingURL=chunk.67f2c1c40269e444b0e0.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.67f2c1c40269e444b0e0.js","sources":["webpack://home-assistant-frontend/chunk.67f2c1c40269e444b0e0.js"],"mappings":"AAAA","sourceRoot":""}

View File

@@ -1,2 +1,2 @@
(self.webpackChunkhome_assistant_frontend=self.webpackChunkhome_assistant_frontend||[]).push([[528],{92914:function(n,e,r){"use strict";r.r(e),r.d(e,{codeMirror:function(){return c},codeMirrorCss:function(){return i}});var t=r(79074),s=r.n(t),o=r(49338),a=(r(22080),r(19393),r(47181));s().commands.save=function(n){(0,a.B)(n.getWrapperElement(),"editor-save")};var c=s(),i=o.Z}}]);
//# sourceMappingURL=chunk.0f03f80679461cebc400.js.map
(self.webpackChunkhome_assistant_frontend=self.webpackChunkhome_assistant_frontend||[]).push([[914],{92914:function(n,e,r){"use strict";r.r(e),r.d(e,{codeMirror:function(){return c},codeMirrorCss:function(){return i}});var t=r(79074),s=r.n(t),o=r(49338),a=(r(22080),r(19393),r(47181));s().commands.save=function(n){(0,a.B)(n.getWrapperElement(),"editor-save")};var c=s(),i=o.Z}}]);
//# sourceMappingURL=chunk.6e5ce6bddf1cc3ddee5c.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.6e5ce6bddf1cc3ddee5c.js","sources":["webpack://home-assistant-frontend/chunk.6e5ce6bddf1cc3ddee5c.js"],"mappings":"AAAA","sourceRoot":""}

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.70406e582810ae5fec16.js","sources":["webpack://home-assistant-frontend/chunk.70406e582810ae5fec16.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.712a551bcc67f5a1a334.js","sources":["webpack://home-assistant-frontend/chunk.712a551bcc67f5a1a334.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.79b4e240c46ccbe25e4d.js","sources":["webpack://home-assistant-frontend/chunk.79b4e240c46ccbe25e4d.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.a38cb3d17010dfd8ff6e.js","sources":["webpack://home-assistant-frontend/chunk.a38cb3d17010dfd8ff6e.js"],"mappings":";AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.bb85ff337912276d8e9b.js","sources":["webpack://home-assistant-frontend/chunk.bb85ff337912276d8e9b.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
{"version":3,"file":"chunk.c3099d3d125acb803c0f.js","sources":["webpack://home-assistant-frontend/chunk.c3099d3d125acb803c0f.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
{"version":3,"file":"chunk.d0222f0b152d21991ec4.js","sources":["webpack://home-assistant-frontend/chunk.d0222f0b152d21991ec4.js"],"mappings":"AAAA","sourceRoot":""}

File diff suppressed because one or more lines are too long

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