github.com/endophage/docker@v1.4.2-0.20161027011718-242853499895/plugin/manager.go (about) 1 package plugin 2 3 import ( 4 "encoding/json" 5 "io" 6 "os" 7 "path/filepath" 8 "sync" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/docker/libcontainerd" 12 "github.com/docker/docker/plugin/store" 13 "github.com/docker/docker/plugin/v2" 14 "github.com/docker/docker/registry" 15 ) 16 17 var ( 18 manager *Manager 19 ) 20 21 func (pm *Manager) restorePlugin(p *v2.Plugin) error { 22 p.RuntimeSourcePath = filepath.Join(pm.runRoot, p.GetID()) 23 if p.IsEnabled() { 24 return pm.restore(p) 25 } 26 return nil 27 } 28 29 type eventLogger func(id, name, action string) 30 31 // Manager controls the plugin subsystem. 32 type Manager struct { 33 libRoot string 34 runRoot string 35 pluginStore *store.Store 36 containerdClient libcontainerd.Client 37 registryService registry.Service 38 liveRestore bool 39 pluginEventLogger eventLogger 40 } 41 42 // GetManager returns the singleton plugin Manager 43 func GetManager() *Manager { 44 return manager 45 } 46 47 // Init (was NewManager) instantiates the singleton Manager. 48 // TODO: revert this to NewManager once we get rid of all the singletons. 49 func Init(root string, ps *store.Store, remote libcontainerd.Remote, rs registry.Service, liveRestore bool, evL eventLogger) (err error) { 50 if manager != nil { 51 return nil 52 } 53 54 root = filepath.Join(root, "plugins") 55 manager = &Manager{ 56 libRoot: root, 57 runRoot: "/run/docker", 58 pluginStore: ps, 59 registryService: rs, 60 liveRestore: liveRestore, 61 pluginEventLogger: evL, 62 } 63 if err := os.MkdirAll(manager.runRoot, 0700); err != nil { 64 return err 65 } 66 manager.containerdClient, err = remote.Client(manager) 67 if err != nil { 68 return err 69 } 70 if err := manager.init(); err != nil { 71 return err 72 } 73 return nil 74 } 75 76 // StateChanged updates plugin internals using libcontainerd events. 77 func (pm *Manager) StateChanged(id string, e libcontainerd.StateInfo) error { 78 logrus.Debugf("plugin state changed %s %#v", id, e) 79 80 switch e.State { 81 case libcontainerd.StateExit: 82 p, err := pm.pluginStore.GetByID(id) 83 if err != nil { 84 return err 85 } 86 p.RLock() 87 if p.ExitChan != nil { 88 close(p.ExitChan) 89 } 90 restart := p.Restart 91 p.RUnlock() 92 p.RemoveFromDisk() 93 if restart { 94 pm.enable(p, true) 95 } 96 } 97 98 return nil 99 } 100 101 func (pm *Manager) init() error { 102 dt, err := os.Open(filepath.Join(pm.libRoot, "plugins.json")) 103 if err != nil { 104 if os.IsNotExist(err) { 105 return nil 106 } 107 return err 108 } 109 defer dt.Close() 110 111 plugins := make(map[string]*v2.Plugin) 112 if err := json.NewDecoder(dt).Decode(&plugins); err != nil { 113 return err 114 } 115 pm.pluginStore.SetAll(plugins) 116 117 var group sync.WaitGroup 118 group.Add(len(plugins)) 119 for _, p := range plugins { 120 go func(p *v2.Plugin) { 121 defer group.Done() 122 if err := pm.restorePlugin(p); err != nil { 123 logrus.Errorf("failed to restore plugin '%s': %s", p.Name(), err) 124 return 125 } 126 127 pm.pluginStore.Add(p) 128 requiresManualRestore := !pm.liveRestore && p.IsEnabled() 129 130 if requiresManualRestore { 131 // if liveRestore is not enabled, the plugin will be stopped now so we should enable it 132 if err := pm.enable(p, true); err != nil { 133 logrus.Errorf("failed to enable plugin '%s': %s", p.Name(), err) 134 } 135 } 136 }(p) 137 } 138 group.Wait() 139 return nil 140 } 141 142 type logHook struct{ id string } 143 144 func (logHook) Levels() []logrus.Level { 145 return logrus.AllLevels 146 } 147 148 func (l logHook) Fire(entry *logrus.Entry) error { 149 entry.Data = logrus.Fields{"plugin": l.id} 150 return nil 151 } 152 153 func attachToLog(id string) func(libcontainerd.IOPipe) error { 154 return func(iop libcontainerd.IOPipe) error { 155 iop.Stdin.Close() 156 157 logger := logrus.New() 158 logger.Hooks.Add(logHook{id}) 159 // TODO: cache writer per id 160 w := logger.Writer() 161 go func() { 162 io.Copy(w, iop.Stdout) 163 }() 164 go func() { 165 // TODO: update logrus and use logger.WriterLevel 166 io.Copy(w, iop.Stderr) 167 }() 168 return nil 169 } 170 }