github.com/sld880311/docker@v0.0.0-20200524143708-d5593973a475/api/server/router/swarm/cluster_routes.go (about) 1 package swarm 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 "strconv" 8 9 "github.com/Sirupsen/logrus" 10 "github.com/docker/docker/api/errors" 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 "golang.org/x/net/context" 17 ) 18 19 func (sr *swarmRouter) initCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 20 var req types.InitRequest 21 if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 22 return err 23 } 24 nodeID, err := sr.backend.Init(req) 25 if err != nil { 26 logrus.Errorf("Error initializing swarm: %v", err) 27 return err 28 } 29 return httputils.WriteJSON(w, http.StatusOK, nodeID) 30 } 31 32 func (sr *swarmRouter) joinCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 33 var req types.JoinRequest 34 if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 35 return err 36 } 37 return sr.backend.Join(req) 38 } 39 40 func (sr *swarmRouter) leaveCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 41 if err := httputils.ParseForm(r); err != nil { 42 return err 43 } 44 45 force := httputils.BoolValue(r, "force") 46 return sr.backend.Leave(force) 47 } 48 49 func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 50 swarm, err := sr.backend.Inspect() 51 if err != nil { 52 logrus.Errorf("Error getting swarm: %v", err) 53 return err 54 } 55 56 return httputils.WriteJSON(w, http.StatusOK, swarm) 57 } 58 59 func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 60 var swarm types.Spec 61 if err := json.NewDecoder(r.Body).Decode(&swarm); err != nil { 62 return err 63 } 64 65 rawVersion := r.URL.Query().Get("version") 66 version, err := strconv.ParseUint(rawVersion, 10, 64) 67 if err != nil { 68 err := fmt.Errorf("invalid swarm version '%s': %v", rawVersion, err) 69 return errors.NewBadRequestError(err) 70 } 71 72 var flags types.UpdateFlags 73 74 if value := r.URL.Query().Get("rotateWorkerToken"); value != "" { 75 rot, err := strconv.ParseBool(value) 76 if err != nil { 77 err := fmt.Errorf("invalid value for rotateWorkerToken: %s", value) 78 return errors.NewBadRequestError(err) 79 } 80 81 flags.RotateWorkerToken = rot 82 } 83 84 if value := r.URL.Query().Get("rotateManagerToken"); value != "" { 85 rot, err := strconv.ParseBool(value) 86 if err != nil { 87 err := fmt.Errorf("invalid value for rotateManagerToken: %s", value) 88 return errors.NewBadRequestError(err) 89 } 90 91 flags.RotateManagerToken = rot 92 } 93 94 if value := r.URL.Query().Get("rotateManagerUnlockKey"); value != "" { 95 rot, err := strconv.ParseBool(value) 96 if err != nil { 97 return errors.NewBadRequestError(fmt.Errorf("invalid value for rotateManagerUnlockKey: %s", value)) 98 } 99 100 flags.RotateManagerUnlockKey = rot 101 } 102 103 if err := sr.backend.Update(version, swarm, flags); err != nil { 104 logrus.Errorf("Error configuring swarm: %v", err) 105 return err 106 } 107 return nil 108 } 109 110 func (sr *swarmRouter) unlockCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 111 var req types.UnlockRequest 112 if err := json.NewDecoder(r.Body).Decode(&req); err != nil { 113 return err 114 } 115 116 if err := sr.backend.UnlockSwarm(req); err != nil { 117 logrus.Errorf("Error unlocking swarm: %v", err) 118 return err 119 } 120 return nil 121 } 122 123 func (sr *swarmRouter) getUnlockKey(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 124 unlockKey, err := sr.backend.GetUnlockKey() 125 if err != nil { 126 logrus.WithError(err).Errorf("Error retrieving swarm unlock key") 127 return err 128 } 129 130 return httputils.WriteJSON(w, http.StatusOK, &basictypes.SwarmUnlockKeyResponse{ 131 UnlockKey: unlockKey, 132 }) 133 } 134 135 func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 136 if err := httputils.ParseForm(r); err != nil { 137 return err 138 } 139 filter, err := filters.FromParam(r.Form.Get("filters")) 140 if err != nil { 141 return err 142 } 143 144 services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter}) 145 if err != nil { 146 logrus.Errorf("Error getting services: %v", err) 147 return err 148 } 149 150 return httputils.WriteJSON(w, http.StatusOK, services) 151 } 152 153 func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 154 service, err := sr.backend.GetService(vars["id"]) 155 if err != nil { 156 logrus.Errorf("Error getting service %s: %v", vars["id"], err) 157 return err 158 } 159 160 return httputils.WriteJSON(w, http.StatusOK, service) 161 } 162 163 func (sr *swarmRouter) createService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 164 var service types.ServiceSpec 165 if err := json.NewDecoder(r.Body).Decode(&service); err != nil { 166 return err 167 } 168 169 // Get returns "" if the header does not exist 170 encodedAuth := r.Header.Get("X-Registry-Auth") 171 172 resp, err := sr.backend.CreateService(service, encodedAuth) 173 if err != nil { 174 logrus.Errorf("Error creating service %s: %v", service.Name, err) 175 return err 176 } 177 178 return httputils.WriteJSON(w, http.StatusCreated, resp) 179 } 180 181 func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 182 var service types.ServiceSpec 183 if err := json.NewDecoder(r.Body).Decode(&service); err != nil { 184 return err 185 } 186 187 rawVersion := r.URL.Query().Get("version") 188 version, err := strconv.ParseUint(rawVersion, 10, 64) 189 if err != nil { 190 err := fmt.Errorf("invalid service version '%s': %v", rawVersion, err) 191 return errors.NewBadRequestError(err) 192 } 193 194 // Get returns "" if the header does not exist 195 encodedAuth := r.Header.Get("X-Registry-Auth") 196 197 registryAuthFrom := r.URL.Query().Get("registryAuthFrom") 198 199 resp, err := sr.backend.UpdateService(vars["id"], version, service, encodedAuth, registryAuthFrom) 200 if err != nil { 201 logrus.Errorf("Error updating service %s: %v", vars["id"], err) 202 return err 203 } 204 return httputils.WriteJSON(w, http.StatusOK, resp) 205 } 206 207 func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 208 if err := sr.backend.RemoveService(vars["id"]); err != nil { 209 logrus.Errorf("Error removing service %s: %v", vars["id"], err) 210 return err 211 } 212 return nil 213 } 214 215 func (sr *swarmRouter) getServiceLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 216 if err := httputils.ParseForm(r); err != nil { 217 return err 218 } 219 220 // Args are validated before the stream starts because when it starts we're 221 // sending HTTP 200 by writing an empty chunk of data to tell the client that 222 // daemon is going to stream. By sending this initial HTTP 200 we can't report 223 // any error after the stream starts (i.e. container not found, wrong parameters) 224 // with the appropriate status code. 225 stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr") 226 if !(stdout || stderr) { 227 return fmt.Errorf("Bad parameters: you must choose at least one stream") 228 } 229 230 serviceName := vars["id"] 231 logsConfig := &backend.ContainerLogsConfig{ 232 ContainerLogsOptions: basictypes.ContainerLogsOptions{ 233 Follow: httputils.BoolValue(r, "follow"), 234 Timestamps: httputils.BoolValue(r, "timestamps"), 235 Since: r.Form.Get("since"), 236 Tail: r.Form.Get("tail"), 237 ShowStdout: stdout, 238 ShowStderr: stderr, 239 Details: httputils.BoolValue(r, "details"), 240 }, 241 OutStream: w, 242 } 243 244 if logsConfig.Details { 245 return fmt.Errorf("Bad parameters: details is not currently supported") 246 } 247 248 chStarted := make(chan struct{}) 249 if err := sr.backend.ServiceLogs(ctx, serviceName, logsConfig, chStarted); err != nil { 250 select { 251 case <-chStarted: 252 // The client may be expecting all of the data we're sending to 253 // be multiplexed, so send it through OutStream, which will 254 // have been set up to handle that if needed. 255 fmt.Fprintf(logsConfig.OutStream, "Error grabbing service logs: %v\n", err) 256 default: 257 return err 258 } 259 } 260 261 return nil 262 } 263 264 func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 265 if err := httputils.ParseForm(r); err != nil { 266 return err 267 } 268 filter, err := filters.FromParam(r.Form.Get("filters")) 269 if err != nil { 270 return err 271 } 272 273 nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter}) 274 if err != nil { 275 logrus.Errorf("Error getting nodes: %v", err) 276 return err 277 } 278 279 return httputils.WriteJSON(w, http.StatusOK, nodes) 280 } 281 282 func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 283 node, err := sr.backend.GetNode(vars["id"]) 284 if err != nil { 285 logrus.Errorf("Error getting node %s: %v", vars["id"], err) 286 return err 287 } 288 289 return httputils.WriteJSON(w, http.StatusOK, node) 290 } 291 292 func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 293 var node types.NodeSpec 294 if err := json.NewDecoder(r.Body).Decode(&node); err != nil { 295 return err 296 } 297 298 rawVersion := r.URL.Query().Get("version") 299 version, err := strconv.ParseUint(rawVersion, 10, 64) 300 if err != nil { 301 err := fmt.Errorf("invalid node version '%s': %v", rawVersion, err) 302 return errors.NewBadRequestError(err) 303 } 304 305 if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil { 306 logrus.Errorf("Error updating node %s: %v", vars["id"], err) 307 return err 308 } 309 return nil 310 } 311 312 func (sr *swarmRouter) removeNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 313 if err := httputils.ParseForm(r); err != nil { 314 return err 315 } 316 317 force := httputils.BoolValue(r, "force") 318 319 if err := sr.backend.RemoveNode(vars["id"], force); err != nil { 320 logrus.Errorf("Error removing node %s: %v", vars["id"], err) 321 return err 322 } 323 return nil 324 } 325 326 func (sr *swarmRouter) getTasks(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 327 if err := httputils.ParseForm(r); err != nil { 328 return err 329 } 330 filter, err := filters.FromParam(r.Form.Get("filters")) 331 if err != nil { 332 return err 333 } 334 335 tasks, err := sr.backend.GetTasks(basictypes.TaskListOptions{Filters: filter}) 336 if err != nil { 337 logrus.Errorf("Error getting tasks: %v", err) 338 return err 339 } 340 341 return httputils.WriteJSON(w, http.StatusOK, tasks) 342 } 343 344 func (sr *swarmRouter) getTask(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 345 task, err := sr.backend.GetTask(vars["id"]) 346 if err != nil { 347 logrus.Errorf("Error getting task %s: %v", vars["id"], err) 348 return err 349 } 350 351 return httputils.WriteJSON(w, http.StatusOK, task) 352 } 353 354 func (sr *swarmRouter) getSecrets(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 355 if err := httputils.ParseForm(r); err != nil { 356 return err 357 } 358 filters, err := filters.FromParam(r.Form.Get("filters")) 359 if err != nil { 360 return err 361 } 362 363 secrets, err := sr.backend.GetSecrets(basictypes.SecretListOptions{Filters: filters}) 364 if err != nil { 365 return err 366 } 367 368 return httputils.WriteJSON(w, http.StatusOK, secrets) 369 } 370 371 func (sr *swarmRouter) createSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 372 var secret types.SecretSpec 373 if err := json.NewDecoder(r.Body).Decode(&secret); err != nil { 374 return err 375 } 376 377 id, err := sr.backend.CreateSecret(secret) 378 if err != nil { 379 return err 380 } 381 382 return httputils.WriteJSON(w, http.StatusCreated, &basictypes.SecretCreateResponse{ 383 ID: id, 384 }) 385 } 386 387 func (sr *swarmRouter) removeSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 388 if err := sr.backend.RemoveSecret(vars["id"]); err != nil { 389 return err 390 } 391 w.WriteHeader(http.StatusNoContent) 392 393 return nil 394 } 395 396 func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 397 secret, err := sr.backend.GetSecret(vars["id"]) 398 if err != nil { 399 return err 400 } 401 402 return httputils.WriteJSON(w, http.StatusOK, secret) 403 } 404 405 func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 406 var secret types.SecretSpec 407 if err := json.NewDecoder(r.Body).Decode(&secret); err != nil { 408 return errors.NewBadRequestError(err) 409 } 410 411 rawVersion := r.URL.Query().Get("version") 412 version, err := strconv.ParseUint(rawVersion, 10, 64) 413 if err != nil { 414 return errors.NewBadRequestError(fmt.Errorf("invalid secret version")) 415 } 416 417 id := vars["id"] 418 if err := sr.backend.UpdateSecret(id, version, secret); err != nil { 419 return err 420 } 421 422 return nil 423 }