-
Notifications
You must be signed in to change notification settings - Fork 351
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
support reloadable EnvoyGateway configuration (#4451)
* support reloadable EnvoyGateway configuration Signed-off-by: zirain <[email protected]> * lint Signed-off-by: zirain <[email protected]> * shutdown wasm http server Signed-off-by: zirain <[email protected]> --------- Signed-off-by: zirain <[email protected]>
- Loading branch information
Showing
14 changed files
with
1,010 additions
and
17 deletions.
There are no files selected for viewing
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,113 @@ | ||
// Copyright Envoy Gateway Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// The full text of the Apache license is available in the LICENSE file at | ||
// the root of the repo. | ||
|
||
package loader | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/envoyproxy/gateway/internal/envoygateway/config" | ||
"github.com/envoyproxy/gateway/internal/filewatcher" | ||
"github.com/envoyproxy/gateway/internal/logging" | ||
) | ||
|
||
type HookFunc func(c context.Context, cfg *config.Server) error | ||
|
||
type Loader struct { | ||
cfgPath string | ||
cfg *config.Server | ||
logger logging.Logger | ||
cancel context.CancelFunc | ||
hook HookFunc | ||
|
||
w filewatcher.FileWatcher | ||
} | ||
|
||
func New(cfgPath string, cfg *config.Server, f HookFunc) *Loader { | ||
return &Loader{ | ||
cfgPath: cfgPath, | ||
cfg: cfg, | ||
logger: cfg.Logger.WithName("config-loader"), | ||
hook: f, | ||
w: filewatcher.NewWatcher(), | ||
} | ||
} | ||
|
||
func (r *Loader) Start(ctx context.Context) error { | ||
r.runHook() | ||
|
||
if r.cfgPath == "" { | ||
r.logger.Info("no config file provided, skipping config watcher") | ||
return nil | ||
} | ||
|
||
r.logger.Info("watching for changes to the EnvoyGateway configuration", "path", r.cfgPath) | ||
if err := r.w.Add(r.cfgPath); err != nil { | ||
r.logger.Error(err, "failed to add config file to watcher") | ||
return err | ||
} | ||
|
||
go func() { | ||
defer func() { | ||
_ = r.w.Close() | ||
}() | ||
for { | ||
select { | ||
case e := <-r.w.Events(r.cfgPath): | ||
r.logger.Info("received fsnotify events", "name", e.Name, "op", e.Op.String()) | ||
|
||
// Load the config file. | ||
eg, err := config.Decode(r.cfgPath) | ||
if err != nil { | ||
r.logger.Info("failed to decode config file", "name", r.cfgPath, "error", err) | ||
// TODO: add a metric for this? | ||
continue | ||
} | ||
// Set defaults for unset fields | ||
eg.SetEnvoyGatewayDefaults() | ||
r.cfg.EnvoyGateway = eg | ||
// update cfg logger | ||
eg.Logging.SetEnvoyGatewayLoggingDefaults() | ||
r.cfg.Logger = logging.NewLogger(eg.Logging) | ||
|
||
// cancel last | ||
if r.cancel != nil { | ||
r.cancel() | ||
} | ||
|
||
// TODO: we need to make sure that all runners are stopped, before we start the new ones | ||
// Otherwise we might end up with error listening on:8081 | ||
time.Sleep(3 * time.Second) | ||
|
||
r.runHook() | ||
case err := <-r.w.Errors(r.cfgPath): | ||
r.logger.Error(err, "watcher error") | ||
case <-ctx.Done(): | ||
if r.cancel != nil { | ||
r.cancel() | ||
} | ||
return | ||
} | ||
} | ||
}() | ||
|
||
return nil | ||
} | ||
|
||
func (r *Loader) runHook() { | ||
if r.hook == nil { | ||
return | ||
} | ||
|
||
r.logger.Info("running hook") | ||
c, cancel := context.WithCancel(context.TODO()) | ||
r.cancel = cancel | ||
go func(ctx context.Context) { | ||
if err := r.hook(ctx, r.cfg); err != nil { | ||
r.logger.Error(err, "hook error") | ||
} | ||
}(c) | ||
} |
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,59 @@ | ||
// Copyright Envoy Gateway Authors | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// The full text of the Apache license is available in the LICENSE file at | ||
// the root of the repo. | ||
|
||
package loader | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/envoyproxy/gateway/internal/envoygateway/config" | ||
) | ||
|
||
var ( | ||
//go:embed testdata/default.yaml | ||
defaultConfig string | ||
//go:embed testdata/enable-redis.yaml | ||
redisConfig string | ||
) | ||
|
||
func TestConfigLoader(t *testing.T) { | ||
tmpDir, err := os.MkdirTemp("", "envoy-gateway-configloader-test") | ||
require.NoError(t, err) | ||
defer func(path string) { | ||
_ = os.RemoveAll(path) | ||
}(tmpDir) | ||
|
||
cfgPath := tmpDir + "/config.yaml" | ||
require.NoError(t, os.WriteFile(cfgPath, []byte(defaultConfig), 0o600)) | ||
s, err := config.New() | ||
require.NoError(t, err) | ||
|
||
ctx, cancel := context.WithCancel(context.TODO()) | ||
defer func() { | ||
cancel() | ||
}() | ||
|
||
changed := 0 | ||
loader := New(cfgPath, s, func(_ context.Context, cfg *config.Server) error { | ||
changed++ | ||
t.Logf("config changed %d times", changed) | ||
if changed > 1 { | ||
cancel() | ||
} | ||
return nil | ||
}) | ||
|
||
require.NoError(t, loader.Start(ctx)) | ||
go func() { | ||
_ = os.WriteFile(cfgPath, []byte(redisConfig), 0o600) | ||
}() | ||
|
||
<-ctx.Done() | ||
} |
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,24 @@ | ||
apiVersion: gateway.envoyproxy.io/v1alpha1 | ||
kind: EnvoyGateway | ||
gateway: | ||
controllerName: gateway.envoyproxy.io/gatewayclass-controller | ||
logging: | ||
level: | ||
default: info | ||
provider: | ||
kubernetes: | ||
rateLimitDeployment: | ||
container: | ||
image: docker.io/envoyproxy/ratelimit:master | ||
patch: | ||
type: StrategicMerge | ||
value: | ||
spec: | ||
template: | ||
spec: | ||
containers: | ||
- imagePullPolicy: IfNotPresent | ||
name: envoy-ratelimit | ||
shutdownManager: | ||
image: docker.io/envoyproxy/gateway-dev:latest | ||
type: Kubernetes |
14 changes: 14 additions & 0 deletions
14
internal/envoygateway/config/loader/testdata/enable-redis.yaml
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,14 @@ | ||
apiVersion: gateway.envoyproxy.io/v1alpha1 | ||
kind: EnvoyGateway | ||
provider: | ||
type: Kubernetes | ||
gateway: | ||
controllerName: gateway.envoyproxy.io/gatewayclass-controller | ||
extensionApis: | ||
enableEnvoyPatchPolicy: true | ||
enableBackend: true | ||
rateLimit: | ||
backend: | ||
type: Redis | ||
redis: | ||
url: redis.redis-system.svc.cluster.local:6379 |
Oops, something went wrong.