Merge pull request #74 from home-assistant/dev

Release 0.34
This commit is contained in:
Pascal Vizeli 2017-06-01 00:01:48 +02:00 committed by GitHub
commit 2a09b70294
12 changed files with 139 additions and 190 deletions

View File

@ -191,16 +191,14 @@ class AddonManager(AddonsData):
return False return False
version = version or self.get_last_version(addon) version = version or self.get_last_version(addon)
is_running = await self.dockers[addon].is_running()
# update # update
if await self.dockers[addon].update(version): if not await self.dockers[addon].update(version):
self.set_addon_update(addon, version)
if is_running:
await self.start(addon)
return True
return False return False
self.set_addon_update(addon, version)
return True
async def restart(self, addon): async def restart(self, addon):
"""Restart addon.""" """Restart addon."""
if addon not in self.dockers: if addon not in self.dockers:

View File

@ -16,7 +16,8 @@ from ..const import (
FILE_HASSIO_ADDONS, ATTR_NAME, ATTR_VERSION, ATTR_SLUG, ATTR_DESCRIPTON, FILE_HASSIO_ADDONS, ATTR_NAME, ATTR_VERSION, ATTR_SLUG, ATTR_DESCRIPTON,
ATTR_STARTUP, ATTR_BOOT, ATTR_MAP, ATTR_OPTIONS, ATTR_PORTS, BOOT_AUTO, ATTR_STARTUP, ATTR_BOOT, ATTR_MAP, ATTR_OPTIONS, ATTR_PORTS, BOOT_AUTO,
ATTR_SCHEMA, ATTR_IMAGE, ATTR_REPOSITORY, ATTR_URL, ATTR_ARCH, ATTR_SCHEMA, ATTR_IMAGE, ATTR_REPOSITORY, ATTR_URL, ATTR_ARCH,
ATTR_LOCATON, ATTR_DEVICES, ATTR_ENVIRONMENT, ATTR_HOST_NETWORK) ATTR_LOCATON, ATTR_DEVICES, ATTR_ENVIRONMENT, ATTR_HOST_NETWORK,
ATTR_TMPFS)
from ..config import Config from ..config import Config
from ..tools import read_json_file, write_json_file from ..tools import read_json_file, write_json_file
@ -304,6 +305,10 @@ class AddonsData(Config):
"""Return devices of addon.""" """Return devices of addon."""
return self._system_data[addon].get(ATTR_DEVICES) return self._system_data[addon].get(ATTR_DEVICES)
def get_tmpfs(self, addon):
"""Return tmpfs of addon."""
return self._system_data[addon].get(ATTR_TMPFS)
def get_environment(self, addon): def get_environment(self, addon):
"""Return environment of addon.""" """Return environment of addon."""
return self._system_data[addon].get(ATTR_ENVIRONMENT) return self._system_data[addon].get(ATTR_ENVIRONMENT)

View File

