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