cloudwatch.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package cloudwatch
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "io/ioutil"
  6. "time"
  7. "github.com/aws/aws-sdk-go/aws"
  8. "github.com/aws/aws-sdk-go/aws/awsutil"
  9. "github.com/aws/aws-sdk-go/aws/credentials"
  10. "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
  11. "github.com/aws/aws-sdk-go/aws/ec2metadata"
  12. "github.com/aws/aws-sdk-go/aws/session"
  13. "github.com/aws/aws-sdk-go/service/cloudwatch"
  14. "github.com/aws/aws-sdk-go/service/ec2"
  15. "github.com/grafana/grafana/pkg/middleware"
  16. m "github.com/grafana/grafana/pkg/models"
  17. )
  18. type actionHandler func(*cwRequest, *middleware.Context)
  19. var actionHandlers map[string]actionHandler
  20. type cwRequest struct {
  21. Region string `json:"region"`
  22. Action string `json:"action"`
  23. Body []byte `json:"-"`
  24. DataSource *m.DataSource
  25. }
  26. func init() {
  27. actionHandlers = map[string]actionHandler{
  28. "GetMetricStatistics": handleGetMetricStatistics,
  29. "ListMetrics": handleListMetrics,
  30. "DescribeInstances": handleDescribeInstances,
  31. "__GetRegions": handleGetRegions,
  32. "__GetNamespaces": handleGetNamespaces,
  33. "__GetMetrics": handleGetMetrics,
  34. "__GetDimensions": handleGetDimensions,
  35. }
  36. }
  37. func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
  38. sess := session.New()
  39. creds := credentials.NewChainCredentials(
  40. []credentials.Provider{
  41. &credentials.EnvProvider{},
  42. &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database},
  43. &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
  44. })
  45. cfg := &aws.Config{
  46. Region: aws.String(req.Region),
  47. Credentials: creds,
  48. }
  49. svc := cloudwatch.New(session.New(cfg), cfg)
  50. reqParam := &struct {
  51. Parameters struct {
  52. Namespace string `json:"namespace"`
  53. MetricName string `json:"metricName"`
  54. Dimensions []*cloudwatch.Dimension `json:"dimensions"`
  55. Statistics []*string `json:"statistics"`
  56. StartTime int64 `json:"startTime"`
  57. EndTime int64 `json:"endTime"`
  58. Period int64 `json:"period"`
  59. } `json:"parameters"`
  60. }{}
  61. json.Unmarshal(req.Body, reqParam)
  62. params := &cloudwatch.GetMetricStatisticsInput{
  63. Namespace: aws.String(reqParam.Parameters.Namespace),
  64. MetricName: aws.String(reqParam.Parameters.MetricName),
  65. Dimensions: reqParam.Parameters.Dimensions,
  66. Statistics: reqParam.Parameters.Statistics,
  67. StartTime: aws.Time(time.Unix(reqParam.Parameters.StartTime, 0)),
  68. EndTime: aws.Time(time.Unix(reqParam.Parameters.EndTime, 0)),
  69. Period: aws.Int64(reqParam.Parameters.Period),
  70. }
  71. resp, err := svc.GetMetricStatistics(params)
  72. if err != nil {
  73. c.JsonApiErr(500, "Unable to call AWS API", err)
  74. return
  75. }
  76. c.JSON(200, resp)
  77. }
  78. func handleListMetrics(req *cwRequest, c *middleware.Context) {
  79. sess := session.New()
  80. creds := credentials.NewChainCredentials(
  81. []credentials.Provider{
  82. &credentials.EnvProvider{},
  83. &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database},
  84. &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
  85. })
  86. cfg := &aws.Config{
  87. Region: aws.String(req.Region),
  88. Credentials: creds,
  89. }
  90. svc := cloudwatch.New(session.New(cfg), cfg)
  91. reqParam := &struct {
  92. Parameters struct {
  93. Namespace string `json:"namespace"`
  94. MetricName string `json:"metricName"`
  95. Dimensions []*cloudwatch.DimensionFilter `json:"dimensions"`
  96. } `json:"parameters"`
  97. }{}
  98. json.Unmarshal(req.Body, reqParam)
  99. params := &cloudwatch.ListMetricsInput{
  100. Namespace: aws.String(reqParam.Parameters.Namespace),
  101. MetricName: aws.String(reqParam.Parameters.MetricName),
  102. Dimensions: reqParam.Parameters.Dimensions,
  103. }
  104. var resp cloudwatch.ListMetricsOutput
  105. err := svc.ListMetricsPages(params,
  106. func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool {
  107. metrics, _ := awsutil.ValuesAtPath(page, "Metrics")
  108. for _, metric := range metrics {
  109. resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric))
  110. }
  111. return !lastPage
  112. })
  113. if err != nil {
  114. c.JsonApiErr(500, "Unable to call AWS API", err)
  115. return
  116. }
  117. c.JSON(200, resp)
  118. }
  119. func handleDescribeInstances(req *cwRequest, c *middleware.Context) {
  120. sess := session.New()
  121. creds := credentials.NewChainCredentials(
  122. []credentials.Provider{
  123. &credentials.EnvProvider{},
  124. &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database},
  125. &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
  126. })
  127. cfg := &aws.Config{
  128. Region: aws.String(req.Region),
  129. Credentials: creds,
  130. }
  131. svc := ec2.New(session.New(cfg), cfg)
  132. reqParam := &struct {
  133. Parameters struct {
  134. Filters []*ec2.Filter `json:"filters"`
  135. InstanceIds []*string `json:"instanceIds"`
  136. } `json:"parameters"`
  137. }{}
  138. json.Unmarshal(req.Body, reqParam)
  139. params := &ec2.DescribeInstancesInput{}
  140. if len(reqParam.Parameters.Filters) > 0 {
  141. params.Filters = reqParam.Parameters.Filters
  142. }
  143. if len(reqParam.Parameters.InstanceIds) > 0 {
  144. params.InstanceIds = reqParam.Parameters.InstanceIds
  145. }
  146. var resp ec2.DescribeInstancesOutput
  147. err := svc.DescribeInstancesPages(params,
  148. func(page *ec2.DescribeInstancesOutput, lastPage bool) bool {
  149. reservations, _ := awsutil.ValuesAtPath(page, "Reservations")
  150. for _, reservation := range reservations {
  151. resp.Reservations = append(resp.Reservations, reservation.(*ec2.Reservation))
  152. }
  153. return !lastPage
  154. })
  155. if err != nil {
  156. c.JsonApiErr(500, "Unable to call AWS API", err)
  157. return
  158. }
  159. c.JSON(200, resp)
  160. }
  161. func HandleRequest(c *middleware.Context, ds *m.DataSource) {
  162. var req cwRequest
  163. req.Body, _ = ioutil.ReadAll(c.Req.Request.Body)
  164. req.DataSource = ds
  165. json.Unmarshal(req.Body, &req)
  166. if handler, found := actionHandlers[req.Action]; !found {
  167. c.JsonApiErr(500, "Unexpected AWS Action", errors.New(req.Action))
  168. return
  169. } else {
  170. handler(&req, c)
  171. }
  172. }