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  }