Update api / use local config.json for resinos

This commit is contained in:
pvizeli 2017-04-03 17:00:56 +02:00
parent 9a390f6fc9
commit 931e5f4f6b
12 changed files with 112 additions and 51 deletions

View File

@ -3,7 +3,7 @@ import logging
from aiohttp.web_exceptions import HTTPServiceUnavailable
from .util import api_return_ok
from .util import api_process, json_loads
from ..const import ATTR_VERSION
_LOGGER = logging.getLogger(__name__)
@ -18,12 +18,19 @@ class APIHomeAssistant(object):
self.loop = loop
self.dock_hass = dock_hass
@api_process
async def info(self, request):
"""Return host information."""
return api_return_ok({
info = {
ATTR_VERSION: self.dock_hass.version,
})
}
return info
@api_process
async def update(self, request):
"""Update host OS."""
raise HTTPServiceUnavailable()
body = await request.json(loads=json_loads)
version = body.get(ATTR_VERSION, self.config.current_homeassistant)
return await self.dock_hass.update(version):

View File

@ -44,5 +44,7 @@ class APIHost(object):
@api_process_hostcontroll
async def update(self, request):
"""Update host OS."""
body = await request.json() or {}
return await self.host_controll.host_update(body.get(ATTR_VERSION))
body = await request.json(loads=json_loads)
version = body.get(ATTR_VERSION)
return await self.host_controll.host_update(version=version)

View File

@ -1,7 +1,7 @@
"""Init file for HassIO supervisor rest api."""
import logging
from .util import api_return_ok, api_process_hostcontroll
from .util import api_process, api_process_hostcontroll, json_loads
from ..const import ATTR_VERSION, HASSIO_VERSION
_LOGGER = logging.getLogger(__name__)
@ -16,15 +16,19 @@ class APISupervisor(object):
self.loop = loop
self.host_controll = host_controll
@api_process
async def info(self, request):
"""Return host information."""
return api_return_ok({
info = {
ATTR_VERSION: HASSIO_VERSION,
})
}
return info
@api_process_hostcontroll
async def update(self, request):
"""Update host OS."""
body = await request.json() or {}
return await self.host_controll.supervisor_update(
body.get(ATTR_VERSION))
body = await request.json(loads=json_loads)
version = body.get(ATTR_VERSION, self.config.current_hassio)
return await self.host_controll.supervisor_update(version=version)

View File

