github.com/rawahars/moby@v24.0.4+incompatible/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.WithContext(ctx).WithError(err).Debug("Error initializing swarm")
    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.WithContext(ctx).WithError(err).Debug("Error getting swarm")
    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.WithContext(ctx).WithError(err).Debug("Error configuring swarm")
   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.WithContext(ctx).WithError(err).Debug("Error unlocking swarm")
   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.WithContext(ctx).WithError(err).Debug("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.WithContext(ctx).WithError(err).Debug("Error getting services")
   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.WithContext(ctx).WithFields(logrus.Fields{
   198  			"error":      err,
   199  			"service-id": vars["id"],
   200  		}).Debug("Error getting service")
   201  		return err
   202  	}
   203  
   204  	return httputils.WriteJSON(w, http.StatusOK, service)
   205  }
   206  
   207  func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   208  	var service types.ServiceSpec
   209  	if err := httputils.ReadJSON(r, &service); err != nil {
   210  		return err
   211  	}
   212  
   213  	// Get returns "" if the header does not exist
   214  	encodedAuth := r.Header.Get(registry.AuthHeader)
   215  	queryRegistry := false
   216  	if v := httputils.VersionFromContext(ctx); v != "" {
   217  		if versions.LessThan(v, "1.30") {
   218  			queryRegistry = true
   219  		}
   220  		adjustForAPIVersion(v, &service)
   221  	}
   222  	resp, err := sr.backend.CreateService(service, encodedAuth, queryRegistry)
   223  	if err != nil {
   224  		logrus.WithContext(ctx).WithFields(logrus.Fields{
   225  			"error":        err,
   226  			"service-name": service.Name,
   227  		}).Debug("Error creating service")
   228  		return err
   229  	}
   230  
   231  	return httputils.WriteJSON(w, http.StatusCreated, resp)
   232  }
   233  
   234  func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   235  	var service types.ServiceSpec
   236  	if err := httputils.ReadJSON(r, &service); err != nil {
   237  		return err
   238  	}
   239  
   240  	rawVersion := r.URL.Query().Get("version")
   241  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   242  	if err != nil {
   243  		err := fmt.Errorf("invalid service version '%s': %v", rawVersion, err)
   244  		return errdefs.InvalidParameter(err)
   245  	}
   246  
   247  	var flags basictypes.ServiceUpdateOptions
   248  
   249  	// Get returns "" if the header does not exist
   250  	flags.EncodedRegistryAuth = r.Header.Get(registry.AuthHeader)
   251  	flags.RegistryAuthFrom = r.URL.Query().Get("registryAuthFrom")
   252  	flags.Rollback = r.URL.Query().Get("rollback")
   253  	queryRegistry := false
   254  	if v := httputils.VersionFromContext(ctx); v != "" {
   255  		if versions.LessThan(v, "1.30") {
   256  			queryRegistry = true
   257  		}
   258  		adjustForAPIVersion(v, &service)
   259  	}
   260  
   261  	resp, err := sr.backend.UpdateService(vars["id"], version, service, flags, queryRegistry)
   262  	if err != nil {
   263  		logrus.WithContext(ctx).WithFields(logrus.Fields{
   264  			"error":      err,
   265  			"service-id": vars["id"],
   266  		}).Debug("Error updating service")
   267  		return err
   268  	}
   269  	return httputils.WriteJSON(w, http.StatusOK, resp)
   270  }
   271  
   272  func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   273  	if err := sr.backend.RemoveService(vars["id"]); err != nil {
   274  		logrus.WithContext(ctx).WithFields(logrus.Fields{
   275  			"error":      err,
   276  			"service-id": vars["id"],
   277  		}).Debug("Error removing service")
   278  		return err
   279  	}
   280  	return nil
   281  }
   282  
   283  func (sr *swarmRouter) getTaskLogs(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  		Tasks: []string{vars["id"]},
   291  	}
   292  	return sr.swarmLogs(ctx, w, r, selector)
   293  }
   294  
   295  func (sr *swarmRouter) getServiceLogs(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  
   300  	// make a selector to pass to the helper function
   301  	selector := &backend.LogSelector{
   302  		Services: []string{vars["id"]},
   303  	}
   304  	return sr.swarmLogs(ctx, w, r, selector)
   305  }
   306  
   307  func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   308  	if err := httputils.ParseForm(r); err != nil {
   309  		return err
   310  	}
   311  	filter, err := filters.FromJSON(r.Form.Get("filters"))
   312  	if err != nil {
   313  		return err
   314  	}
   315  
   316  	nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter})
   317  	if err != nil {
   318  		logrus.WithContext(ctx).WithError(err).Debug("Error getting nodes")
   319  		return err
   320  	}
   321  
   322  	return httputils.WriteJSON(w, http.StatusOK, nodes)
   323  }
   324  
   325  func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   326  	node, err := sr.backend.GetNode(vars["id"])
   327  	if err != nil {
   328  		logrus.WithContext(ctx).WithFields(logrus.Fields{
   329  			"error":   err,
   330  			"node-id": vars["id"],
   331  		}).Debug("Error getting node")
   332  		return err
   333  	}
   334  
   335  	return httputils.WriteJSON(w, http.StatusOK, node)
   336  }
   337  
   338  func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   339  	var node types.NodeSpec
   340  	if err := httputils.ReadJSON(r, &node); err != nil {
   341  		return err
   342  	}
   343  
   344  	rawVersion := r.URL.Query().Get("version")
   345  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   346  	if err != nil {
   347  		err := fmt.Errorf("invalid node version '%s': %v", rawVersion, err)
   348  		return errdefs.InvalidParameter(err)
   349  	}
   350  
   351  	if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil {
   352  		logrus.WithContext(ctx).WithFields(logrus.Fields{
   353  			"error":   err,
   354  			"node-id": vars["id"],
   355  		}).Debug("Error updating node")
   356  		return err
   357  	}
   358  	return nil
   359  }
   360  
   361  func (sr *swarmRouter) removeNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   362  	if err := httputils.ParseForm(r); err != nil {
   363  		return err
   364  	}
   365  
   366  	force := httputils.BoolValue(r, "force")
   367  
   368  	if err := sr.backend.RemoveNode(vars["id"], force); err != nil {
   369  		logrus.WithContext(ctx).WithFields(logrus.Fields{
   370  			"error":   err,
   371  			"node-id": vars["id"],
   372  		}).Debug("Error removing node")
   373  		return err
   374  	}
   375  	return nil
   376  }
   377  
   378  func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   379  	if err := httputils.ParseForm(r); err != nil {
   380  		return err
   381  	}
   382  	filter, err := filters.FromJSON(r.Form.Get("filters"))
   383  	if err != nil {
   384  		return err
   385  	}
   386  
   387  	tasks, err := sr.backend.GetTasks(basictypes.TaskListOptions{Filters: filter})
   388  	if err != nil {
   389  		logrus.WithContext(ctx).WithError(err).Debug("Error getting tasks")
   390  		return err
   391  	}
   392  
   393  	return httputils.WriteJSON(w, http.StatusOK, tasks)
   394  }
   395  
   396  func (sr *swarmRouter) getTask(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   397  	task, err := sr.backend.GetTask(vars["id"])
   398  	if err != nil {
   399  		logrus.WithContext(ctx).WithFields(logrus.Fields{
   400  			"error":   err,
   401  			"task-id": vars["id"],
   402  		}).Debug("Error getting task")
   403  		return err
   404  	}
   405  
   406  	return httputils.WriteJSON(w, http.StatusOK, task)
   407  }
   408  
   409  func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   410  	if err := httputils.ParseForm(r); err != nil {
   411  		return err
   412  	}
   413  	filters, err := filters.FromJSON(r.Form.Get("filters"))
   414  	if err != nil {
   415  		return err
   416  	}
   417  
   418  	secrets, err := sr.backend.GetSecrets(basictypes.SecretListOptions{Filters: filters})
   419  	if err != nil {
   420  		return err
   421  	}
   422  
   423  	return httputils.WriteJSON(w, http.StatusOK, secrets)
   424  }
   425  
   426  func (sr *swarmRouter) createSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   427  	var secret types.SecretSpec
   428  	if err := httputils.ReadJSON(r, &secret); err != nil {
   429  		return err
   430  	}
   431  	version := httputils.VersionFromContext(ctx)
   432  	if secret.Templating != nil && versions.LessThan(version, "1.37") {
   433  		return errdefs.InvalidParameter(errors.Errorf("secret templating is not supported on the specified API version: %s", version))
   434  	}
   435  
   436  	id, err := sr.backend.CreateSecret(secret)
   437  	if err != nil {
   438  		return err
   439  	}
   440  
   441  	return httputils.WriteJSON(w, http.StatusCreated, &basictypes.SecretCreateResponse{
   442  		ID: id,
   443  	})
   444  }
   445  
   446  func (sr *swarmRouter) removeSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   447  	if err := sr.backend.RemoveSecret(vars["id"]); err != nil {
   448  		return err
   449  	}
   450  	w.WriteHeader(http.StatusNoContent)
   451  
   452  	return nil
   453  }
   454  
   455  func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   456  	secret, err := sr.backend.GetSecret(vars["id"])
   457  	if err != nil {
   458  		return err
   459  	}
   460  
   461  	return httputils.WriteJSON(w, http.StatusOK, secret)
   462  }
   463  
   464  func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   465  	var secret types.SecretSpec
   466  	if err := httputils.ReadJSON(r, &secret); err != nil {
   467  		return err
   468  	}
   469  
   470  	rawVersion := r.URL.Query().Get("version")
   471  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   472  	if err != nil {
   473  		return errdefs.InvalidParameter(fmt.Errorf("invalid secret version"))
   474  	}
   475  
   476  	id := vars["id"]
   477  	return sr.backend.UpdateSecret(id, version, secret)
   478  }
   479  
   480  func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   481  	if err := httputils.ParseForm(r); err != nil {
   482  		return err
   483  	}
   484  	filters, err := filters.FromJSON(r.Form.Get("filters"))
   485  	if err != nil {
   486  		return err
   487  	}
   488  
   489  	configs, err := sr.backend.GetConfigs(basictypes.ConfigListOptions{Filters: filters})
   490  	if err != nil {
   491  		return err
   492  	}
   493  
   494  	return httputils.WriteJSON(w, http.StatusOK, configs)
   495  }
   496  
   497  func (sr *swarmRouter) createConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   498  	var config types.ConfigSpec
   499  	if err := httputils.ReadJSON(r, &config); err != nil {
   500  		return err
   501  	}
   502  
   503  	version := httputils.VersionFromContext(ctx)
   504  	if config.Templating != nil && versions.LessThan(version, "1.37") {
   505  		return errdefs.InvalidParameter(errors.Errorf("config templating is not supported on the specified API version: %s", version))
   506  	}
   507  
   508  	id, err := sr.backend.CreateConfig(config)
   509  	if err != nil {
   510  		return err
   511  	}
   512  
   513  	return httputils.WriteJSON(w, http.StatusCreated, &basictypes.ConfigCreateResponse{
   514  		ID: id,
   515  	})
   516  }
   517  
   518  func (sr *swarmRouter) removeConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   519  	if err := sr.backend.RemoveConfig(vars["id"]); err != nil {
   520  		return err
   521  	}
   522  	w.WriteHeader(http.StatusNoContent)
   523  
   524  	return nil
   525  }
   526  
   527  func (sr *swarmRouter) getConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   528  	config, err := sr.backend.GetConfig(vars["id"])
   529  	if err != nil {
   530  		return err
   531  	}
   532  
   533  	return httputils.WriteJSON(w, http.StatusOK, config)
   534  }
   535  
   536  func (sr *swarmRouter) updateConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
   537  	var config types.ConfigSpec
   538  	if err := httputils.ReadJSON(r, &config); err != nil {
   539  		return err
   540  	}
   541  
   542  	rawVersion := r.URL.Query().Get("version")
   543  	version, err := strconv.ParseUint(rawVersion, 10, 64)
   544  	if err != nil {
   545  		return errdefs.InvalidParameter(fmt.Errorf("invalid config version"))
   546  	}
   547  
   548  	id := vars["id"]
   549  	return sr.backend.UpdateConfig(id, version, config)
   550  }