-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create a `golock` program this is based on the following: https://github.com/kvz/cronlock This is because the above hasn't been maintained for many years, and I need something that does the equivalent but to be able to talk to Redis servers that enforce TLS encryption. Add `util.GenEnv()`, `util.GetEnvBool()`, and `util.GetEnvInt()` functions to get values from the environment variables and return them in a certain type. If the environment variables are not set, then the default value to be returned is passed to these functions. Add a `util.Run()` function to execute a command with an optional timeout so that it will be killed if it exceeds that runtime.
- Loading branch information
1 parent
13f2ddc
commit 050a873
Showing
13 changed files
with
995 additions
and
7 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* @jim-barber-he |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
|
||
# My Go repository | ||
|
||
## Introduction | ||
|
||
This repository was created for me to use as I'm learning to write Go. | ||
I decided that the best way for me to learn it was to write some utilities that will be useful for me in my line of work. | ||
|
||
## Utilities | ||
|
||
The utilities in this repository are: | ||
|
||
- [golock](golock/) Creates locks in a [Redis](https://redis.io/) server to coordinate running a command on distributed servers. | ||
- [kubectl-n](kubectl-plugins/kubectl-n) A [kubectl](https://kubernetes.io/docs/reference/kubectl/) plugin that is an alternate | ||
version of `kubectl get nodes`. | ||
- [kubectl-p](kubectl-plugins/kubectl-p) A [kubectl](https://kubernetes.io/docs/reference/kubectl/) plugin that is an alternate | ||
version of `kubectl get pods`. | ||
- [ssm](ssm/) A tool for managing AWS SSM parameters. | ||
|
||
## Go Libraries | ||
|
||
The following libraries in this repository were written to implement the utilities above. | ||
|
||
- [aws](aws/) Implements functions to interact with Amazon Web Services. | ||
- [k8s](k8s/) Implements functions to interact with Kubernetes clusters. | ||
- [texttable](texttable/) Implements functions for handling outputting a text based table. | ||
- [util](util/) Implements various utility functions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,7 @@ | ||
# Things to do | ||
|
||
* Add README.md | ||
* Make repo public. | ||
* Add JSON output for the `get` and `list` commands for `ssm`. | ||
* Improve tests and add tests for the AWS stuff once I work out how to mock them. | ||
* `ssm` command to handle advanced parameters; policies; intelligent tiering. | ||
* Add `--no-value` parameter to `ssm list` to return just the names of parameters. | ||
* `ssm` command to handle advanced parameters; policies; and intelligent tiering. | ||
* Implement `ssm copy` command. | ||
* Command line completion for the --namespace option in k8s commands. | ||
* Improve / add tests and add tests for the AWS stuff once I work out how to mock them. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
ARCH := $(shell uname -s | tr '[A-Z]' '[a-z]') | ||
BINARY_NAME=golock | ||
|
||
.PHONY: all build clean install lint run vet | ||
|
||
all: vet lint build install | ||
|
||
build: | ||
GOARCH=amd64 GOOS=darwin go build -o ${BINARY_NAME}-darwin -race main.go | ||
GOARCH=amd64 GOOS=linux go build -o ${BINARY_NAME}-linux -race main.go | ||
|
||
clean: | ||
go clean | ||
rm -f ${BINARY_NAME}-darwin ${BINARY_NAME}-linux | ||
|
||
install: | ||
go install -ldflags='-s' | ||
|
||
lint: | ||
golangci-lint run | ||
|
||
lintall: | ||
golangci-lint run --enable-all | ||
|
||
run: build | ||
./${BINARY_NAME}-${ARCH} | ||
|
||
vet: | ||
go vet |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
|
||
# golock | ||
|
||
## Introduction | ||
|
||
golock uses a central Redis server to globally coordinate the running of a job across a distributed system. | ||
This is useful where you only want a job to run once, but want to schedule it on multiple servers for redundancy. | ||
|
||
Also by only allowing one job to run at a time, it can stop jobs that are scheduled to frequently run, from overlapping | ||
themselves. | ||
|
||
It is a cronlock replacement, based on https://github.com/kvz/cronlock | ||
It creates locks with the same names as cronlock does, and uses many of the same environment variables. | ||
|
||
The purpose of writing golock is because cronlock does not support Redis servers where TLS is enforced. | ||
And also it is an exercise in me learning Golang. | ||
|
||
## Options. | ||
|
||
- `CRONLOCK_HOST` the Redis hostname. default: `localhost` | ||
- `CRONLOCK_PORT` the Redis port. default: `6379` | ||
- `CRONLOCK_AUTH` the Redis auth password. default: Not present | ||
- `CRONLOCK_DB` the Redis database. default: `0` | ||
- `CRONLOCK_REDIS_TIMEOUT` the length of time to wait for a response from Redis before considering it in an errored state. | ||
This ensures that if the Redis connection goes away that we don't wait forever waiting for a response. default: `30` | ||
- `CRONLOCK_GRACE` determines how many seconds a lock should at least persist. | ||
Prevents fast running jobs scheduled on multiple servers with some clock drift, from executing multiple times. | ||
- `CRONLOCK_RELEASE` determines how long a lock can persist at most. | ||
Acts as a failsafe so there can be no locks that persist forever in case of failure. default is a day: `86400` | ||
- `CRONLOCK_RECONNECT_ATTEMPTS` the number of times to try to reconnect before erroring. | ||
If the Redis connection is closed, attempt to reconnect upto this amount of times. default: `5` | ||
- `CRONLOCK_RECONNECT_BACKOFF` the length of time to increase the wait between reconnects. | ||
Acts as a failsafe to allow Redis to be started before trying to reconnect. | ||
Set to 0 to retry the connection immediately. default: `5` | ||
- `CRONLOCK_KEY` a unique key for this command in the global Redis server. default: an md5 hash of golock's arguments. | ||
- `CRONLOCK_PREFIX` Redis key prefix used by all keys. default: `cronlock` | ||
- `CRONLOCK_VERBOSE` set to `yes` to print debug messages. default: `no` | ||
- `CRONLOCK_TIMEOUT` how long the command can run before it gets issued a `kill -9`. default: `0`; no timeout | ||
- `CRONLOCK_TLS` use TLS to connect to Redis. default `false` | ||
- `CRONLOCK_TLS_SKIP_VERIFY` donot verify TLS certificates when using TLS connections. default `false`; | ||
certificates are verified. | ||
- `CRONLOCK_RESET` removes the lock and exits immediately. Needs to golock arguments passed in order to remove the right lock. | ||
|
||
## Exit Codes | ||
|
||
- = `200` Success (delete succeeded or lock not acquired, but normal execution) | ||
- = `201` Failure (cronlock error) | ||
- = `202` Failure (cronlock timeout) | ||
- < `200` Success (acquired lock, executed your command), passes the exit code of your command | ||
|
||
## Examples | ||
|
||
### Single server | ||
|
||
``` | ||
* * * * * golock command.sh | ||
``` | ||
The above crontab entry launches `command.sh` every minute. | ||
If the previous `command.sh` has not finished yet, another is not started. | ||
This works on one server since the default `CRONLOCK_HOST` of `localhost` is used. | ||
|
||
### Distributed | ||
|
||
``` | ||
00 08 * * * CRONLOCK_HOST=redis.example.com golock command.sh | ||
``` | ||
In this configuration, a central Redis server is used to track the locking for `command.sh`. | ||
If this crontab entry was on many servers, just one instance of `command.sh` would be run each morning. | ||
|
||
### Lock commands that have different arguments | ||
|
||
By default golock uses your command and its arguments to make a unique identifier by which the global lock is acquired. | ||
However if you want to run `ls -al` or `ls -a`, but just one instance of either, you'll need to provide your own key: | ||
``` | ||
# One of two will be executed because they share the same KEY | ||
* * * * * CRONLOCK_KEY="ls" golock ls -al | ||
* * * * * CRONLOCK_KEY="ls" golock ls -a | ||
``` | ||
|
||
### Per application | ||
|
||
If you use the same command and Redis server for multiple applications and you need them to run without impacting each other, | ||
use the `CRONLOCK_PREFIX`: | ||
``` | ||
# Crontab for app1 | ||
* * * * * CRONLOCK_PREFIX="lock.app1." cronlock command.sh | ||
``` | ||
``` | ||
# Crontab for app2 | ||
* * * * * CRONLOCK_PREFIX="lock.app2." cronlock command.sh | ||
``` | ||
Now `command.sh` will be able to run for each application at the same time, because even though `command.sh` will produce the same | ||
md5 hash for both, the key's prefix makes it unique. | ||
|
||
## Local Redis for testing | ||
|
||
A quick way of getting a Redis server locally if you have Docker available is to run: | ||
```shell | ||
docker run --rm -it -p 6379:6379 redis:latest | ||
``` |
Oops, something went wrong.