LoginSignup
3
3

More than 3 years have passed since last update.

Health APIでメンテナンス必要な件数をMackerelで可視化

Last updated at Posted at 2019-12-20

はじめに

AWSでメンテナンスが行われる場合、それぞれのアカウントに対してメールで通知が行われます。
対象のアカウントが多いと、メールも大量になり、重要なメンテナンス通知を漏らすことがあります。
(メールの文面が変わってしまったりすることもあり、完全にフィルタリングを行うことは難しいです。。。)

Health APIを用いると、APIで必要なメンテナンス情報を取得することができるので、対応漏れを防ぐことができます。

ドキュメントにあるように、Healthイベントのステータス変化をイベントとして、再起動や通知を行ったりもできますが、今回は対処が必要なリソースが、どのアカウントで何件あるのかをMackerelで確認できるようにしたいと思います。

構成

簡単ですが構成は以下の通りです。
日次でCloudWatch EventsからLambdaをスケジュール起動し、各アカウントのメンテナンス情報を収集します。
収集した結果をサービスメトリックとしてMackerlに投稿するようにしました。

Health APIへのアクセスにはhealth:Describe*の許可が必要です。
各アカウントの環境にアクセスできるように、実行環境へのAssumeRoleを設定しています。

コード

MackerelのAPIKEYはひとまず環境変数に持たせています。
ターゲットアカウントのロールと、Mackerlへ投稿する際のサービス、メトリック名をパラメータとして渡すことにしています。

testparam.png

main.go
main.go
package main

import (
    "log"
    "os"
    "time"

    "github.com/aws/aws-lambda-go/lambda"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/health"
    "github.com/aws/aws-sdk-go/service/sts"
    mackerel "github.com/mackerelio/mackerel-client-go"
)

var (
    client  = mackerel.NewClient(os.Getenv("APIKEY"))
    nowTime = time.Now()
)

// Request is argument specified at call
type Request struct {
    TargetList []TargetAccount `json:"TargetList"`
}

// TargetAccount is target account
type TargetAccount struct {
    Service string `json:"Service"`
    Name    string `json:"Name"`
    Role    string `json:"Role"`
}

func handler(req Request) (string, error) {

    sess := session.Must(session.NewSession())
    assumeRoler := sts.New(sess)

    eventParam := &health.DescribeEventsInput{
        Filter: &health.EventFilter{
            EventStatusCodes: []*string{
                aws.String(health.EventStatusCodeOpen),
                aws.String(health.EventStatusCodeUpcoming),
            },
            EventTypeCategories: []*string{
                aws.String(health.EventTypeCategoryScheduledChange),
            },
        },
    }

    for _, target := range req.TargetList {
        creds := stscreds.NewCredentialsWithClient(assumeRoler, target.Role)
        svc := health.New(sess, aws.NewConfig().WithRegion("us-east-1").WithCredentials(creds))

        var arns []*string
        err := svc.DescribeEventsPages(eventParam, func(resp *health.DescribeEventsOutput, lastPage bool) bool {
            for _, event := range resp.Events {
                arns = append(arns, event.Arn)
            }
            return true
        })

        if err != nil {
            log.Println(err.Error())
            continue
        }

        entityParam := &health.DescribeAffectedEntitiesInput{
            Filter: &health.EntityFilter{
                EventArns: arns,
            },
        }

        var entities []*health.AffectedEntity
        err = svc.DescribeAffectedEntitiesPages(entityParam, func(resp *health.DescribeAffectedEntitiesOutput, lastPage bool) bool {
            entities = append(entities, resp.Entities...)
            return true
        })

        if err != nil {
            log.Println(err.Error())
            continue
        }

        entities = removeUnknown(entities)

        err = client.PostServiceMetricValues(target.Service, []*mackerel.MetricValue{
            &mackerel.MetricValue{
                Name:  "monitor-maintenance." + target.Name,
                Time:  nowTime.Unix(),
                Value: len(entities),
            },
        })
        if err != nil {
            log.Println(err.Error())
            continue
        }
    }
    return "ok", nil
}

func removeUnknown(e []*health.AffectedEntity) []*health.AffectedEntity {
    result := []*health.AffectedEntity{}
    for _, v := range e {
        if *v.EntityValue == health.EntityStatusCodeUnknown {
            continue
        }
        result = append(result, v)
    }
    return result
}

func main() {
    lambda.Start(handler)
}

  • Health APIの実行にはビジネス、またはエンタープライズサポートプランが必要です
  • AWS Healthのエンドポイントは米国東部(バージニア北部)リージョンのみです
  • 試してる間にメンテナンスが発生していなくて、ちゃんとテストできていません。。。
    • 後日問題あれば修正します。スミマセン<( ̄∇ ̄)ゞ

実行結果(想定)

mackerl_sample-service.png
このように描かれるんじゃないかなーと思っています。。

最後に

いよいよ週明け、12/23(月)は5周年イベントのMackerel Day#2ですね!
すごく楽しみです!
https://mackerelio.connpass.com/event/152583/

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3