POST curl 到 cloudwatch 的自定义指标

POST custom metric with curl to cloudwatch

我想记录 api 调用云监视的结果。 我想做的是 post 将指标消耗到云监视中。 我的架构设计为位于 elastic beanstalk 上,所以我更喜欢在上面安装尽可能少的东西。

我想了解是否可以通过简单的 CURL post 云手表 POST。

我有这个tutorial

我不是很理解这个例子。 我可以用 post 吗? (看起来像 get 方法)。 终点是什么?

当我尝试时: curl -X POST https://monitoring.&api-domain;/doc/2010-08-01/?Action=PutMetricData&Version=2010-08-01&Namespace=TestNamespace&MetricData.member.1.MetricName=buffers&MetricData.member.1.Unit=Bytes&&MetricData.member.1.Dimensions.member.1.Name=InstanceType&MetricData.member.1.Dimensions.member.1.Value=m1.small&AUTHPARAMS

我收到这个错误: 'api-domain' is not recognized as an internal or external command, operable program or batch file. 'Version' is not recognized as an internal or external command, operable program or batch file. 'Namespace' is not recognized as an internal or external command, operable program or batch file. 'MetricData.member.1.MetricName' is not recognized as an internal or external command, operable program or batch file. 'MetricData.member.1.Unit' is not recognized as an internal or external command, operable program or batch file. 'MetricData.member.1.Dimensions.member.1.Value' is not recognized as an internal or external command, operable program or batch file. 'AUTHPARAMS' is not recognized as an internal or external command, operable program or batch file.

请不要告诉我使用 aws cli。 我知道我可以使用它。我想尽量不要用。

这是解释如何发出 POST 请求的文档:https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/making-api-requests.html#CloudWatch-API-requests-using-post-method

这是每个区域的端点列表:https://docs.aws.amazon.com/general/latest/gr/rande.html#cw_region

生成的卷曲看起来像这样:

curl -X POST \
  https://monitoring.us-east-1.amazonaws.com \
  -H 'Accept: application/json' \
  -H 'Authorization: AWS4-HMAC-SHA256 Credential=YOUR_ACCESS_KEY_GOES_HERE/20190326/us-east-1/monitoring/aws4_request, SignedHeaders=accept;content-encoding;content-length;content-type;host;x-amz-date;x-amz-target, Signature=SIGV4_SIGNATURE_GOES_HERE' \
  -H 'Content-Encoding: amz-1.0' \
  -H 'Content-Length: 141' \
  -H 'Content-Type: application/json' \
  -H 'X-Amz-Date: 20190326T071934Z' \
  -H 'X-Amz-Target: GraniteServiceVersion20100801.PutMetricData' \
  -H 'host: monitoring.us-east-1.amazonaws.com' \
  -d '{
    "Namespace": "Whosebug",
    "MetricData": [
        {
            "MetricName": "TestMetric",
            "Value": 123.0
        }
    ]
}'

请注意,上例中的 Authorization header 有两个占位符,YOUR_ACCESS_KEY_GOES_HERESIGV4_SIGNATURE_GOES_HERE。这些是您将用于签署请求的凭证中的访问密钥,以及您必须使用此算法构建的签名:https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html,这是使用 CLI 或 SDK 的原因之一推荐的请求方式。

这里是一个纯粹的 bash 例子,只需要 curl 和 openssl。它的灵感来自于:https://github.com/riboseinc/aws-authenticating-secgroup-scripts

#!/bin/bash

set -o errexit
set -o pipefail
set -o nounset

function sha256Hash() {
  printf "" | openssl dgst -sha256 -binary -hex | sed 's/^.* //'
}

function log() {
  local message=""
  local details=""

  printf "${message}\n" >&2
  printf "${details}\n\n" | sed 's/^/    /' >&2
}

function to_hex() {
  printf "" | od -A n -t x1 | tr -d [:space:]
}

function hmac_sha256() {
  printf "" | \
    openssl dgst -binary -hex -sha256 -mac HMAC -macopt hexkey:"" | \
    sed 's/^.* //'
}

## http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
function sig4_create_canonical_request() {
  local http_request_method=""
  local canonical_uri="/${api_uri}"
  local canonical_query=""
  local header_host="host:${api_host}"
  local canonical_headers="${header_host}\n${header_x_amz_date}"
  local request_payload=$(sha256Hash "$metricjson")
  local canonical_request="${http_request_method}\n${canonical_uri}\n${canonical_query}\n${canonical_headers}\n\n${signed_headers}\n${request_payload}"

  printf "$(sha256Hash ${canonical_request})"
}