@ -7,7 +7,7 @@ from ..const import (
STARTUP_BEFORE, STARTUP_INITIALIZE, BOOT_AUTO, BOOT_MANUAL, ATTR_SCHEMA, STARTUP_BEFORE, STARTUP_INITIALIZE, BOOT_AUTO, BOOT_MANUAL, ATTR_SCHEMA,
ATTR_IMAGE, ATTR_URL, ATTR_MAINTAINER, ATTR_ARCH, ATTR_DEVICES, ATTR_IMAGE, ATTR_URL, ATTR_MAINTAINER, ATTR_ARCH, ATTR_DEVICES,
ATTR_ENVIRONMENT, ATTR_HOST_NETWORK, ARCH_ARMHF, ARCH_AARCH64, ARCH_AMD64, ATTR_ENVIRONMENT, ATTR_HOST_NETWORK, ARCH_ARMHF, ARCH_AARCH64, ARCH_AMD64,
ARCH_I386) ARCH_I386, ATTR_TMPFS)
MAP_VOLUME = r"^(config|ssl|addons|backup|share)(?::(rw|:ro))?$" MAP_VOLUME = r"^(config|ssl|addons|backup|share)(?::(rw|:ro))?$"
@ -52,6 +52,8 @@ SCHEMA_ADDON_CONFIG = vol.Schema(vol.All({
vol.Optional(ATTR_PORTS): dict, vol.Optional(ATTR_PORTS): dict,
vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(), vol.Optional(ATTR_HOST_NETWORK, default=False): vol.Boolean(),
vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")], vol.Optional(ATTR_DEVICES): [vol.Match(r"^(.*):(.*):([rwm]{1,3})$")],
vol.Optional(ATTR_TMPFS):
vol.Match(r"^size=(\d)*[kmg](,uid=\d{1,4})?(,rw)?$"),
vol.Optional(ATTR_MAP, default=[]): [vol.Match(MAP_VOLUME)], vol.Optional(ATTR_MAP, default=[]): [vol.Match(MAP_VOLUME)],
vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)}, vol.Optional(ATTR_ENVIRONMENT): {vol.Match(r"\w*"): vol.Coerce(str)},
vol.Required(ATTR_OPTIONS): dict, vol.Required(ATTR_OPTIONS): dict,

View File

@ -21,7 +21,6 @@ HOMEASSISTANT_LAST = 'homeassistant_last'
HASSIO_SSL = PurePath("ssl") HASSIO_SSL = PurePath("ssl")
HASSIO_LAST = 'hassio_last' HASSIO_LAST = 'hassio_last'
HASSIO_CLEANUP = 'hassio_cleanup'
ADDONS_CORE = PurePath("addons/core") ADDONS_CORE = PurePath("addons/core")
ADDONS_LOCAL = PurePath("addons/local") ADDONS_LOCAL = PurePath("addons/local")
@ -51,7 +50,6 @@ SCHEMA_CONFIG = vol.Schema({
vol.Optional(TIMEZONE, default='UTC'): validate_timezone, vol.Optional(TIMEZONE, default='UTC'): validate_timezone,
vol.Optional(HOMEASSISTANT_LAST): vol.Coerce(str), vol.Optional(HOMEASSISTANT_LAST): vol.Coerce(str),
vol.Optional(HASSIO_LAST): vol.Coerce(str), vol.Optional(HASSIO_LAST): vol.Coerce(str),
vol.Optional(HASSIO_CLEANUP): vol.Coerce(str),
vol.Optional(ADDONS_CUSTOM_LIST, default=[]): [vol.Url()], vol.Optional(ADDONS_CUSTOM_LIST, default=[]): [vol.Url()],
vol.Optional(SECURITY_INITIALIZE, default=False): vol.Boolean(), vol.Optional(SECURITY_INITIALIZE, default=False): vol.Boolean(),
vol.Optional(SECURITY_TOTP): vol.Coerce(str), vol.Optional(SECURITY_TOTP): vol.Coerce(str),
@ -148,20 +146,6 @@ class CoreConfig(Config):
self._data[TIMEZONE] = value self._data[TIMEZONE] = value
self.save() self.save()
@property
def hassio_cleanup(self):
"""Return Version they need to cleanup."""
return self._data.get(HASSIO_CLEANUP)
@hassio_cleanup.setter
def hassio_cleanup(self, version):
"""Set or remove cleanup flag."""
if version is None:
self._data.pop(HASSIO_CLEANUP, None)
else:
self._data[HASSIO_CLEANUP] = version
self.save()
@property @property
def homeassistant_image(self): def homeassistant_image(self):
"""Return docker homeassistant repository.""" """Return docker homeassistant repository."""

View File

@ -1,7 +1,7 @@
"""Const file for HassIO.""" """Const file for HassIO."""
from pathlib import Path from pathlib import Path
HASSIO_VERSION = '0.33' HASSIO_VERSION = '0.34'
URL_HASSIO_VERSION = ('https://raw.githubusercontent.com/home-assistant/' URL_HASSIO_VERSION = ('https://raw.githubusercontent.com/home-assistant/'
'hassio/master/version.json') 'hassio/master/version.json')
@ -79,6 +79,7 @@ ATTR_BUILD = 'build'
ATTR_DEVICES = 'devices' ATTR_DEVICES = 'devices'
ATTR_ENVIRONMENT = 'environment' ATTR_ENVIRONMENT = 'environment'
ATTR_HOST_NETWORK = 'host_network' ATTR_HOST_NETWORK = 'host_network'
ATTR_TMPFS = 'tmpfs'
STARTUP_INITIALIZE = 'initialize' STARTUP_INITIALIZE = 'initialize'
STARTUP_BEFORE = 'before' STARTUP_BEFORE = 'before'

View File

@ -41,7 +41,7 @@ class HassIO(object):
# init basic docker container # init basic docker container
self.supervisor = DockerSupervisor( self.supervisor = DockerSupervisor(
self.config, self.loop, self.dock, self) self.config, self.loop, self.dock, self.stop)
self.homeassistant = DockerHomeAssistant( self.homeassistant = DockerHomeAssistant(
self.config, self.loop, self.dock) self.config, self.loop, self.dock)
@ -54,7 +54,8 @@ class HassIO(object):
async def setup(self): async def setup(self):
"""Setup HassIO orchestration.""" """Setup HassIO orchestration."""
# supervisor # supervisor
await self.supervisor.attach() if not await self.supervisor.attach():
_LOGGER.fatal("Can't attach to supervisor docker container!")
await self.supervisor.cleanup() await self.supervisor.cleanup()
# set api endpoint # set api endpoint
@ -96,6 +97,8 @@ class HassIO(object):
_LOGGER.info("No HomeAssistant docker found.") _LOGGER.info("No HomeAssistant docker found.")
await homeassistant_setup( await homeassistant_setup(
self.config, self.loop, self.homeassistant) self.config, self.loop, self.homeassistant)
else:
await self.homeassistant.attach()
# Load addons # Load addons
arch = get_arch_from_image(self.supervisor.image) arch = get_arch_from_image(self.supervisor.image)

View File

@ -6,7 +6,6 @@ import logging
import docker import docker
from ..const import LABEL_VERSION from ..const import LABEL_VERSION
from ..tools import get_version_from_env
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -20,12 +19,11 @@ class DockerBase(object):
self.loop = loop self.loop = loop
self.dock = dock self.dock = dock
self.image = image self.image = image
self.container = None
self.version = None self.version = None
self._lock = asyncio.Lock(loop=loop) self._lock = asyncio.Lock(loop=loop)
@property @property
def docker_name(self): def name(self):
"""Return name of docker container.""" """Return name of docker container."""
return None return None
@ -34,18 +32,18 @@ class DockerBase(object):
"""Return True if a task is in progress.""" """Return True if a task is in progress."""
return self._lock.locked() return self._lock.locked()
def process_metadata(self, metadata=None, force=False): def process_metadata(self, metadata, force=False):
"""Read metadata and set it to object.""" """Read metadata and set it to object."""
if not force and self.version: # read image
return if not self.image:
self.image = metadata['Config']['Image']
# read metadata # read metadata
metadata = metadata or self.container.attrs need_version = force or not self.version
if LABEL_VERSION in metadata['Config']['Labels']: if need_version and LABEL_VERSION in metadata['Config']['Labels']:
self.version = metadata['Config']['Labels'][LABEL_VERSION] self.version = metadata['Config']['Labels'][LABEL_VERSION]
else: elif need_version:
# dedicated _LOGGER.warning("Can't read version from %s", self.name)
self.version = get_version_from_env(metadata['Config']['Env'])
async def install(self, tag): async def install(self, tag):
"""Pull docker image.""" """Pull docker image."""
@ -66,7 +64,7 @@ class DockerBase(object):
image = self.dock.images.pull("{}:{}".format(self.image, tag)) image = self.dock.images.pull("{}:{}".format(self.image, tag))
image.tag(self.image, tag='latest') image.tag(self.image, tag='latest')
self.process_metadata(metadata=image.attrs, force=True) self.process_metadata(image.attrs, force=True)
except docker.errors.APIError as err: except docker.errors.APIError as err:
_LOGGER.error("Can't install %s:%s -> %s.", self.image, tag, err) _LOGGER.error("Can't install %s:%s -> %s.", self.image, tag, err)
return False return False
@ -87,8 +85,7 @@ class DockerBase(object):
Need run inside executor. Need run inside executor.
""" """
try: try:
image = self.dock.images.get(self.image) self.dock.images.get(self.image)
self.process_metadata(metadata=image.attrs)
except docker.errors.DockerException: except docker.errors.DockerException:
return False return False
@ -106,16 +103,21 @@ class DockerBase(object):
Need run inside executor. Need run inside executor.
""" """
if not self.container:
try: try:
self.container = self.dock.containers.get(self.docker_name) container = self.dock.containers.get(self.name)
self.process_metadata() image = self.dock.images.get(self.image)
except docker.errors.DockerException: except docker.errors.DockerException:
return False return False
else:
self.container.reload()
return self.container.status == 'running' # container is not running
if container.status != 'running':
return False
# we run on a old image, stop and start it
if container.image.id != image.id:
return False
return True
async def attach(self): async def attach(self):
"""Attach to running docker container.""" """Attach to running docker container."""
@ -132,16 +134,17 @@ class DockerBase(object):
Need run inside executor. Need run inside executor.
""" """
try: try:
self.container = self.dock.containers.get(self.docker_name) if self.image:
self.image = self.container.attrs['Config']['Image'] obj_data = self.dock.images.get(self.image).attrs
self.process_metadata() else:
_LOGGER.info("Attach to image %s with version %s", obj_data = self.dock.containers.get(self.name).attrs
self.image, self.version) except docker.errors.DockerException:
except (docker.errors.DockerException, KeyError):
_LOGGER.fatal(
"Can't attach to %s docker container!", self.docker_name)
return False return False
self.process_metadata(obj_data)
_LOGGER.info(
"Attach to image %s with version %s", self.image, self.version)
return True return True
async def run(self): async def run(self):
@ -175,20 +178,19 @@ class DockerBase(object):
Need run inside executor. Need run inside executor.
""" """
if not self.container: try:
container = self.dock.containers.get(self.name)
except docker.errors.DockerException:
return return
_LOGGER.info("Stop %s docker application", self.image) _LOGGER.info("Stop %s docker application", self.image)
self.container.reload() if container.status == 'running':
if self.container.status == 'running':
with suppress(docker.errors.DockerException): with suppress(docker.errors.DockerException):
self.container.stop() container.stop()
with suppress(docker.errors.DockerException): with suppress(docker.errors.DockerException):
self.container.remove(force=True) container.remove(force=True)
self.container = None
async def remove(self): async def remove(self):
"""Remove docker container.""" """Remove docker container."""
@ -207,8 +209,8 @@ class DockerBase(object):
if self._is_running(): if self._is_running():
self._stop() self._stop()
_LOGGER.info("Remove docker %s with latest and %s", _LOGGER.info(
self.image, self.version) "Remove docker %s with latest and %s", self.image, self.version)
try: try:
with suppress(docker.errors.ImageNotFound): with suppress(docker.errors.ImageNotFound):
@ -239,24 +241,22 @@ class DockerBase(object):
Need run inside executor. Need run inside executor.
""" """
old_image = "{}:{}".format(self.image, self.version) was_running = self._is_running()
_LOGGER.info("Update docker %s with %s:%s", _LOGGER.info(
old_image, self.image, tag) "Update docker %s with %s:%s", self.version, self.image, tag)
# update docker image # update docker image
if self._install(tag): if not self._install(tag):
_LOGGER.info("Cleanup old %s docker", old_image)
self._stop()
try:
self.dock.images.remove(image=old_image, force=True)
except docker.errors.DockerException as err:
_LOGGER.warning(
"Can't remove old image %s -> %s", old_image, err)
return True
return False return False
# cleanup old stuff
if was_running:
self._run()
self._cleanup()
return True
async def logs(self): async def logs(self):
"""Return docker logs of container.""" """Return docker logs of container."""
if self._lock.locked(): if self._lock.locked():
@ -271,11 +271,13 @@ class DockerBase(object):
Need run inside executor. Need run inside executor.
""" """
if not self.container: try:
return container = self.dock.containers.get(self.name)
except docker.errors.DockerException:
return b""
try: try:
return self.container.logs(tail=100, stdout=True, stderr=True) return container.logs(tail=100, stdout=True, stderr=True)
except docker.errors.DockerException as err: except docker.errors.DockerException as err:
_LOGGER.warning("Can't grap logs from %s -> %s", self.image, err) _LOGGER.warning("Can't grap logs from %s -> %s", self.image, err)
@ -293,15 +295,45 @@ class DockerBase(object):
Need run inside executor. Need run inside executor.
""" """
if not self.container: try:
container = self.dock.containers.get(self.name)
except docker.errors.DockerException:
return False return False
_LOGGER.info("Restart %s", self.image) _LOGGER.info("Restart %s", self.image)
try: try:
self.container.restart(timeout=30) container.restart(timeout=30)
except docker.errors.DockerException as err: except docker.errors.DockerException as err:
_LOGGER.warning("Can't restart %s -> %s", self.image, err) _LOGGER.warning("Can't restart %s -> %s", self.image, err)
return False return False
return True return True
async def cleanup(self):
"""Check if old version exists and cleanup."""
if self._lock.locked():
_LOGGER.error("Can't excute cleanup while a task is in progress")
return False
async with self._lock:
await self.loop.run_in_executor(None, self._cleanup)
def _cleanup(self):
"""Check if old version exists and cleanup.
Need run inside executor.
"""
try:
latest = self.dock.images.get(self.image)
except docker.errors.DockerException:
_LOGGER.warning("Can't find %s for cleanup", self.image)
return
for image in self.dock.images.list(name=self.image):
if latest.id == image.id:
continue
with suppress(docker.errors.DockerException):
_LOGGER.info("Cleanup docker images: %s", image.tags)
self.dock.images.remove(image.id, force=True)

View File

@ -24,7 +24,7 @@ class DockerAddon(DockerBase):
self.addons_data = addons_data self.addons_data = addons_data
@property @property
def docker_name(self): def name(self):
"""Return name of docker container.""" """Return name of docker container."""
return "addon_{}".format(self.addon) return "addon_{}".format(self.addon)
@ -38,6 +38,14 @@ class DockerAddon(DockerBase):
'TZ': self.config.timezone, 'TZ': self.config.timezone,
} }
@property
def tmpfs(self):
"""Return tmpfs for docker add-on."""
options = self.addons_data.get_tmpfs(self.addon)
if options:
return {"/tmpfs": "{}".format(options)}
return None
@property @property
def volumes(self): def volumes(self):
"""Generate volumes for mappings.""" """Generate volumes for mappings."""
@ -88,57 +96,30 @@ class DockerAddon(DockerBase):
if self._is_running(): if self._is_running():
return return
# cleanup old container # cleanup
self._stop() self._stop()
try: try:
self.container = self.dock.containers.run( self.dock.containers.run(
self.image, self.image,
name=self.docker_name, name=self.name,
detach=True, detach=True,
network_mode=self.addons_data.get_network_mode(self.addon), network_mode=self.addons_data.get_network_mode(self.addon),
ports=self.addons_data.get_ports(self.addon), ports=self.addons_data.get_ports(self.addon),
devices=self.addons_data.get_devices(self.addon), devices=self.addons_data.get_devices(self.addon),
environment=self.environment, environment=self.environment,
volumes=self.volumes volumes=self.volumes,
tmpfs=self.tmpfs
) )
self.process_metadata()
_LOGGER.info("Start docker addon %s with version %s",
self.image, self.version)
except docker.errors.DockerException as err: except docker.errors.DockerException as err:
_LOGGER.error("Can't run %s -> %s", self.image, err) _LOGGER.error("Can't run %s -> %s", self.image, err)
return False return False
_LOGGER.info(
"Start docker addon %s with version %s", self.image, self.version)
return True return True
def _attach(self):
"""Attach to running docker container.
Need run inside executor.
"""
# read container
try:
self.container = self.dock.containers.get(self.docker_name)
self.process_metadata()
_LOGGER.info("Attach to container %s with version %s",
self.image, self.version)
return
except (docker.errors.DockerException, KeyError):
pass
# read image
try:
image = self.dock.images.get(self.image)
self.process_metadata(metadata=image.attrs)
_LOGGER.info("Attach to image %s with version %s",
self.image, self.version)
except (docker.errors.DockerException, KeyError):
_LOGGER.error("No container/image found for %s", self.image)
def _install(self, tag): def _install(self, tag):
"""Pull docker image or build it. """Pull docker image or build it.
@ -191,7 +172,7 @@ class DockerAddon(DockerBase):
path=str(build_dir), tag=build_tag, pull=True) path=str(build_dir), tag=build_tag, pull=True)
image.tag(self.image, tag='latest') image.tag(self.image, tag='latest')
self.process_metadata(metadata=image.attrs, force=True) self.process_metadata(image.attrs, force=True)
except (docker.errors.DockerException, TypeError) as err: except (docker.errors.DockerException, TypeError) as err:
_LOGGER.error("Can't build %s -> %s", build_tag, err) _LOGGER.error("Can't build %s -> %s", build_tag, err)

