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