Skip to content

Commit b985e6e

Browse files
authored
Merge pull request #1 from gadost/refactor
Refactor
2 parents 1f7a010 + 45f76f8 commit b985e6e

14 files changed

Lines changed: 566 additions & 201 deletions

File tree

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "*"
7+
8+
jobs:
9+
build:
10+
name: GoReleaser build
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Check out code into the Go module directory
15+
uses: actions/checkout@v2
16+
with:
17+
fetch-depth: 0
18+
19+
- name: Set up Go
20+
uses: actions/setup-go@v2
21+
with:
22+
go-version: 1.17.5
23+
id: go
24+
25+
- name: Run GoReleaser
26+
uses: goreleaser/goreleaser-action@master
27+
with:
28+
version: latest
29+
args: release --rm-dist
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GO_RELEASER_GITHUB_TOKEN_DFSNOTIFY }}

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
FROM golang:1.11-alpine
2-
MAINTAINER nikolaev.makc@gmail.com
1+
FROM golang:1.18-alpine
2+
LABEL maintainer=nikolaev.makc@gmail.com
33
RUN apk add --no-cache git
44
WORKDIR /go/src/docker-fsnotify-event-handler
55
COPY . .
66
RUN go get -d -v ./... && go install -v ./... && rm -rf /go/src
7-
CMD ["docker-fsnotify-event-handler"]
7+
CMD ["docker-fsnotify-event-handler start"]

README.md

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,54 @@
1-
## overview
1+
# docker-fsnotify-event-handler
2+
3+
## Overview
4+
25
docker-fsnotify-event-handler developed for processing some filesystem events like letsencrypt cert renew for one domain on multiply hosts ( f.e. on my case - N nginx instances on different hosts using same certs. On certs renew le companion reloading only one nginx, other all proceed using old certs.).
36

47
## Install
58

69
```bash
7-
go get github.com/gadost/docker-fsnotify-event-handler
8-
cd $GOPATH/src/github.com/gadost/docker-fsnotify-event-handler
10+
git clone github.com/gadost/docker-fsnotify-event-handler
11+
cd docker-fsnotify-event-handler
912
go build .
1013
export WATCH_PATH=/path/to/watch ; ./docker-fsnotify-event-handler
1114

1215
```
13-
## Struct
16+
17+
## Environment
18+
1419
```golang
15-
RedisAddr string `env:"REDIS_ADDR" envDefault:"localhost:6379"`
16-
RedisPass string `env:"REDIS_PASS" envDefault:""`
17-
RedisDB int `env:"REDIS_DB" envDefault:"0"`
18-
AgentsSet string `env:"AGENTS_SET_NAME" envDefault:"agents"`
19-
QueueName string `env:"QUEUE_NAME" envDefault:"lecc"`
20-
AgentName string `env:"HOSTNAME"`
20+
// redis host , pass , db
21+
RedisAddr string `env:"REDIS_ADDR" envDefault:"localhost:6379"`
22+
RedisPass string `env:"REDIS_PASS" envDefault:""`
23+
RedisDB int `env:"REDIS_DB" envDefault:"0"`
24+
25+
// agent set
26+
AgentsSet string `env:"AGENTS_SET_NAME" envDefault:"agents"`
27+
QueueName string `env:"QUEUE_NAME" envDefault:"lecc"`
28+
AgentName string `env:"HOSTNAME"`
29+
30+
//check interval
31+
Interval int `env:"INTERVAL" envDefault:"20"`
32+
33+
// Path to watch
34+
Path string `env:"WATCH_PATH"`
35+
36+
// Docker image "test/image"
37+
Image string `env:"IMAGE"`
38+
39+
// execute command when event happens ( f.e. "nginx -s reload" )
40+
Command string `env:"COMMAND"`
41+
2142
```
2243

2344
## Docker example
2445

