github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/plugins/discovery.go (about) 1 package plugins // import "github.com/demonoid81/moby/pkg/plugins" 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io/ioutil" 7 "net/url" 8 "os" 9 "path/filepath" 10 "strings" 11 "sync" 12 13 "github.com/pkg/errors" 14 ) 15 16 var ( 17 // ErrNotFound plugin not found 18 ErrNotFound = errors.New("plugin not found") 19 socketsPath = "/run/docker/plugins" 20 ) 21 22 // localRegistry defines a registry that is local (using unix socket). 23 type localRegistry struct{} 24 25 func newLocalRegistry() localRegistry { 26 return localRegistry{} 27 } 28 29 // Scan scans all the plugin paths and returns all the names it found 30 func Scan() ([]string, error) { 31 var names []string 32 dirEntries, err := ioutil.ReadDir(socketsPath) 33 if err != nil && !os.IsNotExist(err) { 34 return nil, errors.Wrap(err, "error reading dir entries") 35 } 36 37 for _, fi := range dirEntries { 38 if fi.IsDir() { 39 fi, err = os.Stat(filepath.Join(socketsPath, fi.Name(), fi.Name()+".sock")) 40 if err != nil { 41 continue 42 } 43 } 44 45 if fi.Mode()&os.ModeSocket != 0 { 46 names = append(names, strings.TrimSuffix(filepath.Base(fi.Name()), filepath.Ext(fi.Name()))) 47 } 48 } 49 50 for _, p := range specsPaths { 51 dirEntries, err := ioutil.ReadDir(p) 52 if err != nil && !os.IsNotExist(err) { 53 return nil, errors.Wrap(err, "error reading dir entries") 54 } 55 56 for _, fi := range dirEntries { 57 if fi.IsDir() { 58 infos, err := ioutil.ReadDir(filepath.Join(p, fi.Name())) 59 if err != nil { 60 continue 61 } 62 63 for _, info := range infos { 64 if strings.TrimSuffix(info.Name(), filepath.Ext(info.Name())) == fi.Name() { 65 fi = info 66 break 67 } 68 } 69 } 70 71 ext := filepath.Ext(fi.Name()) 72 switch ext { 73 case ".spec", ".json": 74 plugin := strings.TrimSuffix(fi.Name(), ext) 75 names = append(names, plugin) 76 default: 77 } 78 } 79 } 80 return names, nil 81 } 82 83 // Plugin returns the plugin registered with the given name (or returns an error). 84 func (l *localRegistry) Plugin(name string) (*Plugin, error) { 85 socketpaths := pluginPaths(socketsPath, name, ".sock") 86 87 for _, p := range socketpaths { 88 if fi, err := os.Stat(p); err == nil && fi.Mode()&os.ModeSocket != 0 { 89 return NewLocalPlugin(name, "unix://"+p), nil 90 } 91 } 92 93 var txtspecpaths []string 94 for _, p := range specsPaths { 95 txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".spec")...) 96 txtspecpaths = append(txtspecpaths, pluginPaths(p, name, ".json")...) 97 } 98 99 for _, p := range txtspecpaths { 100 if _, err := os.Stat(p); err == nil { 101 if strings.HasSuffix(p, ".json") { 102 return readPluginJSONInfo(name, p) 103 } 104 return readPluginInfo(name, p) 105 } 106 } 107 return nil, errors.Wrapf(ErrNotFound, "could not find plugin %s in v1 plugin registry", name) 108 } 109 110 func readPluginInfo(name, path string) (*Plugin, error) { 111 content, err := ioutil.ReadFile(path) 112 if err != nil { 113 return nil, err 114 } 115 addr := strings.TrimSpace(string(content)) 116 117 u, err := url.Parse(addr) 118 if err != nil { 119 return nil, err 120 } 121 122 if len(u.Scheme) == 0 { 123 return nil, fmt.Errorf("Unknown protocol") 124 } 125 126 return NewLocalPlugin(name, addr), nil 127 } 128 129 func readPluginJSONInfo(name, path string) (*Plugin, error) { 130 f, err := os.Open(path) 131 if err != nil { 132 return nil, err 133 } 134 defer f.Close() 135 136 var p Plugin 137 if err := json.NewDecoder(f).Decode(&p); err != nil { 138 return nil, err 139 } 140 p.name = name 141 if p.TLSConfig != nil && len(p.TLSConfig.CAFile) == 0 { 142 p.TLSConfig.InsecureSkipVerify = true 143 } 144 p.activateWait = sync.NewCond(&sync.Mutex{}) 145 146 return &p, nil 147 } 148 149 func pluginPaths(base, name, ext string) []string { 150 return []string{ 151 filepath.Join(base, name+ext), 152 filepath.Join(base, name, name+ext), 153 } 154 }