naming update, more configurable with env vars

This commit is contained in:
Morgan Patterson
2021-10-13 08:57:49 -07:00
parent bff93e9bb4
commit b26922b22c
4 changed files with 72 additions and 37 deletions

View File

@@ -1,14 +1,11 @@
from golang:alpine3.14 from golang:alpine3.14
WORKDIR /go/src/app WORKDIR /root/
COPY ./sandman.go . COPY ./lazytainer.go .
RUN go build sandman.go RUN go build lazytainer.go
FROM alpine:latest FROM alpine:latest
RUN apk --no-cache add docker-cli RUN apk --no-cache add docker-cli
WORKDIR /root/ WORKDIR /root/
COPY --from=0 /go/src/app/sandman ./ COPY --from=0 /root/lazytainer ./
ENV TIMEOUT=30
ENV LABEL=sandman
CMD ["./lazytainer"]
CMD ["./sandman"]

View File

@@ -1,7 +1,7 @@
# Sandman # Lazytainer
Putting your containers to sleep Putting your containers to sleep
*man me a sand* *I don't really wanna do the work today*
--- ---
@@ -13,15 +13,14 @@ if it looks like you're trying to access a stopped container, it starts
### Want to test it? ### Want to test it?
``` ```
$ git clone https://github.com/vmorganp/sandman $ git clone https://github.com/vmorganp/Lazytainer
$ cd sandman $ cd Lazytainer
$ docker-compose up -d --build $ docker-compose up
``` ```
## TODO ## TODO
- support multiple ports - support multiple ports
- test on common services - test on common services
- better time adjustment
- docker security probably? this really shouldn't be getting exposed except to forward traffic so idk probably firewall all non listed ports? - docker security probably? this really shouldn't be getting exposed except to forward traffic so idk probably firewall all non listed ports?
- improve logging - improve logging
- inevitable bugfixes - inevitable bugfixes

View File

@@ -1,11 +1,11 @@
version: "3" version: "3"
services: services:
sandman: lazytainer:
container_name: sandman container_name: lazytainer
build: . build: .
environment: environment:
- PORT=81 # TODO make this work with more than one port - PORT=81 # TODO make this work with more than one port
- LABEL=sandman # sandman checks - LABEL=lazytainer # value of com.lazytainer.marker for other containers that lazytainer checks
- TIMEOUT=30 # number of seconds to let container idle - TIMEOUT=30 # number of seconds to let container idle
ports: ports:
- 81:81 - 81:81
@@ -16,10 +16,10 @@ services:
container_name: whoami2 container_name: whoami2
image: containous/whoami image: containous/whoami
command: --port 81 command: --port 81
network_mode: service:sandman network_mode: service:lazytainer
depends_on: depends_on:
- sandman - lazytainer
# ports: # ports:
# - 80:80 # - 80:80
labels: labels:
- "com.sandman.marker=sandman" - "com.lazytainer.marker=lazytainer"

View File