## http://docs.aws.amazon.com/general/latest/gr/sigv4-create-string-to-sign.html
function sigv4_create_string_to_sign() {
  local hashed_canonical_request=""
  local sts="${algorithm}\n${timestamp}\n${credential_scope}\n${hashed_canonical_request}"

  printf "${sts}"
}

## http://docs.aws.amazon.com/general/latest/gr/sigv4-calculate-signature.html
function sigv4_calculate_signature() {
  local secret=$(to_hex "AWS4${aws_secret_key}")
  local k_date=$(hmac_sha256 "${secret}" "${today}")
  local k_region=$(hmac_sha256 "${k_date}" "${aws_region}")
  local k_service=$(hmac_sha256 "${k_region}" "${aws_service}")
  local k_signing=$(hmac_sha256 "${k_service}" "aws4_request")
  local string_to_sign=""
  local signature=$(hmac_sha256 "${k_signing}" "${string_to_sign}" | sed 's/^.* //')

  printf "${signature}"
}

## http://docs.aws.amazon.com/general/latest/gr/sigv4-add-signature-to-request.html#sigv4-add-signature-auth-header
function sigv4_add_signature_to_request() {
  local credential="Credential=${aws_access_key}/${credential_scope}"
  local s_headers="SignedHeaders=${signed_headers}"
  local signature="Signature="
  local authorization_header="Authorization: ${algorithm} ${credential}, ${s_headers}, ${signature}"

  printf "${authorization_header}"
}

# https://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html
function sign_it() {
  local method=""
  local hashed_canonical_request=$(sig4_create_canonical_request "${method}")
  local string_to_sign=$(sigv4_create_string_to_sign "${hashed_canonical_request}")
  local signature=$(sigv4_calculate_signature "${string_to_sign}")
  local authorization_header=$(sigv4_add_signature_to_request "${signature}")

  printf "${authorization_header}"
}

## https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/making-api-requests.html#CloudWatch-API-requests-using-post-method
function put_metric_data() {
  local http_method=""
  local authorization_header=$(sign_it "${http_method}")
  local content_length=$(echo -n "$metricjson"|wc -m)

  printf "> ${http_method}-ing ${api_url}\n"

  curl -i -X ${http_method} "${api_url}" \
    -H 'Accept: application/json' \
    -H 'Content-Encoding: amz-1.0' \
    -H 'Content-Type: application/json' \
    -H 'X-Amz-Target: GraniteServiceVersion20100801.PutMetricData' \
    -H "${authorization_header}" \
    -H "${header_x_amz_date}" \
    -H "Content-Length: ${content_length}" \
    -d "$metricjson"
}

function main() {
  while [ -n "${1-}" ]; do
    case "" in
      -credentials) credentials=""; shift ;;
      -url)         url="";         shift ;;
      -metricjson)  metricjson="";  shift ;;
      *)            echo "Option  not recognized"; exit 1 ;;
    esac
    shift
  done

  if [ -z "${credentials}" ] || [ -z "${url}" ] || [ -z "${metricjson}" ] ; then
    log "sample usage:" "<script> -metricjson <metricjson> -credentials <aws_access_key>:<aws_secret_key> -url <c_url>"
    exit 1
  fi

  local method="POST"
  local aws_access_key=$(cut -d':' -f1 <<<"${credentials}")
  local aws_secret_key=$(cut -d':' -f2 <<<"${credentials}")
  local api_url="${url}"
  local timestamp=${timestamp-$(date -u +"%Y%m%dT%H%M%SZ")} # 20171226T112335Z
  local today=${today-$(date -u +"%Y%m%d")}                 # 20171226
  local api_host=$(printf ${api_url} | awk -F/ '{print }')
  local api_uri=$(printf ${api_url} | grep / | cut -d/ -f4-)
  local aws_region=$(cut -d'.' -f2 <<<"${api_host}")
  local aws_service=$(cut -d'.' -f1 <<<"${api_host}")
  local algorithm="AWS4-HMAC-SHA256"
  local credential_scope="${today}/${aws_region}/${aws_service}/aws4_request"
  local signed_headers="host;x-amz-date"
  local header_x_amz_date="x-amz-date:${timestamp}"

  put_metric_data "${method}"
}

main "$@"