Remove home-assistant devices options (#293)

* Remove home-assistant devices options

* fix version mix/max snapshot

* fix wrong path

* fix import

* fix restore

* fix

* make exists call robust

* Update addon.py

* remove old custom function

* Update homeassistant.py

* Update homeassistant.py

* Update homeassistant.py

* Update snapshot.py

* Update validate.py

* Update snapshot.py

* Update homeassistant.py

* fix lint 1

* fix lint

* fix lint

* Update snapshot.py

* Update homeassistant.py

* Update homeassistant.py

* Update homeassistant.py
This commit is contained in:
Pascal Vizeli 2018-01-04 12:52:17 +01:00 committed by GitHub
parent c84151e9e8
commit 78ec0d1314
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 86 additions and 114 deletions

11
API.md
View File

@ -71,10 +71,10 @@ Optional:
{
"beta_channel": "true|false",
"timezone": "TIMEZONE",
"wait_boot": "int",
"addons_repositories": [
"REPO_URL"
],
"wait_boot": "int"
]
}
```
@ -170,10 +170,7 @@ Return QR-Code
"name": "custom snapshot name / description",
"date": "ISO",
"size": "SIZE_IN_MB",
"homeassistant": {
"version": "INSTALLED_HASS_VERSION",
"devices": []
},
"homeassistant": "version",
"addons": [
{
"slug": "ADDON_SLUG",
@ -286,7 +283,6 @@ Optional:
{
"version": "INSTALL_VERSION",
"last_version": "LAST_VERSION",
"devices": [""],
"image": "str",
"custom": "bool -> if custom image",
"boot": "bool",
@ -319,7 +315,6 @@ Output is the raw Docker log.
```json
{
"devices": [],
"image": "Optional|null",
"last_version": "Optional for custom image|null",
"port": "port for access hass",

View File

@ -703,8 +703,9 @@ class Addon(CoreSysAttributes):
# check version / restore image
version = data[ATTR_VERSION]
if version != self.instance.version:
if not await self.instance.exists():
_LOGGER.info("Restore image for addon %s", self._id)
image_file = Path(temp, "image.tar")
if image_file.is_file():
await self.instance.import_image(image_file, version)

View File

@ -183,7 +183,7 @@ SCHEMA_ADDON_SNAPSHOT = vol.Schema({
vol.Required(ATTR_SYSTEM): SCHEMA_ADDON_SYSTEM,
vol.Required(ATTR_STATE): vol.In([STATE_STARTED, STATE_STOPPED]),
vol.Required(ATTR_VERSION): vol.Coerce(str),
})
}, extra=vol.REMOVE_EXTRA)
def validate_options(raw_schema):

View File

