goservicetools

package module
v0.0.0-...-f1963b3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 19, 2018 License: MIT Imports: 22 Imported by: 0

README

goservicetools - library to write services on go

Build StatusGo Report Card

Framework to make service from your application(with different log types, http, suid, graceful restart)

Overview

This package was written for case you need write own unix service in golang. For example. I want my application to have following things:

  1. Application must have own configuration file and tools to read them. And must work at least in 3 environments defined by ENV variable or command line option(prod, dev, test)
  2. Application must be able write own log files and support at least 2 formats(plain and json) an 4 outputs(stderr, file, syslog, and no output) with syslog like facilities.
  3. Application must be able work as daemon:
    1. Support SIGINT, SIGTERM
    2. Support work with logrotate and reopen logs on SIGHUP signal.
    3. Application must be able open HTTP and HTTPS service and give user configure them
    4. Application must have support for setuid(+self restart) to support open lower ports without using docker or capabilities
    5. Application must support graceful self restart on SIGUSR1 signal with no reopening ports(it must transmit port listener descriptors to new instance)
    6. Things like logfile, pidfile

Quickstart

To setup your application you must define child struct from IAppStartSetup interface or from DefaultAppStartSetup. On code documentation to IAppStartSetup it's described call order of methods.

So this is your first program code.

package main

import (
    "fmt"
    "os"

    "github.com/ilya1st/goservicetools"
)

// CustomAppStart app start there
// Look at goservicetools.DefaultAppStartSetup
// understand on how to write applications
type CustomAppStart struct {
    goservicetools.DefaultAppStartSetup
}

func main() {
    fmt.Println("Just open https://localhost:8000 when ready")
    exitCode, err := goservicetools.AppStart(&CustomAppStart{})
    if err != nil {
        fmt.Fprintf(os.Stderr, "Error occurred while starting app\n%v\n", err)
        os.Exit(exitCode)
    }
    goservicetools.AppRun()
}

Library contains additional API to work with loggers, configuration files, command line arguments. There is examples directory you can see on how to work with library components

External libraries used

  • github.com/rs/zerolog for logging
  • github.com/ilya1st/rotatewriter to support log rotate on SIGHUP
  • github.com/ilya1st/configuration-go to support HJSON(json with not strict syntax) to work with configuration files
  • github.com/theckman/go-flock for lock file

Application configuration file

We use HJSON format. Configuration file contains 3 main sections:

  • prod - for production environments
  • dev - for development
  • test - for test environment(e.g. run unit tests)

Each section contains own options.

You can see in conf/config.hjson documented configuration file with different options. You can add own options there, e.g. number of ports user want to listen. See helloservice example on how to work with configuration.

Graceful port reopening

See AppStop() internals to understand on how does that works and helloservice example where gracefully restarted does not need open socket to listen - it gives file descriptor from previous instance.

Limitations for graceful restart

For correct application restart when setuid enabled in configuration and used lower ports - you may not to change ports numbers in configuration file between restarts

Documentation

Index

Constants

View Source
const (
	ExitCodeNormalExit = iota
	ExitCodeWrongEnv
	ExitCodeConfigError
	ExitCodeLockfileError
	ExitHTTPStartError
	ExitUserDefinedCodeError
	ExitHTTPServeError
	ExitCustomAppError
	ExitSuidError
)

variants of exit codes

Variables

This section is empty.

Functions

func AddExitAction

func AddExitAction(f func())

AddExitAction adds action to our exit function(close logs, remove pid file etc. - for normal exit case)

func AddSighupHandler

func AddSighupHandler(handler func())

AddSighupHandler adds sighup handler to catch suck things as log rotation

func AppRun

func AppRun()

AppRun just to run app when we all do here is no way cover with tests cause need manually test them or make integration tests there

func AppStart

func AppStart(setup IAppStartSetup) (exitCode int, err error)

AppStart app start function if graceful - then to app transmitted http socket in fd 3 https in fd 4 etc.

func AppStop

func AppStop(graceful bool, sd *SetuidData) (exitCode int, err error)

AppStop is intended to control app stop while things: SIGINT handling, SIGTERM handling, SIGUSR handling for a graceful exit to give socket descriptors to new process if graceful==true then function tries make graceful restart function makes app restart and also makes it's suid start NOTICE: if set suid and graceful restart and lower ports are used we assume than you do not change port numbers cause we do not have root controller process to supervise lower ports openings

func CheckAppConfig

func CheckAppConfig(config configuration.IConfig) error

CheckAppConfig checks whole configuration file like their initialization order and returns error if something is wrong NOTE: Environment must be initialized before start this function this function is intended to configtest commandline argument and for application startup

func CheckHTTPConfig

func CheckHTTPConfig(httpConfig configuration.IConfig) error

CheckHTTPConfig to check http config part at startup

