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 }