@ -6,20 +6,19 @@ import voluptuous as vol
from .utils import api_process, api_process_raw, api_validate
from ..const import (
ATTR_VERSION, ATTR_LAST_VERSION, ATTR_DEVICES, ATTR_IMAGE, ATTR_CUSTOM,
ATTR_BOOT, ATTR_PORT, ATTR_PASSWORD, ATTR_SSL, ATTR_WATCHDOG,
CONTENT_TYPE_BINARY)
ATTR_VERSION, ATTR_LAST_VERSION, ATTR_IMAGE, ATTR_CUSTOM, ATTR_BOOT,
ATTR_PORT, ATTR_PASSWORD, ATTR_SSL, ATTR_WATCHDOG, CONTENT_TYPE_BINARY)
from ..coresys import CoreSysAttributes
from ..validate import HASS_DEVICES, NETWORK_PORT
from ..validate import NETWORK_PORT
_LOGGER = logging.getLogger(__name__)
# pylint: disable=no-value-for-parameter
SCHEMA_OPTIONS = vol.Schema({
vol.Optional(ATTR_DEVICES): HASS_DEVICES,
vol.Optional(ATTR_BOOT): vol.Boolean(),
vol.Inclusive(ATTR_IMAGE, 'custom_hass'): vol.Any(None, vol.Coerce(str)),
vol.Inclusive(ATTR_IMAGE, 'custom_hass'):
vol.Any(None, vol.Coerce(str)),
vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'):
vol.Any(None, vol.Coerce(str)),
vol.Optional(ATTR_PORT): NETWORK_PORT,
@ -43,7 +42,6 @@ class APIHomeAssistant(CoreSysAttributes):
ATTR_VERSION: self._homeassistant.version,
ATTR_LAST_VERSION: self._homeassistant.last_version,
ATTR_IMAGE: self._homeassistant.image,
ATTR_DEVICES: self._homeassistant.devices,
ATTR_CUSTOM: self._homeassistant.is_custom_image,
ATTR_BOOT: self._homeassistant.boot,
ATTR_PORT: self._homeassistant.api_port,
@ -56,12 +54,9 @@ class APIHomeAssistant(CoreSysAttributes):
"""Set homeassistant options."""
body = await api_validate(SCHEMA_OPTIONS, request)
if ATTR_DEVICES in body:
self._homeassistant.devices = body[ATTR_DEVICES]
if ATTR_IMAGE in body:
self._homeassistant.set_custom(
body[ATTR_IMAGE], body[ATTR_LAST_VERSION])
if ATTR_IMAGE in body and ATTR_LAST_VERSION in body:
self._homeassistant.image = body[ATTR_IMAGE]
self._homeassistant.last_version = body[ATTR_LAST_VERSION]
if ATTR_BOOT in body:
self._homeassistant.boot = body[ATTR_BOOT]
@ -78,6 +73,7 @@ class APIHomeAssistant(CoreSysAttributes):
if ATTR_WATCHDOG in body:
self._homeassistant.watchdog = body[ATTR_WATCHDOG]
self._homeassistant.save()
return True
@api_process

View File

@ -9,7 +9,7 @@ from ..snapshots.validate import ALL_FOLDERS
from ..const import (
ATTR_NAME, ATTR_SLUG, ATTR_DATE, ATTR_ADDONS, ATTR_REPOSITORIES,
ATTR_HOMEASSISTANT, ATTR_VERSION, ATTR_SIZE, ATTR_FOLDERS, ATTR_TYPE,
ATTR_DEVICES, ATTR_SNAPSHOTS)
ATTR_SNAPSHOTS)
from ..coresys import CoreSysAttributes
_LOGGER = logging.getLogger(__name__)
@ -82,10 +82,7 @@ class APISnapshots(CoreSysAttributes):
ATTR_NAME: snapshot.name,
ATTR_DATE: snapshot.date,
ATTR_SIZE: snapshot.size,
ATTR_HOMEASSISTANT: {
ATTR_VERSION: snapshot.homeassistant_version,
ATTR_DEVICES: snapshot.homeassistant_devices,
},
ATTR_HOMEASSISTANT: snapshot.homeassistant_version,
ATTR_ADDONS: data_addons,
ATTR_REPOSITORIES: snapshot.repositories,
ATTR_FOLDERS: snapshot.folders,

View File

@ -100,8 +100,8 @@ class DockerAddon(DockerInterface):
# Auto mapping UART devices
if self.addon.auto_uart:
for uart_dev in self._hardware.serial_devices:
devices.append("{0}:{0}:rwm".format(uart_dev))
for device in self._hardware.serial_devices:
devices.append(f"{device}:{device}:rwm")
# Return None if no devices is present
return devices or None
@ -135,7 +135,7 @@ class DockerAddon(DockerInterface):
"""Return tmpfs for docker add-on."""
options = self.addon.tmpfs
if options:
return {"/tmpfs": "{}".format(options)}
return {"/tmpfs": f"{options}"}
return None
@property
@ -324,7 +324,7 @@ class DockerAddon(DockerInterface):
"""
try:
with tar_file.open("rb") as read_tar:
self._docker.api.load_image(read_tar)
self._docker.api.load_image(read_tar, quiet=True)
image = self._docker.images.get(self.image)
image.tag(self.image, tag=tag)

View File

@ -26,14 +26,10 @@ class DockerHomeAssistant(DockerInterface):
@property
def devices(self):
"""Create list of special device to map into docker."""
if not self._homeassistant.devices:
return None
devices = []
for device in self._homeassistant.devices:
devices.append("/dev/{0}:/dev/{0}:rwm".format(device))
return devices
for device in self._hardware.serial_devices:
devices.append(f"{device}:{device}:rwm")
return devices or None
def _run(self):
"""Run docker image.

View File

@ -69,7 +69,7 @@ class DockerInterface(CoreSysAttributes):
"""
try:
_LOGGER.info("Pull image %s tag %s.", self.image, tag)
image = self._docker.images.pull("{}:{}".format(self.image, tag))
image = self._docker.images.pull(f"{self.image}:{tag}")
image.tag(self.image, tag='latest')
self._meta = image.attrs
@ -90,8 +90,9 @@ class DockerInterface(CoreSysAttributes):
Need run inside executor.
"""
try:
self._docker.images.get(self.image)
except docker.errors.DockerException:
image = self._docker.images.get(self.image)
assert f"{self.image}:{self.version}" in image.tags
except (docker.errors.DockerException, AssertionError):
return False
return True
@ -204,11 +205,11 @@ class DockerInterface(CoreSysAttributes):
try:
with suppress(docker.errors.ImageNotFound):
self._docker.images.remove(
image="{}:latest".format(self.image), force=True)
image=f"{self.image}:latest", force=True)
with suppress(docker.errors.ImageNotFound):
self._docker.images.remove(
image="{}:{}".format(self.image, self.version), force=True)
image=f"{self.image}:{self.version}", force=True)
except docker.errors.DockerException as err:
_LOGGER.warning("Can't remove image %s: %s", self.image, err)