2546
```bash
26-
docker run -it --privileged --network=host -v /var/run/docker.sock:/var/run/docker.sock -v /root/gotest:/dir -e WATCH_PATH=/dir -e "REDIS_ADDR=somehost:6379" maxn/docker-fsnotify-event-handler:v1
47+
docker run -it --privileged --network=host -v /var/run/docker.sock:/var/run/docker.sock -v /path/to/watching/dir:/dir -e WATCH_PATH=/dir -e "REDIS_ADDR=somehost:6379" maxn/docker-fsnotify-event-handler:latest
2748
```
2849

29-
## build
50+
## Build
51+
3052
```bash
3153
docker build .
3254
```

app/app.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package app
2+
3+
import (
4+
"log"
5+
"os"
6+
"path/filepath"
7+
"time"
8+
9+
"github.com/fsnotify/fsnotify"
10+
"github.com/go-redis/redis"
11+
)
12+
13+
var c Config
14+
15+
func Start() {
16+
c.MarshalConfig()
17+
//define watcher
18+
watcher, err := fsnotify.NewWatcher()
19+
if err != nil {
20+
log.Fatal(err)
21+
}
22+
23+
defer watcher.Close()
24+
25+
client := c.Client()
26+
c.RegisterAgent(client)
27+
go c.Walking(watcher)
28+
go QueueProcessor(client)
29+
c.CheckEvent(watcher, client)
30+
}
31+
32+
func (c *Config) Walking(watcher *fsnotify.Watcher) {
33+
_ = filepath.Walk(c.Path, func(path string, f os.FileInfo, err error) error {
34+
watcher.Add(path)
35+
return nil
36+
})
37+
}
38+
39+
func (c Config) CheckEvent(watcher *fsnotify.Watcher, client *redis.Client) {
40+
done := make(chan bool)
41+
go func() {
42+
for {
43+
select {
44+
case event := <-watcher.Events:
45+
fi, err := os.Stat(event.Name)
46+
if err != nil {
47+
break
48+
}
49+
if fi.Mode().IsDir() {
50+
watcher.Add(event.Name)
51+
break
52+
}
53+
if AllowedEvents(event.Op.String()) {
54+
log.Println("event:", event)
55+
AddToQueue(c.AgentName, "wait", client)
56+
}
57+
case err := <-watcher.Errors:
58+
log.Println("error:", err)
59+
}
60+
}
61+
}()
62+
<-done
63+
}
64+
65+
func QueueProcessor(client *redis.Client) {
66+
for {
67+
<-time.After(time.Duration(c.Interval) * time.Second)
68+
go CheckQueue(c.AgentName, "wait", client)
69+
}
70+
}
71+
72+
func AllowedEvents(e string) bool {
73+
switch e {
74+
case
75+
"RENAME",
76+
"CHMOD",
77+
"CREATE",
78+
"WRITE":
79+
return true
80+
}
81+
return false
82+
}

app/event.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package app
2+
3+
import (
4+
"log"
5+
"strings"
6+
7+
"github.com/docker/docker/api/types"
8+
"github.com/docker/docker/client"
9+
"golang.org/x/net/context"
10+
)
11+
12+
func Handler() {
13+
cli, err := client.NewClientWithOpts(client.FromEnv)
14+
if err != nil {
15+
panic(err)
16+
}
17+
18+
containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{})
19+
if err != nil {
20+
panic(err)
21+
}
22+
23+
for _, container := range containers {
24+
if container.Image == c.Image {
25+
log.Println(container.ID)
26+
config := types.ExecConfig{AttachStdout: true, AttachStderr: true,
27+
Cmd: c.GenerateCmd()}
28+
res, _ := cli.ContainerExecCreate(context.Background(), container.ID, config)
29+
log.Println("Processing event: ", container.ID, " event id: ", res.ID)
30+
err := cli.ContainerExecStart(context.Background(), res.ID, types.ExecStartCheck{Detach: true, Tty: true})
31+
if err != nil {
32+
log.Print(err)
33+
}
34+
}
35+
}
36+
}
37+
38+
func (c Config) GenerateCmd() []string {
39+
return strings.Split(c.Command, " ")
40+
}

