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  }