fix(pkg/daemon): save measured values into postgres database if defined

This commit is contained in:
Markus Pesch 2019-09-04 13:37:50 +02:00
parent 6223f4e79b
commit 04bc3baffe
Signed by: volker.raschek
GPG Key ID: 852BCC170D81A982
60 changed files with 680 additions and 378 deletions

View File

@ -7,11 +7,11 @@ jobs:
include: include:
- stage: build - stage: build
name: go-build name: go-build
script: make container/all script: make container-run/all
deploy: deploy:
- provider: script - provider: script
script: make container/release script: make container-run/release/all
# skip_cleanup: true # skip_cleanup: true
on: on:
tags: true tags: true

3
Dockerfile Normal file
View File

@ -0,0 +1,3 @@
FROM busybox:latest
COPY bin/linux/amd64/flucky /usr/bin/flucky
ENTRYPOINT [ "/usr/bin/flucky" ]

306
Makefile
View File

@ -5,90 +5,185 @@
UID?=$(shell id --user) UID?=$(shell id --user)
GID?=$(shell id --group) GID?=$(shell id --group)
# VERSION IMAGE_VERSION:=$(or ${VERSION}, latest)
# VERSION/RELEASE
# If no version is specified as a parameter of make, the last git hash # If no version is specified as a parameter of make, the last git hash
# value is taken. # value is taken.
VERSION:=$(or ${TRAVIS_TAG}, $(shell git rev-parse --short HEAD)-git) VERSION?=$(shell git describe --abbrev=0)+hash.$(shell git rev-parse --short HEAD)
RELEASE?=1
# CONTAINER_RUNTIME # CONTAINER_RUNTIME
CONTAINER_RUNTIME?=$(shell which docker) CONTAINER_RUNTIME?=$(shell which docker)
# BUILD_IMAGE
BUILD_IMAGE:=volkerraschek/build-image:latest
# GH_USER/GITHUB_TOKEN # GH_USER/GITHUB_TOKEN
# It's the user name from github.com and his token. This token and the username # It's the user name from github.com and his token. This token and the username
# can be set over encrypted environment variables in the ci/cd pipeline # can be set over encrypted environment variables in the ci/cd pipeline
GITHUB_USER=volker-raschek GITHUB_USER=volker-raschek
GITHUB_TOKEN?="" GITHUB_TOKEN?=""
# BUILD_IMAGE
BUILD_IMAGE:=volkerraschek/build-image:latest
# EXECUTABLE # EXECUTABLE
# Executable binary which should be compiled for different architecures # Executable binary which should be compiled for different architecures
EXECUTABLE:=flucky EXECUTABLE:=flucky
# UNIX_EXECUTABLES # DARWIN_EXECUTABLES AND TARGETS
DARWIN_EXECUTABLES:=\
darwin/386/${EXECUTABLE} \
darwin/amd64/${EXECUTABLE}
DARWIN_EXECUTABLE_TARGETS:=${DARWIN_EXECUTABLES:%=bin/%}
# FREEBSD_EXECUTABLES AND TARGETS
FREEBSD_EXECUTABLES:= \
freebsd/amd64/${EXECUTABLE}
FREEBSD_EXECUTABLE_TARGETS:=${FREEBSD_EXECUTABLES:%=bin/%}
# LINUX_EXECUTABLES AND TARGETS
LINUX_EXECUTABLES:= \
linux/amd64/${EXECUTABLE} \
linux/386/${EXECUTABLE} \
linux/arm/5/${EXECUTABLE} \
linux/arm/7/${EXECUTABLE}
LINUX_EXECUTABLE_TARGETS:=${LINUX_EXECUTABLES:%=bin/%}
# UNIX_EXECUTABLES AND TARGETS
# Define all executables for different architectures and operation systems # Define all executables for different architectures and operation systems
UNIX_EXECUTABLES := \ UNIX_EXECUTABLES:= \
darwin/386/$(EXECUTABLE) \ ${DARWIN_EXECUTABLES} \
darwin/amd64/$(EXECUTABLE) \ ${FREEBSD_EXECUTABLES} \
freebsd/amd64/$(EXECUTABLE) \ ${LINUX_EXECUTABLES}
linux/386/$(EXECUTABLE) \
linux/amd64/$(EXECUTABLE) \ UNIX_EXECUTABLE_TARGETS:= \
linux/arm/5/$(EXECUTABLE) \ ${DARWIN_EXECUTABLE_TARGETS} \
linux/arm/7/$(EXECUTABLE) \ ${FREEBSD_EXECUTABLE_TARGETS} \
${LINUX_EXECUTABLE_TARGETS}
# EXECUTABLE_TARGETS # EXECUTABLE_TARGETS
# Include the relative paths to all executables # Include all UNIX and Windows targets.
EXECUTABLE_TARGETS=$(UNIX_EXECUTABLES:%=bin/%) EXECUTABLE_TARGETS:= \
${UNIX_EXECUTABLE_TARGETS}
# COMPRSSED_EXECUTABLES # COMPRSSED_EXECUTABLES
# Append to all defined executables the compression extentions to detect the # Append to all defined executables the compression extentions to detect the
# different make steps which compress the binary # different make steps which compress the binary
COMPRESSED_EXECUTABLES=$(UNIX_EXECUTABLES:%=%.tar.bz2) $(UNIX_EXECUTABLES:%=%.tar.gz) $(UNIX_EXECUTABLES:%=%.tar.xz) COMPRESSED_EXECUTABLES:= \
COMPRESSED_EXECUTABLE_TARGETS=$(COMPRESSED_EXECUTABLES:%=bin/%) ${UNIX_EXECUTABLES:%=%.tar.bz2} \
${UNIX_EXECUTABLES:%=%.tar.gz} \
${UNIX_EXECUTABLES:%=%.tar.xz} \
${UNIX_EXECUTABLES:%=%.zip}
COMPRESSED_EXECUTABLE_TARGETS:=${COMPRESSED_EXECUTABLES:%=bin/%}
# PHONY # RPM_TARGETS
# To avoid a conflict with an existing file and a defined make step RPM_EXECUTABLES:=${LINUX_EXECUTABLES:%=%.rpm}
.PHONY: clean container/${EXECUTABLE_TARGETS} container/test release remote test RPM_EXECUTABLE_TARGETS:=${RPM_EXECUTABLES:%=bin/%}
$(EXECUTABLE): bindata # RELEASE_TARGETS
go build -ldflags "-X main.version=${VERSION}" -o "$@" RELEASE_EXECUTABLES:= \
${COMPRESSED_EXECUTABLE_TARGETS} \
${RPM_EXECUTABLE_TARGETS}
RELEASE_EXECUTABLE_TARGETS:= \
${COMPRESSED_EXECUTABLE_TARGETS:%=release/%} \
${RPM_EXECUTABLE_TARGETS:%=release/%}
# BINARIES
# ==============================================================================
# current os
${EXECUTABLE}: bindata
CGO_ENABLED=0 go build -ldflags "-X main.version=${VERSION}" -o "$@"
# build all binaries
PHONY:=all
all: ${EXECUTABLE_TARGETS} all: ${EXECUTABLE_TARGETS}
container/bin/tmp/${EXECUTABLE}: # darwin os
$(MAKE) container-run COMMAND=$(subst container/,,$@) bin/darwin/386/${EXECUTABLE}: bindata
CGO_ENABLED=0 GOARCH=386 GOOS=darwin go build -ldflags "-X main.version=${VERSION}" -o "$@"
# 386 bin/darwin/amd64/${EXECUTABLE}: bindata
bin/darwin/386/$(EXECUTABLE): bindata CGO_ENABLED=0 GOARCH=amd64 GOOS=darwin go build -ldflags "-X main.version=${VERSION}" -o "$@"
GOARCH=386 GOOS=darwin go build -ldflags "-X main.version=${VERSION}" -o "$@"
bin/linux/386/$(EXECUTABLE): bindata # freebsd os
GOARCH=386 GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@" bin/freebsd/amd64/${EXECUTABLE}: bindata
CGO_ENABLED=0 GOARCH=amd64 GOOS=freebsd go build -ldflags "-X main.version=${VERSION}" -o "$@"
# amd64 # linux os
bin/freebsd/amd64/$(EXECUTABLE): bindata bin/linux/386/${EXECUTABLE}: bindata
GOARCH=amd64 GOOS=freebsd go build -ldflags "-X main.version=${VERSION}" -o "$@" CGO_ENABLED=0 GOARCH=386 GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@"
bin/darwin/amd64/$(EXECUTABLE): bindata bin/linux/amd64/${EXECUTABLE}: bindata
GOARCH=amd64 GOOS=darwin go build -ldflags "-X main.version=${VERSION}" -o "$@" CGO_ENABLED=0 GOARCH=amd64 GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@"
bin/linux/amd64/$(EXECUTABLE): bindata
GOARCH=amd64 GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@"
# arm
bin/linux/arm/5/${EXECUTABLE}: bindata bin/linux/arm/5/${EXECUTABLE}: bindata
GOARM=5 GOARCH=arm go build -ldflags "-X main.version=${VERSION}" -o "$@" CGO_ENABLED=0 GOARM=5 GOARCH=arm GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@"
bin/linux/arm/7/${EXECUTABLE}: bindata bin/linux/arm/7/${EXECUTABLE}: bindata
GOARM=7 GOARCH=arm go build -ldflags "-X main.version=${VERSION}" -o "$@" CGO_ENABLED=0 GOARM=7 GOARCH=arm GOOS=linux go build -ldflags "-X main.version=${VERSION}" -o "$@"
# GO-BINDATA
# ==============================================================================
bindata: bindata:
go-bindata -pkg db -o ./pkg/db/bindataSQL.go ./pkg/db/sql/*** go-bindata -pkg db -o ./pkg/storage/db/bindataSQL.go ./pkg/storage/db/sql/*** ./pkg/storage/db/sql/psql/schema/***
go-bindata -pkg goldenfiles -o ./test/goldenfiles/bindata.go ./test/goldenfiles/json/*** go-bindata -pkg goldenfiles -o ./test/goldenfiles/bindata.go ./test/goldenfiles/json
# TEST
# ==============================================================================
PHONY+=test test-update-all
test: ${EXECUTABLE}
go test -v ./...
test-update-all: ${EXECUTABLE}
go test -v ./pkg/... -update all
# PACKAGES
# ==============================================================================
%.rpm: %
rpm-builder \
--exec-file "$<:/usr/bin/${EXECUTABLE}" \
--dir "systemd:/usr/lib/systemd/system" \
--license AGFA_PROPERTERY \
--version ${VERSION} \
--release ${RELEASE} \
--out $@ \
${EXECUTABLE}
# RELEASE
# ==============================================================================
PHONY+=release/all
release/all: clean ${RELEASE_EXECUTABLES}
github-release release \
--user ${GITHUB_USER} \
--repo ${EXECUTABLE} \
--tag ${VERSION}
$(foreach FILE,${RELEASE_EXECUTABLES},github-release upload --user ${GITHUB_USER} --repo ${EXECUTABLE} --tag ${VERSION} --name $(subst /,-,${FILE}) --file bin/${FILE} --replace;)
PHONY+=${RELEASE_EXECUTABLE_TARGETS}
${RELEASE_EXECUTABLE_TARGETS}: clean
$(MAKE) $(subst release/,,$@)
github-release release \
--user ${GITHUB_USER} \
--repo ${EXECUTABLE} \
--tag ${VERSION}
github-release upload \
--user ${GITHUB_USER} \
--repo ${EXECUTABLE} \
--tag ${VERSION} \
--name $(subst /,-,$(subst release/bin/,,$@)) \
--file $(subst release/,,$@) \
--replace
# COMPRESSION
# ==============================================================================
%.tar.bz2: % %.tar.bz2: %
tar --create --bzip2 --file "$@" "$<" tar --create --bzip2 --file "$@" "$<"
@ -98,66 +193,88 @@ bindata:
%.tar.xz: % %.tar.xz: %
tar --create --xz --file "$@" "$<" tar --create --xz --file "$@" "$<"
%.zip: %
zip "$@" "$<"
test: ${EXECUTABLE} # OTHER STUFF
go test -v ./pkg/... # ==============================================================================
PHONY+=clean
release: clean
$(MAKE) $(COMPRESSED_EXECUTABLE_TARGETS)
github-release release \
--user ${GITHUB_USER} \
--repo ${EXECUTABLE} \
--tag ${VERSION}
$(foreach FILE,$(COMPRESSED_EXECUTABLES),github-release upload --user ${GITHUB_USER} --repo ${EXECUTABLE} --tag ${VERSION} --name $(subst /,-,$(FILE)) --file bin/$(FILE) --replace;)
clean: clean:
rm ${EXECUTABLE} || true rm ${EXECUTABLE} || true
rm ${EXECUTABLE}.* || true
rm --recursive --force bin/ || true rm --recursive --force bin/ || true
# CONTAINER IMAGE STEPS
# ==============================================================================
PHONY+=container-image/build/amd64
container-image/build/amd64: bin/linux/amd64/${EXECUTABLE}
${CONTAINER_RUNTIME} build \
--tag volkerraschek/${EXECUTABLE}:${IMAGE_VERSION} \
.
PHONY+=container-image/push/amd64
container-image/push/amd64: container-image/build/amd64
${CONTAINER_RUNTIME} push volkerraschek/${EXECUTABLE}:${IMAGE_VERSION}
# container # CONTAINER STEPS - BINARY
container/${EXECUTABLE}: # ==============================================================================
$(MAKE) container-run COMMAND=$(subst container/,,$@) # current os
PHONY+=container-run/${EXECUTABLE}
container-run/${EXECUTABLE}:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
container/all: # build all binaries for any operating system
$(MAKE) container-run COMMAND=$(subst container/,,$@) PHONY+=container-run/all
container-run/all:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
container/test: PHONY+=${UNIX_EXECUTABLE_TARGETS:%=container-run/%}
$(MAKE) container-run COMMAND=$(subst container/,,$@) ${UNIX_EXECUTABLE_TARGETS:%=container-run/%}:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
container/release: # CONTAINER STEPS - GO-BINDATA
$(MAKE) container-run COMMAND=$(subst container/,,$@) # ==============================================================================
PHONY+=container-run/bindata
container-run/bindata:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
# container - 386 # CONTAINER STEPS - TEST
container/bin/darwin/386/$(EXECUTABLE): # ==============================================================================
$(MAKE) container-run COMMAND=$(subst container/,,$@) PHONY+=container-run/test
container-run/test:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
container/bin/linux/386/$(EXECUTABLE): PHONY+=container-run/test-update-all
$(MAKE) container-run COMMAND=$(subst container/,,$@) container-run/test-update-all:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
# container - amd # CONTAINER STEPS - COMPRESSED BINARIES AND PACKAGES
container/bin/freebsd/amd64/$(EXECUTABLE): # ==============================================================================
$(MAKE) container-run COMMAND=$(subst container/,,$@) PHONY+=${COMPRESSED_EXECUTABLE_TARGETS:%=container-run/%}
${COMPRESSED_EXECUTABLE_TARGETS:%=container-run/%}:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
container/bin/darwin/amd64/$(EXECUTABLE): PHONY+=${RPM_EXECUTABLE_TARGETS:%=container-run/%}
$(MAKE) container-run COMMAND=$(subst container/,,$@) ${RPM_EXECUTABLE_TARGETS:%=container-run/%}:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
container/bin/linux/amd64/$(EXECUTABLE): # CONTAINER STEPS - RELEASE COMPRESSED BINARIES AND PACKAGES
$(MAKE) container-run COMMAND=$(subst container/,,$@) # ==============================================================================
PHONY+=${RELEASE_EXECUTABLE_TARGETS%=container-run/%}
${RELEASE_EXECUTABLE_TARGETS:%=container-run/%}:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
# container - arm # CONTAINER STEPS - OTHER STUF
container/bin/linux/arm/7/${EXECUTABLE}: # ==============================================================================
$(MAKE) container-run COMMAND=$(subst container/,,$@) PHONY+=container-run/clean
container-run/clean:
$(MAKE) container-run/ COMMAND=$(subst container-run/,,$@)
container/bin/linux/arm/5/${EXECUTABLE}: # GENERAL CONTAINER COMMAND
$(MAKE) container-run COMMAND=$(subst container/,,$@) # ==============================================================================
PHONY+=container-run/
container-run/:
container-run:
${CONTAINER_RUNTIME} run \ ${CONTAINER_RUNTIME} run \
--rm \ --rm \
--volume ${PWD}:/workspace \ --volume ${PWD}:/workspace \
@ -166,8 +283,17 @@ container-run:
UID=${UID} \ UID=${UID} \
GID=${GID} \ GID=${GID} \
VERSION=${VERSION} \ VERSION=${VERSION} \
GITHUB_TOKEN=${GITHUB_TOKEN} RELEASE=${RELEASE}
remote: bin/linux/arm/7/${EXECUTABLE} # REMOTE
scp bin/linux/arm/7/${EXECUTABLE} ${FLUCKY_REMOTE}:/usr/local/bin # ==============================================================================
ssh ${FLUCKY_REMOTE} "chmod +x /usr/local/bin/flucky" PHONY+=${FLUCKY_REMOTE:%=remote/%}
remote/${FLUCKY_REMOTE}: bin/linux/arm/7/${EXECUTABLE}
scp bin/linux/arm/7/${EXECUTABLE} root@${FLUCKY_REMOTE}:/usr/local/bin/${EXECUTABLE}
ssh root@${FLUCKY_REMOTE} 'chmod +x /usr/local/bin/${EXECUTABLE}'
# PHONY
# ==============================================================================
# Declare the contents of the PHONY variable as phony. We keep that information
# in a variable so we can use it in if_changed.
.PHONY: ${PHONY}

View File

@ -47,9 +47,9 @@ var rootCmd = &cobra.Command{
Device: &types.Device{ Device: &types.Device{
DeviceID: uuid.NewV4().String(), DeviceID: uuid.NewV4().String(),
DeviceName: hostname, DeviceName: hostname,
Logfile: "/var/log/flucky/logfile.csv",
CreationDate: t, CreationDate: t,
}, },
Logfile: "/var/log/flucky/logfile.csv",
} }
err = config.Write(&cnf, configFile) err = config.Write(&cnf, configFile)
@ -68,14 +68,14 @@ func Execute(version *semver.Version) {
rootCmd.PersistentFlags().StringVar(&configFile, "config", "/etc/flucky/config.json", "Config file") rootCmd.PersistentFlags().StringVar(&configFile, "config", "/etc/flucky/config.json", "Config file")
compression.InitCmd(rootCmd, &configFile) compression.InitCmd(rootCmd, &configFile, version)
convert.InitCmd(rootCmd, &configFile) convert.InitCmd(rootCmd, &configFile, version)
daemon.InitCmd(rootCmd, &configFile) daemon.InitCmd(rootCmd, &configFile, version)
// db.InitCmd(rootCmd, &configFile) // db.InitCmd(rootCmd, &configFile, version)
humidity.InitCmd(rootCmd, &configFile) humidity.InitCmd(rootCmd, &configFile, version)
pressure.InitCmd(rootCmd, &configFile) pressure.InitCmd(rootCmd, &configFile, version)
rgbled.InitCmd(rootCmd, &configFile) rgbled.InitCmd(rootCmd, &configFile, version)
sensor.InitCmd(rootCmd, &configFile) sensor.InitCmd(rootCmd, &configFile, version)
temperature.InitCmd(rootCmd, &configFile) temperature.InitCmd(rootCmd, &configFile, version)
rootCmd.Execute() rootCmd.Execute()
} }

View File

@ -4,7 +4,7 @@ import (
"log" "log"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/go-flucky/flucky/pkg/logfile" "github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )

View File

@ -4,7 +4,7 @@ import (
"log" "log"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
"github.com/go-flucky/flucky/pkg/logfile" "github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )

View File

@ -37,13 +37,13 @@ var daemonCmd = &cobra.Command{
} }
logger := logger.NewDefaultLogger(logger.LogLevelDebug) logger := logger.NewDefaultLogger(logger.LogLevelDebug)
daemon.SetLogger(logger)
daemon.Start(cnf, duration, compression, round, logger) daemon.Start(cnf, duration, compression, round, version)
}, },
} }
func InitCmd(cmd *cobra.Command, cnfFile *string, sverion *semver.Version) { func InitCmd(cmd *cobra.Command, cnfFile *string, sversion *semver.Version) {
configFile = cnfFile configFile = cnfFile
version = sversion version = sversion

View File

@ -5,7 +5,8 @@ import (
"log" "log"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
database "github.com/go-flucky/flucky/pkg/db" "github.com/go-flucky/flucky/pkg/config"
database "github.com/go-flucky/flucky/pkg/storage/db"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -21,7 +22,13 @@ var dbCmd = &cobra.Command{
Short: "Operates with the configured database", Short: "Operates with the configured database",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
postgresDB, err := database.New(database.DBOTypePostgres, "localhost", "5432", "postgres", "postgres", "postgres") // read configuration
cnf, err := config.Read(*configFile)
if err != nil {
log.Fatalln(err)
}
postgresDB, err := database.New(cnf.DatabaseSettings)
if err != nil { if err != nil {
log.Fatalf("%v", err) log.Fatalf("%v", err)
} }

View File

@ -5,11 +5,11 @@ import (
"log" "log"
"os" "os"
"github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
"github.com/go-flucky/flucky/pkg/cli" "github.com/go-flucky/flucky/pkg/cli"
"github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/logfile"
"github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/rgbled"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,7 +26,7 @@ var listTemperatureCmd = &cobra.Command{
log.Fatalln(err) log.Fatalln(err)
} }
logfile := logfile.New(cnf.Device.Logfile) logfile := logfile.New(cnf.Logfile)
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED) rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
if err := rgbled.Logfile(rgbLEDs); err != nil { if err := rgbled.Logfile(rgbLEDs); err != nil {

View File

@ -5,11 +5,11 @@ import (
"log" "log"
"os" "os"
"github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
"github.com/go-flucky/flucky/pkg/cli" "github.com/go-flucky/flucky/pkg/cli"
"github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/logfile"
"github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/rgbled"
"github.com/go-flucky/flucky/pkg/sensor" "github.com/go-flucky/flucky/pkg/sensor"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -56,7 +56,7 @@ var readHumidityCmd = &cobra.Command{
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout) cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
if logs { if logs {
measuredValuesLogfile := logfile.New(cnf.Device.Logfile) measuredValuesLogfile := logfile.New(cnf.Logfile)
err := logfile.Append(measuredValuesLogfile, compression, round, measuredValues) err := logfile.Append(measuredValuesLogfile, compression, round, measuredValues)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)

View File

@ -5,12 +5,11 @@ import (
"log" "log"
"os" "os"
"github.com/go-flucky/flucky/pkg/types"
"github.com/go-flucky/flucky/pkg/cli" "github.com/go-flucky/flucky/pkg/cli"
"github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/logfile" "github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/rgbled"
"github.com/go-flucky/flucky/pkg/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,7 +25,7 @@ var listTemperatureCmd = &cobra.Command{
log.Fatalln(err) log.Fatalln(err)
} }
logfile := logfile.New(cnf.Device.Logfile) logfile := logfile.New(cnf.Logfile)
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED) rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
if err := rgbled.Logfile(rgbLEDs); err != nil { if err := rgbled.Logfile(rgbLEDs); err != nil {

View File

@ -5,11 +5,11 @@ import (
"log" "log"
"os" "os"
"github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
"github.com/go-flucky/flucky/pkg/cli" "github.com/go-flucky/flucky/pkg/cli"
"github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/logfile"
"github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/rgbled"
"github.com/go-flucky/flucky/pkg/sensor" "github.com/go-flucky/flucky/pkg/sensor"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -56,7 +56,7 @@ var readPressureCmd = &cobra.Command{
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout) cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
if logs { if logs {
measuredValuesLogfile := logfile.New(cnf.Device.Logfile) measuredValuesLogfile := logfile.New(cnf.Logfile)
err := logfile.Append(measuredValuesLogfile, compression, round, measuredValues) err := logfile.Append(measuredValuesLogfile, compression, round, measuredValues)
if err != nil { if err != nil {
log.Fatalln(err) log.Fatalln(err)

View File

@ -5,11 +5,11 @@ import (
"log" "log"
"os" "os"
"github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
"github.com/go-flucky/flucky/pkg/cli" "github.com/go-flucky/flucky/pkg/cli"
"github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/logfile"
"github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/rgbled"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -26,7 +26,7 @@ var listTemperatureCmd = &cobra.Command{
log.Fatalln(err) log.Fatalln(err)
} }
logfile := logfile.New(cnf.Device.Logfile) logfile := logfile.New(cnf.Logfile)
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED) rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
if err := rgbled.Logfile(rgbLEDs); err != nil { if err := rgbled.Logfile(rgbLEDs); err != nil {

View File

@ -7,11 +7,11 @@ import (
"os" "os"
"github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/rgbled"
"github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
"github.com/go-flucky/flucky/pkg/cli" "github.com/go-flucky/flucky/pkg/cli"
"github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/logfile"
"github.com/go-flucky/flucky/pkg/sensor" "github.com/go-flucky/flucky/pkg/sensor"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -60,7 +60,7 @@ var readTemperatureCmd = &cobra.Command{
cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout) cli.PrintMeasuredValues(measuredValues, cnf, os.Stdout)
if logs { if logs {
measuredValuesLogfile := logfile.New(cnf.Device.Logfile) measuredValuesLogfile := logfile.New(cnf.Logfile)
err := logfile.Append(measuredValuesLogfile, compression, round, measuredValues) err := logfile.Append(measuredValuesLogfile, compression, round, measuredValues)
if err != nil { if err != nil {
rgbled.Error(rgbLEDs) rgbled.Error(rgbLEDs)

6
go.mod
View File

@ -7,10 +7,16 @@ require (
github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375 github.com/d2r2/go-bsbmp v0.0.0-20190515110334-3b4b3aea8375
github.com/d2r2/go-i2c v0.0.0-20181113114621-14f8dd4e89ce github.com/d2r2/go-i2c v0.0.0-20181113114621-14f8dd4e89ce
github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e
github.com/docker/distribution v2.7.1+incompatible // indirect
github.com/docker/docker v1.13.1 // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/go-flucky/go-dht v0.1.1 github.com/go-flucky/go-dht v0.1.1
github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/kr/pretty v0.1.0 // indirect github.com/kr/pretty v0.1.0 // indirect
github.com/lib/pq v1.2.0 github.com/lib/pq v1.2.0
github.com/opencontainers/go-digest v1.0.0-rc1 // indirect
github.com/pkg/errors v0.8.1 // indirect
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/spf13/cobra v0.0.3 github.com/spf13/cobra v0.0.3
github.com/spf13/pflag v1.0.3 // indirect github.com/spf13/pflag v1.0.3 // indirect

13
go.sum
View File

@ -8,6 +8,14 @@ github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e h1:ZG3JBA6rPRl0xxQ+
github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e/go.mod h1:oA+9PUt8F1aKJ6o4YU1T120i7sgo1T6/1LWEEBy0BSs= github.com/d2r2/go-logger v0.0.0-20181221090742-9998a510495e/go.mod h1:oA+9PUt8F1aKJ6o4YU1T120i7sgo1T6/1LWEEBy0BSs=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/go-flucky/go-dht v0.1.1 h1:dPz9F5D7oUaTd0GUGTvT4lBH2R043h1bkmhTlpQax1Y= github.com/go-flucky/go-dht v0.1.1 h1:dPz9F5D7oUaTd0GUGTvT4lBH2R043h1bkmhTlpQax1Y=
github.com/go-flucky/go-dht v0.1.1/go.mod h1:Yk/cct+/u+eCS7pB/kc0tc7MrVXdFI4W15MJCj5FRUc= github.com/go-flucky/go-dht v0.1.1/go.mod h1:Yk/cct+/u+eCS7pB/kc0tc7MrVXdFI4W15MJCj5FRUc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
@ -19,6 +27,10 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
@ -33,6 +45,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

View File

@ -29,9 +29,9 @@ func main() {
sversion, err := semver.NewVersion(version) sversion, err := semver.NewVersion(version)
if err != nil { if err != nil {
log.Println("The sematic versioning is invalid: %v", version) log.Printf("The sematic versioning is invalid: %v", version)
os.Exit(1) os.Exit(1)
} }
cmd.Execute(version) cmd.Execute(sversion)
} }

21
pkg/config/dbsettings.go Normal file
View File

@ -0,0 +1,21 @@
package config
type DatabaseSettings struct {
Vendor DatabaseVendor `json:"vendor"`
Host string `json:"host"`
Port string `json:"port"`
Database string `json:"database"`
User string `json:"user"`
Password string `json:"password"`
}
type DatabaseVendor string
func (dv DatabaseVendor) String() string {
return string(dv)
}
const (
VendorPostgreSQL DatabaseVendor = "postgres"
VendorOracle = "oracle"
)

View File

@ -32,9 +32,11 @@ var temperatureSensorModels = map[types.SensorModel]types.SensorModel{
// Configuration of flucky // Configuration of flucky
type Configuration struct { type Configuration struct {
Device *types.Device `json:"device"` DatabaseSettings *DatabaseSettings `json:"database_settings"`
RGBLEDs []*types.RGBLED `json:"rgb_leds"` Device *types.Device `json:"device"`
Sensors []*types.Sensor `json:"sensors"` Logfile string `json:"logfile" xml:"logfile"`
RGBLEDs []*types.RGBLED `json:"rgb_leds"`
Sensors []*types.Sensor `json:"sensors"`
} }
// AddRGBLED add a new RGBLED // AddRGBLED add a new RGBLED
@ -451,6 +453,11 @@ func (c *Configuration) GetTemperatureSensorsByName(names []string) []sensor.Sen
return c.convertSensors(temperatureSensors) return c.convertSensors(temperatureSensors)
} }
// RemoveDatabaseSettings remove data base setting informations
func (c *Configuration) RemoveDatabaseSettings() {
c.DatabaseSettings = nil
}
// RemoveRGBLED deletes a LED by its name or its unique UUID // RemoveRGBLED deletes a LED by its name or its unique UUID
func (c *Configuration) RemoveRGBLED(name string) error { func (c *Configuration) RemoveRGBLED(name string) error {
for i, rgbLED := range c.RGBLEDs { for i, rgbLED := range c.RGBLEDs {
@ -513,6 +520,11 @@ func (c *Configuration) RenameSensor(oldName, newName string) error {
return fmt.Errorf("Could not find remote %v to replace into with %v", oldName, newName) return fmt.Errorf("Could not find remote %v to replace into with %v", oldName, newName)
} }
// SetDatabaseSettings set database setting informations
func (c *Configuration) SetDatabaseSettings(databaseSettings *DatabaseSettings) {
c.DatabaseSettings = databaseSettings
}
func (c *Configuration) convertSensors(sensors []*types.Sensor) []sensor.Sensor { func (c *Configuration) convertSensors(sensors []*types.Sensor) []sensor.Sensor {
cachedSensors := make([]sensor.Sensor, 0) cachedSensors := make([]sensor.Sensor, 0)

View File

@ -7,12 +7,13 @@ import (
"syscall" "syscall"
"time" "time"
"github.com/Masterminds/semver"
"github.com/go-flucky/flucky/pkg/config" "github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/db"
"github.com/go-flucky/flucky/pkg/logfile"
"github.com/go-flucky/flucky/pkg/logger" "github.com/go-flucky/flucky/pkg/logger"
"github.com/go-flucky/flucky/pkg/rgbled" "github.com/go-flucky/flucky/pkg/rgbled"
"github.com/go-flucky/flucky/pkg/sensor" "github.com/go-flucky/flucky/pkg/sensor"
"github.com/go-flucky/flucky/pkg/storage/db"
"github.com/go-flucky/flucky/pkg/storage/logfile"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
) )
@ -22,15 +23,25 @@ var (
postgresDatabase = "postgres" postgresDatabase = "postgres"
postgresUser = "postgres" postgresUser = "postgres"
postgresPassword = "postgres" postgresPassword = "postgres"
flogger logger.Logger
) )
func init() {
flogger = logger.NewSilentLogger()
}
func SetLogger(logger logger.Logger) {
flogger = logger
}
// Start the daemon // Start the daemon
func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compression bool, round float64, logger logger.Logger) { func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compression bool, round float64, version *semver.Version) {
// Info // Info
logger.Info("Use clean-cache-interval: %v", cleanCacheInterval.String()) flogger.Info("Use clean-cache-interval: %v", cleanCacheInterval.String())
logger.Info("Use compression: %v", compression) flogger.Info("Use compression: %v", compression)
logger.Info("Round: %v", round) flogger.Info("Round: %v", round)
ticker := time.Tick(cleanCacheInterval) ticker := time.Tick(cleanCacheInterval)
@ -43,29 +54,44 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress
ctx := context.Background() ctx := context.Background()
childContext, cancel := context.WithCancel(ctx) childContext, cancel := context.WithCancel(ctx)
measuredValuesLogfile := logfile.New(cnf.Device.Logfile) measuredValuesLogfile := logfile.New(cnf.Logfile)
measuredValuesCache := make([]*types.MeasuredValue, 0) measuredValuesCache := make([]*types.MeasuredValue, 0)
go sensor.ReadContinuously(childContext, cnf.GetSensors(config.ENABLED), measuredValuesChannel, errorChannel) var postgres db.Database
if cnf.DatabaseSettings != nil {
p, err := db.New(cnf.DatabaseSettings)
if err != nil {
flogger.Error("%v", err)
}
if err := p.Schema(ctx, version); err != nil {
flogger.Error("%v", err)
}
postgres = p
checkDeviceInDatabase(ctx, cnf.Device, postgres)
checkSensorsInDatabase(ctx, cnf.Sensors, postgres)
defer postgres.Close()
}
rgbLEDs := cnf.GetRGBLEDs(config.ENABLED) rgbLEDs := cnf.GetRGBLEDs(config.ENABLED)
go sensor.ReadContinuously(childContext, cnf.GetSensors(config.ENABLED), measuredValuesChannel, errorChannel)
for { for {
err := rgbled.Run(rgbLEDs) err := rgbled.Run(rgbLEDs)
if err != nil { if err != nil {
logger.Error("Can not turn on green info light: %v", err) flogger.Error("Can not turn on green info light: %v", err)
} }
select { select {
case err, _ := <-errorChannel: case err, _ := <-errorChannel:
logger.Error("%v", err) flogger.Error("%v", err)
err = rgbled.Error(rgbLEDs) err = rgbled.Error(rgbLEDs)
if err != nil { if err != nil {
logger.Error("Can not turn on red info light: %v", err) flogger.Error("Can not turn on red info light: %v", err)
} }
time.Sleep(time.Second * 2) time.Sleep(time.Second * 2)
@ -73,34 +99,25 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress
case <-ticker: case <-ticker:
err := rgbled.Logfile(rgbLEDs) err := rgbled.Logfile(rgbLEDs)
if err != nil { if err != nil {
logger.Error("Can not turn on blue info light: %v", err) flogger.Error("Can not turn on blue info light: %v", err)
} }
// err = logfile.Append(measuredValuesLogfile, compression, round, measuredValuesCache) if err := logfile.Append(measuredValuesLogfile, compression, round, measuredValuesCache); err != nil {
err2 := rgbled.Error(rgbLEDs)
postgres, err := db.New(db.DBOTypePostgres, postgresHost, postgresPort, postgresDatabase, postgresUser, postgresPassword) if err2 != nil {
if err != nil { flogger.Error("Can not turn on red info light: %v", err2)
err = rgbled.Error(rgbLEDs)
if err != nil {
logger.Error("Can not turn on red info light: %v", err)
} }
flogger.Error("Can not save caches measured values in logfile: %v", err)
cancel()
logger.Error("Can not open database connection: %v", err)
} }
postgresCtx := context.Background() if postgres != nil {
err = postgres.InsertMeasuredValues(postgresCtx, measuredValuesCache) if err := postgres.InsertMeasuredValues(ctx, measuredValuesCache); err != nil {
if err != nil { err2 := rgbled.Error(rgbLEDs)
if err2 != nil {
err = rgbled.Error(rgbLEDs) flogger.Error("Can not turn on red info light: %v", err)
if err != nil { }
logger.Error("Can not turn on red info light: %v", err) flogger.Error("Can not save cached measured values in database: %v", err)
} }
cancel()
logger.Error("Can not save caches measured values in database: %v", err)
} }
measuredValuesCache = make([]*types.MeasuredValue, 0) measuredValuesCache = make([]*types.MeasuredValue, 0)
@ -109,22 +126,52 @@ func Start(cnf *config.Configuration, cleanCacheInterval time.Duration, compress
measuredValuesCache = append(measuredValuesCache, measuredValues...) measuredValuesCache = append(measuredValuesCache, measuredValues...)
case killSignal := <-interrupt: case killSignal := <-interrupt:
logger.Warn("Daemon was interruped by system signal %v\n", killSignal) flogger.Warn("Daemon was interruped by system signal %v\n", killSignal)
cancel() cancel()
err := rgbled.Error(rgbLEDs) err := rgbled.Error(rgbLEDs)
if err != nil { if err != nil {
logger.Error("Can not turn on red info light: %v", err) flogger.Error("Can not turn on red info light: %v", err)
} }
logger.Warn("Save remaining data from the cache") flogger.Warn("Save remaining data from the cache")
err = logfile.Append(measuredValuesLogfile, compression, round, measuredValuesCache) err = logfile.Append(measuredValuesLogfile, compression, round, measuredValuesCache)
if err != nil { if err != nil {
logger.Fatal("%v", err) flogger.Fatal("%v", err)
} }
return return
} }
} }
} }
func checkDeviceInDatabase(ctx context.Context, device *types.Device, database db.Database) {
_, err := database.SelectDeviceByID(ctx, device.DeviceID)
if err != nil {
flogger.Debug("It's seems the current device is not registered in the database. Register the device now")
err2 := database.InsertDevices(ctx, []*types.Device{device})
if err2 != nil {
flogger.Fatal("Can not register device into database: %v", err2)
}
flogger.Debug("Device successfully registered into the database")
return
}
flogger.Debug("Device already registered into the database")
}
func checkSensorsInDatabase(ctx context.Context, sensors []*types.Sensor, database db.Database) {
for _, sensor := range sensors {
_, err := database.SelectSensorByID(ctx, sensor.SensorID)
if err != nil {
flogger.Debug("It's seems the sensor %v is not registered in the database. Register the sensor now", sensor.SensorName)
err2 := database.InsertSensors(ctx, []*types.Sensor{sensor})
if err2 != nil {
flogger.Fatal("Can not register sensor %v into database: %v", sensor.SensorName, err2)
}
flogger.Debug("Sensor %v successfully registered into the database", sensor.SensorName)
continue
}
flogger.Debug("Sensor %v is already registered into the database", sensor.SensorName)
}
}

View File

@ -1,25 +0,0 @@
package db
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func New(dboType DBOType, host string, port string, database string, user string, password string) (Database, error) {
connStr := fmt.Sprintf("%v://%v:%v@%v:%v/%v?sslmode=disable", dboType.String(), user, password, host, port, database)
newDBO, err := sql.Open(dboType.String(), connStr)
if err != nil {
return nil, err
}
switch dboType {
case "postgres":
return &Postgres{
dbo: newDBO,
}, nil
default:
return nil, fmt.Errorf("Unknown Database Type")
}
}

View File

@ -1,12 +0,0 @@
package db
type DBOType string
func (dboType DBOType) String() string {
return string(dboType)
}
const (
DBOTypePostgres DBOType = "postgres"
DBOTypeOracle = "oracle"
)

View File

@ -1,10 +0,0 @@
package db
var (
postgreSQLSchemata []*schemaInformation
)
type schemaInformation struct {
Version string
Asset string
}

39
pkg/storage/db/db.go Normal file
View File

@ -0,0 +1,39 @@
package db
import (
"database/sql"
"fmt"
"github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/logger"
_ "github.com/lib/pq"
)
var (
flogger logger.Logger
)
func init() {
flogger = logger.NewSilentLogger()
}
func New(databaseSettings *config.DatabaseSettings) (Database, error) {
connStr := fmt.Sprintf("%v://%v:%v@%v:%v/%v?sslmode=disable", databaseSettings.Vendor.String(), databaseSettings.User, databaseSettings.Password, databaseSettings.Host, databaseSettings.Port, databaseSettings.Database)
newDBO, err := sql.Open(databaseSettings.Vendor.String(), connStr)
if err != nil {
return nil, err
}
switch databaseSettings.Vendor {
case config.VendorPostgreSQL:
return &Postgres{
dbo: newDBO,
}, nil
default:
return nil, fmt.Errorf("Unknown Database Type")
}
}
func SetLogger(logger logger.Logger) {
flogger = logger
}

View File

@ -5,6 +5,7 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"path/filepath" "path/filepath"
"sort"
"strings" "strings"
"github.com/Masterminds/semver" "github.com/Masterminds/semver"
@ -13,71 +14,91 @@ import (
_ "github.com/lib/pq" _ "github.com/lib/pq"
) )
var (
postgresAssetPath = "pkg/storage/db/sql/psql"
)
type Postgres struct { type Postgres struct {
dbo *sql.DB dbo *sql.DB
} }
func (p *Postgres) Close() error { func (p *Postgres) Close() error {
return p.Close() return p.dbo.Close()
} }
// Schema create or upgrade database schema to the version of the flucky binary // Schema create or upgrade database schema to the version of the flucky binary
func (p *Postgres) Schema(ctx context.Context, version *semver.Version) error { func (p *Postgres) Schema(ctx context.Context, version *semver.Version) error {
query := "SELECT value FROM info WHERE key='version';" schemaFunc := func(ctx context.Context, fromVersion *semver.Version, toVersion *semver.Version) error {
stmt, err := p.dbo.PrepareContext(ctx, query) assetPath := fmt.Sprintf("%v/schema", postgresAssetPath)
if err != nil { sqlAssetFiles, err := AssetDir(assetPath)
asset := "pkg/db/sql/psql/schema.sql"
queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("Can not restore asset directory %v: %v", assetPath, err)
}
query = string(queryBytes)
_, err = p.dbo.ExecContext(ctx, query)
if err != nil {
return fmt.Errorf("%v: %v", errorStatementExecute, err)
} }
postgreSQLVersionChanges := make(map[*semver.Version]string, 0)
postgreSQLVersions := make([]*semver.Version, len(sqlAssetFiles))
for i, sqlAssetFile := range sqlAssetFiles {
fileSemVersion, err := semver.NewVersion(strings.ReplaceAll(sqlAssetFile, ".sql", ""))
if err != nil {
return fmt.Errorf("Can not create semantic version from file asset %v: %v", sqlAssetFile, err)
}
postgreSQLVersionChanges[fileSemVersion] = sqlAssetFile
postgreSQLVersions[i] = fileSemVersion
}
sort.Sort(semver.Collection(postgreSQLVersions))
for i, postgreSQLVersion := range postgreSQLVersions {
if fromVersion != nil {
if postgreSQLVersion.LessThan(fromVersion) || postgreSQLVersion.Equal(fromVersion) {
flogger.Debug("SKIP: PostgreSQL schema version '%v' is less or eqal then the local version changes '%v'", postgreSQLVersion.String(), fromVersion.String())
continue
}
}
asset := postgreSQLVersionChanges[postgreSQLVersion]
queryBytes, err := Asset(filepath.Join(assetPath, asset))
if err != nil {
return fmt.Errorf("Can not restore asset %v, %v", asset, err)
}
query := string(queryBytes)
if _, err := p.dbo.ExecContext(ctx, query); err != nil {
return fmt.Errorf("%v: %v", errorStatementExecute, err)
}
if i == 0 {
if err := p.InsertInfo(ctx, "version", postgreSQLVersion.String()); err != nil {
return fmt.Errorf("Can not insert version %v into info table: %v", postgreSQLVersion.String(), err)
}
} else {
if err := p.UpdateInfo(ctx, "version", postgreSQLVersion.String()); err != nil {
return fmt.Errorf("Can not update version %v into info table: %v", postgreSQLVersion.String(), err)
}
}
}
return nil return nil
} }
schemaVersion := "" dbVersion, err := p.SelectInfo(ctx, "version")
row := stmt.QueryRowContext(ctx)
err = row.Scan(&schemaVersion)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorScanRow, err) // can not select version from database, maybe the schema is not initialize
// create db schema for the current flucky version
return schemaFunc(ctx, nil, version)
} else {
fromVersion, err := semver.NewVersion(dbVersion)
if err != nil {
return fmt.Errorf("Can not create semantic version from database entry %v: %v", dbVersion, err)
}
return schemaFunc(ctx, fromVersion, version)
} }
fromVersion, err := semver.NewVersion(schemaVersion)
if err != nil {
return fmt.Errorf("Can not create new sematic version from database: %v", err)
}
if err := schema(fromVersion, version); err != nil {
return err
}
// The result will be 0 if from == to, -1 if from < to, or +1 if from > to.
switch fromVersion.Compare(version) {
case -1:
return schema(fromVersion, version)
case 0:
// fromVersion and toVersion are equal
return nil
case 1:
// fromVersion < toVersion
return fmt.Errorf("Can not downgrade the database schema. Update the flucky binary")
}
return nil
} }
func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) error { func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) error {
asset := "pkg/db/sql/psql/deleteDevice.sql" asset := fmt.Sprintf("%v/deleteDevice.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("%v: %v", errorGetAsset, err)
@ -101,7 +122,7 @@ func (p *Postgres) DeleteDevices(ctx context.Context, devices []*types.Device) e
} }
func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) error { func (p *Postgres) DeleteSensors(ctx context.Context, sensors []*types.Sensor) error {
asset := "pkg/db/sql/psql/deleteSensor.sql" asset := fmt.Sprintf("%v/deleteSensor.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("%v: %v", errorGetAsset, err)
@ -161,7 +182,7 @@ func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*t
for measuredValueType, sortedMeasuredValues := range sortedMeasuredValueTypes { for measuredValueType, sortedMeasuredValues := range sortedMeasuredValueTypes {
switch measuredValueType { switch measuredValueType {
case types.MeasuredValueTypeHumidity: case types.MeasuredValueTypeHumidity:
query, err := assetFunc("pkg/db/sql/psql/deleteHumidity.sql") query, err := assetFunc(fmt.Sprintf("%v/deleteHumidity.sql", postgresAssetPath))
if err != nil { if err != nil {
return err return err
} }
@ -170,7 +191,7 @@ func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*t
return err return err
} }
case types.MeasuredValueTypePressure: case types.MeasuredValueTypePressure:
query, err := assetFunc("pkg/db/sql/psql/deletePressure.sql") query, err := assetFunc(fmt.Sprintf("%v/deletePressure.sql", postgresAssetPath))
if err != nil { if err != nil {
return err return err
} }
@ -179,7 +200,7 @@ func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*t
return err return err
} }
case types.MeasuredValueTypeTemperature: case types.MeasuredValueTypeTemperature:
query, err := assetFunc("pkg/db/sql/psql/deleteTemperature.sql") query, err := assetFunc(fmt.Sprintf("%v/deleteTemperature.sql", postgresAssetPath))
if err != nil { if err != nil {
return err return err
} }
@ -194,7 +215,7 @@ func (p *Postgres) DeleteMeasuredValues(ctx context.Context, measuredValues []*t
} }
func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) error { func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) error {
asset := "pkg/db/sql/psql/insertDevice.sql" asset := fmt.Sprintf("%v/insertDevice.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("%v: %v", errorGetAsset, err)
@ -217,6 +238,28 @@ func (p *Postgres) InsertDevices(ctx context.Context, devices []*types.Device) e
return nil return nil
} }
func (p *Postgres) InsertInfo(ctx context.Context, key string, value string) error {
asset := fmt.Sprintf("%v/insertInfo.sql", postgresAssetPath)
queryBytes, err := Asset(asset)
if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err)
}
query := string(queryBytes)
stmt, err := p.dbo.PrepareContext(ctx, query)
if err != nil {
return fmt.Errorf("%v: %v", errorPrepareStatement, err)
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, key, value)
if err != nil {
return fmt.Errorf("%v: %v", errorStatementExecute, err)
}
return nil
}
func (p *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error { func (p *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
sortedMeasuredValueTypes := make(map[types.MeasuredValueType][]*types.MeasuredValue) sortedMeasuredValueTypes := make(map[types.MeasuredValueType][]*types.MeasuredValue)
@ -250,7 +293,7 @@ func (p *Postgres) InsertMeasuredValues(ctx context.Context, measuredValues []*t
func (p *Postgres) insertHumidity(ctx context.Context, measuredValues []*types.MeasuredValue) error { func (p *Postgres) insertHumidity(ctx context.Context, measuredValues []*types.MeasuredValue) error {
asset := "pkg/db/sql/psql/insertHumidity.sql" asset := fmt.Sprintf("%v/insertHumidity.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("%v: %v", errorGetAsset, err)
@ -279,7 +322,7 @@ func (p *Postgres) insertHumidity(ctx context.Context, measuredValues []*types.M
func (p *Postgres) insertPressure(ctx context.Context, measuredValues []*types.MeasuredValue) error { func (p *Postgres) insertPressure(ctx context.Context, measuredValues []*types.MeasuredValue) error {
asset := "pkg/db/sql/psql/insertPressure.sql" asset := fmt.Sprintf("%v/insertPressure.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("%v: %v", errorGetAsset, err)
@ -308,7 +351,7 @@ func (p *Postgres) insertPressure(ctx context.Context, measuredValues []*types.M
func (p *Postgres) insertTemperature(ctx context.Context, measuredValues []*types.MeasuredValue) error { func (p *Postgres) insertTemperature(ctx context.Context, measuredValues []*types.MeasuredValue) error {
asset := "pkg/db/sql/psql/insertTemperature.sql" asset := fmt.Sprintf("%v/insertTemperature.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("%v: %v", errorGetAsset, err)
@ -337,7 +380,7 @@ func (p *Postgres) insertTemperature(ctx context.Context, measuredValues []*type
func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) error { func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) error {
asset := "pkg/db/sql/psql/insertSensor.sql" asset := fmt.Sprintf("%v/insertSensor.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err) return fmt.Errorf("%v: %v", errorGetAsset, err)
@ -361,7 +404,7 @@ func (p *Postgres) InsertSensors(ctx context.Context, sensors []*types.Sensor) e
} }
func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Device, error) { func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Device, error) {
asset := "pkg/db/sql/psql/selectDeviceByID.sql" asset := fmt.Sprintf("%v/selectDeviceByID.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return nil, fmt.Errorf("%v: %v", errorGetAsset, err) return nil, fmt.Errorf("%v: %v", errorGetAsset, err)
@ -387,21 +430,35 @@ func (p *Postgres) SelectDeviceByID(ctx context.Context, id string) (*types.Devi
return device, nil return device, nil
} }
func (p *Postgres) SelectMeasuredValuesByIDAndType(ctx context.Context, id string, valueType types.MeasuredValueType) (*types.MeasuredValue, error) { func (p *Postgres) SelectInfo(ctx context.Context, key string) (string, error) {
switch valueType { asset := fmt.Sprintf("%v/selectInfo.sql", postgresAssetPath)
case types.MeasuredValueTypeHumidity: queryBytes, err := Asset(asset)
return p.SelectHumidityByID(ctx, id) if err != nil {
case types.MeasuredValueTypePressure: return "", fmt.Errorf("%v: %v", errorGetAsset, err)
return p.SelectPressureByID(ctx, id)
case types.MeasuredValueTypeTemperature:
return p.SelectTemperatureByID(ctx, id)
default:
return nil, fmt.Errorf("%v: %v", errorUnknownMeasuredValueType, valueType)
} }
query := string(queryBytes)
stmt, err := p.dbo.PrepareContext(ctx, query)
if err != nil {
return "", fmt.Errorf("%v: %v", errorPrepareStatement, err)
}
row := stmt.QueryRowContext(ctx, key)
if row == nil {
return "", errorRowNotFound
}
value := ""
err = row.Scan(&value)
if err != nil {
return "", fmt.Errorf("%v: %v", errorScanRow, err)
}
return value, nil
} }
func (p *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) { func (p *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue, error) {
queryFile := "pkg/db/sql/psql/selectHumidities.sql" queryFile := fmt.Sprintf("%v/selectHumidities.sql", postgresAssetPath)
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeHumidity, queryFile, nil) measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeHumidity, queryFile, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -410,7 +467,7 @@ func (p *Postgres) SelectHumidities(ctx context.Context) ([]*types.MeasuredValue
} }
func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error) { func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
queryFile := "pkg/db/sql/psql/selectHumidityByID.sql" queryFile := fmt.Sprintf("%v/selectHumidityByID.sql", postgresAssetPath)
args := []interface{}{id} args := []interface{}{id}
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeHumidity, queryFile, args) measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeHumidity, queryFile, args)
if err != nil { if err != nil {
@ -424,8 +481,21 @@ func (p *Postgres) SelectHumidityByID(ctx context.Context, id string) (*types.Me
return measuredValues[0], nil return measuredValues[0], nil
} }
func (p *Postgres) SelectMeasuredValuesByIDAndType(ctx context.Context, id string, valueType types.MeasuredValueType) (*types.MeasuredValue, error) {
switch valueType {
case types.MeasuredValueTypeHumidity:
return p.SelectHumidityByID(ctx, id)
case types.MeasuredValueTypePressure:
return p.SelectPressureByID(ctx, id)
case types.MeasuredValueTypeTemperature:
return p.SelectTemperatureByID(ctx, id)
default:
return nil, fmt.Errorf("%v: %v", errorUnknownMeasuredValueType, valueType)
}
}
func (p *Postgres) SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error) { func (p *Postgres) SelectPressures(ctx context.Context) ([]*types.MeasuredValue, error) {
queryFile := "pkg/db/sql/psql/selectPressures.sql" queryFile := fmt.Sprintf("%v/selectPressures.sql", postgresAssetPath)
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypePressure, queryFile, nil) measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypePressure, queryFile, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -434,7 +504,7 @@ func (p *Postgres) SelectPressures(ctx context.Context) ([]*types.MeasuredValue,
} }
func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error) { func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
queryFile := "pkg/db/sql/psql/selectPressureByID.sql" queryFile := fmt.Sprintf("%v/selectPressureByID.sql", postgresAssetPath)
args := []interface{}{id} args := []interface{}{id}
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypePressure, queryFile, args) measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypePressure, queryFile, args)
if err != nil { if err != nil {
@ -449,7 +519,7 @@ func (p *Postgres) SelectPressureByID(ctx context.Context, id string) (*types.Me
} }
func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sensor, error) { func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sensor, error) {
asset := "pkg/db/sql/psql/selectSensorByID.sql" asset := fmt.Sprintf("%v/selectSensorByID.sql", postgresAssetPath)
queryBytes, err := Asset(asset) queryBytes, err := Asset(asset)
if err != nil { if err != nil {
return nil, fmt.Errorf("%v: %v", errorGetAsset, err) return nil, fmt.Errorf("%v: %v", errorGetAsset, err)
@ -476,7 +546,7 @@ func (p *Postgres) SelectSensorByID(ctx context.Context, id string) (*types.Sens
} }
func (p *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredValue, error) { func (p *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredValue, error) {
queryFile := "pkg/db/sql/psql/selectTemperatures.sql" queryFile := fmt.Sprintf("%v/selectTemperatures.sql", postgresAssetPath)
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeTemperature, queryFile, nil) measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeTemperature, queryFile, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@ -485,7 +555,7 @@ func (p *Postgres) SelectTemperatures(ctx context.Context) ([]*types.MeasuredVal
} }
func (p *Postgres) SelectTemperatureByID(ctx context.Context, id string) (*types.MeasuredValue, error) { func (p *Postgres) SelectTemperatureByID(ctx context.Context, id string) (*types.MeasuredValue, error) {
queryFile := "pkg/db/sql/psql/selectTemperatureByID.sql" queryFile := fmt.Sprintf("%v/selectTemperatureByID.sql", postgresAssetPath)
args := []interface{}{id} args := []interface{}{id}
measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeTemperature, queryFile, args) measuredValues, err := p.selectMeasuredValues(ctx, types.MeasuredValueTypeTemperature, queryFile, args)
if err != nil { if err != nil {
@ -531,6 +601,28 @@ func (p *Postgres) UpdateDevices(ctx context.Context, devices []*types.Device) e
return nil return nil
} }
func (p *Postgres) UpdateInfo(ctx context.Context, key string, value string) error {
asset := fmt.Sprintf("%v/updateInfo.sql", postgresAssetPath)
queryBytes, err := Asset(asset)
if err != nil {
return fmt.Errorf("%v: %v", errorGetAsset, err)
}
query := string(queryBytes)
stmt, err := p.dbo.PrepareContext(ctx, query)
if err != nil {
return fmt.Errorf("%v: %v", errorPrepareStatement, err)
}
defer stmt.Close()
_, err = stmt.ExecContext(ctx, key, value)
if err != nil {
return fmt.Errorf("%v: %v", errorStatementExecute, err)
}
return nil
}
func (p *Postgres) UpdateMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error { func (p *Postgres) UpdateMeasuredValues(ctx context.Context, measuredValues []*types.MeasuredValue) error {
return nil return nil
} }
@ -538,42 +630,3 @@ func (p *Postgres) UpdateMeasuredValues(ctx context.Context, measuredValues []*t
func (p *Postgres) UpdateSensors(ctx context.Context, sensots []*types.Sensor) error { func (p *Postgres) UpdateSensors(ctx context.Context, sensots []*types.Sensor) error {
return nil return nil
} }
func schema(fromVersion *semver.Version, toVersion *semver.Version) error {
sqlAssetFiles, err := parseAssetDir("pkg/db/sql/psql/schema")
if err != nil {
return fmt.Errorf("Can not restore sql files: %v", err)
}
for _, sqlAssetFile := range sqlAssetFiles {
version := strings.Replace()
sqlSchemaInformations := &schemaInformation{
Version: filepath.Split()
Asset: sqlAssetFile,
}
}
return nil
}
func parseAssetDir(dir string) ([]string, error) {
assetFiles, err := AssetDir(dir)
if err != nil {
return nil, fmt.Errorf("Can not load asset directory %v: %v", dir, err)
}
goldenAssetFiles := assetFiles
for i, assetFile := range assetFiles {
if strings.HasPrefix(assetFile, "/") {
// is directory- SKIP
goldenAssetFiles = append(goldenAssetFiles[:i], goldenAssetFiles[i+1:]...)
}
}
return goldenAssetFiles, nil
}

View File

@ -2,9 +2,12 @@ package db_test
import ( import (
"context" "context"
"strings"
"testing" "testing"
"github.com/go-flucky/flucky/pkg/db" "github.com/Masterminds/semver"
"github.com/go-flucky/flucky/pkg/config"
"github.com/go-flucky/flucky/pkg/storage/db"
"github.com/go-flucky/flucky/pkg/types" "github.com/go-flucky/flucky/pkg/types"
"github.com/go-flucky/flucky/test/goldenfiles" "github.com/go-flucky/flucky/test/goldenfiles"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -19,11 +22,15 @@ var (
database db.Database database db.Database
postgresContainerImage string = "docker.io/postgres/postgres" postgresContainerImage string = "docker.io/postgres/postgres"
postgresHost string = "localhost"
postgresPort string = "5432" postgresSettings = &config.DatabaseSettings{
postgresUser string = "postgres" Vendor: config.VendorPostgreSQL,
postgresPassword string = "postgres" Host: "localhost",
postgresDatabase string = "postgres" Port: "5432",
User: "postgres",
Password: "postgres",
Database: "postgres",
}
goldenDevicesFilePath string = "test/goldenfiles/json/goldenDevices.json" goldenDevicesFilePath string = "test/goldenfiles/json/goldenDevices.json"
goldenSensorsFilePath string = "test/goldenfiles/json/goldenSensors.json" goldenSensorsFilePath string = "test/goldenfiles/json/goldenSensors.json"
@ -74,7 +81,7 @@ func TestPostgres(t *testing.T) {
load(t) load(t)
db, err := db.New(db.DBOTypePostgres, postgresHost, postgresPort, postgresDatabase, postgresUser, postgresPassword) db, err := db.New(postgresSettings)
database = db database = db
require.Nil(err) require.Nil(err)
@ -83,54 +90,54 @@ func TestPostgres(t *testing.T) {
Name: "schema", Name: "schema",
Test: testSchemaCreate, Test: testSchemaCreate,
}, },
// &test{ &test{
// Name: "insertDevices", Name: "insertDevices",
// Test: testInsertDevices, Test: testInsertDevices,
// }, },
// &test{ &test{
// Name: "insertSensors", Name: "insertSensors",
// Test: testInsertSensors, Test: testInsertSensors,
// }, },
// &test{ &test{
// Name: "insertHumidity", Name: "insertHumidity",
// Test: testInsertHumidity, Test: testInsertHumidity,
// }, },
// &test{ &test{
// Name: "insertPressure", Name: "insertPressure",
// Test: testInsertPressure, Test: testInsertPressure,
// }, },
// &test{ &test{
// Name: "insertTemperatures", Name: "insertTemperatures",
// Test: testInsertTemperatures, Test: testInsertTemperatures,
// }, },
// &test{ &test{
// Name: "deleteHumidities", Name: "deleteHumidities",
// Test: testDeleteHumidity, Test: testDeleteHumidity,
// }, },
// &test{ &test{
// Name: "deletePressures", Name: "deletePressures",
// Test: testDeletePressures, Test: testDeletePressures,
// }, },
// &test{ &test{
// Name: "deleteTemperatures", Name: "deleteTemperatures",
// Test: testDeleteTemperatures, Test: testDeleteTemperatures,
// }, },
// &test{ &test{
// Name: "insertMeasuredValues", Name: "insertMeasuredValues",
// Test: testInsertMeasuredValues, Test: testInsertMeasuredValues,
// }, },
// &test{ &test{
// Name: "deleteMeasuredValues", Name: "deleteMeasuredValues",
// Test: testDeleteMeasuredValues, Test: testDeleteMeasuredValues,
// }, },
// &test{ &test{
// Name: "deleteSensors", Name: "deleteSensors",
// Test: testDeleteSensors, Test: testDeleteSensors,
// }, },
// &test{ &test{
// Name: "deleteDevices", Name: "deleteDevices",
// Test: testDeleteDevices, Test: testDeleteDevices,
// }, },
} }
for _, test := range tests { for _, test := range tests {
@ -140,9 +147,18 @@ func TestPostgres(t *testing.T) {
func testSchemaCreate(t *testing.T) { func testSchemaCreate(t *testing.T) {
require := require.New(t) require := require.New(t)
ctx := context.Background()
err := database.Schema(ctx, "v0.1.0") homePath := "pkg/storage/db/sql/psql/schema"
sqlAssetFiles, err := db.AssetDir(homePath)
require.NoError(err) require.NoError(err)
ctx := context.Background()
for _, sqlAssetFile := range sqlAssetFiles {
fromVersion, err := semver.NewVersion(strings.ReplaceAll(sqlAssetFile, ".sql", ""))
require.NoError(err)
err = database.Schema(ctx, fromVersion)
require.NoError(err)
}
} }
func testInsertDevices(t *testing.T) { func testInsertDevices(t *testing.T) {

View File

@ -0,0 +1,2 @@
INSERT INTO info (key, value)
VALUES ($1, $2);

View File

@ -0,0 +1,3 @@
SELECT value
FROM info
WHERE key = $1;

View File

@ -0,0 +1,3 @@
UPDATE info
SET value = $2
WHERE key = $1;

View File

@ -8,6 +8,5 @@ type Device struct {
DeviceName string `json:"device_name" xml:"device_name"` DeviceName string `json:"device_name" xml:"device_name"`
DeviceLocation *string `json:"device_location" xml:"device_location"` DeviceLocation *string `json:"device_location" xml:"device_location"`
DeviceLastContact *time.Time `json:"device_last_contact" xml:"device_last_contact"` DeviceLastContact *time.Time `json:"device_last_contact" xml:"device_last_contact"`
Logfile string `json:"logfile" xml:"logfile"`
CreationDate time.Time `json:"creation_date" xml:"creation_date"` CreationDate time.Time `json:"creation_date" xml:"creation_date"`
} }