app/sqs.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package app
2+
3+
import (
4+
"log"
5+
6+
"github.com/caarlos0/env"
7+
"github.com/go-redis/redis"
8+
)
9+
10+
type Config struct {
11+
RedisAddr string `env:"REDIS_ADDR" envDefault:"localhost:6379"`
12+
RedisPass string `env:"REDIS_PASS" envDefault:""`
13+
RedisDB int `env:"REDIS_DB" envDefault:"0"`
14+
AgentsSet string `env:"AGENTS_SET_NAME" envDefault:"agents"`
15+
QueueName string `env:"QUEUE_NAME" envDefault:"lecc"`
16+
AgentName string `env:"HOSTNAME"`
17+
Interval int `env:"INTERVAL" envDefault:"20"`
18+
Path string `env:"WATCH_PATH"`
19+
Command string `env:"COMMAND"`
20+
Image string `env:"IMAGE"`
21+
}
22+
23+
var rClient *redis.Client
24+
25+
// Define Client Redis from config
26+
func (c *Config) Client() *redis.Client {
27+
rClient = redis.NewClient(&redis.Options{
28+
Addr: c.RedisAddr,
29+
Password: c.RedisPass,
30+
DB: c.RedisDB,
31+
})
32+
_, err := rClient.Ping().Result()
33+
if err != nil {
34+
log.Println("Redis server unreachable! Exit..")
35+
panic(err)
36+
}
37+
return rClient
38+
}
39+
40+
func (c *Config) MarshalConfig() *Config {
41+
cfg := Config{}
42+
if err := env.Parse(&cfg); err != nil {
43+
log.Printf("%+v\n", err)
44+
}
45+
return &cfg
46+
}
47+
48+
func (c *Config) RegisterAgent(rClient *redis.Client) {
49+
err := rClient.SAdd(c.AgentsSet, c.AgentName)
50+
log.Println(err)
51+
}
52+
53+
func QueueComplited(k string, v string, rClient *redis.Client) {
54+
err := rClient.Set(k, v, 0).Err()
55+
if err != nil {
56+
log.Print(err)
57+
}
58+
}
59+
func AddToQueue(k string, v string, rClient *redis.Client) {
60+
err := rClient.Set(k, v, 0).Err()
61+
if err != nil {
62+
log.Print(err)
63+
}
64+
}
65+
66+
func CheckQueue(k string, v string, rClient *redis.Client) {
67+
val, err := rClient.Get(k).Result()
68+
if err != nil {
69+
log.Print(err)
70+
} else {
71+
if val == v {
72+
Handler()
73+
QueueComplited(k, "done", rClient)
74+
}
75+
}
76+
}

cmd/root.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
3+
4+
*/
5+
package cmd
6+
7+
import (
8+
"os"
9+
10+
"github.com/spf13/cobra"
11+
)
12+
13+
14+
15+
// rootCmd represents the base command when called without any subcommands
16+
var rootCmd = &cobra.Command{
17+
Use: "docker-fsnotify-event-handler",
18+
Short: "A brief description of your application",
19+
Long: `A longer description that spans multiple lines and likely contains
20+
examples and usage of using your application. For example:
21+
22+
Cobra is a CLI library for Go that empowers applications.
23+
This application is a tool to generate the needed files
24+
to quickly create a Cobra application.`,
25+
// Uncomment the following line if your bare application
26+
// has an action associated with it:
27+
// Run: func(cmd *cobra.Command, args []string) { },
28+
}
29+
30+
// Execute adds all child commands to the root command and sets flags appropriately.
31+
// This is called by main.main(). It only needs to happen once to the rootCmd.
32+
func Execute() {
33+
err := rootCmd.Execute()
34+
if err != nil {
35+
os.Exit(1)
36+
}
37+
}
38+
39+
func init() {
40+
// Here you will define your flags and configuration settings.
41+
// Cobra supports persistent flags, which, if defined here,
42+
// will be global for your application.
43+
44+
// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.docker-fsnotify-event-handler.yaml)")
45+
46+
// Cobra also supports local flags, which will only run
47+
// when this action is called directly.
48+
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
49+
}
50+
51+

0 commit comments

Comments
 (0)