View File

@ -18,7 +18,7 @@ class DockerHomeAssistant(DockerBase):
super().__init__(config, loop, dock, image=config.homeassistant_image) super().__init__(config, loop, dock, image=config.homeassistant_image)
@property @property
def docker_name(self): def name(self):
"""Return name of docker container.""" """Return name of docker container."""
return HASS_DOCKER_NAME return HASS_DOCKER_NAME
@ -30,13 +30,13 @@ class DockerHomeAssistant(DockerBase):
if self._is_running(): if self._is_running():
return return
# cleanup old container # cleanup
self._stop() self._stop()
try: try:
self.container = self.dock.containers.run( self.dock.containers.run(
self.image, self.image,
name=self.docker_name, name=self.name,
detach=True, detach=True,
privileged=True, privileged=True,
network_mode='host', network_mode='host',
@ -53,26 +53,10 @@ class DockerHomeAssistant(DockerBase):
{'bind': '/share', 'mode': 'rw'}, {'bind': '/share', 'mode': 'rw'},
}) })
self.process_metadata()
_LOGGER.info("Start docker addon %s with version %s",
self.image, self.version)
except docker.errors.DockerException as err: except docker.errors.DockerException as err:
_LOGGER.error("Can't run %s -> %s", self.image, err) _LOGGER.error("Can't run %s -> %s", self.image, err)
return False return False
_LOGGER.info(
"Start homeassistant %s with version %s", self.image, self.version)
return True return True
async def update(self, tag):
"""Update homeassistant docker image."""
if self._lock.locked():
_LOGGER.error("Can't excute update while a task is in progress")
return False
async with self._lock:
if await self.loop.run_in_executor(None, self._update, tag):
await self.loop.run_in_executor(None, self._run)
return True
return False