View File

@ -8,8 +8,8 @@ import aiohttp
from aiohttp.hdrs import CONTENT_TYPE
from .const import (
FILE_HASSIO_HOMEASSISTANT, ATTR_DEVICES, ATTR_IMAGE, ATTR_LAST_VERSION,
ATTR_VERSION, ATTR_BOOT, ATTR_PASSWORD, ATTR_PORT, ATTR_SSL, ATTR_WATCHDOG,
FILE_HASSIO_HOMEASSISTANT, ATTR_IMAGE, ATTR_LAST_VERSION,
ATTR_BOOT, ATTR_PASSWORD, ATTR_PORT, ATTR_SSL, ATTR_WATCHDOG,
HEADER_HA_ACCESS, CONTENT_TYPE_JSON)
from .coresys import CoreSysAttributes
from .docker.homeassistant import DockerHomeAssistant
@ -33,14 +33,11 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
async def load(self):
"""Prepare HomeAssistant object."""
if not await self.instance.exists():
_LOGGER.info("No HomeAssistant docker %s found.", self.image)
if self.is_custom_image:
await self.install()
else:
await self.install_landingpage()
else:
await self.instance.attach()
if await self.instance.attach():
return
_LOGGER.info("No HomeAssistant docker %s found.", self.image)
await self.install_landingpage()
@property
def api_ip(self):
@ -67,7 +64,6 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
def api_password(self, value):
"""Set password for home-assistant instance."""
self._data[ATTR_PASSWORD] = value
self.save()
@property
def api_ssl(self):
@ -78,7 +74,6 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
def api_ssl(self, value):
"""Set SSL for home-assistant instance."""
self._data[ATTR_SSL] = value
self.save()
@property
def api_url(self):
@ -96,7 +91,6 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
def watchdog(self, value):
"""Return True if the watchdog should protect Home-Assistant."""
self._data[ATTR_WATCHDOG] = value
self.save()
@property
def version(self):
@ -110,28 +104,34 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
return self._data.get(ATTR_LAST_VERSION)
return self._updater.version_homeassistant
@last_version.setter
def last_version(self, value):
"""Set last available version of homeassistant."""
if value:
self._data[ATTR_LAST_VERSION] = value
else:
self._data.pop(ATTR_LAST_VERSION, None)
@property
def image(self):
"""Return image name of hass containter."""
if ATTR_IMAGE in self._data:
if self._data.get(ATTR_IMAGE):
return self._data[ATTR_IMAGE]
return os.environ['HOMEASSISTANT_REPOSITORY']
@image.setter
def image(self, value):
"""Set image name of hass containter."""
if value:
self._data[ATTR_IMAGE] = value
else:
self._data.pop(ATTR_IMAGE, None)
@property
def is_custom_image(self):
"""Return True if a custom image is used."""
return ATTR_IMAGE in self._data
@property
def devices(self):
"""Return extend device mapping."""
return self._data[ATTR_DEVICES]
@devices.setter
def devices(self, value):
"""Set extend device mapping."""
self._data[ATTR_DEVICES] = value
self.save()
return all(attr in self._data for attr in
(ATTR_IMAGE, ATTR_LAST_VERSION))
@property
def boot(self):
@ -142,23 +142,6 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
def boot(self, value):
"""Set home-assistant boot options."""
self._data[ATTR_BOOT] = value
self.save()
def set_custom(self, image, version):
"""Set a custom image for homeassistant."""
# reset
if image is None and version is None:
self._data.pop(ATTR_IMAGE, None)
self._data.pop(ATTR_VERSION, None)
self.instance.image = self.image
else:
if image:
self._data[ATTR_IMAGE] = image
self.instance.image = image
if version:
self._data[ATTR_VERSION] = version
self.save()
async def install_landingpage(self):
"""Install a landingpage."""
@ -196,8 +179,9 @@ class HomeAssistant(JsonConfig, CoreSysAttributes):
"""Update HomeAssistant version."""
version = version or self.last_version
running = await self.instance.is_running()
exists = await self.instance.exists()
if version == self.instance.version:
if exists and version == self.instance.version:
_LOGGER.info("Version %s is already installed", version)
return False

