commit 196e17cd2963ed5724cf76c29c491a17f44b48de Author: Aaron Guise Date: Mon Jan 15 12:06:13 2024 +1300 Initial Commit. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d7d73bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +bin +vendor \ No newline at end of file diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..aba0c06 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,9 @@ +# Credits + +## Development Lead + +- Aaron Guise [guisea](https://github.com/guisea) + +## Contributors + +None yet. Why not be the first? \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8ef5d02 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,81 @@ +# Contributing + +Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given. + +You can contribute in many ways: + +## Types of Contributions + +### Report Bugs + +Report bugs at https://github.com/guisea/directdnsonly/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting. +* Detailed steps to reproduce the bug. + +### Fix Bugs + +Look through the GitHub issues for bugs. Anything tagged with "bug" +is open to whoever wants to implement it. + +### Implement Features + +Look through the GitHub issues for features. Anything tagged with "feature" +is open to whoever wants to implement it. + +### Write Documentation + +directdnsonly could always use more documentation, whether as part of the +official directdnsonly docs, in docstrings, or even on the web in blog posts, +articles, and such. + +### Submit Feedback + +The best way to send feedback is to file an issue at https://github.com/guisea/directdnsonly/issues. + +If you are proposing a feature: + +* Explain in detail how it would work. +* Keep the scope as narrow as possible, to make it easier to implement. +* Remember that this is a volunteer-driven project, and that contributions + are welcome :) + +## Get Started! + +Ready to contribute? Here's how to set up `directdnsonly` for local development. + +1. Fork the `directdnsonly` repo on GitHub. +2. Clone your fork locally:: +```bash + $ git clone git@github.com:your_name_here/directdnsonly.git +``` +3. Create a branch for local development:: +```bash + $ git checkout -b name-of-your-bugfix-or-feature +``` + Now you can make your changes locally. + +4. When you're done making changes, check that your changes pass the tests:: +```bash + $ make test +``` +6. Commit your changes and push your branch to GitHub:: +```bash + $ git add . + $ git commit -m "Your detailed description of your changes." + $ git push origin name-of-your-bugfix-or-feature +``` +7. Submit a pull request through the GitHub website. + +Pull Request Guidelines +----------------------- + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests. +2. If the pull request adds functionality, the docs should be updated. Put + your new functionality into a function with a docstring, and add the + feature to the list in README.md. diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8471909 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,40 @@ +# Build Stage +FROM lacion/alpine-golang-buildimage:1.13 AS build-stage + +LABEL app="build-directdnsonly" +LABEL REPO="https://github.com/guisea/directdnsonly" + +ENV PROJPATH=/go/src/github.com/guisea/directdnsonly + +# Because of https://github.com/docker/docker/issues/14914 +ENV PATH=$PATH:$GOROOT/bin:$GOPATH/bin + +ADD . /go/src/github.com/guisea/directdnsonly +WORKDIR /go/src/github.com/guisea/directdnsonly + +RUN make build-alpine + +# Final Stage +FROM lacion/alpine-base-image:latest + +ARG GIT_COMMIT +ARG VERSION +LABEL REPO="https://github.com/guisea/directdnsonly" +LABEL GIT_COMMIT=$GIT_COMMIT +LABEL VERSION=$VERSION + +# Because of https://github.com/docker/docker/issues/14914 +ENV PATH=$PATH:/opt/directdnsonly/bin + +WORKDIR /opt/directdnsonly/bin + +COPY --from=build-stage /go/src/github.com/guisea/directdnsonly/bin/directdnsonly /opt/directdnsonly/bin/ +RUN chmod +x /opt/directdnsonly/bin/directdnsonly + +# Create appuser +RUN adduser -D -g '' directdnsonly +USER directdnsonly + +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +CMD ["/opt/directdnsonly/bin/directdnsonly"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f5d9a22 --- /dev/null +++ b/Makefile @@ -0,0 +1,64 @@ + +.PHONY: build build-alpine clean test help default + + + +BIN_NAME=directdnsonly + +VERSION := $(shell grep "const Version " version/version.go | sed -E 's/.*"(.+)"$$/\1/') +GIT_COMMIT=$(shell git rev-parse HEAD) +GIT_DIRTY=$(shell test -n "`git status --porcelain`" && echo "+CHANGES" || true) +BUILD_DATE=$(shell date '+%Y-%m-%d-%H:%M:%S') +IMAGE_NAME := "guisea/directdnsonly" + +default: test + +help: + @echo 'Management commands for directdnsonly:' + @echo + @echo 'Usage:' + @echo ' make build Compile the project.' + @echo ' make get-deps runs dep ensure, mostly used for ci.' + @echo ' make build-alpine Compile optimized for alpine linux.' + @echo ' make package Build final docker image with just the go binary inside' + @echo ' make tag Tag image created by package with latest, git commit and version' + @echo ' make test Run tests on a compiled project.' + @echo ' make push Push tagged images to registry' + @echo ' make clean Clean the directory tree.' + @echo + +build: + @echo "building ${BIN_NAME} ${VERSION}" + @echo "GOPATH=${GOPATH}" + go build -ldflags "-X github.com/guisea/directdnsonly/version.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X github.com/guisea/directdnsonly/version.BuildDate=${BUILD_DATE}" -o bin/${BIN_NAME} + +get-deps: + dep ensure + +build-alpine: + @echo "building ${BIN_NAME} ${VERSION}" + @echo "GOPATH=${GOPATH}" + go build -ldflags '-w -linkmode external -extldflags "-static" -X github.com/guisea/directdnsonly/version.GitCommit=${GIT_COMMIT}${GIT_DIRTY} -X github.com/guisea/directdnsonly/version.BuildDate=${BUILD_DATE}' -o bin/${BIN_NAME} + +package: + @echo "building image ${BIN_NAME} ${VERSION} $(GIT_COMMIT)" + docker build --build-arg VERSION=${VERSION} --build-arg GIT_COMMIT=$(GIT_COMMIT) -t $(IMAGE_NAME):local . + +tag: + @echo "Tagging: latest ${VERSION} $(GIT_COMMIT)" + docker tag $(IMAGE_NAME):local $(IMAGE_NAME):$(GIT_COMMIT) + docker tag $(IMAGE_NAME):local $(IMAGE_NAME):${VERSION} + docker tag $(IMAGE_NAME):local $(IMAGE_NAME):latest + +push: tag + @echo "Pushing docker image to registry: latest ${VERSION} $(GIT_COMMIT)" + docker push $(IMAGE_NAME):$(GIT_COMMIT) + docker push $(IMAGE_NAME):${VERSION} + docker push $(IMAGE_NAME):latest + +clean: + @test ! -e bin/${BIN_NAME} || rm bin/${BIN_NAME} + +test: + go test ./... + diff --git a/README.md b/README.md new file mode 100644 index 0000000..7a15523 --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# directdnsonly + +DNSOnly for Directadmin Multi-server + +## Getting started + +This project requires Go to be installed. On OS X with Homebrew you can just run `brew install go`. + +Running it then should be as simple as: + +```console +$ make +$ ./bin/directdnsonly +``` + +### Testing + +``make test`` \ No newline at end of file diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..2668ca8 --- /dev/null +++ b/config/config.go @@ -0,0 +1,58 @@ +package config + +import ( + "time" + + "github.com/spf13/viper" +) + +// Provider defines a set of read-only methods for accessing the application +// configuration params as defined in one of the config files. +type Provider interface { + ConfigFileUsed() string + Get(key string) interface{} + GetBool(key string) bool + GetDuration(key string) time.Duration + GetFloat64(key string) float64 + GetInt(key string) int + GetInt64(key string) int64 + GetSizeInBytes(key string) uint + GetString(key string) string + GetStringMap(key string) map[string]interface{} + GetStringMapString(key string) map[string]string + GetStringMapStringSlice(key string) map[string][]string + GetStringSlice(key string) []string + GetTime(key string) time.Time + InConfig(key string) bool + IsSet(key string) bool +} + +var defaultConfig *viper.Viper + +// Config returns a default config providers +func Config() Provider { + return defaultConfig +} + +// LoadConfigProvider returns a configured viper instance +func LoadConfigProvider(appName string) Provider { + return readViperConfig(appName) +} + +func init() { + defaultConfig = readViperConfig("DIRECTDNSONLY") +} + +func readViperConfig(appName string) *viper.Viper { + v := viper.New() + v.SetEnvPrefix(appName) + v.AutomaticEnv() + + // global defaults + + v.SetDefault("json_logs", false) + v.SetDefault("loglevel", "debug") + + + return v +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..49646a5 --- /dev/null +++ b/go.mod @@ -0,0 +1,7 @@ +module github.com/guisea/directdnsonly + +require ( + github.com/sirupsen/logrus v1.4.1 + + github.com/spf13/viper v1.3.2 +) diff --git a/log/log.go b/log/log.go new file mode 100644 index 0000000..bcebf26 --- /dev/null +++ b/log/log.go @@ -0,0 +1,216 @@ +package log + +import ( + "os" + + "github.com/sirupsen/logrus" + "github.com/guisea/directdnsonly/config" +) + +// Logger defines a set of methods for writing application logs. Derived from and +// inspired by logrus.Entry. +type Logger interface { + Debug(args ...interface{}) + Debugf(format string, args ...interface{}) + Debugln(args ...interface{}) + Error(args ...interface{}) + Errorf(format string, args ...interface{}) + Errorln(args ...interface{}) + Fatal(args ...interface{}) + Fatalf(format string, args ...interface{}) + Fatalln(args ...interface{}) + Info(args ...interface{}) + Infof(format string, args ...interface{}) + Infoln(args ...interface{}) + Panic(args ...interface{}) + Panicf(format string, args ...interface{}) + Panicln(args ...interface{}) + Print(args ...interface{}) + Printf(format string, args ...interface{}) + Println(args ...interface{}) + Warn(args ...interface{}) + Warnf(format string, args ...interface{}) + Warning(args ...interface{}) + Warningf(format string, args ...interface{}) + Warningln(args ...interface{}) + Warnln(args ...interface{}) +} + +var defaultLogger *logrus.Logger + +func init() { + defaultLogger = newLogrusLogger(config.Config()) +} + + +// NewLogger returns a configured logrus instance +func NewLogger(cfg config.Provider) *logrus.Logger { + return newLogrusLogger(cfg) +} + + + +func newLogrusLogger(cfg config.Provider) *logrus.Logger { + + l := logrus.New() + + if cfg.GetBool("json_logs") { + l.Formatter = new(logrus.JSONFormatter) + } + l.Out = os.Stderr + + switch cfg.GetString("loglevel") { + case "debug": + l.Level = logrus.DebugLevel + case "warning": + l.Level = logrus.WarnLevel + case "info": + l.Level = logrus.InfoLevel + default: + l.Level = logrus.DebugLevel + } + + return l +} + +// Fields is a map string interface to define fields in the structured log +type Fields map[string]interface{} + +// With allow us to define fields in out structured logs +func (f Fields) With(k string, v interface{}) Fields { + f[k] = v + return f +} + +// WithFields allow us to define fields in out structured logs +func (f Fields) WithFields(f2 Fields) Fields { + for k, v := range f2 { + f[k] = v + } + return f +} + +// WithFields allow us to define fields in out structured logs +func WithFields(fields Fields) Logger { + return defaultLogger.WithFields(logrus.Fields(fields)) +} + +// Debug package-level convenience method. +func Debug(args ...interface{}) { + defaultLogger.Debug(args...) +} + +// Debugf package-level convenience method. +func Debugf(format string, args ...interface{}) { + defaultLogger.Debugf(format, args...) +} + +// Debugln package-level convenience method. +func Debugln(args ...interface{}) { + defaultLogger.Debugln(args...) +} + +// Error package-level convenience method. +func Error(args ...interface{}) { + defaultLogger.Error(args...) +} + +// Errorf package-level convenience method. +func Errorf(format string, args ...interface{}) { + defaultLogger.Errorf(format, args...) +} + +// Errorln package-level convenience method. +func Errorln(args ...interface{}) { + defaultLogger.Errorln(args...) +} + +// Fatal package-level convenience method. +func Fatal(args ...interface{}) { + defaultLogger.Fatal(args...) +} + +// Fatalf package-level convenience method. +func Fatalf(format string, args ...interface{}) { + defaultLogger.Fatalf(format, args...) +} + +// Fatalln package-level convenience method. +func Fatalln(args ...interface{}) { + defaultLogger.Fatalln(args...) +} + +// Info package-level convenience method. +func Info(args ...interface{}) { + defaultLogger.Info(args...) +} + +// Infof package-level convenience method. +func Infof(format string, args ...interface{}) { + defaultLogger.Infof(format, args...) +} + +// Infoln package-level convenience method. +func Infoln(args ...interface{}) { + defaultLogger.Infoln(args...) +} + +// Panic package-level convenience method. +func Panic(args ...interface{}) { + defaultLogger.Panic(args...) +} + +// Panicf package-level convenience method. +func Panicf(format string, args ...interface{}) { + defaultLogger.Panicf(format, args...) +} + +// Panicln package-level convenience method. +func Panicln(args ...interface{}) { + defaultLogger.Panicln(args...) +} + +// Print package-level convenience method. +func Print(args ...interface{}) { + defaultLogger.Print(args...) +} + +// Printf package-level convenience method. +func Printf(format string, args ...interface{}) { + defaultLogger.Printf(format, args...) +} + +// Println package-level convenience method. +func Println(args ...interface{}) { + defaultLogger.Println(args...) +} + +// Warn package-level convenience method. +func Warn(args ...interface{}) { + defaultLogger.Warn(args...) +} + +// Warnf package-level convenience method. +func Warnf(format string, args ...interface{}) { + defaultLogger.Warnf(format, args...) +} + +// Warning package-level convenience method. +func Warning(args ...interface{}) { + defaultLogger.Warning(args...) +} + +// Warningf package-level convenience method. +func Warningf(format string, args ...interface{}) { + defaultLogger.Warningf(format, args...) +} + +// Warningln package-level convenience method. +func Warningln(args ...interface{}) { + defaultLogger.Warningln(args...) +} + +// Warnln package-level convenience method. +func Warnln(args ...interface{}) { + defaultLogger.Warnln(args...) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..290523d --- /dev/null +++ b/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "flag" + "fmt" + "github.com/guisea/directdnsonly/version" + +) + +func main() { + + + versionFlag := flag.Bool("version", false, "Version") + flag.Parse() + + if *versionFlag { + fmt.Println("Build Date:", version.BuildDate) + fmt.Println("Git Commit:", version.GitCommit) + fmt.Println("Version:", version.Version) + fmt.Println("Go Version:", version.GoVersion) + fmt.Println("OS / Arch:", version.OsArch) + return + } + fmt.Println("Hello.") + +} diff --git a/version/version.go b/version/version.go new file mode 100644 index 0000000..0817b7b --- /dev/null +++ b/version/version.go @@ -0,0 +1,21 @@ +package version + +import ( + "fmt" + "runtime" +) + +// GitCommit returns the git commit that was compiled. This will be filled in by the compiler. +var GitCommit string + +// Version returns the main version number that is being run at the moment. +const Version = "0.1.0" + +// BuildDate returns the date the binary was built +var BuildDate = "" + +// GoVersion returns the version of the go runtime used to compile the binary +var GoVersion = runtime.Version() + +// OsArch returns the os and arch used to build the binary +var OsArch = fmt.Sprintf("%s %s", runtime.GOOS, runtime.GOARCH)