func CheckLockFileConfig

func CheckLockFileConfig(conf configuration.IConfig) (err error)

CheckLockFileConfig checks config file if is not correct

func CheckLogConfig

func CheckLogConfig(tag string, conf configuration.IConfig) error

CheckLogConfig checks config internals before and in SetupLog call

func CheckPidfileConfig

func CheckPidfileConfig(pidfileConfig configuration.IConfig) error

CheckPidfileConfig checks pidfile subconfig

func CheckSetuidConfig

func CheckSetuidConfig(setuidConfig configuration.IConfig) error

CheckSetuidConfig checks setuid part of configuration file

func CleanupSighupHandlers

func CleanupSighupHandlers()

CleanupSighupHandlers clears channel and routines

func DropHTTPListener

func DropHTTPListener()

DropHTTPListener close socket. Call when not graceful there

func DropHTTPServer

func DropHTTPServer()

DropHTTPServer shut downs and drop server - not listener

func DropLockFile

func DropLockFile()

DropLockFile drops lock file and removes them

func DropLogger

func DropLogger(tag string)

DropLogger drops log from our internal registry to e.g. reinit them while reload logs

func DropPidfile

func DropPidfile()

DropPidfile deletes pid file on correct app shutdown

func Exit

func Exit(code int)

Exit run exit actions in reverse order one by one and after run os.exit no sense to test cause exits program motherfucker

func GetCommandLineFlags

func GetCommandLineFlags(CustomFlags func(cmdFlags map[string]string)) map[string]string

GetCommandLineFlags generates parameter map from commanline and reports errors on usage CustomFlags function add to cmdFlags additional flags all the same as in function

func GetEnvironment

func GetEnvironment(sl ...interface{}) (env string, err error)

GetEnvironment returns configured application environment function will have 2 parameters first used to reset default false second used to reset to default value - used in error cases I need them for testing purposes too

func GetHTTPListener

func GetHTTPListener() net.Listener

GetHTTPListener returns internal http socket

func GetHTTPLogger

func GetHTTPLogger() *zerolog.Logger

GetHTTPLogger is to avoid env.GetLoggger("http") calls to minimize some work

func GetHTTPServer

func GetHTTPServer() *http.Server

GetHTTPServer gets http server instance if started

func GetLogger

func GetLogger(tag string) *zerolog.Logger

GetLogger returns tagged logger to work with and write logs to

func GetSystemLogger

func GetSystemLogger() *zerolog.Logger

GetSystemLogger is to avoid env.GetLoggger("system") calls to minimize some work is system logger is not initialized out to stderr

func PrepareHTTPListener

func PrepareHTTPListener(graceful bool, httpConfig configuration.IConfig) error

PrepareHTTPListener prepare http socket to run Notice: here we assume config is clean and normal

func SetHTTPServeMux

func SetHTTPServeMux(mux http.Handler)

SetHTTPServeMux sets up server mux

func SetupHTTPServer

func SetupHTTPServer(httpConfig configuration.IConfig) error

SetupHTTPServer setups http server(not stats!). for case of graceful gives their socket graceful or not here depends on was changed configuration file or not this one you must use after PrepareHTTPListener runned

func SetupLockFile

func SetupLockFile(conf configuration.IConfig) (err error)

SetupLockFile sets up LockFile by the given config

func SetupLog

func SetupLog(tag string, config configuration.IConfig) (logger *zerolog.Logger, err error)

SetupLog setup logger to work with

func SetupPidfile

func SetupPidfile(pidfileConfig configuration.IConfig) error

SetupPidfile try setup pidfile if enabled.

func SetupSighupHandlers

func SetupSighupHandlers()

SetupSighupHandlers sets handler at startup got SIGHUP kill We need that e.g. to rotate logs

func SetupSighupRotationForLogs

func SetupSighupRotationForLogs() error

SetupSighupRotationForLogs setups rotation hadlers for logs Call that functions when all logs are set up and configures

func StartHTTPServer

func StartHTTPServer()

StartHTTPServer starts listen http with g

func ValidateEnv

func ValidateEnv(str string) error

ValidateEnv checks correct _Env variable value

Types

type DefaultAppStartSetup

type DefaultAppStartSetup struct {
}

DefaultAppStartSetup implements IAppStartSetup this is default app start setup and an example on how to write own appstart class

func (*DefaultAppStartSetup) CheckUserConfig

func (*DefaultAppStartSetup) CheckUserConfig(mainconf configuration.IConfig) error

CheckUserConfig checks user config parts

func (*DefaultAppStartSetup) CommandLineHook

func (*DefaultAppStartSetup) CommandLineHook(cmdFlags map[string]string)

CommandLineHook implements IAppStartSetup.CommandLineHook() method

func (*DefaultAppStartSetup) ConfigureHTTPServer

