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