View File

@ -13,8 +13,9 @@ from .validate import SCHEMA_SNAPSHOT, ALL_FOLDERS
from .utils import remove_folder
from ..const import (
ATTR_SLUG, ATTR_NAME, ATTR_DATE, ATTR_ADDONS, ATTR_REPOSITORIES,
ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_DEVICES,
ATTR_IMAGE, ATTR_PORT, ATTR_SSL, ATTR_PASSWORD, ATTR_WATCHDOG, ATTR_BOOT)
ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_VERSION, ATTR_TYPE, ATTR_IMAGE,
ATTR_PORT, ATTR_SSL, ATTR_PASSWORD, ATTR_WATCHDOG, ATTR_BOOT,
ATTR_LAST_VERSION)
from ..coresys import CoreSysAttributes
from ..utils.json import write_json_file
@ -82,14 +83,14 @@ class Snapshot(CoreSysAttributes):
self._data[ATTR_HOMEASSISTANT][ATTR_VERSION] = value
@property
def homeassistant_devices(self):
"""Return snapshot homeassistant devices."""
return self._data[ATTR_HOMEASSISTANT].get(ATTR_DEVICES)
def homeassistant_last_version(self):
"""Return snapshot homeassistant last version (custom)."""
return self._data[ATTR_HOMEASSISTANT].get(ATTR_LAST_VERSION)
@homeassistant_devices.setter
def homeassistant_devices(self, value):
"""Set snapshot homeassistant devices."""
self._data[ATTR_HOMEASSISTANT][ATTR_DEVICES] = value
@homeassistant_last_version.setter
def homeassistant_last_version(self, value):
"""Set snapshot homeassistant last version (custom)."""
self._data[ATTR_HOMEASSISTANT][ATTR_LAST_VERSION] = value
@property
def homeassistant_image(self):
@ -335,13 +336,13 @@ class Snapshot(CoreSysAttributes):
def store_homeassistant(self):
"""Read all data from homeassistant object."""
self.homeassistant_version = self._homeassistant.version
self.homeassistant_devices = self._homeassistant.devices
self.homeassistant_watchdog = self._homeassistant.watchdog
self.homeassistant_boot = self._homeassistant.boot
# custom image
if self._homeassistant.is_custom_image:
self.homeassistant_image = self._homeassistant.image
self.homeassistant_last_version = self._homeassistant.last_version
# api
self.homeassistant_port = self._homeassistant.api_port
@ -350,20 +351,22 @@ class Snapshot(CoreSysAttributes):
def restore_homeassistant(self):
"""Write all data to homeassistant object."""
self._homeassistant.devices = self.homeassistant_devices
self._homeassistant.watchdog = self.homeassistant_watchdog
self._homeassistant.boot = self.homeassistant_boot
# custom image
if self.homeassistant_image:
self._homeassistant.set_custom(
self.homeassistant_image, self.homeassistant_version)
self._homeassistant.image = self.homeassistant_image
self._homeassistant.last_version = self.homeassistant_last_version
# api
self._homeassistant.api_port = self.homeassistant_port
self._homeassistant.api_ssl = self.homeassistant_ssl
self._homeassistant.api_password = self.homeassistant_password
# save
self._homeassistant.save()
def store_repositories(self):
"""Store repository list into snapshot."""
self.repositories = self._config.addons_repositories

View File

