github.com/ttys3/engine@v17.12.1-ce-rc2+incompatible/pkg/plugins/discovery.go (about)

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