mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-14 12:46:32 +00:00
Protect docker / Use Longtime poll
This commit is contained in:
parent
49fe7f2da4
commit
bea52bce63
@ -31,4 +31,7 @@ class APIHomeAssistant(object):
|
|||||||
body = await request.json(loads=json_loads)
|
body = await request.json(loads=json_loads)
|
||||||
version = body.get(ATTR_VERSION, self.config.current_homeassistant)
|
version = body.get(ATTR_VERSION, self.config.current_homeassistant)
|
||||||
|
|
||||||
return await self.dock_hass.update(version)
|
if self.dock_hass.in_progress:
|
||||||
|
raise RuntimeError("Other task is in progress!")
|
||||||
|
|
||||||
|
return await asyncio.shield(self.dock_hass.update(version))
|
||||||
|
@ -23,7 +23,11 @@ def api_process(method):
|
|||||||
"""Wrap function with true/false calls to rest api."""
|
"""Wrap function with true/false calls to rest api."""
|
||||||
async def wrap_api(api, *args, **kwargs):
|
async def wrap_api(api, *args, **kwargs):
|
||||||
"""Return api information."""
|
"""Return api information."""
|
||||||
|
try:
|
||||||
answer = await method(api, *args, **kwargs)
|
answer = await method(api, *args, **kwargs)
|
||||||
|
except RuntimeError as err:
|
||||||
|
return api_return_error(message=str(err))
|
||||||
|
|
||||||
if isinstance(answer, dict):
|
if isinstance(answer, dict):
|
||||||
return api_return_ok(data=answer)
|
return api_return_ok(data=answer)
|
||||||
elif answer:
|
elif answer:
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"""Init file for HassIO docker object."""
|
"""Init file for HassIO docker object."""
|
||||||
|
import asyncio
|
||||||
from contextlib import suppress
|
from contextlib import suppress
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -20,18 +21,26 @@ class DockerBase(object):
|
|||||||
self.image = image
|
self.image = image
|
||||||
self.container = None
|
self.container = None
|
||||||
self.version = None
|
self.version = None
|
||||||
|
self._lock = asyncio.Lock(loop=loop)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def docker_name(self):
|
def docker_name(self):
|
||||||
"""Return name of docker container."""
|
"""Return name of docker container."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def install(self, tag):
|
@property
|
||||||
"""Pull docker image.
|
def in_progress(self):
|
||||||
|
"""Return True if a task is in progress."""
|
||||||
|
return self._lock.locked
|
||||||
|
|
||||||
Return a Future.
|
async def install(self, tag):
|
||||||
"""
|
"""Pull docker image."""
|
||||||
return self.loop.run_in_executor(None, self._install, tag)
|
if self._lock.locked:
|
||||||
|
_LOGGER.error("Can't excute install while a task is in progress")
|
||||||
|
return False
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
return await self.loop.run_in_executor(None, self._install, tag)
|
||||||
|
|
||||||
def _install(self, tag):
|
def _install(self, tag):
|
||||||
"""Pull docker image.
|
"""Pull docker image.
|
||||||
@ -44,6 +53,8 @@ class DockerBase(object):
|
|||||||
|
|
||||||
image.tag(self.image, tag='latest')
|
image.tag(self.image, tag='latest')
|
||||||
self.version = get_version_from_env(image.attrs['Config']['Env'])
|
self.version = get_version_from_env(image.attrs['Config']['Env'])
|
||||||
|
_LOGGER.info("Tag image %s with version %s as latest.",
|
||||||
|
self.image, self.version)
|
||||||
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
|
||||||
@ -72,12 +83,14 @@ class DockerBase(object):
|
|||||||
self.container.reload()
|
self.container.reload()
|
||||||
return self.container.status == 'running'
|
return self.container.status == 'running'
|
||||||
|
|
||||||
def attach(self):
|
async def attach(self):
|
||||||
"""Attach to running docker container.
|
"""Attach to running docker container."""
|
||||||
|
if self._lock.locked:
|
||||||
|
_LOGGER.error("Can't excute stop while a task is in progress")
|
||||||
|
return False
|
||||||
|
|
||||||
Return a Future.
|
async with self._lock:
|
||||||
"""
|
return await self.loop.run_in_executor(None, self._attach)
|
||||||
return self.loop.run_in_executor(None, self._attach)
|
|
||||||
|
|
||||||
def _attach(self):
|
def _attach(self):
|
||||||
"""Attach to running docker container.
|
"""Attach to running docker container.
|
||||||
@ -89,16 +102,25 @@ class DockerBase(object):
|
|||||||
self.image = self.container.attrs['Config']['Image']
|
self.image = self.container.attrs['Config']['Image']
|
||||||
self.version = get_version_from_env(
|
self.version = get_version_from_env(
|
||||||
self.container.attrs['Config']['Env'])
|
self.container.attrs['Config']['Env'])
|
||||||
|
_LOGGER.info("Attach to image %s with version %s.",
|
||||||
|
self.image, self.version)
|
||||||
except (docker.errors.DockerException, KeyError):
|
except (docker.errors.DockerException, KeyError):
|
||||||
_LOGGER.fatal(
|
_LOGGER.fatal(
|
||||||
"Can't attach to %s docker container!", self.docker_name)
|
"Can't attach to %s docker container!", self.docker_name)
|
||||||
|
return False
|
||||||
|
|
||||||
def run(self):
|
return True
|
||||||
"""Run docker image.
|
|
||||||
|
|
||||||
Return a Future.
|
async def run(self):
|
||||||
"""
|
"""Run docker image."""
|
||||||
return self.loop.run_in_executor(None, self._run)
|
if self._lock.locked:
|
||||||
|
_LOGGER.error("Can't excute run while a task is in progress")
|
||||||
|
return False
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
_LOGGER.info("Run docker image %s.",
|
||||||
|
self.image)
|
||||||
|
return await self.loop.run_in_executor(None, self._run)
|
||||||
|
|
||||||
def _run(self):
|
def _run(self):
|
||||||
"""Run docker image.
|
"""Run docker image.
|
||||||
@ -107,12 +129,15 @@ class DockerBase(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def stop(self):
|
async def stop(self):
|
||||||
"""Stop/remove docker container.
|
"""Stop/remove docker container."""
|
||||||
|
if self._lock.locked:
|
||||||
|
_LOGGER.error("Can't excute stop while a task is in progress")
|
||||||
|
return False
|
||||||
|
|
||||||
Return a Future.
|
async with self._lock:
|
||||||
"""
|
await self.loop.run_in_executor(None, self._stop)
|
||||||
return self.loop.run_in_executor(None, self._stop)
|
return True
|
||||||
|
|
||||||
def _stop(self):
|
def _stop(self):
|
||||||
"""Stop/remove and remove docker container.
|
"""Stop/remove and remove docker container.
|
||||||
@ -132,12 +157,17 @@ class DockerBase(object):
|
|||||||
|
|
||||||
self.container = None
|
self.container = None
|
||||||
|
|
||||||
def update(self, tag):
|
async def update(self, tag):
|
||||||
"""Update a docker image.
|
"""Update a docker image.
|
||||||
|
|
||||||
Return a Future.
|
Return a Future.
|
||||||
"""
|
"""
|
||||||
return self.loop.run_in_executor(None, self._update, tag)
|
if self._lock.locked:
|
||||||
|
_LOGGER.error("Can't excute update while a task is in progress")
|
||||||
|
return False
|
||||||
|
|
||||||
|
async with self._lock:
|
||||||
|
return await self.loop.run_in_executor(None, self._update, tag)
|
||||||
|
|
||||||
def _update(self, tag):
|
def _update(self, tag):
|
||||||
"""Update a docker image.
|
"""Update a docker image.
|
||||||
@ -145,13 +175,22 @@ class DockerBase(object):
|
|||||||
Need run inside executor.
|
Need run inside executor.
|
||||||
"""
|
"""
|
||||||
old_image = "{}:{}".format(self.image, self.version)
|
old_image = "{}:{}".format(self.image, self.version)
|
||||||
|
old_run = self._is_running()
|
||||||
|
|
||||||
|
_LOGGER.info("Update docker %s with {}:{}.", self.image, tag)
|
||||||
|
|
||||||
|
# update docker image
|
||||||
if self._install(tag):
|
if self._install(tag):
|
||||||
|
_LOGGER.info("Cleanup old %s docker.", old_image)
|
||||||
self._stop()
|
self._stop()
|
||||||
try:
|
try:
|
||||||
self.dock.images.remove(image=old_image, force=True)
|
self.dock.images.remove(image=old_image, force=True)
|
||||||
return True
|
|
||||||
except docker.errors.DockerException as err:
|
except docker.errors.DockerException as err:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Can't remove old image %s -> %s.", old_image, err)
|
"Can't remove old image %s -> %s.", old_image, err)
|
||||||
|
# restore
|
||||||
|
if old_run:
|
||||||
|
self._run()
|
||||||
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
Loading…
x
Reference in New Issue
Block a user