cloudwatch.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. "DescribeAlarmsForMetric": handleDescribeAlarmsForMetric,
  31. "DescribeAlarmHistory": handleDescribeAlarmHistory,
  32. "DescribeInstances": handleDescribeInstances,
  33. "__GetRegions": handleGetRegions,
  34. "__GetNamespaces": handleGetNamespaces,
  35. "__GetMetrics": handleGetMetrics,
  36. "__GetDimensions": handleGetDimensions,
  37. }
  38. }
  39. func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
  40. sess := session.New()
  41. creds := credentials.NewChainCredentials(
  42. []credentials.Provider{
  43. &credentials.EnvProvider{},
  44. &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database},
  45. &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
  46. })
  47. cfg := &aws.Config{
  48. Region: aws.String(req.Region),
  49. Credentials: creds,
  50. }
  51. svc := cloudwatch.New(session.New(cfg), cfg)
  52. reqParam := &struct {
  53. Parameters struct {
  54. Namespace string `json:"namespace"`
  55. MetricName string `json:"metricName"`
  56. Dimensions []*cloudwatch.Dimension `json:"dimensions"`
  57. Statistics []*string `json:"statistics"`
  58. StartTime int64 `json:"startTime"`
  59. EndTime int64 `json:"endTime"`
  60. Period int64 `json:"period"`
  61. } `json:"parameters"`
  62. }{}
  63. json.Unmarshal(req.Body, reqParam)
  64. params := &cloudwatch.GetMetricStatisticsInput{
  65. Namespace: aws.String(reqParam.Parameters.Namespace),
  66. MetricName: aws.String(reqParam.Parameters.MetricName),
  67. Dimensions: reqParam.Parameters.Dimensions,
  68. Statistics: reqParam.Parameters.Statistics,
  69. StartTime: aws.Time(time.Unix(reqParam.Parameters.StartTime, 0)),
  70. EndTime: aws.Time(time.Unix(reqParam.Parameters.EndTime, 0)),
  71. Period: aws.Int64(reqParam.Parameters.Period),
  72. }
  73. resp, err := svc.GetMetricStatistics(params)
  74. if err != nil {
  75. c.JsonApiErr(500, "Unable to call AWS API", err)
  76. return
  77. }
  78. c.JSON(200, resp)
  79. }
  80. func handleListMetrics(req *cwRequest, c *middleware.Context) {
  81. sess := session.New()
  82. creds := credentials.NewChainCredentials(
  83. []credentials.Provider{
  84. &credentials.EnvProvider{},
  85. &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database},
  86. &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
  87. })
  88. cfg := &aws.Config{
  89. Region: aws.String(req.Region),
  90. Credentials: creds,
  91. }
  92. svc := cloudwatch.New(session.New(cfg), cfg)
  93. reqParam := &struct {
  94. Parameters struct {
  95. Namespace string `json:"namespace"`
  96. MetricName string `json:"metricName"`
  97. Dimensions []*cloudwatch.DimensionFilter `json:"dimensions"`
  98. } `json:"parameters"`
  99. }{}
  100. json.Unmarshal(req.Body, reqParam)
  101. params := &cloudwatch.ListMetricsInput{
  102. Namespace: aws.String(reqParam.Parameters.Namespace),
  103. MetricName: aws.String(reqParam.Parameters.MetricName),
  104. Dimensions: reqParam.Parameters.Dimensions,
  105. }
  106. var resp cloudwatch.ListMetricsOutput
  107. err := svc.ListMetricsPages(params,
  108. func(page *cloudwatch.ListMetricsOutput, lastPage bool) bool {
  109. metrics, _ := awsutil.ValuesAtPath(page, "Metrics")
  110. for _, metric := range metrics {
  111. resp.Metrics = append(resp.Metrics, metric.(*cloudwatch.Metric))
  112. }
  113. return !lastPage
  114. })
  115. if err != nil {
  116. c.JsonApiErr(500, "Unable to call AWS API", err)
  117. return
  118. }
  119. c.JSON(200, resp)
  120. }
  121. func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
  122. svc := cloudwatch.New(&aws.Config{Region: aws.String(req.Region)})
  123. reqParam := &struct {
  124. Parameters struct {
  125. Namespace string `json:"namespace"`
  126. MetricName string `json:"metricName"`
  127. Dimensions []*cloudwatch.Dimension `json:"dimensions"`
  128. Statistic string `json:"statistic"`
  129. Period int64 `json:"period"`
  130. } `json:"parameters"`
  131. }{}
  132. json.Unmarshal(req.Body, reqParam)
  133. params := &cloudwatch.DescribeAlarmsForMetricInput{
  134. Namespace: aws.String(reqParam.Parameters.Namespace),
  135. MetricName: aws.String(reqParam.Parameters.MetricName),
  136. Period: aws.Int64(reqParam.Parameters.Period),
  137. }
  138. if len(reqParam.Parameters.Dimensions) != 0 {
  139. params.Dimensions = reqParam.Parameters.Dimensions
  140. }
  141. if reqParam.Parameters.Statistic != "" {
  142. params.Statistic = aws.String(reqParam.Parameters.Statistic)
  143. }
  144. resp, err := svc.DescribeAlarmsForMetric(params)
  145. if err != nil {
  146. c.JsonApiErr(500, "Unable to call AWS API", err)
  147. return
  148. }
  149. c.JSON(200, resp)
  150. }
  151. func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) {
  152. svc := cloudwatch.New(&aws.Config{Region: aws.String(req.Region)})
  153. reqParam := &struct {
  154. Parameters struct {
  155. AlarmName string `json:"alarmName"`
  156. HistoryItemType string `json:"historyItemType"`
  157. StartDate int64 `json:"startDate"`
  158. EndDate int64 `json:"endDate"`
  159. } `json:"parameters"`
  160. }{}
  161. json.Unmarshal(req.Body, reqParam)
  162. params := &cloudwatch.DescribeAlarmHistoryInput{
  163. AlarmName: aws.String(reqParam.Parameters.AlarmName),
  164. StartDate: aws.Time(time.Unix(reqParam.Parameters.StartDate, 0)),
  165. EndDate: aws.Time(time.Unix(reqParam.Parameters.EndDate, 0)),
  166. }
  167. if reqParam.Parameters.HistoryItemType != "" {
  168. params.HistoryItemType = aws.String(reqParam.Parameters.HistoryItemType)
  169. }
  170. resp, err := svc.DescribeAlarmHistory(params)
  171. if err != nil {
  172. c.JsonApiErr(500, "Unable to call AWS API", err)
  173. return
  174. }
  175. c.JSON(200, resp)
  176. }
  177. func handleDescribeInstances(req *cwRequest, c *middleware.Context) {
  178. sess := session.New()
  179. creds := credentials.NewChainCredentials(
  180. []credentials.Provider{
  181. &credentials.EnvProvider{},
  182. &credentials.SharedCredentialsProvider{Filename: "", Profile: req.DataSource.Database},
  183. &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
  184. })
  185. cfg := &aws.Config{
  186. Region: aws.String(req.Region),
  187. Credentials: creds,
  188. }
  189. svc := ec2.New(session.New(cfg), cfg)
  190. reqParam := &struct {
  191. Parameters struct {
  192. Filters []*ec2.Filter `json:"filters"`
  193. InstanceIds []*string `json:"instanceIds"`
  194. } `json:"parameters"`
  195. }{}
  196. json.Unmarshal(req.Body, reqParam)
  197. params := &ec2.DescribeInstancesInput{}
  198. if len(reqParam.Parameters.Filters) > 0 {
  199. params.Filters = reqParam.Parameters.Filters
  200. }
  201. if len(reqParam.Parameters.InstanceIds) > 0 {
  202. params.InstanceIds = reqParam.Parameters.InstanceIds
  203. }
  204. var resp ec2.DescribeInstancesOutput
  205. err := svc.DescribeInstancesPages(params,
  206. func(page *ec2.DescribeInstancesOutput, lastPage bool) bool {
  207. reservations, _ := awsutil.ValuesAtPath(page, "Reservations")
  208. for _, reservation := range reservations {
  209. resp.Reservations = append(resp.Reservations, reservation.(*ec2.Reservation))
  210. }
  211. return !lastPage
  212. })
  213. if err != nil {
  214. c.JsonApiErr(500, "Unable to call AWS API", err)
  215. return
  216. }
  217. c.JSON(200, resp)
  218. }
  219. func HandleRequest(c *middleware.Context, ds *m.DataSource) {
  220. var req cwRequest
  221. req.Body, _ = ioutil.ReadAll(c.Req.Request.Body)
  222. req.DataSource = ds
  223. json.Unmarshal(req.Body, &req)
  224. if handler, found := actionHandlers[req.Action]; !found {
  225. c.JsonApiErr(500, "Unexpected AWS Action", errors.New(req.Action))
  226. return
  227. } else {
  228. handler(&req, c)
  229. }
  230. }