Skip to content

Commit 5694f2a

Browse files
author
Benjamin Huo
authored
Merge pull request #126 from bojand/poll_watcher
Add support for polling watcher
2 parents 5a4a5f6 + 3fb4118 commit 5694f2a

File tree

10 files changed

+480
-21
lines changed

10 files changed

+480
-21
lines changed

api/fluentbitoperator/v1alpha2/fluentbit_types.go

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import (
2828
type FluentBitSpec struct {
2929
// Fluent Bit image.
3030
Image string `json:"image,omitempty"`
31+
// Fluent Bit Watcher command line arguments.
32+
Args []string `json:"args,omitempty"`
3133
// Fluent Bit image pull policy.
3234
ImagePullPolicy corev1.PullPolicy `json:"imagePullPolicy,omitempty"`
3335
// Fluent Bit image pull secret

cmd/fluent-bit-watcher/Dockerfile

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,16 @@
11
FROM golang:1.13.6-alpine3.11 as buildergo
22
RUN mkdir -p /fluent-bit
3-
COPY cmd/fluent-bit-watcher/main.go go.mod /fluent-bit/
4-
WORKDIR /fluent-bit
5-
RUN CGO_ENABLED=0 go build -i -ldflags '-w -s' -o fluent-bit main.go
3+
RUN mkdir -p /code
4+
COPY . /code/
5+
WORKDIR /code
6+
RUN echo $(ls -al /code)
7+
RUN CGO_ENABLED=0 go build -i -ldflags '-w -s' -o /fluent-bit/fluent-bit /code/cmd/fluent-bit-watcher/main.go
68

7-
# FROM gcr.io/distroless/cc-debian10
89
FROM fluent/fluent-bit:1.8.3
9-
MAINTAINER KubeSphere <[email protected]>
1010
LABEL Description="Fluent Bit docker image" Vendor="KubeSphere" Version="1.0"
1111

1212
COPY conf/fluent-bit.conf conf/parsers.conf /fluent-bit/etc/
1313
COPY --from=buildergo /fluent-bit/fluent-bit /fluent-bit/bin/fluent-bit-watcher
1414

15-
#
16-
EXPOSE 2020
17-
1815
# Entry point
19-
CMD ["/fluent-bit/bin/fluent-bit-watcher", "-c", "/fluent-bit/etc/fluent-bit.conf"]
16+
ENTRYPOINT ["/fluent-bit/bin/fluent-bit-watcher"]

cmd/fluent-bit-watcher/main.go

+47-11
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"context"
5+
"flag"
56
"math"
67
"os"
78
"os/exec"
@@ -14,14 +15,17 @@ import (
1415
"github.com/go-kit/kit/log"
1516
"github.com/go-kit/kit/log/level"
1617
"github.com/oklog/run"
18+
"kubesphere.io/fluentbit-operator/pkg/filenotify"
1719
)
1820

1921
const (
20-
binPath = "/fluent-bit/bin/fluent-bit"
21-
cfgPath = "/fluent-bit/etc/fluent-bit.conf"
22-
watchDir = "/fluent-bit/config"
23-
MaxDelayTime = time.Minute * 5
24-
ResetTime = time.Minute * 10
22+
defaultBinPath = "/fluent-bit/bin/fluent-bit"
23+
defaultCfgPath = "/fluent-bit/etc/fluent-bit.conf"
24+
defaultWatchDir = "/fluent-bit/config"
25+
defaultPollInterval = 1 * time.Second
26+
27+
MaxDelayTime = 5 * time.Minute
28+
ResetTime = 10 * time.Minute
2529
)
2630

2731
var (
@@ -33,7 +37,22 @@ var (
3337
timerCancel context.CancelFunc
3438
)
3539

40+
var configPath string
41+
var binPath string
42+
var watchPath string
43+
var poll bool
44+
var pollInterval time.Duration
45+
3646
func main() {
47+
48+
flag.StringVar(&binPath, "b", defaultBinPath, "The fluent bit binary path.")
49+
flag.StringVar(&configPath, "c", defaultCfgPath, "The config file path.")
50+
flag.StringVar(&watchPath, "watch-path", defaultWatchDir, "The path to watch.")
51+
flag.BoolVar(&poll, "poll", false, "Use poll watcher instead of ionotify.")
52+
flag.DurationVar(&pollInterval, "poll-interval", defaultPollInterval, "Poll interval if using poll watcher.")
53+
54+
flag.Parse()
55+
3756
logger = log.NewLogfmtLogger(os.Stdout)
3857

3958
timerCtx, timerCancel = context.WithCancel(context.Background())
@@ -77,14 +96,14 @@ func main() {
7796
}
7897
{
7998
// Watch the config file, if the config file changed, stop Fluent bit.
80-
watcher, err := fsnotify.NewWatcher()
99+
watcher, err := newWatcher(poll, pollInterval)
81100
if err != nil {
82101
_ = level.Error(logger).Log("err", err)
83102
return
84103
}
85104

86105
// Start watcher.
87-
err = watcher.Add(watchDir)
106+
err = watcher.Add(watchPath)
88107
if err != nil {
89108
_ = level.Error(logger).Log("err", err)
90109
return
@@ -98,7 +117,7 @@ func main() {
98117
select {
99118
case <-cancel:
100119
return nil
101-
case event := <-watcher.Events:
120+
case event := <-watcher.Events():
102121
if !isValidEvent(event) {
103122
continue
104123
}
@@ -110,7 +129,7 @@ func main() {
110129
stop()
111130
resetTimer()
112131
_ = level.Info(logger).Log("msg", "Config file changed, stopped Fluent Bit")
113-
case <-watcher.Errors:
132+
case <-watcher.Errors():
114133
_ = level.Error(logger).Log("msg", "Watcher stopped")
115134
return nil
116135
}
@@ -130,9 +149,26 @@ func main() {
130149
_ = level.Info(logger).Log("msg", "See you next time!")
131150
}
132151

152+
func newWatcher(poll bool, interval time.Duration) (filenotify.FileWatcher, error) {
153+
var err error
154+
var watcher filenotify.FileWatcher
155+
156+
if poll {
157+
watcher = filenotify.NewPollingWatcher(interval)
158+
} else {
159+
watcher, err = filenotify.New(interval)
160+
}
161+
162+
if err != nil {
163+
return nil, err
164+
}
165+
166+
return watcher, nil
167+
}
168+
133169
// Inspired by https://github.com/jimmidyson/configmap-reload
134170
func isValidEvent(event fsnotify.Event) bool {
135-
return event.Op&fsnotify.Create == fsnotify.Create
171+
return event.Op == fsnotify.Create || event.Op == fsnotify.Write
136172
}
137173

138174
func start() {
@@ -144,7 +180,7 @@ func start() {
144180
return
145181
}
146182

147-
cmd = exec.Command(binPath, "-c", cfgPath)
183+
cmd = exec.Command(binPath, "-c", configPath)
148184
cmd.Stdout = os.Stdout
149185
cmd.Stderr = os.Stderr
150186
if err := cmd.Start(); err != nil {

config/crd/bases/logging.kubesphere.io_fluentbits.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,11 @@ spec:
629629
type: array
630630
type: object
631631
type: object
632+
args:
633+
description: Fluent Bit Watcher command line arguments.
634+
items:
635+
type: string
636+
type: array
632637
containerLogRealPath:
633638
description: Container log path
634639
type: string

manifests/setup/fluentbit-operator-crd.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,11 @@ spec:
933933
type: array
934934
type: object
935935
type: object
936+
args:
937+
description: Fluent Bit Watcher command line arguments.
938+
items:
939+
type: string
940+
type: array
936941
containerLogRealPath:
937942
description: Container log path
938943
type: string

manifests/setup/setup.yaml

+7-1
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,11 @@ spec:
938938
type: array
939939
type: object
940940
type: object
941+
args:
942+
description: Fluent Bit Watcher command line arguments.
943+
items:
944+
type: string
945+
type: array
941946
containerLogRealPath:
942947
description: Container log path
943948
type: string
@@ -3269,7 +3274,8 @@ spec:
32693274
- command:
32703275
- /bin/sh
32713276
- -c
3272-
- set -ex; echo CONTAINER_ROOT_DIR=$(docker info -f '{{.DockerRootDir}}') > /fluentbit-operator/fluent-bit.env
3277+
- set -ex; echo CONTAINER_ROOT_DIR=$(docker info -f '{{.DockerRootDir}}')
3278+
> /fluentbit-operator/fluent-bit.env
32733279
image: docker:19.03
32743280
name: setenv
32753281
volumeMounts:

pkg/filenotify/filenotify.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Adapted from https://github.com/gohugoio/hugo
2+
// Apache License 2.0
3+
// Copyright Hugo Authors
4+
//
5+
// Package filenotify provides a mechanism for watching file(s) for changes.
6+
// Generally leans on fsnotify, but provides a poll-based notifier which fsnotify does not support.
7+
// These are wrapped up in a common interface so that either can be used interchangeably in your code.
8+
//
9+
// This package is adapted from https://github.com/moby/moby/tree/master/pkg/filenotify, Apache-2.0 License.
10+
// Hopefully this can be replaced with an external package sometime in the future, see https://github.com/fsnotify/fsnotify/issues/9
11+
package filenotify
12+
13+
import (
14+
"time"
15+
16+
"github.com/fsnotify/fsnotify"
17+
)
18+
19+
// FileWatcher is an interface for implementing file notification watchers
20+
type FileWatcher interface {
21+
Events() <-chan fsnotify.Event
22+
Errors() <-chan error
23+
Add(name string) error
24+
Remove(name string) error
25+
Close() error
26+
}
27+
28+
// New tries to use an fs-event watcher, and falls back to the poller if there is an error
29+
func New(interval time.Duration) (FileWatcher, error) {
30+
if watcher, err := NewEventWatcher(); err == nil {
31+
return watcher, nil
32+
}
33+
return NewPollingWatcher(interval), nil
34+
}
35+
36+
// NewPollingWatcher returns a poll-based file watcher
37+
func NewPollingWatcher(interval time.Duration) FileWatcher {
38+
return &filePoller{
39+
interval: interval,
40+
done: make(chan struct{}),
41+
events: make(chan fsnotify.Event),
42+
errors: make(chan error),
43+
}
44+
}
45+
46+
// NewEventWatcher returns an fs-event based file watcher
47+
func NewEventWatcher() (FileWatcher, error) {
48+
watcher, err := fsnotify.NewWatcher()
49+
if err != nil {
50+
return nil, err
51+
}
52+
return &fsNotifyWatcher{watcher}, nil
53+
}

pkg/filenotify/fsnotify.go

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Adapted from https://github.com/gohugoio/hugo
2+
// Apache License 2.0
3+
// Copyright Hugo Authors
4+
//
5+
// Package filenotify is adapted from https://github.com/moby/moby/tree/master/pkg/filenotify, Apache-2.0 License.
6+
// Hopefully this can be replaced with an external package sometime in the future, see https://github.com/fsnotify/fsnotify/issues/9
7+
package filenotify
8+
9+
import "github.com/fsnotify/fsnotify"
10+
11+
// fsNotifyWatcher wraps the fsnotify package to satisfy the FileNotifier interface
12+
type fsNotifyWatcher struct {
13+
*fsnotify.Watcher
14+
}
15+
16+
// Events returns the fsnotify event channel receiver
17+
func (w *fsNotifyWatcher) Events() <-chan fsnotify.Event {
18+
return w.Watcher.Events
19+
}
20+
21+
// Errors returns the fsnotify error channel receiver
22+
func (w *fsNotifyWatcher) Errors() <-chan error {
23+
return w.Watcher.Errors
24+
}

0 commit comments

Comments
 (0)