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