@@ -11,12 +11,37 @@ import (
func main() { func main() {
inactive_seconds := 0 inactive_seconds := 0
// label := os.Getenv("LABEL") // check if all of the necessary env vars are set, otherwise, use defaults
// how long a container is allowed to have no traffic before being stopped
inactive_timeout, err := strconv.Atoi(os.Getenv("TIMEOUT")) inactive_timeout, err := strconv.Atoi(os.Getenv("TIMEOUT"))
check(err) if check_env_fetch_recoverable(err) {
// tx fmt.Println("using default because env variable TIMEOUT not set ")
// port := os.Getenv("PORT") inactive_timeout = 30
rx_history := []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
// how many polls to keep around
rx_history_length, err := strconv.Atoi(os.Getenv("RXHISTLENGTH"))
if check_env_fetch_recoverable(err) {
fmt.Println("using default because env variable RXHISTLENGTH not set ")
rx_history_length = 10
}
// number of packets required between first and last poll to keep container alive
min_packet_threshhold, err := strconv.Atoi(os.Getenv("MINPACKETTHRESH"))
if check_env_fetch_recoverable(err) {
fmt.Println("using default because env variable MINPACKETTHRESH not set ")
min_packet_threshhold = 10
}
// how many seconds to wait in between polls
poll_rate, err := strconv.Atoi(os.Getenv("POLLRATE"))
if check_env_fetch_recoverable(err) {
fmt.Println("using default because env variable POLLRATE not set ")
poll_rate = 1
}
rx_history := make([]int, rx_history_length)
for { for {
// check if container is on // check if container is on
container_state_on := is_container_on() container_state_on := is_container_on()
@@ -27,6 +52,7 @@ func main() {
rx_packets, err := strconv.Atoi(strings.TrimSpace(string(rx))) rx_packets, err := strconv.Atoi(strings.TrimSpace(string(rx)))
check(err) check(err)
rx_history = append(rx_history[1:], rx_packets) rx_history = append(rx_history[1:], rx_packets)
fmt.Println(rx_packets, "rx packets")
// if the container is running, see if it needs to be stopped // if the container is running, see if it needs to be stopped
if container_state_on { if container_state_on {
@@ -37,29 +63,31 @@ func main() {
check(err) check(err)
// log out the results // log out the results
println(active_clients, "active clients") fmt.Println(active_clients, "active clients")
println(rx_packets, "rx packets") // println(rx_packets, "rx packets")
fmt.Printf("%v rx history\n\n", rx_history) // fmt.Printf("%v rx history", rx_history)
if active_clients == 0 && rx_history[0]+10 > rx_history[9] { if active_clients == 0 && rx_history[0]+min_packet_threshhold > rx_history[len(rx_history)-1] {
// count up if we have no active clients // count up if we have no active clients
// if no clients are active and less than 10 packets recieved in the last 10 seconds // if no clients are active and less than 10 packets recieved in the last 10 seconds
inactive_seconds++ inactive_seconds++
println(inactive_seconds, "seconds without an active client") fmt.Println(inactive_seconds, "seconds without an active client")
if inactive_seconds > inactive_timeout { if inactive_seconds > inactive_timeout {
stop_containers() stop_containers()
} }
} }
} else { } else {
// if more than 10 rx in last 10 seconds, start the container // if more than 10 rx in last 10 seconds, start the container
if rx_history[0]+10 < rx_history[9] { if rx_history[0]+min_packet_threshhold < rx_history[len(rx_history)-1] {
start_containers() start_containers()
} }
} }
fmt.Println("//////////////////////////////////////////////////////////////////////////////////")
for i := 0; i < poll_rate; i++ {
time.Sleep(time.Second) time.Sleep(time.Second)
} }
} }
}
type container struct { type container struct {
id string id string
@@ -74,7 +102,7 @@ func newContainer(id string, state string) *container {
func get_containers() []container { func get_containers() []container {
containers := []container{} containers := []container{}
out, err := exec.Command("/bin/sh", "-c", "docker ps -a --no-trunc --filter label=\"com.sandman.marker=$LABEL\" --format \"{{.ID}} {{.State}}\"").Output() // todo make this handle multiple ports? out, err := exec.Command("/bin/sh", "-c", "docker ps -a --no-trunc --filter label=\"com.lazytainer.marker=$LABEL\" --format \"{{.ID}} {{.State}}\"").Output() // todo make this handle multiple ports?
check(err) check(err)
fmt.Println(string(out)) fmt.Println(string(out))
if strings.TrimSpace(string(out)) == "" { if strings.TrimSpace(string(out)) == "" {
@@ -98,7 +126,7 @@ func is_container_on() bool {
} }
func stop_containers() { func stop_containers() {
println("stopping container(s)") fmt.Println("stopping container(s)")
containers := get_containers() containers := get_containers()
idString := "" idString := ""
for _, c := range containers { for _, c := range containers {
@@ -111,7 +139,7 @@ func stop_containers() {
} }
func start_containers() { func start_containers() {
println("starting container(s)") fmt.Println("starting container(s)")
containers := get_containers() containers := get_containers()
idString := "" idString := ""
for _, c := range containers { for _, c := range containers {
@@ -125,6 +153,17 @@ func start_containers() {
func check(err error) { func check(err error) {
if err != nil { if err != nil {
fmt.Println(err)
// panic(err)
}
}
func check_env_fetch_recoverable(err error) bool {
if err != nil {
if strings.Contains(err.Error(), "strconv.Atoi: parsing \"\": invalid syntax") {
return true
}
panic(err) panic(err)
} }
return false
} }