github.com/kaisenlinux/docker@v0.0.0-20230510090727-ea55db55fac7/swarmkit/agent/exec/dockerapi/executor.go (about)

     1  package dockerapi
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  	"strings"
     7  	"sync"
     8  
     9  	"github.com/docker/docker/api/types/filters"
    10  	engineapi "github.com/docker/docker/client"
    11  	"github.com/docker/swarmkit/agent/exec"
    12  	"github.com/docker/swarmkit/agent/secrets"
    13  	"github.com/docker/swarmkit/api"
    14  	"github.com/docker/swarmkit/log"
    15  )
    16  
    17  type executor struct {
    18  	client           engineapi.APIClient
    19  	secrets          exec.SecretsManager
    20  	genericResources []*api.GenericResource
    21  	mutex            sync.Mutex // This mutex protects the following node field
    22  	node             *api.NodeDescription
    23  }
    24  
    25  // NewExecutor returns an executor from the docker client.
    26  func NewExecutor(client engineapi.APIClient, genericResources []*api.GenericResource) exec.Executor {
    27  	var executor = &executor{
    28  		client:           client,
    29  		secrets:          secrets.NewManager(),
    30  		genericResources: genericResources,
    31  	}
    32  	return executor
    33  }
    34  
    35  // Describe returns the underlying node description from the docker client.
    36  func (e *executor) Describe(ctx context.Context) (*api.NodeDescription, error) {
    37  	info, err := e.client.Info(ctx)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	plugins := map[api.PluginDescription]struct{}{}
    43  	addPlugins := func(typ string, names []string) {
    44  		for _, name := range names {
    45  			plugins[api.PluginDescription{
    46  				Type: typ,
    47  				Name: name,
    48  			}] = struct{}{}
    49  		}
    50  	}
    51  
    52  	// add v1 plugins to 'plugins'
    53  	addPlugins("Volume", info.Plugins.Volume)
    54  	// Add builtin driver "overlay" (the only builtin multi-host driver) to
    55  	// the plugin list by default.
    56  	addPlugins("Network", append([]string{"overlay"}, info.Plugins.Network...))
    57  	addPlugins("Authorization", info.Plugins.Authorization)
    58  
    59  	// retrieve v2 plugins
    60  	v2plugins, err := e.client.PluginList(ctx, filters.NewArgs())
    61  	if err != nil {
    62  		log.L.WithError(err).Warning("PluginList operation failed")
    63  	} else {
    64  		// add v2 plugins to 'plugins'
    65  		for _, plgn := range v2plugins {
    66  			for _, typ := range plgn.Config.Interface.Types {
    67  				if typ.Prefix == "docker" && plgn.Enabled {
    68  					plgnTyp := typ.Capability
    69  					if typ.Capability == "volumedriver" {
    70  						plgnTyp = "Volume"
    71  					} else if typ.Capability == "networkdriver" {
    72  						plgnTyp = "Network"
    73  					}
    74  					plugins[api.PluginDescription{
    75  						Type: plgnTyp,
    76  						Name: plgn.Name,
    77  					}] = struct{}{}
    78  				}
    79  			}
    80  		}
    81  	}
    82  
    83  	pluginFields := make([]api.PluginDescription, 0, len(plugins))
    84  	for k := range plugins {
    85  		pluginFields = append(pluginFields, k)
    86  	}
    87  	sort.Sort(sortedPlugins(pluginFields))
    88  
    89  	// parse []string labels into a map[string]string
    90  	labels := map[string]string{}
    91  	for _, l := range info.Labels {
    92  		stringSlice := strings.SplitN(l, "=", 2)
    93  		// this will take the last value in the list for a given key
    94  		// ideally, one shouldn't assign multiple values to the same key
    95  		if len(stringSlice) > 1 {
    96  			labels[stringSlice[0]] = stringSlice[1]
    97  		}
    98  	}
    99  
   100  	description := &api.NodeDescription{
   101  		Hostname: info.Name,
   102  		Platform: &api.Platform{
   103  			Architecture: info.Architecture,
   104  			OS:           info.OSType,
   105  		},
   106  		Engine: &api.EngineDescription{
   107  			EngineVersion: info.ServerVersion,
   108  			Labels:        labels,
   109  			Plugins:       pluginFields,
   110  		},
   111  		Resources: &api.Resources{
   112  			NanoCPUs:    int64(info.NCPU) * 1e9,
   113  			MemoryBytes: info.MemTotal,
   114  			Generic:     e.genericResources,
   115  		},
   116  	}
   117  
   118  	// Save the node information in the executor field
   119  	e.mutex.Lock()
   120  	e.node = description
   121  	e.mutex.Unlock()
   122  
   123  	return description, nil
   124  }
   125  
   126  func (e *executor) Configure(ctx context.Context, node *api.Node) error {
   127  	return nil
   128  }
   129  
   130  // Controller returns a docker container controller.
   131  func (e *executor) Controller(t *api.Task) (exec.Controller, error) {
   132  	// Get the node description from the executor field
   133  	e.mutex.Lock()
   134  	nodeDescription := e.node
   135  	e.mutex.Unlock()
   136  	ctlr, err := newController(e.client, nodeDescription, t, secrets.Restrict(e.secrets, t))
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	return ctlr, nil
   142  }
   143  
   144  func (e *executor) SetNetworkBootstrapKeys([]*api.EncryptionKey) error {
   145  	return nil
   146  }
   147  
   148  func (e *executor) Secrets() exec.SecretsManager {
   149  	return e.secrets
   150  }
   151  
   152  type sortedPlugins []api.PluginDescription
   153  
   154  func (sp sortedPlugins) Len() int { return len(sp) }
   155  
   156  func (sp sortedPlugins) Swap(i, j int) { sp[i], sp[j] = sp[j], sp[i] }
   157  
   158  func (sp sortedPlugins) Less(i, j int) bool {
   159  	if sp[i].Type != sp[j].Type {
   160  		return sp[i].Type < sp[j].Type
   161  	}
   162  	return sp[i].Name < sp[j].Name
   163  }