func (*DefaultAppStartSetup) ConfigureHTTPServer(graceful bool) error

ConfigureHTTPServer implements IAppStartSetup.ConfigureHTTPServer() method

func (*DefaultAppStartSetup) HandleSignal

func (*DefaultAppStartSetup) HandleSignal(sg os.Signal) error

HandleSignal handles signal from OS

func (*DefaultAppStartSetup) NeedHTTP

func (*DefaultAppStartSetup) NeedHTTP() bool

NeedHTTP implements IAppStartSetup.NeedHTTP() method

func (*DefaultAppStartSetup) SetupOwnExtraFiles

func (*DefaultAppStartSetup) SetupOwnExtraFiles(cmd *exec.Cmd, newConfig configuration.IConfig) error

SetupOwnExtraFiles for graceful restart

func (*DefaultAppStartSetup) SystemSetup

func (*DefaultAppStartSetup) SystemSetup(graceful bool) error

SystemSetup implements IAppStartSetup.SystemSetup() method

func (*DefaultAppStartSetup) SystemShutdown

func (*DefaultAppStartSetup) SystemShutdown(graceful bool) error

SystemShutdown implements IAppStartSetup.SystemShutdown

func (*DefaultAppStartSetup) SystemStart

func (*DefaultAppStartSetup) SystemStart(graceful bool) error

SystemStart start custom services

type IAppStartSetup

type IAppStartSetup interface {
	// NeedHTTP does app need http service or not
	NeedHTTP() bool
	// CommandLineHookadds additional command line flags to global cmdFlags structure
	CommandLineHook(cmdFlags map[string]string)
	// checks user config parts
	CheckUserConfig(mainconf configuration.IConfig) error
	// SystemSetup setup other suid ports here, sockets, etc
	SystemSetup(graceful bool) error
	// SetupOwnExtraFiles for graceful restart - transfer suid ports to graceful child
	// for made System setup when suid or graceful restart
	//  newConfig is full new app config to compare settings
	SetupOwnExtraFiles(cmd *exec.Cmd, newConfig configuration.IConfig) error
	// HandleSignal handles signal from OS
	HandleSignal(sg os.Signal) error
	// Set up custom http mux, log, etc
	ConfigureHTTPServer(graceful bool) error
	// Start custom services - after ports are ready
	SystemStart(graceful bool) error
	// Run on app shutdown
	SystemShutdown(graceful bool) error
}

IAppStartSetup appstart setup for application Methods at start are called at following order: 1. CommandLineHook add command line reading 2. CheckUserConfig add additional config tests 3. SystemSetup - prepare own socket listeners etc 3. ConfigureHTTPServer configure e.g. mux for http 4. SystemStart - stat listen listeners, etc. At SIGINT or SIGTERM are called: 1. HandleSignal - to determine type of signal and handle them 2. SystemShutdown - shutdown listenere At SIGUSR1 - system does graceful restart and calls: 1. SystemShutdown if there is graceful flag - do not close listeners - just shut down your services 2. SetupOwnExtraFiles - setup them here to make restart app with open sockets

type NullWriter

type NullWriter struct{}

NullWriter writes nothing writer - to loopback logs

func (*NullWriter) Write

func (*NullWriter) Write(p []byte) (n int, err error)

type SetuidData

type SetuidData struct {
	// contains filtered or unexported fields
}

SetuidData intended to transmit data to AppStop to set credentials there

func GetSetUIDGIDData

func GetSetUIDGIDData(setuidConf configuration.IConfig) (*SetuidData, error)

GetSetUIDGIDData lookups Setuid gid data to suid no tests here cause too system dependent

Directories

Path Synopsis
examples
helloservice
Here would be main program file located to work To run: ENV=dev go run helloservice.go Also it can do suid from lower ports We listen on default HTTP port and answer hello there and open specific config with special section for our miniservice
Here would be main program file located to work To run: ENV=dev go run helloservice.go Also it can do suid from lower ports We listen on default HTTP port and answer hello there and open specific config with special section for our miniservice
helloservicenohttp
Here would be main program file located to work To run: ENV=dev go run helloservicenohttp.go Also it can do suid from lower ports config with special section for our miniservice This is example for case when http subservice is disabled - see NeedHTTP() method of application object
Here would be main program file located to work To run: ENV=dev go run helloservicenohttp.go Also it can do suid from lower ports config with special section for our miniservice This is example for case when http subservice is disabled - see NeedHTTP() method of application object
simplestart
Here would be main program file located to work To run: ENV=dev go run simplestart.go Or: go build ENV=test ./simplestart and try killall -HUP simplestart to see on how reload works Also it can do suid from lower ports
Here would be main program file located to work To run: ENV=dev go run simplestart.go Or: go build ENV=test ./simplestart and try killall -HUP simplestart to see on how reload works Also it can do suid from lower ports

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL