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