github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/api/server/router/swarm/cluster_routes.go (about)

     1  package swarm // import "github.com/docker/docker/api/server/router/swarm"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net/http"
     7  	"strconv"
     8  
     9  	"github.com/docker/docker/api/server/httputils"
    10  	basictypes "github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/api/types/backend"
    12  	"github.com/docker/docker/api/types/filters"
    13  	"github.com/docker/docker/api/types/registry"
    14  	types "github.com/docker/docker/api/types/swarm"
    15  	"github.com/docker/docker/api/types/versions"
    16  	"github.com/docker/docker/errdefs"
    17  	"github.com/pkg/errors"
    18  	"github.com/sirupsen/logrus"
    19  )
    20  
    21  func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    22  	var req types.InitRequest
    23  	if err := httputils.ReadJSON(r, &req); err != nil {
    24  		return err
    25  	}
    26  	version := httputils.VersionFromContext(ctx)
    27  
    28  	// DefaultAddrPool and SubnetSize were added in API 1.39. Ignore on older API versions.
    29  	if versions.LessThan(version, "1.39") {
    30  		req.DefaultAddrPool = nil
    31  		req.SubnetSize = 0
    32  	}
    33  	// DataPathPort was added in API 1.40. Ignore this option on older API versions.
    34  	if versions.LessThan(version, "1.40") {
    35  		req.DataPathPort = 0
    36  	}
    37  	nodeID, err := sr.backend.Init(req)
    38  	if err != nil {
    39  		logrus.Errorf("Error initializing swarm: %v", err)
    40  		return err
    41  	}
    42  	return httputils.WriteJSON(w, http.StatusOK, nodeID)
    43  }
    44  
    45  func (sr *swarmRouter) joinCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    46  	var req types.JoinRequest
    47  	if err := httputils.ReadJSON(r, &req); err != nil {
    48  		return err
    49  	}
    50  	return sr.backend.Join(req)
    51  }
    52  
    53  func (sr *swarmRouter) leaveCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    54  	if err := httputils.ParseForm(r); err != nil {
    55  		return err
    56  	}
    57  
    58  	force := httputils.BoolValue(r, "force")
    59  	return sr.backend.Leave(ctx, force)
    60  }
    61  
    62  func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    63  	swarm, err := sr.backend.Inspect()
    64  	if err != nil {
    65  		logrus.Errorf("Error getting swarm: %v", err)
    66  		return err
    67  	}
    68  
    69  	return httputils.WriteJSON(w, http.StatusOK, swarm)
    70  }
    71  
    72  func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
    73  	var swarm types.Spec
    74  	if err := httputils.ReadJSON(r, &swarm); err != nil {
    75  		return err
    76  	}
    77  
    78  	rawVersion := r.URL.Query().Get("version")
    79  	version, err := strconv.ParseUint(rawVersion, 10, 64)
    80  	if err != nil {
    81  		err := fmt.Errorf("invalid swarm version '%s': %v", rawVersion, err)
    82  		return errdefs.InvalidParameter(err)
    83  	}
    84  
    85  	var flags types.UpdateFlags
    86  
    87  	if value := r.URL.Query().Get("rotateWorkerToken"); value != "" {
    88  		rot, err := strconv.ParseBool(value)
    89  		if err != nil {
    90  			err := fmt.Errorf("invalid value for rotateWorkerToken: %s", value)
    91  			return errdefs.InvalidParameter(err)
    92  		}
    93  
    94  		flags.RotateWorkerToken = rot
    95  	}
    96  
    97  	if value := r.URL.Query().Get("rotateManagerToken"); value != "" {
    98  		rot, err := strconv.ParseBool(value)
    99  		if err != nil {
   100  			err := fmt.Errorf("invalid value for rotateManagerToken: %s", value)
   101  			return errdefs.InvalidParameter(err)
   102  		}
   103  
   104  		flags.RotateManagerToken = rot
   105  	}
   106  
   107  	if value := r.URL.Query().Get("rotateManagerUnlockKey"); value != "" {
   108  		rot, err := strconv.ParseBool(value)
   109  		if err != nil {
   110  			return errdefs.InvalidParameter(fmt.Errorf("invalid value for rotateManagerUnlockKey: %s", value))
   111  		}
   112  
   113  		flags.RotateManagerUnlockKey = rot
   114  	}
   115  
   116  	if err := sr.backend.Update(version, swarm, flags); err != nil {
   117  		logrus.Errorf("Error configuring swarm: %v", err)
   118  		return err
   119  	}
   120  	return nil
   121  }
   122  
   123  func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   124  	var req types.UnlockRequest
   125  	if err := httputils.ReadJSON(r, &req); err != nil {
   126  		return err
   127  	}
   128  
   129  	if err := sr.backend.UnlockSwarm(req); err != nil {
   130  		logrus.Errorf("Error unlocking swarm: %v", err)
   131  		return err
   132  	}
   133  	return nil
   134  }
   135  
   136  func (sr *swarmRouter) getUnlockKey(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   137  	unlockKey, err := sr.backend.GetUnlockKey()
   138  	if err != nil {
   139  		logrus.WithError(err).Errorf("Error retrieving swarm unlock key")
   140  		return err
   141  	}
   142  
   143  	return httputils.WriteJSON(w, http.StatusOK, &basictypes.SwarmUnlockKeyResponse{
   144  		UnlockKey: unlockKey,
   145  	})
   146  }
   147  
   148  func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   149  	if err := httputils.ParseForm(r); err != nil {
   150  		return err
   151  	}
   152  	filter, err := filters.FromJSON(r.Form.Get("filters"))
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	// the status query parameter is only support in API versions >= 1.41. If
   158  	// the client is using a lesser version, ignore the parameter.
   159  	cliVersion := httputils.VersionFromContext(ctx)
   160  	var status bool
   161  	if value := r.URL.Query().Get("status"); value != "" && !versions.LessThan(cliVersion, "1.41") {
   162  		var err error
   163  		status, err = strconv.ParseBool(value)
   164  		if err != nil {
   165  			return errors.Wrapf(errdefs.InvalidParameter(err), "invalid value for status: %s", value)
   166  		}
   167  	}
   168  
   169  	services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter, Status: status})
   170  	if err != nil {
   171  		logrus.Errorf("Error getting services: %v", err)
   172  		return err
   173  	}
   174  
   175  	return httputils.WriteJSON(w, http.StatusOK, services)
   176  }
   177  
   178  func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   179  	var insertDefaults bool
   180  
   181  	if value := r.URL.Query().Get("insertDefaults"); value != "" {
   182  		var err error
   183  		insertDefaults, err = strconv.ParseBool(value)
   184  		if err != nil {
   185  			return errors.Wrapf(errdefs.InvalidParameter(err), "invalid value for insertDefaults: %s", value)
   186  		}
   187  	}
   188  
   189  	// you may note that there is no code here to handle the "status" query
   190  	// parameter, as in getServices. the Status field is not supported when
   191  	// retrieving an individual service because the Backend API changes
   192  	// required to accommodate it would be too disruptive, and because that
   193  	// field is so rarely needed as part of an individual service inspection.
   194  
   195  	service, err := sr.backend.GetService(vars["id"], insertDefaults)
   196  	if err != nil {
   197  		logrus.Errorf("Error getting service %s: %v", vars["id"], err)
   198  		return err
   199  	}
   200  
   201  	return httputils.WriteJSON(w, http.StatusOK, service)
   202  }
   203  
   204  func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   205  	var service types.ServiceSpec
   206  	if err := httputils.ReadJSON(r, &service); err != nil {
   207  		return err
   208  	}
   209  
   210  	// Get returns "" if the header does not exist
   211  	encodedAuth := r.Header.Get(registry.AuthHeader)
   212  	queryRegistry := false
   213  	if v := httputils.VersionFromContext(ctx); v != "" {
   214  		if versions.LessThan(v, "1.30") {
   215  			queryRegistry = true
   216  		}
   217  		adjustForAPIVersion(v, &service)
   218  	}
   219  	resp, err := sr.backend.CreateService(service, encodedAuth, queryRegistry)
   220  	if err != nil {
   221  		logrus.Errorf("Error creating service %s: %v", service.Name, err)
   222  		return err
   223  	}
   224  
   225  	return httputils.WriteJSON(w, http.StatusCreated, resp)
   226  }
   227  
   228  func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   229  	var service types.ServiceSpec
   230  	if err := httputils.ReadJSON(r, &service); err != nil {
   231  		return err
   232  	}
   233  
   234  	rawVersion := r.URL.Query().Get("version")
   235  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   236  	if err != nil {
   237  		err := fmt.Errorf("invalid service version '%s': %v", rawVersion, err)
   238  		return errdefs.InvalidParameter(err)
   239  	}
   240  
   241  	var flags basictypes.ServiceUpdateOptions
   242  
   243  	// Get returns "" if the header does not exist
   244  	flags.EncodedRegistryAuth = r.Header.Get(registry.AuthHeader)
   245  	flags.RegistryAuthFrom = r.URL.Query().Get("registryAuthFrom")
   246  	flags.Rollback = r.URL.Query().Get("rollback")
   247  	queryRegistry := false
   248  	if v := httputils.VersionFromContext(ctx); v != "" {
   249  		if versions.LessThan(v, "1.30") {
   250  			queryRegistry = true
   251  		}
   252  		adjustForAPIVersion(v, &service)
   253  	}
   254  
   255  	resp, err := sr.backend.UpdateService(vars["id"], version, service, flags, queryRegistry)
   256  	if err != nil {
   257  		logrus.Errorf("Error updating service %s: %v", vars["id"], err)
   258  		return err
   259  	}
   260  	return httputils.WriteJSON(w, http.StatusOK, resp)
   261  }
   262  
   263  func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   264  	if err := sr.backend.RemoveService(vars["id"]); err != nil {
   265  		logrus.Errorf("Error removing service %s: %v", vars["id"], err)
   266  		return err
   267  	}
   268  	return nil
   269  }
   270  
   271  func (sr *swarmRouter) getTaskLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   272  	if err := httputils.ParseForm(r); err != nil {
   273  		return err
   274  	}
   275  
   276  	// make a selector to pass to the helper function
   277  	selector := &backend.LogSelector{
   278  		Tasks: []string{vars["id"]},
   279  	}
   280  	return sr.swarmLogs(ctx, w, r, selector)
   281  }
   282  
   283  func (sr *swarmRouter) getServiceLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   284  	if err := httputils.ParseForm(r); err != nil {
   285  		return err
   286  	}
   287  
   288  	// make a selector to pass to the helper function
   289  	selector := &backend.LogSelector{
   290  		Services: []string{vars["id"]},
   291  	}
   292  	return sr.swarmLogs(ctx, w, r, selector)
   293  }
   294  
   295  func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   296  	if err := httputils.ParseForm(r); err != nil {
   297  		return err
   298  	}
   299  	filter, err := filters.FromJSON(r.Form.Get("filters"))
   300  	if err != nil {
   301  		return err
   302  	}
   303  
   304  	nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter})
   305  	if err != nil {
   306  		logrus.Errorf("Error getting nodes: %v", err)
   307  		return err
   308  	}
   309  
   310  	return httputils.WriteJSON(w, http.StatusOK, nodes)
   311  }
   312  
   313  func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   314  	node, err := sr.backend.GetNode(vars["id"])
   315  	if err != nil {
   316  		logrus.Errorf("Error getting node %s: %v", vars["id"], err)
   317  		return err
   318  	}
   319  
   320  	return httputils.WriteJSON(w, http.StatusOK, node)
   321  }
   322  
   323  func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   324  	var node types.NodeSpec
   325  	if err := httputils.ReadJSON(r, &node); err != nil {
   326  		return err
   327  	}
   328  
   329  	rawVersion := r.URL.Query().Get("version")
   330  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   331  	if err != nil {
   332  		err := fmt.Errorf("invalid node version '%s': %v", rawVersion, err)
   333  		return errdefs.InvalidParameter(err)
   334  	}
   335  
   336  	if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil {
   337  		logrus.Errorf("Error updating node %s: %v", vars["id"], err)
   338  		return err
   339  	}
   340  	return nil
   341  }
   342  
   343  func (sr *swarmRouter) removeNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   344  	if err := httputils.ParseForm(r); err != nil {
   345  		return err
   346  	}
   347  
   348  	force := httputils.BoolValue(r, "force")
   349  
   350  	if err := sr.backend.RemoveNode(vars["id"], force); err != nil {
   351  		logrus.Errorf("Error removing node %s: %v", vars["id"], err)
   352  		return err
   353  	}
   354  	return nil
   355  }
   356  
   357  func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   358  	if err := httputils.ParseForm(r); err != nil {
   359  		return err
   360  	}
   361  	filter, err := filters.FromJSON(r.Form.Get("filters"))
   362  	if err != nil {
   363  		return err
   364  	}
   365  
   366  	tasks, err := sr.backend.GetTasks(basictypes.TaskListOptions{Filters: filter})
   367  	if err != nil {
   368  		logrus.Errorf("Error getting tasks: %v", err)
   369  		return err
   370  	}
   371  
   372  	return httputils.WriteJSON(w, http.StatusOK, tasks)
   373  }
   374  
   375  func (sr *swarmRouter) getTask(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   376  	task, err := sr.backend.GetTask(vars["id"])
   377  	if err != nil {
   378  		logrus.Errorf("Error getting task %s: %v", vars["id"], err)
   379  		return err
   380  	}
   381  
   382  	return httputils.WriteJSON(w, http.StatusOK, task)
   383  }
   384  
   385  func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   386  	if err := httputils.ParseForm(r); err != nil {
   387  		return err
   388  	}
   389  	filters, err := filters.FromJSON(r.Form.Get("filters"))
   390  	if err != nil {
   391  		return err
   392  	}
   393  
   394  	secrets, err := sr.backend.GetSecrets(basictypes.SecretListOptions{Filters: filters})
   395  	if err != nil {
   396  		return err
   397  	}
   398  
   399  	return httputils.WriteJSON(w, http.StatusOK, secrets)
   400  }
   401  
   402  func (sr *swarmRouter) createSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   403  	var secret types.SecretSpec
   404  	if err := httputils.ReadJSON(r, &secret); err != nil {
   405  		return err
   406  	}
   407  	version := httputils.VersionFromContext(ctx)
   408  	if secret.Templating != nil && versions.LessThan(version, "1.37") {
   409  		return errdefs.InvalidParameter(errors.Errorf("secret templating is not supported on the specified API version: %s", version))
   410  	}
   411  
   412  	id, err := sr.backend.CreateSecret(secret)
   413  	if err != nil {
   414  		return err
   415  	}
   416  
   417  	return httputils.WriteJSON(w, http.StatusCreated, &basictypes.SecretCreateResponse{
   418  		ID: id,
   419  	})
   420  }
   421  
   422  func (sr *swarmRouter) removeSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   423  	if err := sr.backend.RemoveSecret(vars["id"]); err != nil {
   424  		return err
   425  	}
   426  	w.WriteHeader(http.StatusNoContent)
   427  
   428  	return nil
   429  }
   430  
   431  func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   432  	secret, err := sr.backend.GetSecret(vars["id"])
   433  	if err != nil {
   434  		return err
   435  	}
   436  
   437  	return httputils.WriteJSON(w, http.StatusOK, secret)
   438  }
   439  
   440  func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   441  	var secret types.SecretSpec
   442  	if err := httputils.ReadJSON(r, &secret); err != nil {
   443  		return err
   444  	}
   445  
   446  	rawVersion := r.URL.Query().Get("version")
   447  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   448  	if err != nil {
   449  		return errdefs.InvalidParameter(fmt.Errorf("invalid secret version"))
   450  	}
   451  
   452  	id := vars["id"]
   453  	return sr.backend.UpdateSecret(id, version, secret)
   454  }
   455  
   456  func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   457  	if err := httputils.ParseForm(r); err != nil {
   458  		return err
   459  	}
   460  	filters, err := filters.FromJSON(r.Form.Get("filters"))
   461  	if err != nil {
   462  		return err
   463  	}
   464  
   465  	configs, err := sr.backend.GetConfigs(basictypes.ConfigListOptions{Filters: filters})
   466  	if err != nil {
   467  		return err
   468  	}
   469  
   470  	return httputils.WriteJSON(w, http.StatusOK, configs)
   471  }
   472  
   473  func (sr *swarmRouter) createConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   474  	var config types.ConfigSpec
   475  	if err := httputils.ReadJSON(r, &config); err != nil {
   476  		return err
   477  	}
   478  
   479  	version := httputils.VersionFromContext(ctx)
   480  	if config.Templating != nil && versions.LessThan(version, "1.37") {
   481  		return errdefs.InvalidParameter(errors.Errorf("config templating is not supported on the specified API version: %s", version))
   482  	}
   483  
   484  	id, err := sr.backend.CreateConfig(config)
   485  	if err != nil {
   486  		return err
   487  	}
   488  
   489  	return httputils.WriteJSON(w, http.StatusCreated, &basictypes.ConfigCreateResponse{
   490  		ID: id,
   491  	})
   492  }
   493  
   494  func (sr *swarmRouter) removeConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   495  	if err := sr.backend.RemoveConfig(vars["id"]); err != nil {
   496  		return err
   497  	}
   498  	w.WriteHeader(http.StatusNoContent)
   499  
   500  	return nil
   501  }
   502  
   503  func (sr *swarmRouter) getConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   504  	config, err := sr.backend.GetConfig(vars["id"])
   505  	if err != nil {
   506  		return err
   507  	}
   508  
   509  	return httputils.WriteJSON(w, http.StatusOK, config)
   510  }
   511  
   512  func (sr *swarmRouter) updateConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   513  	var config types.ConfigSpec
   514  	if err := httputils.ReadJSON(r, &config); err != nil {
   515  		return err
   516  	}
   517  
   518  	rawVersion := r.URL.Query().Get("version")
   519  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   520  	if err != nil {
   521  		return errdefs.InvalidParameter(fmt.Errorf("invalid config version"))
   522  	}
   523  
   524  	id := vars["id"]
   525  	return sr.backend.UpdateConfig(id, version, config)
   526  }