github.com/nullne/docker@v1.13.0-rc1/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 id, 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, &basictypes.ServiceCreateResponse{ 176 ID: id, 177 }) 178 } 179 180 func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 181 var service types.ServiceSpec 182 if err := json.NewDecoder(r.Body).Decode(&service); err != nil { 183 return err 184 } 185 186 rawVersion := r.URL.Query().Get("version") 187 version, err := strconv.ParseUint(rawVersion, 10, 64) 188 if err != nil { 189 return fmt.Errorf("Invalid service version '%s': %s", rawVersion, err.Error()) 190 } 191 192 // Get returns "" if the header does not exist 193 encodedAuth := r.Header.Get("X-Registry-Auth") 194 195 registryAuthFrom := r.URL.Query().Get("registryAuthFrom") 196 197 if err := sr.backend.UpdateService(vars["id"], version, service, encodedAuth, registryAuthFrom); err != nil { 198 logrus.Errorf("Error updating service %s: %v", vars["id"], err) 199 return err 200 } 201 return nil 202 } 203 204 func (sr *swarmRouter) removeService(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 205 if err := sr.backend.RemoveService(vars["id"]); err != nil { 206 logrus.Errorf("Error removing service %s: %v", vars["id"], err) 207 return err 208 } 209 return nil 210 } 211 212 func (sr *swarmRouter) getServiceLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 213 if err := httputils.ParseForm(r); err != nil { 214 return err 215 } 216 217 // Args are validated before the stream starts because when it starts we're 218 // sending HTTP 200 by writing an empty chunk of data to tell the client that 219 // daemon is going to stream. By sending this initial HTTP 200 we can't report 220 // any error after the stream starts (i.e. container not found, wrong parameters) 221 // with the appropriate status code. 222 stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr") 223 if !(stdout || stderr) { 224 return fmt.Errorf("Bad parameters: you must choose at least one stream") 225 } 226 227 serviceName := vars["id"] 228 logsConfig := &backend.ContainerLogsConfig{ 229 ContainerLogsOptions: basictypes.ContainerLogsOptions{ 230 Follow: httputils.BoolValue(r, "follow"), 231 Timestamps: httputils.BoolValue(r, "timestamps"), 232 Since: r.Form.Get("since"), 233 Tail: r.Form.Get("tail"), 234 ShowStdout: stdout, 235 ShowStderr: stderr, 236 Details: httputils.BoolValue(r, "details"), 237 }, 238 OutStream: w, 239 } 240 241 if !logsConfig.Follow { 242 return fmt.Errorf("Bad parameters: Only follow mode is currently supported") 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 fmt.Fprintf(logsConfig.OutStream, "Error grabbing service logs: %v\n", err) 257 default: 258 return err 259 } 260 } 261 262 return nil 263 } 264 265 func (sr *swarmRouter) getNodes(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 266 if err := httputils.ParseForm(r); err != nil { 267 return err 268 } 269 filter, err := filters.FromParam(r.Form.Get("filters")) 270 if err != nil { 271 return err 272 } 273 274 nodes, err := sr.backend.GetNodes(basictypes.NodeListOptions{Filters: filter}) 275 if err != nil { 276 logrus.Errorf("Error getting nodes: %v", err) 277 return err 278 } 279 280 return httputils.WriteJSON(w, http.StatusOK, nodes) 281 } 282 283 func (sr *swarmRouter) getNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 284 node, err := sr.backend.GetNode(vars["id"]) 285 if err != nil { 286 logrus.Errorf("Error getting node %s: %v", vars["id"], err) 287 return err 288 } 289 290 return httputils.WriteJSON(w, http.StatusOK, node) 291 } 292 293 func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 294 var node types.NodeSpec 295 if err := json.NewDecoder(r.Body).Decode(&node); err != nil { 296 return err 297 } 298 299 rawVersion := r.URL.Query().Get("version") 300 version, err := strconv.ParseUint(rawVersion, 10, 64) 301 if err != nil { 302 return fmt.Errorf("Invalid node version '%s': %s", rawVersion, err.Error()) 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 392 return nil 393 } 394 395 func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 396 secret, err := sr.backend.GetSecret(vars["id"]) 397 if err != nil { 398 return err 399 } 400 401 return httputils.WriteJSON(w, http.StatusOK, secret) 402 } 403 404 func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { 405 var secret types.SecretSpec 406 if err := json.NewDecoder(r.Body).Decode(&secret); err != nil { 407 return errors.NewBadRequestError(err) 408 } 409 410 rawVersion := r.URL.Query().Get("version") 411 version, err := strconv.ParseUint(rawVersion, 10, 64) 412 if err != nil { 413 return errors.NewBadRequestError(fmt.Errorf("invalid secret version")) 414 } 415 416 id := vars["id"] 417 if err := sr.backend.UpdateSecret(id, version, secret); err != nil { 418 return err 419 } 420 421 return nil 422 }