server: fsnotify on hooks
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
parent
d6c32fa88e
commit
ca94095739
4 changed files with 91 additions and 5 deletions
|
@ -485,6 +485,9 @@ func main() {
|
||||||
go func() {
|
go func() {
|
||||||
service.StartExitMonitor()
|
service.StartExitMonitor()
|
||||||
}()
|
}()
|
||||||
|
go func() {
|
||||||
|
service.StartHooksMonitor()
|
||||||
|
}()
|
||||||
|
|
||||||
m := cmux.New(lis)
|
m := cmux.New(lis)
|
||||||
grpcL := m.Match(cmux.HTTP2HeaderField("content-type", "application/grpc"))
|
grpcL := m.Match(cmux.HTTP2HeaderField("content-type", "application/grpc"))
|
||||||
|
@ -527,7 +530,7 @@ func main() {
|
||||||
<-streamServerCloseCh
|
<-streamServerCloseCh
|
||||||
logrus.Debug("closed stream server")
|
logrus.Debug("closed stream server")
|
||||||
<-serverMonitorsCh
|
<-serverMonitorsCh
|
||||||
logrus.Debug("closed exit monitor")
|
logrus.Debug("closed monitors")
|
||||||
<-serverCloseCh
|
<-serverCloseCh
|
||||||
logrus.Debug("closed main server")
|
logrus.Debug("closed main server")
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@ type ContainerServer struct {
|
||||||
podNameIndex *registrar.Registrar
|
podNameIndex *registrar.Registrar
|
||||||
podIDIndex *truncindex.TruncIndex
|
podIDIndex *truncindex.TruncIndex
|
||||||
hooks map[string]HookParams
|
hooks map[string]HookParams
|
||||||
|
hooksLock sync.Mutex
|
||||||
|
|
||||||
imageContext *types.SystemContext
|
imageContext *types.SystemContext
|
||||||
stateLock sync.Locker
|
stateLock sync.Locker
|
||||||
|
@ -53,7 +54,41 @@ func (c *ContainerServer) Runtime() *oci.Runtime {
|
||||||
|
|
||||||
// Hooks returns the oci hooks for the ContainerServer
|
// Hooks returns the oci hooks for the ContainerServer
|
||||||
func (c *ContainerServer) Hooks() map[string]HookParams {
|
func (c *ContainerServer) Hooks() map[string]HookParams {
|
||||||
return c.hooks
|
hooks := map[string]HookParams{}
|
||||||
|
c.hooksLock.Lock()
|
||||||
|
defer c.hooksLock.Unlock()
|
||||||
|
for key, h := range c.hooks {
|
||||||
|
hooks[key] = h
|
||||||
|
}
|
||||||
|
return hooks
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveHook removes an hook by name
|
||||||
|
func (c *ContainerServer) RemoveHook(hook string) {
|
||||||
|
c.hooksLock.Lock()
|
||||||
|
defer c.hooksLock.Unlock()
|
||||||
|
if _, ok := c.hooks[hook]; ok {
|
||||||
|
delete(c.hooks, hook)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddHook adds an hook by hook's path
|
||||||
|
func (c *ContainerServer) AddHook(hookPath string) {
|
||||||
|
c.hooksLock.Lock()
|
||||||
|
defer c.hooksLock.Unlock()
|
||||||
|
hook, err := readHook(hookPath)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Debugf("error while reading hook %s", hookPath)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for key, h := range c.hooks {
|
||||||
|
// hook.Hook can only be defined in one hook file, unless it has the
|
||||||
|
// same name in the override path.
|
||||||
|
if hook.Hook == h.Hook && key != filepath.Base(hookPath) {
|
||||||
|
logrus.Debugf("duplicate path, hook %q from %q already defined in %q", hook.Hook, c.config.HooksDirPath, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.hooks[filepath.Base(hookPath)] = hook
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store returns the Store for the ContainerServer
|
// Store returns the Store for the ContainerServer
|
||||||
|
@ -153,6 +188,7 @@ func New(config *Config) (*ContainerServer, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logrus.Debugf("hooks %+v", hooks)
|
||||||
|
|
||||||
return &ContainerServer{
|
return &ContainerServer{
|
||||||
runtime: runtime,
|
runtime: runtime,
|
||||||
|
|
13
lib/hooks.go
13
lib/hooks.go
|
@ -30,9 +30,16 @@ type HookParams struct {
|
||||||
Arguments []string `json:"arguments"`
|
Arguments []string `json:"arguments"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNotJSON = errors.New("hook file isn't a JSON")
|
||||||
|
)
|
||||||
|
|
||||||
// readHook reads hooks json files, verifies it and returns the json config
|
// readHook reads hooks json files, verifies it and returns the json config
|
||||||
func readHook(hookPath string) (HookParams, error) {
|
func readHook(hookPath string) (HookParams, error) {
|
||||||
var hook HookParams
|
var hook HookParams
|
||||||
|
if !strings.HasSuffix(hookPath, ".json") {
|
||||||
|
return hook, errNotJSON
|
||||||
|
}
|
||||||
raw, err := ioutil.ReadFile(hookPath)
|
raw, err := ioutil.ReadFile(hookPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hook, errors.Wrapf(err, "error Reading hook %q", hookPath)
|
return hook, errors.Wrapf(err, "error Reading hook %q", hookPath)
|
||||||
|
@ -83,11 +90,11 @@ func readHooks(hooksPath string, hooks map[string]HookParams) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if !strings.HasSuffix(file.Name(), ".json") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
hook, err := readHook(filepath.Join(hooksPath, file.Name()))
|
hook, err := readHook(filepath.Join(hooksPath, file.Name()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == errNotJSON {
|
||||||
|
continue
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for key, h := range hooks {
|
for key, h := range hooks {
|
||||||
|
|
|
@ -365,6 +365,46 @@ func (s *Server) MonitorsCloseChan() chan struct{} {
|
||||||
return s.monitorsChan
|
return s.monitorsChan
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartHooksMonitor starts a goroutine to dynamically add hooks at runtime
|
||||||
|
func (s *Server) StartHooksMonitor() {
|
||||||
|
watcher, err := fsnotify.NewWatcher()
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatalf("Failed to create new watch: %v", err)
|
||||||
|
}
|
||||||
|
defer watcher.Close()
|
||||||
|
|
||||||
|
done := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case event := <-watcher.Events:
|
||||||
|
logrus.Debugf("event: %v", event)
|
||||||
|
if event.Op&fsnotify.Remove == fsnotify.Remove {
|
||||||
|
logrus.Debugf("removing hook %s", event.Name)
|
||||||
|
s.ContainerServer.RemoveHook(filepath.Base(event.Name))
|
||||||
|
}
|
||||||
|
if event.Op&fsnotify.Create == fsnotify.Create || event.Op&fsnotify.Write == fsnotify.Write {
|
||||||
|
logrus.Debugf("adding hook %s", event.Name)
|
||||||
|
s.ContainerServer.AddHook(event.Name)
|
||||||
|
}
|
||||||
|
case err := <-watcher.Errors:
|
||||||
|
logrus.Debugf("watch error: %v", err)
|
||||||
|
close(done)
|
||||||
|
return
|
||||||
|
case <-s.monitorsChan:
|
||||||
|
logrus.Debug("closing hooks monitor...")
|
||||||
|
close(done)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
if err := watcher.Add(s.config.HooksDirPath); err != nil {
|
||||||
|
logrus.Errorf("watcher.Add(%q) failed: %s", s.config.HooksDirPath, err)
|
||||||
|
close(done)
|
||||||
|
}
|
||||||
|
<-done
|
||||||
|
}
|
||||||
|
|
||||||
// StartExitMonitor start a routine that monitors container exits
|
// StartExitMonitor start a routine that monitors container exits
|
||||||
// and updates the container status
|
// and updates the container status
|
||||||
func (s *Server) StartExitMonitor() {
|
func (s *Server) StartExitMonitor() {
|
||||||
|
|
Loading…
Reference in a new issue