github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/moby/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 // the status query parameter is only support in API versions >= 1.41. If 171 // the client is using a lesser version, ignore the parameter. 172 cliVersion := httputils.VersionFromContext(ctx) 173 var status bool 174 if value := r.URL.Query().Get("status"); value != "" && !versions.LessThan(cliVersion, "1.41") { 175 var err error 176 status, err = strconv.ParseBool(value) 177 if err != nil { 178 return errors.Wrapf(errdefs.InvalidParameter(err), "invalid value for status: %s", value) 179 } 180 } 181 182 services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter, Status: status}) 183 if err != nil { 184 logrus.Errorf("Error getting services: %v", err) 185 return err 186 } 187 188 return httputils.WriteJSON(w, http.StatusOK, services) 189 } 190 191 func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 192 var insertDefaults bool 193 194 if value := r.URL.Query().Get("insertDefaults"); value != "" { 195 var err error 196 insertDefaults, err = strconv.ParseBool(value) 197 if err != nil { 198 return errors.Wrapf(errdefs.InvalidParameter(err), "invalid value for insertDefaults: %s", value) 199 } 200 } 201 202 // you may note that there is no code here to handle the "status" query 203 // parameter, as in getServices. the Status field is not supported when 204 // retrieving an individual service because the Backend API changes 205 // required to accommodate it would be too disruptive, and because that 206 // field is so rarely needed as part of an individual service inspection. 207 208 service, err := sr.backend.GetService(vars["id"], insertDefaults) 209 if err != nil { 210 logrus.Errorf("Error getting service %s: %v", vars["id"], err) 211 return err 212 } 213 214 return httputils.WriteJSON(w, http.StatusOK, service) 215 } 216 217 func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 218 var service types.ServiceSpec 219 if err := json.NewDecoder(r.Body).Decode(&service); err != nil { 220 if err == io.EOF { 221 return errdefs.InvalidParameter(errors.New("got EOF while reading request body")) 222 } 223 return errdefs.InvalidParameter(err) 224 } 225 226 // Get returns "" if the header does not exist 227 encodedAuth := r.Header.Get("X-Registry-Auth") 228 queryRegistry := false 229 if v := httputils.VersionFromContext(ctx); v != "" { 230 if versions.LessThan(v, "1.30") { 231 queryRegistry = true 232 } 233 adjustForAPIVersion(v, &service) 234 } 235 resp, err := sr.backend.CreateService(service, encodedAuth, queryRegistry) 236 if err != nil { 237 logrus.Errorf("Error creating service %s: %v", service.Name, err) 238 return err 239 } 240 241 return httputils.WriteJSON(w, http.StatusCreated, resp) 242 } 243 244 func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 245 var service types.ServiceSpec 246 if err := json.NewDecoder(r.Body).Decode(&service); err != nil { 247 if err == io.EOF { 248 return errdefs.InvalidParameter(errors.New("got EOF while reading request body")) 249 } 250 return errdefs.InvalidParameter(err) 251 } 252 253 rawVersion := r.URL.Query().Get("version") 254 version, err := strconv.ParseUint(rawVersion, 10, 64) 255 if err != nil { 256 err := fmt.Errorf("invalid service version '%s': %v", rawVersion, err) 257 return errdefs.InvalidParameter(err) 258 } 259 260 var flags basictypes.ServiceUpdateOptions 261 262 // Get returns "" if the header does not exist 263 flags.EncodedRegistryAuth = r.Header.Get("X-Registry-Auth") 264 flags.RegistryAuthFrom = r.URL.Query().Get("registryAuthFrom") 265 flags.Rollback = r.URL.Query().Get("rollback") 266 queryRegistry := false 267 if v := httputils.VersionFromContext(ctx); v != "" { 268 if versions.LessThan(v, "1.30") { 269 queryRegistry = true 270 } 271 adjustForAPIVersion(v, &service) 272 } 273 274 resp, err := sr.backend.UpdateService(vars["id"], version, service, flags, queryRegistry) 275 if err != nil { 276 logrus.Errorf("Error updating service %s: %v", vars["id"], err) 277 return err 278 } 279 return httputils.WriteJSON(w, http.StatusOK, resp) 280 } 281 282 func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 283 if err := sr.backend.RemoveService(vars["id"]); err != nil { 284 logrus.Errorf("Error removing service %s: %v", vars["id"], err) 285 return err 286 } 287 return nil 288 } 289 290 func (sr *swarmRouter) getTaskLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 291 if err := httputils.ParseForm(r); err != nil { 292 return err 293 } 294 295 // make a selector to pass to the helper function 296 selector := &backend.LogSelector{ 297 Tasks: []string{vars["id"]}, 298 } 299 return sr.swarmLogs(ctx, w, r, selector) 300 } 301 302 func (sr *swarmRouter) getServiceLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 303 if err := httputils.ParseForm(r); err != nil { 304 return err 305 } 306 307 // make a selector to pass to the helper function 308 selector := &backend.LogSelector{ 309 Services: []string{vars["id"]}, 310 } 311 return sr.swarmLogs(ctx, w, r, selector) 312 } 313 314 func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 315 if err := httputils.ParseForm(r); err != nil { 316 return err 317 } 318 filter, err := filters.FromJSON(r.Form.Get("filters")) 319 if err != nil { 320 return err 321 } 322 323 nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter}) 324 if err != nil { 325 logrus.Errorf("Error getting nodes: %v", err) 326 return err 327 } 328 329 return httputils.WriteJSON(w, http.StatusOK, nodes) 330 } 331 332 func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 333 node, err := sr.backend.GetNode(vars["id"]) 334 if err != nil { 335 logrus.Errorf("Error getting node %s: %v", vars["id"], err) 336 return err 337 } 338 339 return httputils.WriteJSON(w, http.StatusOK, node) 340 } 341 342 func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 343 var node types.NodeSpec 344 if err := json.NewDecoder(r.Body).Decode(&node); err != nil { 345 if err == io.EOF { 346 return errdefs.InvalidParameter(errors.New("got EOF while reading request body")) 347 } 348 return errdefs.InvalidParameter(err) 349 } 350 351 rawVersion := r.URL.Query().Get("version") 352 version, err := strconv.ParseUint(rawVersion, 10, 64) 353 if err != nil { 354 err := fmt.Errorf("invalid node version '%s': %v", rawVersion, err) 355 return errdefs.InvalidParameter(err) 356 } 357 358 if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil { 359 logrus.Errorf("Error updating node %s: %v", vars["id"], err) 360 return err 361 } 362 return nil 363 } 364 365 func (sr *swarmRouter) removeNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 366 if err := httputils.ParseForm(r); err != nil { 367 return err 368 } 369 370 force := httputils.BoolValue(r, "force") 371 372 if err := sr.backend.RemoveNode(vars["id"], force); err != nil { 373 logrus.Errorf("Error removing node %s: %v", vars["id"], err) 374 return err 375 } 376 return nil 377 } 378 379 func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 380 if err := httputils.ParseForm(r); err != nil { 381 return err 382 } 383 filter, err := filters.FromJSON(r.Form.Get("filters")) 384 if err != nil { 385 return err 386 } 387 388 tasks, err := sr.backend.GetTasks(basictypes.TaskListOptions{Filters: filter}) 389 if err != nil { 390 logrus.Errorf("Error getting tasks: %v", err) 391 return err 392 } 393 394 return httputils.WriteJSON(w, http.StatusOK, tasks) 395 } 396 397 func (sr *swarmRouter) getTask(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 398 task, err := sr.backend.GetTask(vars["id"]) 399 if err != nil { 400 logrus.Errorf("Error getting task %s: %v", vars["id"], err) 401 return err 402 } 403 404 return httputils.WriteJSON(w, http.StatusOK, task) 405 } 406 407 func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 408 if err := httputils.ParseForm(r); err != nil { 409 return err 410 } 411 filters, err := filters.FromJSON(r.Form.Get("filters")) 412 if err != nil { 413 return err 414 } 415 416 secrets, err := sr.backend.GetSecrets(basictypes.SecretListOptions{Filters: filters}) 417 if err != nil { 418 return err 419 } 420 421 return httputils.WriteJSON(w, http.StatusOK, secrets) 422 } 423 424 func (sr *swarmRouter) createSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 425 var secret types.SecretSpec 426 if err := json.NewDecoder(r.Body).Decode(&secret); err != nil { 427 if err == io.EOF { 428 return errdefs.InvalidParameter(errors.New("got EOF while reading request body")) 429 } 430 return errdefs.InvalidParameter(err) 431 } 432 version := httputils.VersionFromContext(ctx) 433 if secret.Templating != nil && versions.LessThan(version, "1.37") { 434 return errdefs.InvalidParameter(errors.Errorf("secret templating is not supported on the specified API version: %s", version)) 435 } 436 437 id, err := sr.backend.CreateSecret(secret) 438 if err != nil { 439 return err 440 } 441 442 return httputils.WriteJSON(w, http.StatusCreated, &basictypes.SecretCreateResponse{ 443 ID: id, 444 }) 445 } 446 447 func (sr *swarmRouter) removeSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 448 if err := sr.backend.RemoveSecret(vars["id"]); err != nil { 449 return err 450 } 451 w.WriteHeader(http.StatusNoContent) 452 453 return nil 454 } 455 456 func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 457 secret, err := sr.backend.GetSecret(vars["id"]) 458 if err != nil { 459 return err 460 } 461 462 return httputils.WriteJSON(w, http.StatusOK, secret) 463 } 464 465 func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 466 var secret types.SecretSpec 467 if err := json.NewDecoder(r.Body).Decode(&secret); err != nil { 468 if err == io.EOF { 469 return errdefs.InvalidParameter(errors.New("got EOF while reading request body")) 470 } 471 return errdefs.InvalidParameter(err) 472 } 473 474 rawVersion := r.URL.Query().Get("version") 475 version, err := strconv.ParseUint(rawVersion, 10, 64) 476 if err != nil { 477 return errdefs.InvalidParameter(fmt.Errorf("invalid secret version")) 478 } 479 480 id := vars["id"] 481 return sr.backend.UpdateSecret(id, version, secret) 482 } 483 484 func (sr *swarmRouter) getConfigs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 485 if err := httputils.ParseForm(r); err != nil { 486 return err 487 } 488 filters, err := filters.FromJSON(r.Form.Get("filters")) 489 if err != nil { 490 return err 491 } 492 493 configs, err := sr.backend.GetConfigs(basictypes.ConfigListOptions{Filters: filters}) 494 if err != nil { 495 return err 496 } 497 498 return httputils.WriteJSON(w, http.StatusOK, configs) 499 } 500 501 func (sr *swarmRouter) createConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 502 var config types.ConfigSpec 503 if err := json.NewDecoder(r.Body).Decode(&config); err != nil { 504 if err == io.EOF { 505 return errdefs.InvalidParameter(errors.New("got EOF while reading request body")) 506 } 507 return errdefs.InvalidParameter(err) 508 } 509 510 version := httputils.VersionFromContext(ctx) 511 if config.Templating != nil && versions.LessThan(version, "1.37") { 512 return errdefs.InvalidParameter(errors.Errorf("config templating is not supported on the specified API version: %s", version)) 513 } 514 515 id, err := sr.backend.CreateConfig(config) 516 if err != nil { 517 return err 518 } 519 520 return httputils.WriteJSON(w, http.StatusCreated, &basictypes.ConfigCreateResponse{ 521 ID: id, 522 }) 523 } 524 525 func (sr *swarmRouter) removeConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 526 if err := sr.backend.RemoveConfig(vars["id"]); err != nil { 527 return err 528 } 529 w.WriteHeader(http.StatusNoContent) 530 531 return nil 532 } 533 534 func (sr *swarmRouter) getConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 535 config, err := sr.backend.GetConfig(vars["id"]) 536 if err != nil { 537 return err 538 } 539 540 return httputils.WriteJSON(w, http.StatusOK, config) 541 } 542 543 func (sr *swarmRouter) updateConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 544 var config types.ConfigSpec 545 if err := json.NewDecoder(r.Body).Decode(&config); err != nil { 546 if err == io.EOF { 547 return errdefs.InvalidParameter(errors.New("got EOF while reading request body")) 548 } 549 return errdefs.InvalidParameter(err) 550 } 551 552 rawVersion := r.URL.Query().Get("version") 553 version, err := strconv.ParseUint(rawVersion, 10, 64) 554 if err != nil { 555 return errdefs.InvalidParameter(fmt.Errorf("invalid config version")) 556 } 557 558 id := vars["id"] 559 return sr.backend.UpdateConfig(id, version, config) 560 }