@ -4,11 +4,12 @@ import voluptuous as vol
from ..const import (
ATTR_REPOSITORIES, ATTR_ADDONS, ATTR_NAME, ATTR_SLUG, ATTR_DATE,
ATTR_VERSION, ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_TYPE, ATTR_DEVICES,
ATTR_IMAGE, ATTR_PASSWORD, ATTR_PORT, ATTR_SSL, ATTR_WATCHDOG, ATTR_BOOT,
ATTR_VERSION, ATTR_HOMEASSISTANT, ATTR_FOLDERS, ATTR_TYPE, ATTR_IMAGE,
ATTR_PASSWORD, ATTR_PORT, ATTR_SSL, ATTR_WATCHDOG, ATTR_BOOT,
ATTR_LAST_VERSION,
FOLDER_SHARE, FOLDER_HOMEASSISTANT, FOLDER_ADDONS, FOLDER_SSL,
SNAPSHOT_FULL, SNAPSHOT_PARTIAL)
from ..validate import HASS_DEVICES, NETWORK_PORT
from ..validate import NETWORK_PORT
ALL_FOLDERS = [FOLDER_HOMEASSISTANT, FOLDER_SHARE, FOLDER_ADDONS, FOLDER_SSL]
@ -20,19 +21,19 @@ SCHEMA_SNAPSHOT = vol.Schema({
vol.Required(ATTR_DATE): vol.Coerce(str),
vol.Optional(ATTR_HOMEASSISTANT, default={}): vol.Schema({
vol.Required(ATTR_VERSION): vol.Coerce(str),
vol.Optional(ATTR_DEVICES, default=[]): HASS_DEVICES,
vol.Optional(ATTR_IMAGE): vol.Coerce(str),
vol.Optional(ATTR_LAST_VERSION): vol.Coerce(str),
vol.Optional(ATTR_BOOT, default=True): vol.Boolean(),
vol.Optional(ATTR_SSL, default=False): vol.Boolean(),
vol.Optional(ATTR_PORT, default=8123): NETWORK_PORT,
vol.Optional(ATTR_PASSWORD): vol.Any(None, vol.Coerce(str)),
vol.Optional(ATTR_WATCHDOG, default=True): vol.Boolean(),
}),
}, extra=vol.REMOVE_EXTRA),
vol.Optional(ATTR_FOLDERS, default=[]): [vol.In(ALL_FOLDERS)],
vol.Optional(ATTR_ADDONS, default=[]): [vol.Schema({
vol.Required(ATTR_SLUG): vol.Coerce(str),
vol.Required(ATTR_NAME): vol.Coerce(str),
vol.Required(ATTR_VERSION): vol.Coerce(str),
})],
}, extra=vol.REMOVE_EXTRA)],
vol.Optional(ATTR_REPOSITORIES, default=[]): [vol.Url()],
}, extra=vol.ALLOW_EXTRA)

View File

@ -4,15 +4,14 @@ import voluptuous as vol
import pytz
from .const import (
ATTR_DEVICES, ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_SESSIONS, ATTR_PASSWORD,
ATTR_TOTP, ATTR_SECURITY, ATTR_BETA_CHANNEL, ATTR_TIMEZONE,
ATTR_ADDONS_CUSTOM_LIST, ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT,
ATTR_HOMEASSISTANT, ATTR_HASSIO, ATTR_BOOT, ATTR_LAST_BOOT, ATTR_SSL,
ATTR_PORT, ATTR_WATCHDOG, ATTR_WAIT_BOOT)
ATTR_IMAGE, ATTR_LAST_VERSION, ATTR_SESSIONS, ATTR_PASSWORD, ATTR_TOTP,
ATTR_SECURITY, ATTR_BETA_CHANNEL, ATTR_TIMEZONE, ATTR_ADDONS_CUSTOM_LIST,
ATTR_AUDIO_OUTPUT, ATTR_AUDIO_INPUT, ATTR_HOMEASSISTANT, ATTR_HASSIO,
ATTR_BOOT, ATTR_LAST_BOOT, ATTR_SSL, ATTR_PORT, ATTR_WATCHDOG,
ATTR_WAIT_BOOT)
NETWORK_PORT = vol.All(vol.Coerce(int), vol.Range(min=1, max=65535))
HASS_DEVICES = [vol.Match(r"^[^/]*$")]
ALSA_CHANNEL = vol.Match(r"\d+,\d+")
WAIT_BOOT = vol.All(vol.Coerce(int), vol.Range(min=1, max=60))
@ -60,7 +59,6 @@ DOCKER_PORTS = vol.Schema({
# pylint: disable=no-value-for-parameter
SCHEMA_HASS_CONFIG = vol.Schema({
vol.Optional(ATTR_DEVICES, default=[]): HASS_DEVICES,
vol.Optional(ATTR_BOOT, default=True): vol.Boolean(),
vol.Inclusive(ATTR_IMAGE, 'custom_hass'): vol.Coerce(str),
vol.Inclusive(ATTR_LAST_VERSION, 'custom_hass'): vol.Coerce(str),