From 89dc78bc0551b52650d715c531a98bb271a528a7 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 5 Jun 2019 17:10:44 +0200 Subject: [PATCH 01/16] Bump version 167 --- hassio/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hassio/const.py b/hassio/const.py index 7fd9d9d37..8e49f1b5e 100644 --- a/hassio/const.py +++ b/hassio/const.py @@ -3,7 +3,7 @@ from pathlib import Path from ipaddress import ip_network -HASSIO_VERSION = "166" +HASSIO_VERSION = "167" URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons" URL_HASSIO_VERSION = "https://s3.amazonaws.com/hassio-version/{channel}.json" From 3e645b61757eee406c81223bd59cd6e5eec8d9e0 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 5 Jun 2019 17:49:05 +0200 Subject: [PATCH 02/16] Fix timeout on check port (#1116) --- hassio/utils/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hassio/utils/__init__.py b/hassio/utils/__init__.py index 0f46f7f58..c675c6f6d 100644 --- a/hassio/utils/__init__.py +++ b/hassio/utils/__init__.py @@ -60,6 +60,7 @@ class AsyncThrottle: def check_port(address: IPv4Address, port: int) -> bool: """Check if port is mapped.""" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(0.5) try: result = sock.connect_ex((str(address), port)) sock.close() From d5c3850a3fcc330d7ddb6084332aaa7fd62c37a3 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 6 Jun 2019 10:57:36 +0200 Subject: [PATCH 03/16] Don't break on supervisor update (#1118) * Don't break on supervisor update * Update core.py * Fix lint --- hassio/core.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/hassio/core.py b/hassio/core.py index 3a3a38911..cd3d08f41 100644 --- a/hassio/core.py +++ b/hassio/core.py @@ -12,7 +12,7 @@ from .const import ( STARTUP_APPLICATION, STARTUP_INITIALIZE, ) -from .exceptions import HassioError, HomeAssistantError +from .exceptions import HassioError, HomeAssistantError, SupervisorUpdateError _LOGGER = logging.getLogger(__name__) @@ -75,10 +75,16 @@ class HassIO(CoreSysAttributes): """Start Hass.io orchestration.""" # on release channel, try update itself if self.sys_supervisor.need_update: - if self.sys_dev: - _LOGGER.warning("Ignore Hass.io updates on dev!") - elif await self.sys_supervisor.update(): - return + try: + if self.sys_dev: + _LOGGER.warning("Ignore Hass.io updates on dev!") + else: + await self.sys_supervisor.update() + except SupervisorUpdateError: + _LOGGER.fatal( + "Can't update supervisor! This will break some Add-ons or affect " + "future version of Home Assistant!" + ) # start api await self.sys_api.start() From 86305d4fe4e094daec7f519f5ce832fbd7fddd20 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2019 09:50:28 +0200 Subject: [PATCH 04/16] Bump docker from 4.0.1 to 4.0.2 (#1133) Bumps [docker](https://github.com/docker/docker-py) from 4.0.1 to 4.0.2. - [Release notes](https://github.com/docker/docker-py/releases) - [Commits](https://github.com/docker/docker-py/compare/4.0.1...4.0.2) Signed-off-by: dependabot-preview[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 1e316099e..bdfa609c3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,7 +5,7 @@ cchardet==2.1.4 colorlog==4.0.2 cpe==1.2.1 cryptography==2.7 -docker==4.0.1 +docker==4.0.2 gitpython==2.1.11 pytz==2019.1 pyudev==0.21.0 From 69151b962a66f64cd72e4cb1cd1c3e4b12410cb7 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 21 Jun 2019 09:50:42 +0200 Subject: [PATCH 05/16] Bump pytest from 4.6.2 to 4.6.3 (#1125) Bumps [pytest](https://github.com/pytest-dev/pytest) from 4.6.2 to 4.6.3. - [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/4.6.2...4.6.3) Signed-off-by: dependabot-preview[bot] --- requirements_tests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements_tests.txt b/requirements_tests.txt index bd4ac14d1..a5678efc3 100644 --- a/requirements_tests.txt +++ b/requirements_tests.txt @@ -1,5 +1,5 @@ flake8==3.7.7 pylint==2.3.1 -pytest==4.6.2 +pytest==4.6.3 pytest-timeout==1.3.3 pytest-aiohttp==0.3.0 From 7bd77c6e99c96ef8b435976ef15f6efb1d05ef35 Mon Sep 17 00:00:00 2001 From: Jakub Date: Mon, 24 Jun 2019 09:53:54 +0200 Subject: [PATCH 06/16] Append devlinks to serial dev_list (#1131) * append devlinks to dev_list * replace eudev-libs with eudev * include only devlinks starting with /dev/serial/by-id * add missing package, move udev init to entry.sh * fix mode on entry.sh * Update homeassistant.py * Update homeassistant.py --- Dockerfile | 5 +++++ entry.sh | 13 +++++++++++++ hassio/docker/homeassistant.py | 10 ---------- hassio/misc/hardware.py | 9 +++++++++ 4 files changed, 27 insertions(+), 10 deletions(-) create mode 100755 entry.sh diff --git a/Dockerfile b/Dockerfile index 846675b9b..a1124d652 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,6 +12,7 @@ RUN apk add --no-cache \ socat \ glib \ libstdc++ \ + eudev \ eudev-libs # Install requirements @@ -25,4 +26,8 @@ RUN export MAKEFLAGS="-j$(nproc)" \ COPY . /usr/src/hassio RUN pip3 install --no-cache-dir -e /usr/src/hassio +# Initialize udev daemon, handle CMD +COPY entry.sh /bin/ +ENTRYPOINT ["/bin/entry.sh"] + CMD [ "python3", "-m", "hassio" ] diff --git a/entry.sh b/entry.sh new file mode 100755 index 000000000..b46d3d916 --- /dev/null +++ b/entry.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e + +udevd --daemon +udevadm trigger + +if CMD="$(command -v "$1")"; then + shift + exec "$CMD" "$@" +else + echo "Command not found: $1" + exit 1 +fi diff --git a/hassio/docker/homeassistant.py b/hassio/docker/homeassistant.py index 29c196628..f9367cfa2 100644 --- a/hassio/docker/homeassistant.py +++ b/hassio/docker/homeassistant.py @@ -40,14 +40,6 @@ class DockerHomeAssistant(DockerInterface): """Return timeout for Docker actions.""" return 60 - @property - def devices(self): - """Create list of special device to map into Docker.""" - devices = [] - for device in self.sys_hardware.serial_devices: - devices.append(f"{device}:{device}:rwm") - return devices or None - @property def ip_address(self) -> IPv4Address: """Return IP address of this container.""" @@ -73,7 +65,6 @@ class DockerHomeAssistant(DockerInterface): detach=True, privileged=True, init=True, - devices=self.devices, network_mode="host", environment={ "HASSIO": self.sys_docker.network.supervisor, @@ -106,7 +97,6 @@ class DockerHomeAssistant(DockerInterface): command, privileged=True, init=True, - devices=self.devices, detach=True, stdout=True, stderr=True, diff --git a/hassio/misc/hardware.py b/hassio/misc/hardware.py index 701526495..4748d4a1a 100644 --- a/hassio/misc/hardware.py +++ b/hassio/misc/hardware.py @@ -39,6 +39,15 @@ class Hardware: if "ID_VENDOR" in device or RE_TTY.search(device.device_node): dev_list.add(device.device_node) + # Add /dev/serial/by-id devlink for current device + if "DEVLINKS" in device and device["DEVLINKS"]: + devlinks = [ + symlink + for symlink in device["DEVLINKS"].split(" ") + if symlink.startswith("/dev/serial/by-id") + ] + dev_list.update(devlinks) + return dev_list @property From 72338eb5b88ac2cf9031affe6d194f74acc58b94 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jun 2019 14:48:10 +0200 Subject: [PATCH 07/16] Add devcontainer support (#1134) --- .devcontainer/Dockerfile | 12 ++++++++++++ .devcontainer/devcontainer.json | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..594abb81c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,12 @@ +FROM python:3.7 + +WORKDIR /workspace + +# Install Python dependencies from requirements.txt if it exists +COPY requirements.txt requirements_tests.txt /workspace/ +RUN pip install -r requirements.txt \ + && pip3 install -r requirements_tests.txt \ + && pip install black tox + +# Set the default shell to bash instead of sh +ENV SHELL /bin/bash diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..a27fe99b0 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,18 @@ +// See https://aka.ms/vscode-remote/devcontainer.json for format details. +{ + "name": "Hass.io dev", + "context": "..", + "dockerFile": "Dockerfile", + "extensions": [ + "ms-python.python" + ], + "settings": { + "python.pythonPath": "/usr/local/bin/python", + "python.linting.pylintEnabled": true, + "python.linting.enabled": true, + "python.formatting.provider": "black", + "editor.formatOnPaste": false, + "editor.formatOnSave": true, + "editor.formatOnType": true + } +} \ No newline at end of file From 626a9f06c4a41042d1c651c8a6bfdcde2f829266 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jun 2019 18:49:43 +0200 Subject: [PATCH 08/16] Update to alpine 3.10 (#1135) --- Dockerfile | 2 +- azure-pipelines.yml | 43 ++++++++++++------------------------------- 2 files changed, 13 insertions(+), 32 deletions(-) diff --git a/Dockerfile b/Dockerfile index a1124d652..19bd18a4a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,7 @@ RUN apk add --no-cache \ # Install requirements COPY requirements.txt /usr/src/ RUN export MAKEFLAGS="-j$(nproc)" \ - && pip3 install --no-cache-dir --find-links https://wheels.hass.io/alpine-3.9/${BUILD_ARCH}/ \ + && pip3 install --no-cache-dir --find-links "https://wheels.home-assistant.io/alpine-$(cut -d '.' -f 1-2 < /etc/alpine-release)/${BUILD_ARCH}/" \ -r /usr/src/requirements.txt \ && rm -f /usr/src/requirements.txt diff --git a/azure-pipelines.yml b/azure-pipelines.yml index cd88507ca..c57d9c376 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,12 +14,14 @@ trigger: pr: - dev variables: + - name: basePythonTag + value: '3.7-alpine3.10' - name: versionHadolint value: 'v1.16.3' - name: versionBuilder - value: '3.2' + value: '4.4' - name: versionWheels - value: '0.6' + value: '0.10' - group: docker - group: wheels @@ -115,12 +117,12 @@ jobs: ssh-keyscan -H $(wheelsHost) >> .ssh/known_hosts chmod 600 .ssh/* displayName: 'Install ssh key' - - script: sudo docker pull homeassistant/$(buildArch)-wheels:$(versionWheels) + - script: sudo docker pull homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) displayName: 'Install wheels builder' - script: | curl -s -o requirements_diff.txt https://raw.githubusercontent.com/home-assistant/hassio/master/requirements.txt sudo docker run --rm -v $(pwd):/data:ro -v $(pwd)/.ssh:/root/.ssh:rw \ - homeassistant/$(buildArch)-wheels:$(versionWheels) \ + homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) \ --apk "build-base;libffi-dev;openssl-dev" \ --index $(wheelsIndex) \ --requirement requirements.txt \ @@ -130,31 +132,8 @@ jobs: displayName: 'Run wheels build' -- job: 'ReleaseDEV' - condition: and(eq(variables['Build.SourceBranchName'], 'dev'), succeeded('JQ'), succeeded('Tox'), succeeded('Hadolint'), succeeded('Wheels')) - dependsOn: - - 'JQ' - - 'Tox' - - 'Hadolint' - - 'Wheels' - pool: - vmImage: 'ubuntu-latest' - steps: - - script: sudo docker login -u $(dockerUser) -p $(dockerPassword) - displayName: 'Docker hub login' - - script: sudo docker pull homeassistant/amd64-builder:$(versionBuilder) - displayName: 'Install Builder' - - script: | - sudo docker run --rm --privileged \ - -v ~/.docker:/root/.docker \ - -v /run/docker.sock:/run/docker.sock:rw -v $(pwd):/data:ro \ - homeassistant/amd64-builder:$(versionBuilder) \ - --supervisor --all -t /data --version dev --docker-hub homeassistant - displayName: 'Build DEV' - - - job: 'VersionValidate' - condition: startsWith(variables['Build.SourceBranch'], 'refs/tags') + condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), eq(variables['Build.SourceBranchName'], 'dev')) pool: vmImage: 'ubuntu-latest' steps: @@ -166,7 +145,9 @@ jobs: setup_version="$(python setup.py -V)" branch_version="$(Build.SourceBranchName)" - if [ "${setup_version}" != "${branch_version}" ]; then + if [ "${branch_version}" == "dev" ]; then + exit 0 + elif [ "${setup_version}" != "${branch_version}" ]; then echo "Version of tag ${branch_version} don't match with ${setup_version}!" exit 1 fi @@ -174,7 +155,6 @@ jobs: - job: 'Release' - condition: and(startsWith(variables['Build.SourceBranch'], 'refs/tags'), succeeded('JQ'), succeeded('Tox'), succeeded('Hadolint'), succeeded('VersionValidate')) dependsOn: - 'JQ' - 'Tox' @@ -192,5 +172,6 @@ jobs: -v ~/.docker:/root/.docker \ -v /run/docker.sock:/run/docker.sock:rw -v $(pwd):/data:ro \ homeassistant/amd64-builder:$(versionBuilder) \ - --supervisor --all -t /data --docker-hub homeassistant + --supervisor $(basePythonTag) --version $(Build.SourceBranchName) \ + --all -t /data --docker-hub homeassistant displayName: 'Build Release' From 5291e6c1f3b9c633a633132b782883070c5c26f2 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jun 2019 19:04:52 +0200 Subject: [PATCH 09/16] Use multistage --- azure-pipelines.yml | 283 +++++++++++++++++++++----------------------- 1 file changed, 138 insertions(+), 145 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c57d9c376..b571976a0 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,157 +21,150 @@ variables: - name: versionBuilder value: '4.4' - name: versionWheels - value: '0.10' + value: '0.11' - group: docker - group: wheels -jobs: +stages: -- job: 'Tox' - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: '3.7' - - script: pip install tox - displayName: 'Install Tox' - - script: tox - displayName: 'Run Tox' +- stage: 'Test' + jobs: + - job: 'Tox' + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: '3.7' + - script: pip install tox + displayName: 'Install Tox' + - script: tox + displayName: 'Run Tox' + - job: 'Black' + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python $(python.version)' + inputs: + versionSpec: '3.7' + - script: pip install black + displayName: 'Install black' + - script: black --check hassio tests + displayName: 'Run Black' + - job: 'JQ' + pool: + vmImage: 'ubuntu-latest' + steps: + - script: sudo apt-get install -y jq + displayName: 'Install JQ' + - bash: | + shopt -s globstar + cat **/*.json | jq '.' + displayName: 'Run JQ' + - job: 'Hadolint' + pool: + vmImage: 'ubuntu-latest' + steps: + - script: sudo docker pull hadolint/hadolint:$(versionHadolint) + displayName: 'Install Hadolint' + - script: | + sudo docker run --rm -i \ + -v $(pwd)/.hadolint.yaml:/.hadolint.yaml:ro \ + hadolint/hadolint:$(versionHadolint) < Dockerfile + displayName: 'Run Hadolint' +- stage: 'Wheels' + jobs: + - job: 'Wheels' + condition: eq(variables['Build.SourceBranchName'], 'dev') + timeoutInMinutes: 360 + pool: + vmImage: 'ubuntu-latest' + strategy: + maxParallel: 3 + matrix: + amd64: + buildArch: 'amd64' + i386: + buildArch: 'i386' + armhf: + buildArch: 'armhf' + armv7: + buildArch: 'armv7' + aarch64: + buildArch: 'aarch64' + steps: + - script: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + qemu-user-static \ + binfmt-support \ + curl -- job: 'Black' - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python $(python.version)' - inputs: - versionSpec: '3.7' - - script: pip install black - displayName: 'Install black' - - script: black --check hassio tests - displayName: 'Run Black' + sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc + sudo update-binfmts --enable qemu-arm + sudo update-binfmts --enable qemu-aarch64 + displayName: 'Initial cross build' + - script: | + mkdir -p .ssh + echo -e "-----BEGIN RSA PRIVATE KEY-----\n$(wheelsSSH)\n-----END RSA PRIVATE KEY-----" >> .ssh/id_rsa + ssh-keyscan -H $(wheelsHost) >> .ssh/known_hosts + chmod 600 .ssh/* + displayName: 'Install ssh key' + - script: sudo docker pull homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) + displayName: 'Install wheels builder' + - script: | + curl -s -o requirements_diff.txt https://raw.githubusercontent.com/home-assistant/hassio/master/requirements.txt + sudo docker run --rm -v $(pwd):/data:ro -v $(pwd)/.ssh:/root/.ssh:rw \ + homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) \ + --apk "build-base;libffi-dev;openssl-dev" \ + --index $(wheelsIndex) \ + --requirement requirements.txt \ + --requirement-diff requirements_diff.txt \ + --upload rsync \ + --remote wheels@$(wheelsHost):/opt/wheels + displayName: 'Run wheels build' +- stage: 'Deploy' + jobs: + - job: 'VersionValidate' + condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), eq(variables['Build.SourceBranchName'], 'dev')) + pool: + vmImage: 'ubuntu-latest' + steps: + - task: UsePythonVersion@0 + displayName: 'Use Python 3.7' + inputs: + versionSpec: '3.7' + - script: | + setup_version="$(python setup.py -V)" + branch_version="$(Build.SourceBranchName)" -- job: 'JQ' - pool: - vmImage: 'ubuntu-latest' - steps: - - script: sudo apt-get install -y jq - displayName: 'Install JQ' - - bash: | - shopt -s globstar - cat **/*.json | jq '.' - displayName: 'Run JQ' - - -- job: 'Hadolint' - pool: - vmImage: 'ubuntu-latest' - steps: - - script: sudo docker pull hadolint/hadolint:$(versionHadolint) - displayName: 'Install Hadolint' - - script: | - sudo docker run --rm -i \ - -v $(pwd)/.hadolint.yaml:/.hadolint.yaml:ro \ - hadolint/hadolint:$(versionHadolint) < Dockerfile - displayName: 'Run Hadolint' - - -- job: 'Wheels' - condition: eq(variables['Build.SourceBranchName'], 'dev') - timeoutInMinutes: 360 - pool: - vmImage: 'ubuntu-latest' - strategy: - maxParallel: 3 - matrix: - amd64: - buildArch: 'amd64' - i386: - buildArch: 'i386' - armhf: - buildArch: 'armhf' - armv7: - buildArch: 'armv7' - aarch64: - buildArch: 'aarch64' - steps: - - script: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ - qemu-user-static \ - binfmt-support \ - curl - - sudo mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc - sudo update-binfmts --enable qemu-arm - sudo update-binfmts --enable qemu-aarch64 - displayName: 'Initial cross build' - - script: | - mkdir -p .ssh - echo -e "-----BEGIN RSA PRIVATE KEY-----\n$(wheelsSSH)\n-----END RSA PRIVATE KEY-----" >> .ssh/id_rsa - ssh-keyscan -H $(wheelsHost) >> .ssh/known_hosts - chmod 600 .ssh/* - displayName: 'Install ssh key' - - script: sudo docker pull homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) - displayName: 'Install wheels builder' - - script: | - curl -s -o requirements_diff.txt https://raw.githubusercontent.com/home-assistant/hassio/master/requirements.txt - sudo docker run --rm -v $(pwd):/data:ro -v $(pwd)/.ssh:/root/.ssh:rw \ - homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) \ - --apk "build-base;libffi-dev;openssl-dev" \ - --index $(wheelsIndex) \ - --requirement requirements.txt \ - --requirement-diff requirements_diff.txt \ - --upload rsync \ - --remote wheels@$(wheelsHost):/opt/wheels - displayName: 'Run wheels build' - - -- job: 'VersionValidate' - condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), eq(variables['Build.SourceBranchName'], 'dev')) - pool: - vmImage: 'ubuntu-latest' - steps: - - task: UsePythonVersion@0 - displayName: 'Use Python 3.7' - inputs: - versionSpec: '3.7' - - script: | - setup_version="$(python setup.py -V)" - branch_version="$(Build.SourceBranchName)" - - if [ "${branch_version}" == "dev" ]; then - exit 0 - elif [ "${setup_version}" != "${branch_version}" ]; then - echo "Version of tag ${branch_version} don't match with ${setup_version}!" - exit 1 - fi - displayName: 'Check version of branch/tag' - - -- job: 'Release' - dependsOn: - - 'JQ' - - 'Tox' - - 'Hadolint' - - 'VersionValidate' - pool: - vmImage: 'ubuntu-latest' - steps: - - script: sudo docker login -u $(dockerUser) -p $(dockerPassword) - displayName: 'Docker hub login' - - script: sudo docker pull homeassistant/amd64-builder:$(versionBuilder) - displayName: 'Install Builder' - - script: | - sudo docker run --rm --privileged \ - -v ~/.docker:/root/.docker \ - -v /run/docker.sock:/run/docker.sock:rw -v $(pwd):/data:ro \ - homeassistant/amd64-builder:$(versionBuilder) \ - --supervisor $(basePythonTag) --version $(Build.SourceBranchName) \ - --all -t /data --docker-hub homeassistant - displayName: 'Build Release' + if [ "${branch_version}" == "dev" ]; then + exit 0 + elif [ "${setup_version}" != "${branch_version}" ]; then + echo "Version of tag ${branch_version} don't match with ${setup_version}!" + exit 1 + fi + displayName: 'Check version of branch/tag' + - job: 'Release' + dependsOn: + - 'VersionValidate' + pool: + vmImage: 'ubuntu-latest' + steps: + - script: sudo docker login -u $(dockerUser) -p $(dockerPassword) + displayName: 'Docker hub login' + - script: sudo docker pull homeassistant/amd64-builder:$(versionBuilder) + displayName: 'Install Builder' + - script: | + sudo docker run --rm --privileged \ + -v ~/.docker:/root/.docker \ + -v /run/docker.sock:/run/docker.sock:rw -v $(pwd):/data:ro \ + homeassistant/amd64-builder:$(versionBuilder) \ + --supervisor $(basePythonTag) --version $(Build.SourceBranchName) \ + --all -t /data --docker-hub homeassistant + displayName: 'Build Release' From b8b73cf8808ee25adc2678fcf935eeaa940e5ca6 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jun 2019 19:16:26 +0200 Subject: [PATCH 10/16] remove diff wheels build --- azure-pipelines.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b571976a0..4a4e38290 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -117,13 +117,11 @@ stages: - script: sudo docker pull homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) displayName: 'Install wheels builder' - script: | - curl -s -o requirements_diff.txt https://raw.githubusercontent.com/home-assistant/hassio/master/requirements.txt sudo docker run --rm -v $(pwd):/data:ro -v $(pwd)/.ssh:/root/.ssh:rw \ homeassistant/$(buildArch)-wheels:$(versionWheels)-$(basePythonTag) \ --apk "build-base;libffi-dev;openssl-dev" \ --index $(wheelsIndex) \ --requirement requirements.txt \ - --requirement-diff requirements_diff.txt \ --upload rsync \ --remote wheels@$(wheelsHost):/opt/wheels displayName: 'Run wheels build' From ce18183daa1c56adbb4757ae3752d6a8b1cff102 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jun 2019 23:29:42 +0200 Subject: [PATCH 11/16] Allow update discovery messages (#1136) * Allow update discovery messages * Update __init__.py * Update __init__.py * Update __init__.py * fix lint * Fix style --- hassio/discovery/__init__.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/hassio/discovery/__init__.py b/hassio/discovery/__init__.py index 46f3b1ff4..0c0a17b68 100644 --- a/hassio/discovery/__init__.py +++ b/hassio/discovery/__init__.py @@ -85,11 +85,16 @@ class Discovery(CoreSysAttributes, JsonConfig): message = Message(addon.slug, service, config) # Already exists? - for old_message in self.list_messages: - if old_message != message: + for exists_msg in self.list_messages: + if exists_msg != message: continue - _LOGGER.info("Duplicate discovery message from %s", addon.slug) - return old_message + if exists_msg.config != config: + message = exists_msg + message.config = config + else: + _LOGGER.debug("Duplicate discovery message from %s", addon.slug) + return exists_msg + break _LOGGER.info("Send discovery to Home Assistant %s from %s", service, addon.slug) self.message_obj[message.uuid] = message From d31ab5139d695e74c6038e68c88c7f1d003c5e7a Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jun 2019 23:09:08 +0000 Subject: [PATCH 12/16] compile all --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 19bd18a4a..0572a9065 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,7 +24,8 @@ RUN export MAKEFLAGS="-j$(nproc)" \ # Install HassIO COPY . /usr/src/hassio -RUN pip3 install --no-cache-dir -e /usr/src/hassio +RUN pip3 install --no-cache-dir -e /usr/src/hassio \ + && python3 -m compileall /usr/src/hassio # Initialize udev daemon, handle CMD COPY entry.sh /bin/ From 51efcefdab3063506662ac1588caf9fd6f8fcbb2 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 24 Jun 2019 23:21:15 +0000 Subject: [PATCH 13/16] Compile only hassio --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0572a9065..8728509ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,7 @@ RUN export MAKEFLAGS="-j$(nproc)" \ # Install HassIO COPY . /usr/src/hassio RUN pip3 install --no-cache-dir -e /usr/src/hassio \ - && python3 -m compileall /usr/src/hassio + && python3 -m compileall /usr/src/hassio/hassio # Initialize udev daemon, handle CMD COPY entry.sh /bin/ From 5771b417bc6ae6121c11070197615ac8b7ca027a Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 25 Jun 2019 12:54:45 +0000 Subject: [PATCH 14/16] sort import --- hassio/addons/validate.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hassio/addons/validate.py b/hassio/addons/validate.py index 93b0b7ef8..3cc630b76 100644 --- a/hassio/addons/validate.py +++ b/hassio/addons/validate.py @@ -39,12 +39,9 @@ from ..const import ( ATTR_IMAGE, ATTR_INGRESS, ATTR_INGRESS_ENTRY, + ATTR_INGRESS_PANEL, ATTR_INGRESS_PORT, ATTR_INGRESS_TOKEN, - ATTR_INGRESS_PANEL, - ATTR_PANEL_ADMIN, - ATTR_PANEL_ICON, - ATTR_PANEL_TITLE, ATTR_KERNEL_MODULES, ATTR_LEGACY, ATTR_LOCATON, @@ -53,6 +50,9 @@ from ..const import ( ATTR_NAME, ATTR_NETWORK, ATTR_OPTIONS, + ATTR_PANEL_ADMIN, + ATTR_PANEL_ICON, + ATTR_PANEL_TITLE, ATTR_PORTS, ATTR_PORTS_DESCRIPTION, ATTR_PRIVILEGED, From 6d6deb8c6648e67243f19be5754840c057b5906c Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 25 Jun 2019 16:15:02 +0200 Subject: [PATCH 15/16] Cleanup udev handling (#1137) * Cleanup udev handling * Update hardware.py --- hassio/misc/hardware.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/hassio/misc/hardware.py b/hassio/misc/hardware.py index 4748d4a1a..eb79708e4 100644 --- a/hassio/misc/hardware.py +++ b/hassio/misc/hardware.py @@ -36,17 +36,14 @@ class Hardware: """Return all serial and connected devices.""" dev_list = set() for device in self.context.list_devices(subsystem="tty"): - if "ID_VENDOR" in device or RE_TTY.search(device.device_node): + if "ID_VENDOR" in device.properties or RE_TTY.search(device.device_node): dev_list.add(device.device_node) # Add /dev/serial/by-id devlink for current device - if "DEVLINKS" in device and device["DEVLINKS"]: - devlinks = [ - symlink - for symlink in device["DEVLINKS"].split(" ") - if symlink.startswith("/dev/serial/by-id") - ] - dev_list.update(devlinks) + for dev_link in device.device_links: + if not dev_link.startswith("/dev/serial/by-id"): + continue + dev_list.add(dev_link) return dev_list @@ -55,8 +52,8 @@ class Hardware: """Return all input devices.""" dev_list = set() for device in self.context.list_devices(subsystem="input"): - if "NAME" in device: - dev_list.add(device["NAME"].replace('"', "")) + if "NAME" in device.properties: + dev_list.add(device.properties["NAME"].replace('"', "")) return dev_list @@ -65,7 +62,7 @@ class Hardware: """Return all disk devices.""" dev_list = set() for device in self.context.list_devices(subsystem="block"): - if device.device_node.startswith("/dev/sd"): + if "ID_NAME" in device.properties: dev_list.add(device.device_node) return dev_list From 709f034f2eb290cdb8f369c68da2532c2826c618 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Tue, 25 Jun 2019 17:09:14 +0200 Subject: [PATCH 16/16] New TimeZone handling (#1138) * Remove function to get TZ from config file * Readd old timezone handling * Fix tests --- hassio/bootstrap.py | 7 ++++++- hassio/config.py | 21 +-------------------- hassio/utils/dt.py | 19 +++++++++++++++++++ tests/common.py | 17 +++++++++++++++++ tests/conftest.py | 7 ++++++- 5 files changed, 49 insertions(+), 22 deletions(-) diff --git a/hassio/bootstrap.py b/hassio/bootstrap.py index 1f1efa11b..f6c07118c 100644 --- a/hassio/bootstrap.py +++ b/hassio/bootstrap.py @@ -22,10 +22,11 @@ from .host import HostManager from .ingress import Ingress from .services import ServiceManager from .snapshots import SnapshotManager -from .supervisor import Supervisor from .store import StoreManager +from .supervisor import Supervisor from .tasks import Tasks from .updater import Updater +from .utils.dt import fetch_timezone _LOGGER = logging.getLogger(__name__) @@ -66,6 +67,10 @@ async def initialize_coresys(): if MACHINE_ID.exists(): coresys.machine_id = MACHINE_ID.read_text().strip() + # Init TimeZone + if coresys.config.timezone == "UTC": + coresys.config.timezone = await fetch_timezone(coresys.websession) + return coresys diff --git a/hassio/config.py b/hassio/config.py index eb569beb5..37b59362e 100644 --- a/hassio/config.py +++ b/hassio/config.py @@ -3,9 +3,6 @@ from datetime import datetime import logging import os from pathlib import Path, PurePath -import re - -import pytz from .const import ( ATTR_ADDONS_CUSTOM_LIST, @@ -40,8 +37,6 @@ APPARMOR_DATA = PurePath("apparmor") DEFAULT_BOOT_TIME = datetime.utcfromtimestamp(0).isoformat() -RE_TIMEZONE = re.compile(r"time_zone: (?P[\w/\-+]+)") - class CoreConfig(JsonConfig): """Hold all core config data.""" @@ -53,21 +48,7 @@ class CoreConfig(JsonConfig): @property def timezone(self): """Return system timezone.""" - config_file = Path(self.path_homeassistant, "configuration.yaml") - try: - assert config_file.exists() - configuration = config_file.read_text() - - data = RE_TIMEZONE.search(configuration) - assert data - - timezone = data.group("timezone") - pytz.timezone(timezone) - except (pytz.exceptions.UnknownTimeZoneError, OSError, AssertionError): - _LOGGER.debug("Can't parse Home Assistant timezone") - return self._data[ATTR_TIMEZONE] - - return timezone + return self._data[ATTR_TIMEZONE] @timezone.setter def timezone(self, value): diff --git a/hassio/utils/dt.py b/hassio/utils/dt.py index 59992b79f..afa3f8ea5 100644 --- a/hassio/utils/dt.py +++ b/hassio/utils/dt.py @@ -1,13 +1,17 @@ """Tools file for Hass.io.""" +import asyncio from datetime import datetime, timedelta, timezone, tzinfo import logging import re from typing import Any, Dict, Optional +import aiohttp import pytz UTC = pytz.utc +GEOIP_URL = "http://ip-api.com/json/" + _LOGGER = logging.getLogger(__name__) @@ -22,6 +26,21 @@ DATETIME_RE = re.compile( ) +async def fetch_timezone(websession): + """Read timezone from freegeoip.""" + data = {} + try: + async with websession.get(GEOIP_URL, timeout=10) as request: + data = await request.json() + + except (aiohttp.ClientError, asyncio.TimeoutError) as err: + _LOGGER.warning("Can't fetch freegeoip data: %s", err) + except ValueError as err: + _LOGGER.warning("Error on parse freegeoip data: %s", err) + + return data.get("timezone", "UTC") + + # Copyright (c) Django Software Foundation and individual contributors. # All rights reserved. # https://github.com/django/django/blob/master/LICENSE diff --git a/tests/common.py b/tests/common.py index c432bc037..eed83c84d 100644 --- a/tests/common.py +++ b/tests/common.py @@ -7,3 +7,20 @@ def load_json_fixture(filename): """Load a fixture.""" path = Path(Path(__file__).parent.joinpath("fixtures"), filename) return json.loads(path.read_text()) + + +def mock_coro(return_value=None, exception=None): + """Return a coro that returns a value or raise an exception.""" + return mock_coro_func(return_value, exception)() + + +def mock_coro_func(return_value=None, exception=None): + """Return a method to create a coro function that returns a value.""" + + async def coro(*args, **kwargs): + """Fake coroutine.""" + if exception: + raise exception + return return_value + + return coro diff --git a/tests/conftest.py b/tests/conftest.py index d30c8dcae..ac105e071 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,6 +5,8 @@ import pytest from hassio.bootstrap import initialize_coresys +from tests.common import mock_coro + # pylint: disable=redefined-outer-name @@ -18,7 +20,10 @@ def docker(): @pytest.fixture async def coresys(loop, docker): """Create a CoreSys Mock.""" - with patch("hassio.bootstrap.initialize_system_data"): + with patch("hassio.bootstrap.initialize_system_data"), patch( + "hassio.bootstrap.fetch_timezone", + return_value=mock_coro(return_value="Europe/Zurich"), + ): coresys_obj = await initialize_coresys() coresys_obj.ingress.save_data = MagicMock()