Rewrite MariaDB add-on (#1067)

* mariadb: Pin add-on to Alpine 3.11

* mariadb: Redirect MariaDB error log to add-on logs

* mariadb: Remove grant and host options

* mariadb: Add support for the mysql service

* mariadb: Use a more secure default on install

* mariadb: Skip DNS name resolving

* mariadb: Improve integrity checks and recovery

* mariadb: Small tweaks to shell scripts

* mariadb: Tune MariaDB for lower memory usage

* mariadb: Update documentation to match changes

* mariadb: Update changelog, bump version 2.0

* mariadb: Fix log ouput redirect for non-local builds

* Close port to world

* mariadb: Fix issue with user permissions

* mariadb: Ensure we are using a proper collation set

* mariadb: Add upgrade process for internal mariadb system tables

* mariadb: Change default username from hass to homeassistant

* mariadb: Update changelog

* mariadb: Update readme

Co-authored-by: Pascal Vizeli <pascal.vizeli@syshack.ch>
This commit is contained in:
Franck Nijhof
2020-02-14 14:03:29 +01:00
committed by GitHub
parent 67fe35809f
commit bd438e7570
7 changed files with 152 additions and 57 deletions

View File

@@ -1,5 +1,20 @@
# Changelog
## 2.0
- Pin add-on to Alpine Linux 3.11
- Redirect MariaDB error log to add-on logs
- Remove grant & host options
- Add support for the mysql service
- Use a more secure default on install
- Skip DNS name resolving
- Improve integrity checks and recovery
- Tune MariaDB for lower memory usage
- Close port 3306 by default
- Ensure a proper collation set is used
- Adds database upgrade process during startup
- Change default configuration username from "hass" to "homeassistant"
## 1.3
- Update from bash to bashio

View File

@@ -5,7 +5,11 @@ FROM $BUILD_FROM
ENV LANG C.UTF-8
# Setup base
RUN apk add --no-cache mariadb mariadb-client
RUN apk add --no-cache \
mariadb \
mariadb-client \
mariadb-server-utils \
pwgen
# Copy data
COPY data/run.sh /

View File

@@ -34,14 +34,11 @@ Example add-on configuration:
databases:
- homeassistant
logins:
- username: hass
host: "%"
password:
- username: homeassistant
password: PASSWORD
rights:
- username: hass
host: "%"
- username: homeassistant
database: homeassistant
grant: ALL PRIVILEGES ON
```
### Option: `databases` (required)
@@ -54,11 +51,7 @@ This section defines a create user definition in MariaDB. [Create User][createus
### Option: `logins.username` (required)
Database user login, e.g., `hass`. [User Name][username] documentation.
### Option: `logins.host` (required)
Hostname allowed to connect to database. [Host Name][hostname] documentation.
Database user login, e.g., `homeassistant`. [User Name][username] documentation.
### Option: `logins.password` (required)
@@ -72,18 +65,10 @@ This section grant privileges to users in MariaDB. [Grant][grant] documentation.
This should be the same user name defined in `logins` -> `username`.
### Option: `rights.host` (required)
This should be the same hostname defined in `logins` -> `host`.
### Option: `rights.database` (required)
This should be the same database defined in `databases`.
### Option: `rights.grant` (required)
This is the grant statement giving your user access to the database.
## Home Assistant Configuration
MariaDB will be used by the `recorder` and `history` components within Home Assistant. For more information about setting this up, see the [MariaDB][mariadb-hass] documentation for Home Assistant.
@@ -92,7 +77,7 @@ Example Home Assistant configuration:
```yaml
recorder:
db_url: mysql://hass:password@core-mariadb/homeassistant?charset=utf8
db_url: mysql://homeassistant:password@core-mariadb/homeassistant?charset=utf8
```
## Support

9
mariadb/build.json Normal file
View File

@@ -0,0 +1,9 @@
{
"build_from": {
"aarch64": "homeassistant/aarch64-base:3.11",
"amd64": "homeassistant/amd64-base:3.11",
"armhf": "homeassistant/armhf-base:3.11",
"armv7": "homeassistant/armv7-base:3.11",
"i386": "homeassistant/i386-base:3.11"
}
}

View File

@@ -1,33 +1,30 @@
{
"name": "MariaDB",
"version": "1.3",
"version": "2.0",
"slug": "mariadb",
"description": "An SQL database server",
"url": "https://github.com/home-assistant/hassio-addons/tree/master/mariadb",
"arch": ["armhf", "armv7", "aarch64", "amd64", "i386"],
"startup": "system",
"boot": "auto",
"services": ["mysql:provide"],
"ports": {
"3306/tcp": 3306
"3306/tcp": null
},
"options": {
"databases": ["homeassistant"],
"logins": [{ "username": "hass", "host": "%", "password": null }],
"logins": [{ "username": "homeassistant", "password": null }],
"rights": [
{
"username": "hass",
"host": "%",
"database": "homeassistant",
"grant": "ALL PRIVILEGES ON"
"username": "homeassistant",
"database": "homeassistant"
}
]
},
"schema": {
"databases": ["str"],
"logins": [{ "username": "str", "host": "str", "password": "str" }],
"rights": [
{ "username": "str", "host": "str", "database": "str", "grant": "str" }
]
"logins": [{ "username": "str", "password": "str" }],
"rights": [{ "username": "str", "database": "str" }]
},
"image": "homeassistant/{arch}-addon-mariadb",
"timeout": 20

View File

@@ -1,10 +1,40 @@
[server]
[mysqld]
port=3306
log_error=mariadb.err
# Persistent storage location
datadir=/data/databases
[galera]
# Use a proper collation set
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
[mariadb]
# Do not resolve DNS names
skip-name-resolve
# Tune for low-end devices (Like a Raspberry Pi)
key_buffer_size = 16M
max_connections = 64
myisam_recover_options = FORCE
myisam_sort_buffer_size = 8M
net_buffer_length = 16K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
sort_buffer_size = 512K
join_buffer_size = 128K
table_open_cache = 64
thread_cache_size = 8
thread_stack = 192K
tmp_table_size = 16M
# Disable query cache
query_cache_limit = 1M
query_cache_size = 0M
query_cache_type = 0
# InnoDB Tweaks
innodb_buffer_pool_instances = 1
innodb_buffer_pool_size = 64M
innodb_log_buffer_size = 8M
innodb_log_file_size = 48M
max_binlog_size = 96M

View File

@@ -2,18 +2,24 @@
set -e
MARIADB_DATA=/data/databases
NEW_INSTALL=false
# Init mariadb
if ! bashio::fs.directory_exists "${MARIADB_DATA}"; then
bashio::log.info "Create a new mariadb initial system"
mysql_install_db --user=root --datadir="$MARIADB_DATA" > /dev/null
mysql_install_db --user=root --datadir="${MARIADB_DATA}" --skip-name-resolve --skip-test-db > /dev/null
NEW_INSTALL=true
else
bashio::log.info "Using existing mariadb initial system"
fi
# Redirect log output
rm -f /data/databases/mariadb.err
ln -s /proc/1/fd/1 /data/databases/mariadb.err
# Start mariadb
bashio::log.info "Starting MariaDB"
mysqld_safe --datadir="$MARIADB_DATA" --user=root --skip-log-bin < /dev/null &
mysqld_safe --datadir="${MARIADB_DATA}" --user=root < /dev/null &
MARIADB_PID=$!
# Wait until DB is running
@@ -22,29 +28,52 @@ while ! mysql -e "" 2> /dev/null; do
done
bashio::log.info "Check data integrity and fix corruptions"
mysqlcheck --no-defaults --check-upgrade --auto-repair --databases mysql --skip-write-binlog > /dev/null || true
mysqlcheck --no-defaults --all-databases --fix-db-names --fix-table-names --skip-write-binlog > /dev/null || true
mysqlcheck --no-defaults --check-upgrade --all-databases --auto-repair --skip-write-binlog > /dev/null || true
mysqlcheck --no-defaults --databases mysql --fix-db-names --fix-table-names || true
mysqlcheck --no-defaults --databases mysql --check --check-upgrade --auto-repair || true
mysqlcheck --no-defaults --all-databases --skip-database=mysql --fix-db-names --fix-table-names || true
mysqlcheck --no-defaults --all-databases --skip-database=mysql --check --check-upgrade --auto-repair || true
bashio::log.info "Ensuring internal database upgrades are performed"
mysql_upgrade --silent
# Set default secure values after inital setup
if bashio::var.true "${NEW_INSTALL}"; then
# Secure the installation.
mysql <<-EOSQL
SET @@SESSION.SQL_LOG_BIN=0;
DELETE FROM
mysql.user
WHERE
user NOT IN ('mysql.sys', 'mysqlxsys', 'root', 'mysql', 'proxies_priv')
OR host NOT IN ('localhost');
DELETE FROM
mysql.proxies_priv
WHERE
user NOT IN ('mysql.sys', 'mysqlxsys', 'root', 'mysql', 'proxies_priv')
OR host NOT IN ('localhost');
DROP DATABASE IF EXISTS test;
FLUSH PRIVILEGES;
EOSQL
fi
# Init databases
bashio::log.info "Init custom database"
for line in $(bashio::config "databases"); do
bashio::log.info "Create database $line"
mysql -e "CREATE DATABASE $line;" 2> /dev/null || true
bashio::log.info "Ensure databases exists"
for database in $(bashio::config "databases"); do
bashio::log.info "Create database ${database}"
mysql -e "CREATE DATABASE ${database};" 2> /dev/null || true
done
# Init logins
bashio::log.info "Init/Update users"
bashio::log.info "Ensure users exists and are updated"
for login in $(bashio::config "logins|keys"); do
USERNAME=$(bashio::config "logins[${login}].username")
PASSWORD=$(bashio::config "logins[${login}].password")
HOST=$(bashio::config "logins[${login}].host")
if mysql -e "SET PASSWORD FOR '$USERNAME'@'$HOST' = PASSWORD('$PASSWORD');" 2> /dev/null; then
bashio::log.info "Update user $USERNAME"
if mysql -e "SET PASSWORD FOR '${USERNAME}'@'%' = PASSWORD('${PASSWORD}');" 2> /dev/null; then
bashio::log.info "Update user ${USERNAME}"
else
bashio::log.info "Create user $USERNAME"
mysql -e "CREATE USER '$USERNAME'@'$HOST' IDENTIFIED BY '$PASSWORD';" 2> /dev/null || true
bashio::log.info "Create user ${USERNAME}"
mysql -e "CREATE USER '${USERNAME}'@'%' IDENTIFIED BY '${PASSWORD}';" 2> /dev/null || true
fi
done
@@ -52,18 +81,44 @@ done
bashio::log.info "Init/Update rights"
for right in $(bashio::config "rights|keys"); do
USERNAME=$(bashio::config "rights[${right}].username")
HOST=$(bashio::config "rights[${right}].host")
DATABASE=$(bashio::config "rights[${right}].database")
GRANT=$(bashio::config "rights[${right}].grant")
bashio::log.info "Alter rights for $USERNAME@$HOST - $DATABASE"
mysql -e "GRANT $GRANT $DATABASE.* TO '$USERNAME'@'$HOST';" 2> /dev/null || true
bashio::log.info "Alter rights for ${USERNAME} to ${DATABASE}"
mysql -e "GRANT ALL PRIVILEGES ON ${DATABASE}.* TO '${USERNAME}'@'%';" 2> /dev/null || true
done
# Generate service user
if ! bashio::fs.file_exists "/data/secret"; then
pwgen 64 1 > /data/secret
fi
SECRET=$(</data/secret)
mysql -e "CREATE USER 'service'@'172.30.32.%' IDENTIFIED BY '${SECRET}';" 2> /dev/null || true
mysql -e "CREATE USER 'service'@'172.30.33.%' IDENTIFIED BY '${SECRET}';" 2> /dev/null || true
mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'service'@'172.30.32.%' WITH GRANT OPTION;" 2> /dev/null || true
mysql -e "GRANT ALL PRIVILEGES ON *.* TO 'service'@'172.30.33.%' WITH GRANT OPTION;" 2> /dev/null || true
# Flush privileges
mysql -e "FLUSH PRIVILEGES;" 2> /dev/null || true
# Send service information to the Supervisor
PAYLOAD=$(\
bashio::var.json \
host "$(hostname)" \
port "^3306" \
username "service" \
password "${SECRET}"
)
if bashio::services.publish "mysql" "${PAYLOAD}"; then
bashio::log.info "Successfully send service information to Home Assistant."
else
bashio::log.warning "Service message to Home Assistant failed!"
fi
# Register stop
function stop_mariadb() {
bashio::services.delete "mysql"
mysqladmin shutdown
}
trap "stop_mariadb" SIGTERM SIGHUP
wait "$MARIADB_PID"
wait "${MARIADB_PID}"