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 }