@ -1,4 +1,5 @@
"""Init file for HassIO util for rest api."""
import json
import logging
from aiohttp import web
@ -10,6 +11,28 @@ from ..const import (
_LOGGER = logging.getLogger(__name__)
def json_loads(data):
"""Extract json from string with support for '' and None."""
try:
return json.loads(data)
except json.JSONDecodeError:
return {}
def api_process(method):
"""Wrap function with true/false calls to rest api."""
async def wrap_api(api, *args, **kwargs):
"""Return api information."""
answer = await method(api, *args, **kwargs)
if isinstance(answer, dict):
return api_return_ok(data=answer)
elif answer:
return api_return_ok()
return api_return_error()
return wrap_api
def api_process_hostcontroll(method):
"""Wrap HostControll calls to rest api."""
async def wrap_hostcontroll(api, *args, **kwargs):
@ -19,7 +42,7 @@ def api_process_hostcontroll(method):
answer = await method(api, *args, **kwargs)
if isinstance(answer, dict):
return web.json_response(answer)
return api_return_ok(data=answer)
elif answer is None:
return api_not_supported()
elif answer:

View File

@ -11,9 +11,9 @@ from .config import CoreConfig
_LOGGER = logging.getLogger(__name__)
def initialize_system_data():
def initialize_system_data(websession):
"""Setup default config and create folders."""
config = CoreConfig()
config = CoreConfig(websession)
# homeassistant config folder
if not os.path.isdir(config.path_config):

View File

@ -3,18 +3,26 @@ import json
import logging
import os
from .const import (
FILE_HASSIO_CONFIG, HOMEASSISTANT_TAG, HOMEASSISTANT_IMAGE,
HOMEASSISTANT_SSL, HOMEASSISTANT_CONFIG, HASSIO_SHARE)
from .const import FILE_HASSIO_CONFIG, HASSIO_SHARE
from .tools import fetch_current_versions
_LOGGER = logging.getLogger(__name__)
HOMEASSISTANT_CONFIG = "{}/homeassistant_config"
HOMEASSISTANT_SSL = "{}/homeassistant_ssl"
HOMEASSISTANT_IMAGE = 'homeassistant_image'
HOMEASSISTANT_TAG = 'homeassistant_tag'
HOMEASSISTANT_CURRENT = 'homeassistant_current'
HASSIO_CURRENT = 'hassio_current'
class CoreConfig(object):
"""Hold all config data."""
def __init__(self, config_file=FILE_HASSIO_CONFIG):
def __init__(self, websession, config_file=FILE_HASSIO_CONFIG):
"""Initialize config object."""
self.websession = websession
self._filename = config_file
self._data = {}
@ -40,6 +48,20 @@ class CoreConfig(object):
except OSError:
_LOGGER.exception("Can't store config in %s", self._filename)
async def fetch_update_infos():
"""Read current versions from web."""
avilable_updates = await fetch_current_versions(self.websession)
if avilable_updates:
self._data.update({
HOMEASSISTANT_CURRENT: current.get('homeassistant_tag'),
HASSIO_CURRENT: current.get('hassio_tag'),
})
self.save()
return True
return False
@property
def homeassistant_image(self):
"""Return docker homeassistant repository."""
@ -56,6 +78,16 @@ class CoreConfig(object):
self._data[HOMEASSISTANT_TAG] = value
self.save()
@property
def current_homeassistant(self):
"""Actual version of homeassistant."""
return self._data.get(HOMEASSISTANT_CURRENT)
@property
def current_hassio(self):
"""Actual version of hassio."""
return self._data.get(HASSIO_CURRENT)
@property
def path_config_docker(self):
"""Return config path extern for docker."""

View File

@ -6,24 +6,14 @@ URL_HASSIO_VERSION = \
URL_ADDONS_REPO = 'https://github.com/pvizeli/hassio-addons'
FILE_HOST_CONFIG = '/boot/config.json'
FILE_HOST_NETWORK = '/boot/network'
FILE_HASSIO_ADDONS = '/data/addons.json'
FILE_HASSIO_CONFIG = '/data/config.json'
HASSIO_SHARE = "/data"
HASSIO_SHARE = '/data'
FILE_HASSIO_ADDONS = "{}/addons.json".format(HASSIO_SHARE)
FILE_HASSIO_CONFIG = "{}/config.json".format(HASSIO_SHARE)
SOCKET_DOCKER = "/var/run/docker.sock"
SOCKET_HC = "/var/run/hassio-hc.sock"
HOMEASSISTANT_CONFIG = "{}/homeassistant_config"
HOMEASSISTANT_SSL = "{}/homeassistant_ssl"
HTTP_PORT = 9123
HOMEASSISTANT_IMAGE = 'homeassistant_image'
HOMEASSISTANT_TAG = 'homeassistant_tag'
JSON_RESULT = 'result'
JSON_DATA = 'data'
JSON_MESSAGE = 'message'

View File

@ -21,8 +21,8 @@ class HassIO(object):
def __init__(self, loop):
"""Initialize hassio object."""
self.loop = loop
self.config = bootstrap.initialize_system_data()
self.websession = aiohttp.ClientSession(loop=self.loop)
self.config = bootstrap.initialize_system_data(self.websession)
self.api = RestAPI(self.config, self.loop)
self.dock = docker.DockerClient(
base_url="unix:/{}".format(SOCKET_DOCKER), version='auto')
@ -79,18 +79,17 @@ class HassIO(object):
async def _setup_homeassistant(self):
"""Install a homeassistant docker container."""
current = None
while True:
# read homeassistant tag and install it
current = await tools.fetch_current_versions(self.websession)
if current and HOMEASSISTANT_TAG in current:
resp = await self.homeassistant.install(
current[HOMEASSISTANT_TAG])
if resp:
break
if not self.config.current_homeassistant:
await self.config.fetch_update_infos():
tag = self.config.current_homeassistant
if tag and await self.homeassistant.install(tag):
break
_LOGGER.warning("Error on setup HomeAssistant. Retry in 60.")
await asyncio.sleep(60, loop=self.loop)
# store version
self.config.homeassistant_tag = current[HOMEASSISTANT_TAG]
self.config.homeassistant_tag = self.config.current_homeassistant
_LOGGER.info("HomeAssistant docker now exists.")

View File

@ -151,6 +151,8 @@ class DockerBase(object):
if self._install(tag):
try:
self.dock.images.remove(image=old_image, force=True)
return True
except docker.errors.DockerException as err:
_LOGGER.warning(
"Can't remove old image %s -> %s.", old_image, err)
return False

View File

@ -62,7 +62,7 @@ class HostControll(object):
else:
try:
return json.loads(response)
except ValueError:
except json.JSONDecodeError:
_LOGGER.warning("Json parse error from HostControll.")
except asyncio.TimeoutError:

View File

@ -1,7 +1,6 @@
"""Tools file for HassIO."""
import asyncio
import logging
import json
import re
import socket
@ -23,8 +22,7 @@ async def fetch_current_versions(websession):
try:
with async_timeout.timeout(10, loop=websession.loop):
async with websession.get(URL_HASSIO_VERSION) as request:
data = await request.text()
return json.loads(data)
return await request.json(content_type=None)
except (ValueError, aiohttp.ClientError, asyncio.TimeoutError) as err:
_LOGGER.warning("Can't fetch versions from github! %s", err)

View File

@ -1,6 +1,8 @@
#!/bin/bash
set -o pipefail
SUPERVISOR_CONFIG="/resin-data/config.json"
# Help function
function update-resin-supervisor-help {
cat << EOF
@ -70,15 +72,12 @@ function error_handler {
trap 'error_handler $LINENO' ERR
if tag=$(curl --silent $ENDPOINT | jq -e -r '.hassio_tag'); then
if [ -f $SUPERVISOR_CONFIG ]; then
tag=$(jq --raw-output ".hassio_current // empty" $SUPERVISOR_CONFIG)
image_name=$SUPERVISOR_IMAGE
# Check that we didn't somehow get an empty tag version.
if [ -z $tag ] || [ -z $image_name ]; then
error_handler $LINENO "no tag received"
fi
fi
# override from params
if [ ! -z $UPDATER_SUPERVISOR_TAG ]; then
tag=$UPDATER_SUPERVISOR_TAG
fi
@ -86,6 +85,11 @@ if [ ! -z $UPDATER_SUPERVISOR_IMAGE ]; then
image_name=$UPDATER_SUPERVISOR_IMAGE
fi
# Check that we didn't somehow get an empty tag version.
if [ -z $tag ] || [ -z $image_name ]; then
error_handler $LINENO "no tag received"
fi
# Get image id of tag. This will be non-empty only in case it's already downloaded.
echo "Getting image id..."
imageid=$(docker inspect -f '{{.Id}}' "$image_name:$tag") || imageid=""