View File

@ -2,8 +2,6 @@
import logging import logging
import os import os
import docker
from . import DockerBase from . import DockerBase
from ..const import RESTART_EXIT_CODE from ..const import RESTART_EXIT_CODE
@ -13,14 +11,13 @@ _LOGGER = logging.getLogger(__name__)
class DockerSupervisor(DockerBase): class DockerSupervisor(DockerBase):
"""Docker hassio wrapper for HomeAssistant.""" """Docker hassio wrapper for HomeAssistant."""
def __init__(self, config, loop, dock, hassio, image=None): def __init__(self, config, loop, dock, stop_callback, image=None):
"""Initialize docker base wrapper.""" """Initialize docker base wrapper."""
super().__init__(config, loop, dock, image=image) super().__init__(config, loop, dock, image=image)
self.stop_callback = stop_callback
self.hassio = hassio
@property @property
def docker_name(self): def name(self):
"""Return name of docker container.""" """Return name of docker container."""
return os.environ['SUPERVISOR_NAME'] return os.environ['SUPERVISOR_NAME']
@ -31,41 +28,14 @@ class DockerSupervisor(DockerBase):
return False return False
_LOGGER.info("Update supervisor docker to %s:%s", self.image, tag) _LOGGER.info("Update supervisor docker to %s:%s", self.image, tag)
old_version = self.version
async with self._lock: async with self._lock:
if await self.loop.run_in_executor(None, self._install, tag): if await self.loop.run_in_executor(None, self._install, tag):
self.config.hassio_cleanup = old_version self.loop.create_task(self.stop_callback(RESTART_EXIT_CODE))
self.loop.create_task(self.hassio.stop(RESTART_EXIT_CODE))
return True return True
return False return False
async def cleanup(self):
"""Check if old supervisor version exists and cleanup."""
if not self.config.hassio_cleanup:
return
async with self._lock:
if await self.loop.run_in_executor(None, self._cleanup):
self.config.hassio_cleanup = None
def _cleanup(self):
"""Remove old image.
Need run inside executor.
"""
old_image = "{}:{}".format(self.image, self.config.hassio_cleanup)
_LOGGER.info("Old supervisor docker found %s", old_image)
try:
self.dock.images.remove(image=old_image, force=True)
except docker.errors.DockerException as err:
_LOGGER.warning("Can't remove old image %s -> %s", old_image, err)
return False
return True
async def run(self): async def run(self):
"""Run docker image.""" """Run docker image."""
raise RuntimeError("Not support on supervisor docker container!") raise RuntimeError("Not support on supervisor docker container!")

View File

@ -46,17 +46,6 @@ def get_arch_from_image(image):
return found.group(1) return found.group(1)
def get_version_from_env(env_list):
"""Extract Version from ENV list."""
for env in env_list:
found = _RE_VERSION.match(env)
if found:
return found.group(1)
_LOGGER.error("Can't find VERSION in env")
return None
def get_local_ip(loop): def get_local_ip(loop):
"""Retrieve local IP address. """Retrieve local IP address.

View File

@ -1,5 +1,5 @@
{ {
"hassio": "0.33", "hassio": "0.34",
"homeassistant": "0.45.1", "homeassistant": "0.45.1",
"resinos": "0.8", "resinos": "0.8",
"resinhup": "0.1", "resinhup": "0.1",