github.com/in4it/ecs-deploy@v0.0.42-0.20240508120354-ed77ff16df25/api/api.go (about) 1 package api 2 3 import ( 4 //"github.com/RobotsAndPencils/go-saml" 5 jwt "github.com/appleboy/gin-jwt/v2" 6 "github.com/gin-contrib/location" 7 "github.com/gin-gonic/gin" 8 _ "github.com/in4it/ecs-deploy/docs" 9 "github.com/in4it/ecs-deploy/ipfilter" 10 "github.com/in4it/ecs-deploy/ngserve" 11 "github.com/in4it/ecs-deploy/provider/ecs" 12 "github.com/in4it/ecs-deploy/service" 13 "github.com/in4it/ecs-deploy/session" 14 "github.com/in4it/ecs-deploy/util" 15 "github.com/juju/loggo" 16 sns "github.com/robbiet480/go.sns" 17 swaggerfiles "github.com/swaggo/files" // swagger embed files 18 ginSwagger "github.com/swaggo/gin-swagger" // gin-swagger middleware 19 20 "encoding/json" 21 "errors" 22 "net/http" 23 "strconv" 24 "strings" 25 "time" 26 ) 27 28 // logging 29 var apiLogger = loggo.GetLogger("api") 30 31 // version 32 var apiVersion = "1.2" 33 34 // API struct 35 type API struct { 36 authMiddleware *jwt.GinJWTMiddleware 37 //sp saml.ServiceProviderSettings 38 samlHelper *SAML 39 asController AutoscalingController 40 } 41 42 type User struct { 43 UserID string 44 } 45 type login struct { 46 Username string `form:"username" json:"username" binding:"required"` 47 Password string `form:"password" json:"password" binding:"required"` 48 } 49 50 func (a *API) Launch() error { 51 if util.GetEnv("SAML_ENABLED", "") == "yes" { 52 err := a.initSAML() 53 if err != nil { 54 return err 55 } 56 } 57 58 a.asController = AutoscalingController{} 59 60 a.createAuthMiddleware() 61 a.createRoutes() 62 63 return nil 64 } 65 66 func (a *API) initSAML() error { 67 // initialize samlHelper 68 var err error 69 a.samlHelper, err = newSAML(util.GetEnv("SAML_METADATA_URL", ""), []byte(util.GetEnv("SAML_CERTIFICATE", "")), []byte(util.GetEnv("SAML_PRIVATE_KEY", ""))) 70 if err != nil { 71 return err 72 } 73 74 return nil 75 } 76 77 func (a *API) createRoutes() { 78 // create 79 r := gin.Default() 80 81 // location 82 r.Use(location.Default()) 83 84 // cookie sessions 85 r.Use(session.SessionHandler("ecs-deploy", util.GetEnv("JWT_SECRET", "unsecure secret key 8a045eb"))) 86 87 // prefix 88 prefix := util.GetEnv("URL_PREFIX", "") 89 apiPrefix := prefix + util.GetEnv("URL_PREFIX_API", "/api/v1") 90 91 // ip whitelisting 92 r.Use(ipfilter.IPWhiteList(util.GetEnv("ECS_WHITELIST", "0.0.0.0/0"))) 93 94 // webapp 95 r.Use(ngserve.ServeWithDefault(prefix+"/webapp", ngserve.LocalFile("./webapp/dist", false), "./webapp/dist/index.html")) 96 97 auth := r.Group(apiPrefix) 98 auth.Use(a.authMiddleware.MiddlewareFunc()) 99 { 100 // frontend redirect 101 r.GET(prefix, a.redirectFrontendHandler) 102 r.GET(prefix+"/", a.redirectFrontendHandler) 103 104 // health check 105 r.GET(prefix+"/health", a.healthHandler) 106 107 // saml init 108 if util.GetEnv("SAML_ENABLED", "") == "yes" { 109 r.POST(prefix+"/saml/acs", a.samlHelper.samlInitHandler) 110 r.GET(prefix+"/saml/acs", a.samlHelper.samlInitHandler) 111 } 112 r.GET(prefix+"/saml/enabled", a.samlHelper.samlEnabledHandler) 113 114 // swagger 115 r.GET(prefix+"/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) 116 117 // webhook 118 r.POST(prefix+"/webhook", a.webhookHandler) 119 120 // login handlers 121 r.POST(prefix+"/login", a.authMiddleware.LoginHandler) 122 123 // health with auth 124 auth.GET("/health", a.healthHandler) 125 126 // refresh token 127 auth.GET("/refresh_token", a.authMiddleware.RefreshHandler) 128 129 // ECR 130 auth.POST("/ecr/create/:repository", a.ecrCreateHandler) 131 132 // Deploy 133 auth.POST("/deploy/:service", a.deployServiceHandler) 134 auth.POST("/deploy", a.deployServicesHandler) 135 136 // Redeploy existing version 137 auth.POST("/deploy/:service/:time", a.redeployServiceHandler) 138 139 // Export 140 auth.GET("/export/terraform", a.exportTerraformHandler) 141 auth.GET("/export/terraform/:service/targetgrouparn", a.exportTerraformTargetGroupArnHandler) 142 auth.GET("/export/terraform/:service/listenerrulearn", a.exportTerraformListenerRuleArnsHandler) 143 auth.GET("/export/terraform/:service/listenerrulearn/:rule", a.exportTerraformListenerRuleArnHandler) 144 145 // deploy list 146 auth.GET("/deploy/list", a.listDeploysHandler) 147 auth.GET("/deploy/list/:service", a.listDeploysForServiceHandler) 148 auth.GET("/deploy/status/:service/:time", a.getDeploymentStatusHandler) 149 auth.GET("/deploy/get/:service/:time", a.getDeploymentHandler) 150 // service list 151 auth.GET("/service/list", a.listServicesHandler) 152 // service list 153 auth.GET("/service/describe", a.describeServicesHandler) 154 // get service information 155 auth.GET("/service/describe/:service", a.describeServiceHandler) 156 // get version information 157 auth.GET("/service/describe/:service/versions", a.describeServiceVersionsHandler) 158 // scale service 159 auth.POST("/service/scale/:service/:count", a.scaleServiceHandler) 160 // run task 161 auth.POST("/service/runtask/:service", a.runTaskHandler) 162 // get taskdefinition 163 auth.GET("/service/describe/:service/taskdefinition", a.describeServiceTaskdefinitionHandler) 164 // get all tasks 165 auth.GET("/service/describe/:service/tasks", a.describeTasksHandler) 166 167 // parameter store 168 auth.GET("/service/parameter/:service/list", a.listServiceParametersHandler) 169 auth.POST("/service/parameter/:service/put", a.putServiceParameterHandler) 170 auth.POST("/service/parameter/:service/delete/:parameter", a.deleteServiceParameterHandler) 171 172 // cloudwatch logs 173 auth.GET("/service/log/:service/get/:taskarn/:container/:start/:end", a.getServiceLogsHandler) 174 175 // service autoscaling 176 auth.POST("/service/autoscaling/:service/put", a.putServiceAutoscalingHandler) 177 auth.GET("/service/autoscaling/:service/get", a.getServiceAutoscalingHandler) 178 auth.POST("/service/autoscaling/:service/delete/:policyname", a.deleteServiceAutoscalingPolicyHandler) 179 auth.POST("/service/autoscaling/:service/delete", a.deleteServiceAutoscalingHandler) 180 } 181 182 // run API 183 r.Run() 184 } 185 186 // @summary login to receive jwt token 187 // @description login with user and password to receive jwt token 188 // @id login 189 // @accept json 190 // @produce json 191 // @router /login [post] 192 func (a *API) createAuthMiddleware() { 193 var ( 194 identityKey = "id" 195 err error 196 ) 197 a.authMiddleware, err = jwt.New(&jwt.GinJWTMiddleware{ 198 Realm: "ecs-deploy", 199 Key: []byte(util.GetEnv("JWT_SECRET", "unsecure secret key 8a045eb")), 200 SigningAlgorithm: "HS256", 201 Timeout: time.Hour, 202 MaxRefresh: time.Hour, 203 IdentityKey: identityKey, 204 PayloadFunc: func(data interface{}) jwt.MapClaims { 205 if v, ok := data.(*User); ok { 206 return jwt.MapClaims{ 207 identityKey: v.UserID, 208 } 209 } 210 return jwt.MapClaims{} 211 }, 212 IdentityHandler: func(c *gin.Context) interface{} { 213 claims := jwt.ExtractClaims(c) 214 return &User{ 215 UserID: claims["id"].(string), 216 } 217 }, 218 Authenticator: func(c *gin.Context) (interface{}, error) { 219 var loginVals login 220 if err := c.ShouldBind(&loginVals); err != nil { 221 return "", jwt.ErrMissingLoginValues 222 } 223 userID := loginVals.Username 224 password := loginVals.Password 225 226 if (userID == "deploy" && password == util.GetEnv("DEPLOY_PASSWORD", "deploy")) || (userID == "developer" && password == util.GetEnv("DEVELOPER_PASSWORD", "developer")) { 227 return &User{UserID: userID}, nil 228 } 229 230 return nil, jwt.ErrFailedAuthentication 231 }, 232 Authorizator: func(data interface{}, c *gin.Context) bool { 233 if v, ok := data.(*User); ok && v.UserID != "" { 234 return true 235 } 236 237 return false 238 }, 239 Unauthorized: func(c *gin.Context, code int, message string) { 240 c.JSON(code, gin.H{ 241 "code": code, 242 "message": message, 243 }) 244 }, 245 // TokenLookup is a string in the form of "<source>:<name>" that is used 246 // to extract token from the request. 247 // Optional. Default value "header:Authorization". 248 // Possible values: 249 // - "header:<name>" 250 // - "query:<name>" 251 // - "cookie:<name>" 252 TokenLookup: "header:Authorization", 253 // TokenLookup: "query:token", 254 // TokenLookup: "cookie:token", 255 256 // TokenHeadName is a string in the header. Default value is "Bearer" 257 TokenHeadName: "Bearer", 258 259 // TimeFunc provides the current time. You can override it to use another time value. This is useful for testing or if your server uses a different time zone than your tokens. 260 TimeFunc: time.Now, 261 }) 262 if err != nil { 263 panic(err) 264 } 265 } 266 267 // @summary Create ECR repository 268 // @description Creates AWS ECR (Docker) repository using repository name as parameter 269 // @id ecr-create-repository 270 // @accept json 271 // @produce json 272 // @param repository path string true "repository" 273 // @router /api/v1/ecr/create/{repository} [post] 274 func (a *API) ecrCreateHandler(c *gin.Context) { 275 controller := Controller{} 276 res, err := controller.createRepository(c.Param("repository")) 277 if err == nil { 278 c.JSON(200, gin.H{ 279 "message": res, 280 }) 281 } else { 282 c.JSON(200, gin.H{ 283 "error": err.Error(), 284 }) 285 } 286 } 287 288 // @summary Healthcheck 289 // @description Healthcheck for loadbalancer 290 // @id healthcheck 291 // @accept json 292 // @produce json 293 // @router /api/v1/healthcheck [get] 294 func (a *API) healthHandler(c *gin.Context) { 295 c.JSON(200, gin.H{ 296 "message": "OK", 297 }) 298 } 299 300 // @summary Deploy service to ECS 301 // @description Deploy a service to ECS 302 // @id ecs-deploy-service 303 // @accept json 304 // @produce json 305 // @param service path string true "service name" 306 // @router /api/v1/deploy/{service} [post] 307 func (a *API) deployServiceHandler(c *gin.Context) { 308 var json service.Deploy 309 controller := Controller{} 310 service.SetDeployDefaults(&json) 311 if err := c.ShouldBindJSON(&json); err == nil { 312 if err = a.deployServiceValidator(c.Param("service"), json); err == nil { 313 res, err := controller.Deploy(c.Param("service"), json) 314 if err == nil { 315 c.JSON(200, gin.H{ 316 "message": res, 317 }) 318 } else { 319 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 320 } 321 } else { 322 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 323 } 324 } else { 325 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 326 } 327 } 328 329 // @summary Deploy services to ECS 330 // @description Deploy services to ECS 331 // @id ecs-deploy-service 332 // @accept json 333 // @produce json 334 // @router /api/v1/deploy [post] 335 func (a *API) deployServicesHandler(c *gin.Context) { 336 var json service.DeployServices 337 var errors map[string]string 338 var results []*service.DeployResult 339 var err error 340 var res *service.DeployResult 341 var failures int 342 errors = make(map[string]string) 343 controller := Controller{} 344 if err = c.ShouldBindJSON(&json); err == nil { 345 for i, v := range json.Services { 346 if err = a.deployServiceValidator(v.ServiceName, json.Services[i]); err == nil { 347 res, err = controller.Deploy(v.ServiceName, json.Services[i]) 348 if err == nil { 349 results = append(results, res) 350 } 351 } 352 if err != nil { 353 failures += 1 354 errors[v.ServiceName] = err.Error() 355 } 356 } 357 c.JSON(200, gin.H{ 358 "messages": results, 359 "failures": failures, 360 "errors": errors, 361 }) 362 } else { 363 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 364 } 365 } 366 367 // @summary Redeploy existing service to ECS 368 // @description Redeploy existing service to ECS 369 // @id ecs-redeploy-service 370 // @accept json 371 // @produce json 372 // @param service path string true "service name" 373 // @param time path time true "timestamp" 374 // @router /api/v1/deploy/{service} [post] 375 func (a *API) redeployServiceHandler(c *gin.Context) { 376 controller := Controller{} 377 res, err := controller.redeploy(c.Param("service"), c.Param("time")) 378 if err == nil { 379 c.JSON(200, gin.H{ 380 "message": res, 381 }) 382 } else { 383 c.JSON(200, gin.H{ 384 "error": err.Error(), 385 }) 386 } 387 } 388 389 func (a *API) deployServiceValidator(serviceName string, d service.Deploy) error { 390 if len(serviceName) < 3 { 391 return errors.New("service name needs to be at least 3 characters") 392 } 393 if strings.ToLower(d.ServiceProtocol) != "none" && d.ServicePort == 0 { 394 return errors.New("ServicePort needs to be set if ServiceProtocol is not set to none.") 395 } 396 t := false 397 for _, container := range d.Containers { 398 if container.ContainerName == serviceName { 399 t = true 400 } 401 } 402 if !t { 403 return errors.New("At least one container needs to have the same name as the service (" + serviceName + ")") 404 } 405 406 return nil 407 } 408 409 // @summary Export current services to terraform 410 // @description Export service data stored in dynamodb into terraform tf files 411 // @id export-terraform 412 // @produce json 413 // @router /api/v1/export/terraform [get] 414 func (a *API) exportTerraformHandler(c *gin.Context) { 415 e := Export{} 416 exp, err := e.terraform() 417 if err == nil { 418 if exp == nil { 419 c.JSON(200, gin.H{ 420 "export": "", 421 }) 422 } else { 423 c.JSON(200, gin.H{ 424 "export": *exp, 425 }) 426 } 427 } else { 428 c.JSON(200, gin.H{ 429 "error": err.Error(), 430 }) 431 } 432 } 433 434 // @summary Export targetgroup arn 435 // @description Export target group arn stored in dynamodb into terraform tf files 436 // @id export-terraform-targetgroup-arn 437 // @produce json 438 // @router /api/v1/export/terraform/:service/targetgrouparn [get] 439 func (a *API) exportTerraformTargetGroupArnHandler(c *gin.Context) { 440 e := Export{} 441 targetGroupArn, err := e.getTargetGroupArn(c.Param("service")) 442 if err == nil && targetGroupArn != nil { 443 c.JSON(200, gin.H{ 444 "targetGroupArn": targetGroupArn, 445 }) 446 } else { 447 c.JSON(200, gin.H{ 448 "error": err.Error(), 449 }) 450 } 451 } 452 453 // @summary Export listener rule arn 454 // @description Export listener rule arn 455 // @id export-terraform-listener-rule-arn 456 // @produce json 457 // @router /api/v1/export/terraform/:service/listenerrulearn/:rule [get] 458 func (a *API) exportTerraformListenerRuleArnHandler(c *gin.Context) { 459 e := Export{} 460 listenerRuleArn, err := e.getListenerRuleArn(c.Param("service"), c.Param("rule")) 461 if err == nil && listenerRuleArn != nil { 462 c.JSON(200, gin.H{ 463 "listenerRuleArn": listenerRuleArn, 464 }) 465 } else { 466 c.JSON(200, gin.H{ 467 "error": err.Error(), 468 }) 469 } 470 } 471 472 // @summary Export listener rule arns 473 // @description Export listener rule arns 474 // @id export-terraform-listener-rule-arns 475 // @produce json 476 // @router /api/v1/export/terraform/:service/listenerrulearn [get] 477 func (a *API) exportTerraformListenerRuleArnsHandler(c *gin.Context) { 478 e := Export{} 479 listenerRuleArns, err := e.getListenerRuleArns(c.Param("service")) 480 if err == nil && listenerRuleArns != nil { 481 c.JSON(200, gin.H{ 482 "listenerRuleKeys": listenerRuleArns.RuleKeys, 483 "listenerRules": listenerRuleArns.Rules, 484 }) 485 } else { 486 c.JSON(200, gin.H{ 487 "error": err.Error(), 488 }) 489 } 490 } 491 func (a *API) listDeploysHandler(c *gin.Context) { 492 controller := Controller{} 493 deploys, err := controller.getDeploys() 494 if err == nil { 495 c.JSON(200, gin.H{ 496 "deployments": deploys, 497 }) 498 } else { 499 c.JSON(200, gin.H{ 500 "error": err.Error(), 501 }) 502 } 503 } 504 func (a *API) listDeploysForServiceHandler(c *gin.Context) { 505 controller := Controller{} 506 deploys, err := controller.getDeploysForService(c.Param("service")) 507 if err == nil { 508 c.JSON(200, gin.H{ 509 "deployments": deploys, 510 }) 511 } else { 512 c.JSON(200, gin.H{ 513 "error": err.Error(), 514 }) 515 } 516 } 517 func (a *API) listServicesHandler(c *gin.Context) { 518 controller := Controller{} 519 services, err := controller.getServices() 520 if err == nil { 521 c.JSON(200, gin.H{ 522 "services": services, 523 }) 524 } else { 525 c.JSON(200, gin.H{ 526 "error": err.Error(), 527 }) 528 } 529 } 530 531 func (a *API) describeServicesHandler(c *gin.Context) { 532 controller := Controller{} 533 services, err := controller.describeServices() 534 if err == nil { 535 c.JSON(200, gin.H{ 536 "services": services, 537 }) 538 } else { 539 c.JSON(200, gin.H{ 540 "error": err.Error(), 541 }) 542 } 543 } 544 func (a *API) describeServiceHandler(c *gin.Context) { 545 controller := Controller{} 546 service, err := controller.describeService(c.Param("service")) 547 if err == nil { 548 c.JSON(200, gin.H{ 549 "service": service, 550 }) 551 } else { 552 c.JSON(200, gin.H{ 553 "error": err.Error(), 554 }) 555 } 556 } 557 func (a *API) describeServiceVersionsHandler(c *gin.Context) { 558 controller := Controller{} 559 versions, err := controller.describeServiceVersions(c.Param("service")) 560 if err == nil { 561 c.JSON(200, gin.H{ 562 "versions": versions, 563 }) 564 } else { 565 c.JSON(200, gin.H{ 566 "error": err.Error(), 567 }) 568 } 569 } 570 func (a *API) getDeploymentStatusHandler(c *gin.Context) { 571 controller := Controller{} 572 service, err := controller.getDeploymentStatus(c.Param("service"), c.Param("time")) 573 if err == nil { 574 c.JSON(200, gin.H{ 575 "service": service, 576 }) 577 } else { 578 c.JSON(200, gin.H{ 579 "error": err.Error(), 580 }) 581 } 582 } 583 func (a *API) getDeploymentHandler(c *gin.Context) { 584 controller := Controller{} 585 deployment, err := controller.getDeployment(c.Param("service"), c.Param("time")) 586 if err == nil { 587 c.JSON(200, gin.H{ 588 "deployment": deployment, 589 }) 590 } else { 591 c.JSON(200, gin.H{ 592 "error": err.Error(), 593 }) 594 } 595 } 596 597 func (a *API) redirectFrontendHandler(c *gin.Context) { 598 c.Redirect(http.StatusMovedPermanently, util.GetEnv("URL_PREFIX", "")+"/webapp/") 599 } 600 601 func (a *API) listServiceParametersHandler(c *gin.Context) { 602 var creds string 603 claims := jwt.ExtractClaims(c) 604 controller := Controller{} 605 session, sessionExists := session.RetrieveSession(c) 606 if sessionExists { 607 if c, ok := session.Get("paramstore_creds").(string); ok { 608 creds = c 609 } 610 } 611 parameters, creds, err := controller.getServiceParameters(c.Param("service"), claims["id"].(string), creds) 612 session.Set("paramstore_creds", creds) 613 session.Save() 614 if err == nil { 615 c.JSON(200, gin.H{ 616 "parameters": parameters, 617 }) 618 } else { 619 c.JSON(200, gin.H{ 620 "error": err.Error(), 621 }) 622 } 623 } 624 func (a *API) putServiceParameterHandler(c *gin.Context) { 625 var json service.DeployServiceParameter 626 var creds string 627 claims := jwt.ExtractClaims(c) 628 controller := Controller{} 629 session, sessionExists := session.RetrieveSession(c) 630 if sessionExists { 631 if c, ok := session.Get("paramstore_creds").(string); ok { 632 creds = c 633 } 634 } 635 if err := c.ShouldBindJSON(&json); err == nil { 636 res, creds, err := controller.putServiceParameter(c.Param("service"), claims["id"].(string), creds, json) 637 session.Set("paramstore_creds", creds) 638 session.Save() 639 if err == nil { 640 c.JSON(200, gin.H{ 641 "parameters": res, 642 }) 643 } else { 644 c.JSON(200, gin.H{ 645 "error": err.Error(), 646 }) 647 } 648 } else { 649 c.JSON(200, gin.H{ 650 "error": "Invalid input", 651 }) 652 } 653 } 654 func (a *API) deleteServiceParameterHandler(c *gin.Context) { 655 var creds string 656 claims := jwt.ExtractClaims(c) 657 controller := Controller{} 658 session, sessionExists := session.RetrieveSession(c) 659 if sessionExists { 660 if c, ok := session.Get("paramstore_creds").(string); ok { 661 creds = c 662 } 663 } 664 creds, err := controller.deleteServiceParameter(c.Param("service"), claims["id"].(string), creds, c.Param("parameter")) 665 session.Set("paramstore_creds", creds) 666 session.Save() 667 if err == nil { 668 c.JSON(200, gin.H{ 669 "message": "OK", 670 }) 671 } else { 672 c.JSON(200, gin.H{ 673 "error": err.Error(), 674 }) 675 } 676 } 677 func (a *API) scaleServiceHandler(c *gin.Context) { 678 controller := Controller{} 679 desiredCount, err := strconv.ParseInt(c.Param("count"), 10, 64) 680 if err != nil { 681 c.JSON(200, gin.H{ 682 "error": err.Error(), 683 }) 684 return 685 } 686 err = controller.scaleService(c.Param("service"), desiredCount) 687 if err == nil { 688 c.JSON(200, gin.H{ 689 "message": "OK", 690 }) 691 } else { 692 c.JSON(200, gin.H{ 693 "error": err.Error(), 694 }) 695 } 696 } 697 698 func (a *API) webhookHandler(c *gin.Context) { 699 var err error 700 701 snsMessageType := c.GetHeader("x-amz-sns-message-type") 702 apiLogger.Tracef("Checking message type: %v", snsMessageType) 703 var snsPayload sns.Payload 704 if err = c.ShouldBindJSON(&snsPayload); err == nil { 705 err = snsPayload.VerifyPayload() 706 if err == nil { 707 apiLogger.Tracef("Verified Payload.") 708 if snsMessageType == "SubscriptionConfirmation" { 709 apiLogger.Debugf("Subscribing...") 710 _, err = snsPayload.Subscribe() 711 } else if snsMessageType == "Notification" { 712 apiLogger.Debugf("Incoming Notification") 713 var genericMessage ecs.SNSPayloadGeneric 714 if err = json.Unmarshal([]byte(snsPayload.Message), &genericMessage); err == nil { 715 apiLogger.Tracef("Message detail type: %v", genericMessage.DetailType) 716 if genericMessage.DetailType == "ECS Container Instance State Change" { 717 var ecsMessage ecs.SNSPayloadEcs 718 if err = json.Unmarshal([]byte(snsPayload.Message), &ecsMessage); err == nil { 719 apiLogger.Tracef("ECS Message: %v", snsPayload.Message) 720 err = a.asController.processEcsMessage(ecsMessage) 721 } 722 } else if genericMessage.DetailType == "EC2 Instance-terminate Lifecycle Action" { 723 var lifecycleMessage ecs.SNSPayloadLifecycle 724 if err = json.Unmarshal([]byte(snsPayload.Message), &lifecycleMessage); err == nil { 725 apiLogger.Debugf("Lifecycle Message: %v", snsPayload.Message) 726 err = a.asController.processLifecycleMessage(lifecycleMessage) 727 } 728 } 729 } 730 } else { 731 err = errors.New("MessageType not recognized") 732 } 733 } 734 } 735 if err == nil { 736 c.JSON(200, gin.H{ 737 "message": "OK", 738 }) 739 } else { 740 apiLogger.Errorf("Error: %v", err.Error()) 741 c.JSON(200, gin.H{ 742 "error": err.Error(), 743 }) 744 } 745 } 746 func (a *API) runTaskHandler(c *gin.Context) { 747 var json service.RunTask 748 controller := Controller{} 749 if err := c.ShouldBindJSON(&json); err == nil { 750 claims := jwt.ExtractClaims(c) 751 json.StartedBy = strings.Replace(claims["id"].(string), "@", "-", -1) 752 taskArn, err := controller.runTask(c.Param("service"), json) 753 if err == nil { 754 c.JSON(200, gin.H{ 755 "taskArn": taskArn, 756 }) 757 } else { 758 c.JSON(200, gin.H{ 759 "error": err.Error(), 760 }) 761 } 762 } else { 763 c.JSON(200, gin.H{ 764 "error": err.Error(), 765 }) 766 } 767 } 768 func (a *API) describeServiceTaskdefinitionHandler(c *gin.Context) { 769 controller := Controller{} 770 taskDefinition, err := controller.describeTaskDefinition(c.Param("service")) 771 if err == nil { 772 c.JSON(200, gin.H{ 773 "taskDefinition": taskDefinition, 774 }) 775 } else { 776 c.JSON(200, gin.H{ 777 "error": err.Error(), 778 }) 779 } 780 } 781 func (a *API) describeTasksHandler(c *gin.Context) { 782 controller := Controller{} 783 taskArns, err := controller.listTasks(c.Param("service")) 784 if err == nil { 785 c.JSON(200, gin.H{ 786 "tasks": taskArns, 787 }) 788 } else { 789 c.JSON(200, gin.H{ 790 "error": err.Error(), 791 }) 792 } 793 } 794 func (a *API) getServiceLogsHandler(c *gin.Context) { 795 controller := Controller{} 796 layout := "2006-01-02T15:04:05.9Z" 797 start, err := time.Parse(layout, c.Param("start")) 798 if err != nil { 799 c.JSON(200, gin.H{ 800 "error": "Can't parse start date: " + err.Error(), 801 }) 802 return 803 } 804 end, err := time.Parse(layout, c.Param("end")) 805 if err != nil { 806 c.JSON(200, gin.H{ 807 "error": "Can't parse end date", 808 }) 809 return 810 } 811 logs, err := controller.getServiceLogs(c.Param("service"), c.Param("taskarn"), c.Param("container"), start, end) 812 if err == nil { 813 c.JSON(200, gin.H{ 814 "logs": logs, 815 }) 816 } else { 817 c.JSON(200, gin.H{ 818 "error": err.Error(), 819 }) 820 } 821 } 822 func (a *API) putServiceAutoscalingHandler(c *gin.Context) { 823 var json service.Autoscaling 824 controller := Controller{} 825 if err := c.ShouldBindJSON(&json); err == nil { 826 result, err := controller.putServiceAutoscaling(c.Param("service"), json) 827 if err == nil { 828 c.JSON(200, gin.H{ 829 "autoscaling": result, 830 }) 831 } else { 832 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 833 } 834 } else { 835 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 836 } 837 } 838 func (a *API) getServiceAutoscalingHandler(c *gin.Context) { 839 controller := Controller{} 840 result, err := controller.getServiceAutoscaling(c.Param("service")) 841 if err == nil { 842 c.JSON(200, gin.H{ 843 "autoscaling": result, 844 }) 845 } else { 846 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 847 } 848 } 849 func (a *API) deleteServiceAutoscalingPolicyHandler(c *gin.Context) { 850 controller := Controller{} 851 err := controller.deleteServiceAutoscalingPolicy(c.Param("service"), c.Param("policyname")) 852 if err == nil { 853 c.JSON(200, gin.H{ 854 "autoscaling": "deleted", 855 }) 856 } else { 857 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 858 } 859 } 860 861 func (a *API) deleteServiceAutoscalingHandler(c *gin.Context) { 862 controller := Controller{} 863 err := controller.deleteServiceAutoscaling(c.Param("service")) 864 if err == nil { 865 c.JSON(200, gin.H{ 866 "autoscaling": "deleted", 867 }) 868 } else { 869 c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 870 } 871 }