読者です 読者をやめる 読者になる 読者になる

vague memory

うろ覚えを無くしていこうともがき苦しむ人の備忘録

Terraform Datadog Provider を試してみる

Datadog

Datadog 公式で Terraform を使った管理方法のブログが公開されていました。(多分2017/04/07公開)

Datadog Provider は結構前から用意されていたようですが、 触れたことが無かったので、ほぼDatadogブログの内容のままですが実際に使用してみます。


目次


Datadog Provider

Terraform 公式ドキュメントは以下です。

管理できるリソースは今の所以下の4つです。

  • Downtime
  • Monitor
  • Timeboard
  • User

Datadog API Key 設定

Terraform はインストール済みの前提です。 今回利用したバージョンは Terraform v0.9.2

tfvars

Datadog の API Key を設定した tfvars ファイルを作成します。

$ cat terraform.tfvars
datadog_api_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
datadog_app_key="YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"

tf

tfvars から API Key を読み込みます。main.tfとして作成しました。

$ cat main.tf
# Variables
variable "datadog_api_key" {}
variable "datadog_app_key" {}

# Configure the Datadog provider
provider "datadog" {
  api_key = "${var.datadog_api_key}"
  app_key = "${var.datadog_app_key}"
}

plan

API Key 設定を行った後、リソース部分が空の状態で plan 実行した結果が以下になります。 エラー出力されるようなら設定に何かしら誤りがあります。

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
# Variables
persisted to local or remote state storage.

No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, Terraform
doesn't need to do anything.

実行例(Monitor)

モニター定義を管理します。

パラメータ未指定での実行

パラメータを未指定で実行すると必須パラメータ不足のエラーとなります。

cat monitor.tf
# Monitors
resource "datadog_monitor" "cpumonitor" {
}
$ terraform plan
4 error(s) occurred:

* datadog_monitor.cpumonitors: "message": required field is not set
* datadog_monitor.cpumonitors: "name": required field is not set
* datadog_monitor.cpumonitors: "query": required field is not set
* datadog_monitor.cpumonitors: "type": required field is not set

必須パラメータ指定での実行

必須パラメータ name,type,message,query を指定してplan実行します。

$ cat monitor.tf
# Monitors
resource "datadog_monitor" "cpumonitor" {
  name = "cpu monitor"
  type = "metric alert"
  message = "CPU usage alert"
  query = "avg(last_1m):avg:system.cpu.system{*} by {host} > 60"
}
$ terraform plan
・・・
+ datadog_monitor.cpumonitor
    include_tags:        "true"
    message:             "CPU usage alert"
    name:                "cpu monitor"
    new_host_delay:      "<computed>"
    notify_no_data:      "false"
    query:               "avg(last_1m):avg:system.cpu.system{*} by {host} > 60"
    require_full_window: "true"
    type:                "metric alert"


Plan: 1 to add, 0 to change, 0 to destroy.

plan は問題無いので apply を実行します。

$ terraform apply
datadog_monitor.cpumonitor: Creating...
  include_tags:        "" => "true"
  message:             "" => "CPU usage alert"
  name:                "" => "cpu monitor"
  new_host_delay:      "" => "<computed>"
  notify_no_data:      "" => "false"
  query:               "" => "avg(last_1m):avg:system.cpu.system{*} by {host} > 60"
  require_full_window: "" => "true"
  type:                "" => "metric alert"
datadog_monitor.cpumonitor: Creation complete (ID: XXXX732)

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

実行結果

事前にインポートを行っていない限りは、新規作成となります。

f:id:htnosm:20170409231844p:plain

$ terraform show
datadog_monitor.cpumonitor:
  id = XXXX732
  include_tags = true
  message = CPU usage alert
  name = cpu monitor
  notify_no_data = false
  query = avg(last_1m):avg:system.cpu.system{*} by {host} > 60
  require_full_window = true
  type = metric alert
$ cat terraform.tfstate
{
    "version": 3,
    "terraform_version": "0.9.2",
    "serial": 0,
    "lineage": "f751ef78-ced3-4035-896b-aa0008b760e3",
    "modules": [
        {
            "path": [
                "root"
            ],
            "outputs": {},
            "resources": {
                "datadog_monitor.cpumonitor": {
                    "type": "datadog_monitor",
                    "depends_on": [],
                    "primary": {
                        "id": "XXXX732",
                        "attributes": {
                            "id": "XXXX732",
                            "include_tags": "true",
                            "message": "CPU usage alert",
                            "name": "cpu monitor",
                            "notify_no_data": "false",
                            "query": "avg(last_1m):avg:system.cpu.system{*} by {host} \u003e 60",
                            "require_full_window": "true",
                            "type": "metric alert"
                        },
                        "meta": {},
                        "tainted": false
                    },
                    "deposed": [],
                    "provider": ""
                }
            },
            "depends_on": []
        }
    ]
}

変更無しの状態で確認

何も変更を行っていない状態で、更新が掛からない事を確認します。

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

datadog_monitor.cpumonitor: Refreshing state... (ID: XXXX732)
No changes. Infrastructure is up-to-date.

This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, Terraform
doesn't need to do anything.
$ terraform apply
datadog_monitor.cpumonitor: Refreshing state... (ID: XXXX732)

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

更新

閾値を追加して更新を行います。

$ cat monitor.tf
# Monitors
resource "datadog_monitor" "cpumonitor" {
  name = "cpu monitor"
  type = "metric alert"
  message = "CPU usage alert"
  query = "avg(last_1m):avg:system.cpu.system{*} by {host} > 60"
  thresholds {
    ok = 20
    warning = 50
    critical = 60
  }
}
$ terraform plan
・・・
datadog_monitor.cpumonitor: Refreshing state... (ID: XXXX732)
・・・

~ datadog_monitor.cpumonitor
    thresholds.%:        "0" => "3"
    thresholds.critical: "" => "60"
    thresholds.ok:       "" => "20"
    thresholds.warning:  "" => "50"


Plan: 0 to add, 1 to change, 0 to destroy.
$ terraform apply
datadog_monitor.cpumonitor: Refreshing state... (ID: XXXX732)
datadog_monitor.cpumonitor: Modifying... (ID: XXXX732)
  thresholds.%:        "0" => "3"
  thresholds.critical: "" => "60"
  thresholds.ok:       "" => "20"
  thresholds.warning:  "" => "50"
datadog_monitor.cpumonitor: Modifications complete (ID: XXXX732)

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
・・・

更新結果

閾値設定されたことを確認できます。

f:id:htnosm:20170409231845p:plain

$ terraform show
datadog_monitor.cpumonitor:
  id = XXXX732
  escalation_message =
  include_tags = true
  locked = false
  message = CPU usage alert
  name = cpu monitor
  new_host_delay = 300
  no_data_timeframe = 0
  notify_audit = false
  notify_no_data = false
  query = avg(last_1m):avg:system.cpu.system{*} by {host} > 60
  renotify_interval = 0
  require_full_window = true
  silenced.% = 0
  tags.# = 0
  thresholds.% = 3
  thresholds.critical = 60.0
  thresholds.ok = 20.0
  thresholds.warning = 50.0
  timeout_h = 0
  type = metric alert

show結果を見ると、指定していないパラメータについても値が出力されています。
注意点としては、これらのデフォルト値は Datadog API ではなく、 Terraform provider 側で指定される事です。

削除

Terraformで管理している設定の削除を実行します。

$ terraform destroy
Do you really want to destroy?
  Terraform will delete all your managed infrastructure.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

datadog_monitor.cpumonitor: Refreshing state... (ID: XXXX732)
datadog_monitor.cpumonitor: Destroying... (ID: XXXX732)
datadog_monitor.cpumonitor: Destruction complete

Destroy complete! Resources: 1 destroyed.

f:id:htnosm:20170409231846p:plain

AWS EC2 インスタンス起動と合わせて Monitor 作成

他Providerと組み合わせる例として EC2インスタンスとの連携例がありました。

ec2.tf

$ cat ec2.tf
# Configure the AWS Provider
provider "aws" {
  access_key = "${var.aws_access_key}"
  secret_key = "${var.aws_secret_key}"
  region     = "ap-northeast-1"
}

resource "aws_instance" "base" {
  ami = "ami-859bbfe2" # Amazon Linux AMI 2017.03.0 (HVM), SSD Volume Type
  instance_type = "t2.micro"
}

resource "datadog_monitor" "cpumonitor" {
  name = "cpu monitor ${aws_instance.base.id}"
  type = "metric alert"
  message = "CPU usage alert"
  query = "avg(last_1m):avg:system.cpu.system{host:${aws_instance.base.id}} by {host} > 10"
  new_host_delay = 30
}

plan

$ terraform plan
・・・
+ aws_instance.base
    ami:                         "ami-859bbfe2"
    associate_public_ip_address: "<computed>"
    availability_zone:           "<computed>"
    ebs_block_device.#:          "<computed>"
    ephemeral_block_device.#:    "<computed>"
    instance_state:              "<computed>"
    instance_type:               "t2.micro"
    ipv6_addresses.#:            "<computed>"
    key_name:                    "<computed>"
    network_interface_id:        "<computed>"
    placement_group:             "<computed>"
    private_dns:                 "<computed>"
    private_ip:                  "<computed>"
    public_dns:                  "<computed>"
    public_ip:                   "<computed>"
    root_block_device.#:         "<computed>"
    security_groups.#:           "<computed>"
    source_dest_check:           "true"
    subnet_id:                   "<computed>"
    tenancy:                     "<computed>"
    vpc_security_group_ids.#:    "<computed>"

+ datadog_monitor.cpumonitor
    include_tags:        "true"
    message:             "CPU usage alert"
    name:                "cpu monitor ${aws_instance.base.id}"
    new_host_delay:      "30"
    notify_no_data:      "false"
    query:               "avg(last_1m):avg:system.cpu.system{host:${aws_instance.base.id}} by {host} > 10"
    require_full_window: "true"
    type:                "metric alert"


Plan: 2 to add, 0 to change, 0 to destroy.

apply

$ terraform apply
aws_instance.base: Creating...
  ami:                         "" => "ami-859bbfe2"
  associate_public_ip_address: "" => "<computed>"
  availability_zone:           "" => "<computed>"
  ebs_block_device.#:          "" => "<computed>"
  ephemeral_block_device.#:    "" => "<computed>"
  instance_state:              "" => "<computed>"
  instance_type:               "" => "t2.micro"
  ipv6_addresses.#:            "" => "<computed>"
  key_name:                    "" => "<computed>"
  network_interface_id:        "" => "<computed>"
  placement_group:             "" => "<computed>"
  private_dns:                 "" => "<computed>"
  private_ip:                  "" => "<computed>"
  public_dns:                  "" => "<computed>"
  public_ip:                   "" => "<computed>"
  root_block_device.#:         "" => "<computed>"
  security_groups.#:           "" => "<computed>"
  source_dest_check:           "" => "true"
  subnet_id:                   "" => "<computed>"
  tenancy:                     "" => "<computed>"
  vpc_security_group_ids.#:    "" => "<computed>"
aws_instance.base: Still creating... (10s elapsed)
aws_instance.base: Still creating... (20s elapsed)
aws_instance.base: Creation complete (ID: i-0XXXXXXXXXXX6f52e)
datadog_monitor.cpumonitor: Creating...
  include_tags:        "" => "true"
  message:             "" => "CPU usage alert"
  name:                "" => "cpu monitor i-0XXXXXXXXXXX6f52e"
  new_host_delay:      "" => "30"
  notify_no_data:      "" => "false"
  query:               "" => "avg(last_1m):avg:system.cpu.system{host:i-0XXXXXXXXXXX6f52e} by {host} > 10"
  require_full_window: "" => "true"
  type:                "" => "metric alert"
datadog_monitor.cpumonitor: Creation complete (ID: XXXX862)

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
・・・
|        AZ        |      InstanceId       | InstanceType  |  State   |
+------------------+-----------------------+---------------+----------+
|  ap-northeast-1a |  i-0XXXXXXXXXXX6f52e  |  t2.micro     |  running |

f:id:htnosm:20170409233431p:plain

WebUI上での手動更新を行う

変更点が無い状態であることを確認します。

$ terraform plan
・・・
aws_instance.base: Refreshing state... (ID: i-0XXXXXXXXXXX6f52e)
datadog_monitor.cpumonitor: Refreshing state... (ID: XXXX862)
No changes. Infrastructure is up-to-date.
・・・

DatadogのWebUI上でMonitorを更新します。

f:id:htnosm:20170409231848p:plain

再度planを実行します。

$ terraform plan -target datadog_monitor.cpumonitor
・・・
aws_instance.base: Refreshing state... (ID: i-0XXXXXXXXXXX6f52e)
datadog_monitor.cpumonitor: Refreshing state... (ID: XXXX862)
・・・
~ datadog_monitor.cpumonitor
    name:                "cpu monitor terraform-dd-test" => "cpu monitor i-0XXXXXXXXXXX6f52e"
    no_data_timeframe:   "2" => "0"
    thresholds.%:        "1" => "0"
    thresholds.critical: "10.0" => ""


Plan: 0 to add, 1 to change, 0 to destroy.

変更をしていないパラメータも変更有りと認識されるようになってしまいました。 Datadog Provider に限りませんが、意図しない更新には注意が必要です。

まとめ

Terraform でのホスト管理にDatadog監視設定も併せて設定できます。 Datadog上のリソースはID指定となっているため、他の設定に影響することも無く、使い勝手は良いと思います。
期間限定で起動するインスタンスで他の設定に影響を与えず、管理・更新する等で使えそうです。

Datadog DogPushの使い方

Datadog

Datadog の Help でも紹介されている、Monitor の管理ツールの DogPush に触れる機会があったので、使い方をまとめます。

f:id:htnosm:20170402235739j:plain


目次


前提・注意事項

基本的には全Monitorが対象

タグ等による絞り込み機能はありません。 出力や比較には全 Monitor の定義が使用されます。

同名 Monitor は未サポート

Datadog の Monitor は 同名の物を定義できますが、dogpush では未サポートとなります。
Monitor 名称で管理しているため重複エラーとなります。 dogpush に限らず、 Datadog のツール系はこの制約に引っ掛かる事が多い気がします。

$ dogpush init
Duplicate name: MonitorTest4
Traceback (most recent call last):
  File "/usr/bin/dogpush", line 5, in <module>
    dogpush.main()
  File "/usr/lib/python2.7/site-packages/dogpush/dogpush.py", line 397, in main
    args.command()
  File "/usr/lib/python2.7/site-packages/dogpush/dogpush.py", line 215, in command_init
    remote_monitors = [m['obj'] for m in get_datadog_monitors().values()]
  File "/usr/lib/python2.7/site-packages/dogpush/dogpush.py", line 139, in get_datadog_monitors
    'Duplicate names found in remote datadog monitors.')
dogpush.dogpush.DogPushException: Duplicate names found in remote datadog monitors.

Message が空の Monitor は未サポート

f:id:htnosm:20170402235740p:plain

実運用ではあまり無いかと思いますが、 現バージョンでは本文部分が空の場合に失敗します。Web UI 上では空での作成は不可ですが、APIだと作成できてしまいます。
message 部分に以下のようなメッセージが含まれてしまい、出力内容をそのまま利用することができません。

- message: !!python/unicode ''

一見上記部分を排除すれば利用できそうですが、重複エラーに引っ掛かります。

インストール

README を参考にインストールを行います。 今回は素に近い CentOS7 で試してます。必要パッケージは環境により変わると思います。

$ cat /etc/redhat-release
CentOS Linux release 7.3.1611 (Core)
$ python -V
Python 2.7.5
$ sudo yum install python2-pip openssl-devel python-devel libffi-devel
・・・
Complete!
$ pip -V
pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7)
$ sudo pip install -U pip dogpush
・・・
Successfully installed PyYAML-3.12 datadog-0.15.0 decorator-4.0.11 dogpush-0.3.3 pip-9.0.1 pytz-2017.2 requests-2.13.0 simplejson-3.10.0
$ pip -V
pip 9.0.1 from /usr/lib/python2.7/site-packages (python 2.7)
$ dog -v
dog 0.15.0
$ dogpush -h
usage: dogpush [-h] [--config CONFIG] {init,push,diff,mute} ...

positional arguments:
  {init,push,diff,mute}
                        sub-command help
    init                init new alerts file
    push                push monitors to datadog
    diff                show diff between local monitors and datadog
    mute                Mute alerts based on their `mute_when` key

optional arguments:
  -h, --help            show this help message and exit
  --config CONFIG, -c CONFIG
                        configuration file to load (default: ./config.yaml)

datadog パッケージが依存関係として含まれるため、 dogshell(dogコマンド)もインストールされます。
尚、後述 delete_untracked オプションで記載していますが、バージョンが古いようでしたので再度 GitHub からインストールし直しています。

config.yaml ファイル

Datadog の Key 情報を定義する config.yaml が無いとエラーとなります。

$ dogpush init
Traceback (most recent call last):
  File "/usr/bin/dogpush", line 3, in <module>
    from dogpush import dogpush
  File "/usr/lib/python2.7/site-packages/dogpush/dogpush.py", line 391, in <module>
    CONFIG = _load_config(args.config)
  File "/usr/lib/python2.7/site-packages/dogpush/dogpush.py", line 29, in _load_config
    with open(config_file, 'r') as f:
IOError: [Errno 2] No such file or directory: './config.yaml'

config.yaml の作成

Datadog の API Key、App Key を記載します。

cat <<_EOF > config.yaml
datadog:
  api_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
  app_key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
_EOF

デフォルトルール(default_rules)

パラメータ未指定時の既定値となる値を指定します。 README 上は multi,message とありますが、 実際は multi,type かと思います。

ルール 既定値 内容
multi False Multi アラートか否か {true, false}
type metric alert モニターのタイプ {metric alert, service check, event alert}

init,diff 時は config で指定した値は未出力となり、 push 時は既定値として設定されます。 そのため、本来 metric alert である設定項目に対し、service check をデフォルト値とした場合等はAPIエラーとなります。

$ dogpush push
Pushing 1 new monitors.
Traceback (most recent call last):
  File "/usr/bin/dogpush", line 5, in <module>
    pkg_resources.run_script('DogPush==0.3.3', 'dogpush')
  File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 540, in run_script
    self.require(requires)[0].run_script(script_name, ns)
  File "/usr/lib/python2.7/site-packages/pkg_resources.py", line 1455, in run_script
    execfile(script_filename, namespace, namespace)
  File "/usr/lib/python2.7/site-packages/DogPush-0.3.3-py2.7.egg/EGG-INFO/scripts/dogpush", line 5, in <module>
    dogpush.main()
  File "/usr/lib/python2.7/site-packages/DogPush-0.3.3-py2.7.egg/dogpush/dogpush.py", line 407, in main
    args.command(args)
  File "/usr/lib/python2.7/site-packages/DogPush-0.3.3-py2.7.egg/dogpush/dogpush.py", line 230, in command_push
    datadog.api.Monitor.create(**_prepare_monitor(local_monitors[name]))
  File "/usr/lib/python2.7/site-packages/datadog/api/resources.py", line 40, in create
    attach_host_name=attach_host_name, **params)
  File "/usr/lib/python2.7/site-packages/datadog/api/api_client.py", line 150, in submit
    raise ApiError(response_obj)
datadog.api.exceptions.ApiError: {'errors': ["The value provided for parameter 'query' is invalid"]}

デフォルトルールオプション(default_rule_options)

使い方がわかりませんでした。 config.yaml へ記述すると AssertionError となってしまい、利用できませんでした。
ルールファイル(〜.yaml) へ記述して既定値を設定するのかと思いましたが、ルールファイルへの記述は無視されました。

チーム(teams)

通知設定を記述できます。 config.yaml へ通知先の指定を行い、各ルールファイルの先頭で定義したteamを指定します。
各 monitor 設定で severity を指定することで通知先の振分が行えます。

  • config.yamlへの記載例
    • シングルクォート囲み必須
    • servirity は CRITICAL がデフォルト、その他は任意文字列可
teams:
  team-A:
    notifications:
      CRITICAL: '@hoge@example.com @slack-XXXXX'
      WARNING: '@hoge@example.com'
      INFO: '通知無し'
      FATAL: 'Fatal @all'
  team-B:
    notifications:
      CRITICAL: '@hoge@example.com'
  • ルール yaml への記載例(team)
$ head -n 3 monitors.team*
==> monitors.team1.yaml <==
team: team-A

alerts:

==> monitors.team2.yaml <==
team: team-B

alerts:
  • ルール yaml への記載例(severity)
- message: 'Test Team Alert 1-1'
  name: TeamAlert1-1
  options: {new_host_delay: 300, require_full_window: true, thresholds: {critical: 50.0, warning: 30.0}}
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50

- message: 'Test Team Alert 1-2'
  name: TeamAlert1-2
  options: {new_host_delay: 300, require_full_window: true, thresholds: {critical: 50.0, warning: 30.0}}
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50
  severity: WARNING

- message: 'Test Team Alert 1-3'
  name: TeamAlert1-3
  options: {new_host_delay: 300, require_full_window: true, thresholds: {critical: 50.0, warning: 30.0}}
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50
  severity: INFO

- message: 'Test Team Alert 1-4'
  name: TeamAlert1-4
  options: {new_host_delay: 300, require_full_window: true, thresholds: {critical: 50.0, warning: 30.0}}
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50
  severity: FATAL

message 末尾に通知設定を追加することができます。

{"name":"TeamAlert1-1","message":"Test Team Alert 1-1\n@hoge@example.com @slack-XXXXX"}
{"name":"TeamAlert1-2","message":"Test Team Alert 1-2\n@hoge@example.com"}
{"name":"TeamAlert1-3","message":"Test Team Alert 1-3\n通知無し"}
{"name":"TeamAlert1-4","message":"Test Team Alert 1-4\nFatal @all"}

init コマンド

全 Monitor を対象とした YAML を出力します。
絞り込みのオプションはありません。

usage: dogpush init [-h]

実行例

そのまま実行すると標準出力となるため、リダイレクトなどでファイル出力とすることになると思います。

$ dogpush init
# team: TEAMNAME

alerts:

- message: 'Test2: alert message to @hoge@example.com'
  multi: true
  name: MonitorTest2
  options: {new_host_delay: 300, notify_no_data: false, require_full_window: true}
  overall_state_modified: 'yyyy-mm-ddThh:mm:ss.560069+00:00'
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50

- message: 'Test3: alert message to @hoge@example.com'
  multi: true
・・・略
$ dogpush init > my_monitors.yaml
$

diff コマンド

Datadog 上の Monitor 登録内容とローカルのYAMLとの比較を行います。
対象とする monitor 定義(ここでは my_monitors.yaml) を config.yaml へ追加した上で利用します。

cat <<_EOF >> config.yaml
rule_files:
- my_monitors.yaml
_EOF

差分が無い場合は何も出力されません。

$ dogpush diff
$

差分がある場合は diff 結果が出力されます。

$ dogpush diff
---------------------------------------------------------
 TO BE UPDATED.  These monitors exist in datadog, but are
 different than the local version.  Use "dogpush push"
 to push them to datadog.
---------------------------------------------------------

--- datadog:MonitorTest2
+++ /home/vagrant/dogpush/my_monitors.yaml:MonitorTest2
@@ -1,4 +1,4 @@
-message: 'Test2: alert message to @hoge@example.com'
+message: 'Test2: alert message to @hoge@example.com Update'
 multi: true
 name: MonitorTest2
 options: {new_host_delay: 300, notify_no_data: false, require_full_window: true}
$

差分が name の場合は更新ではなく、新規追加として扱われます。

$ dogpush diff
---------------------------------------------------------
 NEW MONITORS.  These monitors are currently missing in
 datadog and can be pushed using "dogpush push"
---------------------------------------------------------

- message: MonitorTest1
  multi: true
  name: MonitorTest1 Update
  options:
    new_host_delay: 300
    no_data_timeframe: 2
    notify_no_data: false
    renotify_interval: 0
    require_full_window: true
    thresholds: {critical: 50.0}
    timeout_h: 0
  overall_state_modified: 'yyyy-mm-ddThh:mm:ss.560069+00:00'
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50

------------------------------------------------------------
 UNTRACKED MONITORS.  These monitors are only in datadog
 and needed to be MANUALLY added to a local file or removed
 from datadog.
------------------------------------------------------------

- message: MonitorTest1
  multi: true
  name: MonitorTest1
  options:
    new_host_delay: 300
    no_data_timeframe: 2
    notify_no_data: false
    renotify_interval: 0
    require_full_window: true
    thresholds: {critical: 50.0}
    timeout_h: 0
  overall_state_modified: 'yyyy-mm-ddThh:mm:ss.560069+00:00'
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50

*** FAILED *** Untracked monitors found.

push コマンド

Datadog 上の Monitor へローカルのYAMLの変更点を反映します。
対象とする monitor を config.yaml へ追加した上で利用します。

usage: dogpush push [-h]
$ dogpush push
Pushing 1 new monitors.
Updating 1 modified alerts

削除は行われません。 その為、 nameの変更を行った場合は別途削除が必要になります。

  • name を更新した場合、更新前の情報が残る
------------------------------------------------------------
 UNTRACKED MONITORS.  These monitors are only in datadog
 and needed to be MANUALLY added to a local file or removed
 from datadog.
------------------------------------------------------------

- message: MonitorTest1
  multi: true
  name: MonitorTest1
  options:
    new_host_delay: 300
    no_data_timeframe: 2
    notify_no_data: false
    renotify_interval: 0
    require_full_window: true
    thresholds: {critical: 50.0}
    timeout_h: 0
  overall_state_modified: 'yyyy-mm-ddThh:mm:ss.560069+00:00'
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50

*** FAILED *** Untracked monitors found.

delete_untracked オプション

yaml に含まれていない monitor を削除するオプションです。
pip からインストールした物は少々バージョンが古いようで、使用できませんでした。

$ dogpush push --delete_untracked
usage: dogpush [-h] [--config CONFIG] {init,push,diff,mute} ...
dogpush: error: unrecognized arguments: --delete_untracked

GitHub 上では追加されているようでしたので、 git clone して再導入します。

# pip でインストールしたバージョンの削除
$ sudo pip uninstall dogpush
Uninstalling DogPush-0.3.3:
  /usr/bin/dogpush
  /usr/lib/python2.7/site-packages/DogPush-0.3.3-py2.7.egg
Proceed (y/n)? y
  Successfully uninstalled DogPush-0.3.3
# GitHub からインストール
$ git clone https://github.com/trueaccord/DogPush.git
$ cd DogPush
$ sudo python setup.py install
・・・
Finished processing dependencies for DogPush==0.3.3
# dlete_untracked オプションが追加されていることを確認
$ dogpush push -h
usage: dogpush push [-h] [-d]

optional arguments:
  -h, --help            show this help message and exit
  -d, --delete_untracked
                        Delete untracked monitors.

オプションを付けた状態で実行すると monitor の削除が行われます。

$ dogpush push --delete_untracked
Deleting 1 untracked monitors.
$ dogpush diff
$

mute コマンド

mute_tags を定義済みの Monitor へ Downtime を設定します。

usage: dogpush mute [-h]

mute_tags 定義

config.yaml へ mute 対象時間帯の定義を行い、各 monitor 設定で mute_when を指定することで mute 対象モニターとします。

  • config.yamlへの記載例
mute_tags:
  mute_a:
    timezone: Asia/Tokyo
    expr: now.hour < 10 or now.hour > 19
  • ルール yaml への記載例(mute_when)
- message: 'Test MuteAlert'
  name: MuteAlert
  options: {new_host_delay: 300, require_full_window: true, thresholds: {critical: 50.0, warning: 30.0}}
  query: avg(last_5m):max:system.cpu.user{*} by {host} >= 50
  mute_when: mute_a
  • 実行例
$ dogpush mute
Muting alert 'MuteAlert' until yyyy-mm-dd 10:00:00+09:00

対象モニターが mute 状態となります。

f:id:htnosm:20170402235741p:plain

Downtimes でも確認できます。

f:id:htnosm:20170402235742p:plain

まとめ

Datadog 公式の dogshell には monitor の pull/push がありません(ダッシュボード screenboard/timeboard 操作は用意されていますが、 monitor はありません。)ので、 その部分を補完できると思います。
注意事項に記載した通りいくつか制約はありますが、 YAML での記述となるので、JSONファイルよりは扱い易いかと思いました。

Datadog (dogコマンド) service_check編

Datadog

Datadog公式のツール dog 使用方法まとめ service_check 編です。

f:id:htnosm:20170325135420p:plain

service_check Modes

カスタムステータスチェックの送信を行います。 APIcheck_run が該当します。

check

usage: dog service_check check [-h] [--timestamp TIMESTAMP]
                               [--message MESSAGE] [--tags TAGS]
                               check host_name status

positional arguments:

引数 説明
check 送信メッセージ
host_name 関連ホスト名
status ステータス値。整数。(‘0’:OK, ‘1’:WARNING, ‘2’:CRITICAL, ‘3’:UNKNOWN)

optional arguments:

ロングオプション 説明
–timestamp イベント発生日時。POSIX。(デフォルト現在日時)
–message ステータス値の説明
–tags タグを付与

実行例

timestamp、message オプションは必須のようです。
message 未指定だとエラーとなり、 timestamp 未指定だと Datadog(WebUI)側で表示されませんでした。

# message 未指定
$ dog service_check check "customService" "$(uname -n)" 0
ERROR: "message" parameter should be a string
# message 指定
$ dog service_check check --timestamp $(date +'%s') --message "CustomServiceMessage" "customService" "$(uname -n)" 0
{"status": "ok"}

正常に登録できた場合、[Check Summary]に表示されます。

f:id:htnosm:20170325135421p:plain

host_name に指定した値の host: タグが付与されます。

f:id:htnosm:20170325135423p:plain

Monitor(Custom Check) 作成時の指定も可能になります。

f:id:htnosm:20170325135422p:plain

tag オプション

任意のタグを付与します。
複数タグはできないようです。 (タブ区切り、スペース区切りを試しましたが、 _ に置換され結合されてしまいました。)

$ dog service_check check --timestamp $(date +'%s') --message "CustomServiceMessage" "customService" --tags "stage:dev" "$(uname -n)" 0
{"status": "ok"}

f:id:htnosm:20170325135424p:plain

status 値

status に不正な値を入れるとエラーが返ります。

Traceback (most recent call last):
  File "/usr/bin/dog", line 9, in <module>
    load_entry_point('datadog==0.15.0', 'console_scripts', 'dog')()
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/__init__.py", line 69, in main
    args.func(args)
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/service_check.py", line 34, in _check
    timestamp=args.timestamp, message=args.message, tags=args.tags)
  File "/usr/lib/python2.7/site-packages/datadog/api/service_checks.py", line 37, in check
    % ', '.join(str(v) for v in CheckStatus.ALL))
datadog.api.exceptions.ApiError: Invalid status, expected one of: 0, 1, 2, 3

message 値

Monitor に {{check_message}} を設定することで、 –message で指定した内容を通知に含むことができます。

f:id:htnosm:20170325135426p:plain

  • Slackへの通知例

f:id:htnosm:20170325135425p:plain


0からカスタムチェックを作成するよりは、手軽に実装できると思います。

Datadog (dogコマンド) downtime編

Datadog

Datadog公式のツール dog 使用方法まとめ downtime 編です。

f:id:htnosm:20170325135413p:plain


目次


downtime Modes

downtime 設定を行います。

f:id:htnosm:20170325135414p:plain

サブコマンド 説明
show ダウンタイム情報出力
show_all 全ダウンタイム情報出力
post ダウンタイムスケジュール作成
update ダウンタイムスケジュール更新
delete ダウンタイムスケジュール削除

show

ダウンタイム情報を出力します。

usage: dog downtime show [-h] downtime_id

実行例

JSON 形式で出力されます。

$ downtime_id=XXXXXXXX2
$ dog downtime show ${downtime_id} | jq '.'
{
  "recurrence": null,
  "end": null,
  "parent_id": null,
  "monitor_id": null,
  "start": NNNNNNNNN4,
  "disabled": false,
  "canceled": null,
  "creator_id": XXXXX8,
  "scope": [
    "host:i-XXXXXXXX"
  ],
  "active": true,
  "timezone": "UTC",
  "message": null,
  "id": XXXXXXXX2,
  "updater_id": null
}

show_all

全ダウンタイム情報を出力します。

usage: dog downtime show_all [-h] [--current_only CURRENT_ONLY]

optional arguments:

ロングオプション 説明
–current_only CURRENT_ONLY を指定。active=true のみ出力

実行例

オプション無し

JSON 形式で出力されます。 active = false (Web画面上表示されない) 設定も含めて返却されます。

$ dog downtime show_all | jq '.'
[
  {
    "recurrence": null,
    "end": null,
    "parent_id": null,
    "monitor_id": null,
    "start": NNNNNNNNN1,
    "disabled": true,
    "canceled": NNNNNNNNN6,
    "creator_id": XXXXX8,
    "scope": [
      "host:i-XXXXXXXX"
    ],
    "active": false,
    "timezone": "UTC",
    "message": null,
    "id": XXXXXXXX3,
    "updater_id": XXXXX8
  },
・・・略
  {
    "recurrence": null,
    "end": null,
    "parent_id": null,
    "monitor_id": XXXXXXXX8,
    "start": NNNNNNNNN4,
    "disabled": false,
    "canceled": null,
    "creator_id": XXXXX8,
    "scope": [
      "*"
    ],
    "active": true,
    "timezone": "UTC",
    "message": "Monitor muted from web",
    "id": XXXXXXXX9,
    "updater_id": null
  },
・・・略
  }
]

current_only オプション

active = true (Web画面上表示される) 設定のみ返却されます。 ロングオプション指定のみではなく、--current_only CURRENT_ONLY の記述が必要です。

$ dog downtime show_all --current_only CURRENT_ONLY | jq '.'
[
  {
    "recurrence": null,
    "end": null,
    "parent_id": null,
    "monitor_id": null,
    "start": NNNNNNNNN4,
    "disabled": false,
    "canceled": null,
    "creator_id": XXXXX8,
    "scope": [
      "host:i-XXXXXXXX"
    ],
    "active": true,
    "timezone": "UTC",
    "message": null,
    "id": XXXXXXXX2,
    "updater_id": null
  },
  {
    "recurrence": null,
    "end": null,
    "parent_id": null,
    "monitor_id": null,
    "start": NNNNNNNNN7,
    "disabled": false,
    "canceled": null,
    "creator_id": null,
    "scope": [
      "host:i-XXXXXXXXXXXXXXXXX"
    ],
    "active": true,
    "timezone": "UTC",
    "message": "This manually stopped or terminated AWS instance has been automatically silenced by Datadog.\n\nAWS reported host i-XXXXXXXXXXXXXXXXX as 'stopping' with the reason: 'Client.UserInitiatedShutdown: User initiated (yyyy-mm-dd hh:mm:ss GMT)'",
    "id": XXXXXXXX1,
    "updater_id": null
  },
  {
    "recurrence": null,
    "end": null,
    "parent_id": null,
    "monitor_id": XXXXXXXX8,
    "start": NNNNNNNNN4,
    "disabled": false,
    "canceled": null,
    "creator_id": XXXXX8,
    "scope": [
      "*"
    ],
    "active": true,
    "timezone": "UTC",
    "message": "Monitor muted from web",
    "id": XXXXXXXX9,
    "updater_id": null
  }
]

自動で作成される automatically muted hosts のダウンタイムも含みます。

f:id:htnosm:20170325135415p:plain

post

ダウンタイムスケジュールを作成します。

usage: dog downtime post [-h] [--end END] [--message MESSAGE] scope start

Monitor 指定、繰り返しスケジュールは未サポートです。 APIとしては存在します。(monitor_id指定はドキュメント記載が無いです。)

f:id:htnosm:20170325135418p:plain

positional arguments:

引数 説明
scope 適用対象タグ
start 開始日時を指定。POSIX timestamp

optional arguments:

ロングオプション 説明
–end 終了日時を指定。POSIX timestamp。指定無しの場合は forever(無限)
–message 関連付けるメッセージ本文

実行例

オプション無し

スコープ、開始日時を指定する必要があります。(現在日時の自動設定はありません)

$ dog downtime post "*" "$(date +'%s')" | jq '.'
{
  "recurrence": null,
  "end": null,
  "parent_id": null,
  "monitor_id": null,
  "start": NNNNNNNNN9,
  "disabled": false,
  "canceled": null,
  "creator_id": XXXXX8,
  "scope": [
    "*"
  ],
  "active": true,
  "timezone": "UTC",
  "message": null,
  "id": XXXXXXXX4,
  "updater_id": null
}

message オプション

downtime にメッセージを関連付けます。各種通知を行うことも可能です。

$ dog downtime post --end "$(date -d '1 hour' +'%s')" --message "1時間止めます @slack-xxxxxx" "*" "$(date +'%s')" | jq '.'
{
  "recurrence": null,
  "end": NNNNNNNNN3,
  "parent_id": null,
  "monitor_id": null,
  "start": NNNNNNNNN3,
  "disabled": false,
  "canceled": null,
  "creator_id": XXXXX8,
  "scope": [
    "*"
  ],
  "active": true,
  "timezone": "UTC",
  "message": "1時間止めます @slack-xxxxxx",
  "id": XXXXXXXX8,
  "updater_id": null
}

f:id:htnosm:20170325135416p:plain

  • Slackへの通知例

f:id:htnosm:20170325135417p:plain

update

ダウンタイムスケジュールを更新します。post とほぼ同じ構文で、対象の downtime_id を指定します。
scope,start は必須オプションではなくなっています。(部分更新可能)

usage: dog downtime update [-h] [--scope SCOPE] [--start START] [--end END]
                           [--message MESSAGE]
                           downtime_id

実行例

$ dog downtime update --start "$(date -d '1 hour' +'%s')" --end "$(date -d '2 hour' +'%s')" --message "開始を1時間遅らせます" ${downtime_id} | jq '.'
{
  "recurrence": null,
  "end": NNNNNNNNN1,
  "parent_id": null,
  "monitor_id": null,
  "start": NNNNNNNNN1,
  "disabled": false,
  "canceled": null,
  "creator_id": XXXXX8,
  "scope": [
    "*"
  ],
  "active": false,
  "timezone": "UTC",
  "message": "開始を1時間遅らせます",
  "id": XXXXXXXX8,
  "updater_id": XXXXX8
}

f:id:htnosm:20170325135419p:plain

start > end を指定した場合はエラーとなります。

$ dog downtime update --start "$(date -d '2 hour' +'%s')" --end "$(date -d '1 hour' +'%s')" --message "start > end で指定" ${downtime_id} | jq '.'
ERROR: Downtime cannot end before it begins

delete

ダウンタイムスケジュールを削除します。

usage: dog downtime delete [-h] downtime_id

実行例

レスポンスはありません。 disabled = true が設定されます。(WebUI上は表示されなくなります。)

$ dog downtime delete ${downtime_id}
$
$ dog downtime show ${downtime_id} | jq '.'
{
  "recurrence": null,
  "end": NNNNNNNNN1,
  "parent_id": null,
  "monitor_id": null,
  "start": NNNNNNNNN1,
  "disabled": true,
  "canceled": XXXXXXXX8,
  "creator_id": XXXXX8,
  "scope": [
    "*"
  ],
  "active": false,
  "timezone": "UTC",
  "message": "開始を1時間遅らせます",
  "id": XXXXXXXX8,
  "updater_id": XXXXX8
}

Datadog (dogコマンド) host編

Datadog

Datadog公式のツール dog 使用方法まとめ host 編です。

f:id:htnosm:20170325010528p:plain


目次


host Modes

host とありますが、操作できるのは mute|unmute のみです。

サブコマンド 説明
mute ホストのmute(通知無効化)
unmute ホストのunmute(通知無効化解除)

mute

usage: dog host mute [-h] [--end END] [--message MESSAGE] [--override]
                     host_name

optional arguments:

ロングオプション 説明
–end 終了日時を指定。POSIX timestamp。指定無しの場合は forever(無限)
–message 関連付けるメッセージ本文
–override 既に mute 状態の場合でも終了期間を上書きする

実行例

$ host_name="i-XXXXXXXX"
$ dog host mute ${host_name}
{"action": "Muted", "downtime_id": XXXXXXX33, "hostname": "i-XXXXXXXX"}

[Infrastracture List]、または、[Manage Downtime] で確認できます。

f:id:htnosm:20170325010529p:plain

デフォルトで設定されるスケジュールは登録日時から Forever です。

f:id:htnosm:20170325010530p:plain

既に mute 済みの場合は override オプションを使用するようメッセージが出力されます。

$ dog host mute ${host_name}
ERROR: host:i-XXXXXXXX is already muted. To mute this host with a different end timestamp,                             add ?override=true to your request.

message オプション

downtime にメッセージを関連付けます。各種通知を行うことも可能です。

$ dog host mute --end $(date -d '1 hour' +'%s') --message "1時間無効化します @slack-xxxxxx" ${host_name}
{"action": "Muted", "downtime_id": XXXXXXX73, "hostname": "i-XXXXXXXX", "end": NNNNNNNNN9, "message": "1\u6642\u9593\u7121\u52b9\u5316\u3057\u307e\u3059 @slack-xxxxxx"}

f:id:htnosm:20170325010532p:plain

指定したスケジュール(登録日時から1時間)、通知設定が入ります。

f:id:htnosm:20170325010533p:plain

  • Slackへの通知例

f:id:htnosm:20170325010534p:plain

既に mute 済みの場合は、end、message 共に更新不可です。オプション無し時と同様に override オプションを使用するようメッセージが出力されます。

$ dog host mute --end $(date -d '2 hour' +'%s') --message "2時間無効化に伸ばします" ${host_name}
ERROR: host:i-XXXXXXXX is already muted. To mute this host with a different end timestamp,                             add ?override=true to your request.

override オプション

unmuteの状態に加え、既にmute済みでも更新できるようになります。

$ dog host mute --end $(date -d '2 hour' +'%s') --message "2時間無効化に伸ばします" --override ${host_name}
{"action": "Muted", "downtime_id": XXXXXXX75, "hostname": "i-XXXXXXXX", "end": NNNNNNNNN0, "message": "2\u6642\u9593\u7121\u52b9\u5316\u306b\u4f38\u3070\u3057\u307e\u3059"}

f:id:htnosm:20170325010535p:plain

unmute

オプションはありません。

usage: dog host unmute [-h] host_name

実行例

$ host_name="i-XXXXXXXX"
$ dog host unmute ${host_name}
{"action": "Unmuted", "downtime_id": XXXXXXX33, "hostname": "i-XXXXXXXX"}

f:id:htnosm:20170325010531p:plain

unmute 済みの場合はメッセージ出力のみです。

$ dog host unmute ${host_name}
ERROR: host:i-XXXXXXXX is not muted.

monitor {mute|unmute} コマンドはモニターを軸にタグ(スコープ)による指定を行うのに対し、 指定 host 単体の全モニターが対象になります。 対象ホストをメンテナンス(mute)状態にしたい場合に利用できると思います。

Datadog (dogコマンド) screenboard編

Datadog

Datadog公式のツール dog 使用方法まとめ screenboard 編です。

f:id:htnosm:20170323212159p:plain


目次


screenboard Modes

ダッシュボード(screenboard) 操作を行います。

f:id:htnosm:20170323212200p:plain

サブコマンド 説明
show スクリーンボード情報出力
post スクリーンボード新規作成
update スクリーンボード更新
pull スクリーンボード定義取得
push スクリーンボード更新
new_file スクリーンボードの新規作成と定義取得 (post後にpull)
delete スクリーンボードの削除
share Public URL の払い出し
revoke Public URL の削除

timeboard と異なる点としては、show_all、pull_all、web_view が無い事と、 public URL を操作する shore,revoke がある事です。

JSON形式で定義することになりますが、 1からJSONを作るのは中々難しいため、 参照用のスクリーンボードを用意して確認します。

  • サンプルスクリーンボード

f:id:htnosm:20170323212201p:plain

show

スクリーンボード定義を出力します。JSON形式で出力されます。

usage: dog screenboard show [-h] screenboard_id

前述の通り、全ダッシュボードを対象としたリスト出力(show_all)は未サポートです。 (APIとしては存在します)

実行結果

$ board_id=XXXXX3
$ dog screenboard show ${board_id} | jq '.'
{
  "board_title": "SampleScreenBoard",
  "read_only": false,
  "isIntegration": false,
  "board_bgtype": "board_graph",
  "created": "yyyy-mm-ddThh:mm:ss.454510+00:00",
  "original_title": "SampleScreenBoard",
  "modified": "yyyy-mm-ddThh:mm:ss.634253+00:00",
  "disableEditing": false,
  "height": 80,
  "width": "100%",
  "template_variables": [
    {
      "default": "*",
      "prefix": null,
      "name": "scope"
    },
・・・略
    }
  ],
  "templated": true,
  "widgets": [
    {
      "metric": "aws.ec2.host_ok",
・・・略
      },
      "res_calc_func": "raw",
      "aggr": "sum",
      "y": 13,
      "calc_func": "raw"
    },
・・・略
    }
  ],
  "disableCog": false,
  "id": XXXXX3,
  "title_edited": false,
  "isShared": false
}
# 存在しないID指定の場合
$ dog screenboard show ${board_id}X | jq '.'
ERROR: The value provided for parameter 'board_id' is invalid

post

スクリーンボードを作成します。

usage: dog screenboard post [-h] [--template_variables TEMPLATE_VARIABLES]
                            [--width WIDTH] [--height HEIGHT]
                            title description [graphs]

意図した動作となりません
新規スクリーンボードの作成は行えましたが、APIに問題があるようで、指定値が反映されません。

positional arguments:

引数 説明
title スクリーンボード名
description スクリーンボードの説明
graphs グラフ定義JSON。標準入力から読み込ませる事も可能。

optional arguments:

ロングオプション 説明
–template_variables テンプレート変数定義JSON
–width スクリーンボードの横幅を指定。pixel
–height スクリーンボードの縦幅を指定。pixel

実行例(エラー)

未修正、show コマンド結果JSONの使用

graphs の扱いに問題が有り、読み込みが行われません。 引数として渡した場合、中断(Ctrl+C)するまで返ってこず、標準入力から渡した場合、エラー Exception: bad json parameter となります。

# 引数として渡す
$ dog screenboard post "sb1" "ScreenBoard Test 1" "$(cat SampleScreenBoard.post.single.json)"
^CTraceback (most recent call last):
  File "/usr/bin/dog", line 9, in <module>
    load_entry_point('datadog==0.15.0', 'console_scripts', 'dog')()
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/__init__.py", line 69, in main
    args.func(args)
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/screenboard.py", line 169, in _post
    graphs = sys.stdin.read()
KeyboardInterrupt
# 標準入力から渡す
$ cat SampleScreenBoard.post.single.json | dog screenboard post "sb1" "ScreenBoard Test 1"
Traceback (most recent call last):
  File "/usr/bin/dog", line 9, in <module>
    load_entry_point('datadog==0.15.0', 'console_scripts', 'dog')()
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/__init__.py", line 69, in main
    args.func(args)
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/screenboard.py", line 178, in _post
    raise Exception('bad json parameter')
Exception: bad json parameter

一部修正、show コマンド結果JSONの使用(widgets配下)

post 時の不要な読み込みを削除し、showコマンド結果JSONwidgets 配下の状態で実行するとコマンド実行は成功しました。

  • screenboard.py
@@ -166,7 +166,7 @@

     @classmethod
     def _post(cls, args):
-        graphs = sys.stdin.read()
+#        graphs = sys.stdin.read()
         api._timeout = args.timeout
         format = args.format
         graphs = args.graphs
$ dog screenboard post "sb1" "ScreenBoard Test 1" "$(cat SampleScreenBoard.post.single.json)" | jq '.'
{
  "read_only": false,
  "description": "ScreenBoard Test 1",
  "title": "sb1",
  "created": "yyyy-mm-ddThh:mm:ss.739591+00:00",
  "modified": "yyyy-mm-ddThh:mm:ss.739608+00:00",
  "height": null,
  "graphs": [
    {
      "board_id": XXXX6,
      "title_size": 13,
      "title": true,
      "title_align": "left",
      "title_text": "CPU utilization by name (top 10)",
      "height": 21,
      "tile_def": {
        "viz": "timeseries",
        "requests": [
          {
            "q": "top(avg:aws.ec2.cpuutilization{$scope,$region,$availability-zone} by {name},10,'mean','desc')",
            "aggregator": "avg",
            "style": {
              "palette": "warm"
            },
            "type": "line",
            "conditional_formats": []
          }
        ]
      },
      "width": 42,
      "timeframe": "4h",
      "y": 0,
      "x": 82,
      "legend_size": "0",
      "type": "timeseries",
      "legend": false
    }
  ],
  "template_variables": [],
  "id": XXXXX1,
  "width": null
}

作成されたダッシュボードを見ると、空の状態で作成されてしまっています。

f:id:htnosm:20170323212202p:plain

show コマンドで返却される値は正しいように見えます。

$ dog screenboard show XXXXX1 | jq '.'
{
  "read_only": false,
  "description": "ScreenBoard Test 1",
  "title": "sb1",
  "created": "yyyy-mm-ddThh:mm:ss.739591+00:00",
  "modified": "yyyy-mm-ddThh:mm:ss.739608+00:00",
  "height": null,
  "graphs": [
    {
      "board_id": XXXX6,
      "title_size": 13,
      "title": true,
      "title_align": "left",
      "title_text": "CPU utilization by name (top 10)",
      "height": 21,
      "tile_def": {
        "viz": "timeseries",
        "requests": [
          {
            "q": "top(avg:aws.ec2.cpuutilization{$scope,$region,$availability-zone} by {name},10,'mean','desc')",
            "aggregator": "avg",
            "style": {
              "palette": "warm"
            },
            "type": "line",
            "conditional_formats": []
          }
        ]
      },
      "width": 42,
      "timeframe": "4h",
      "y": 0,
      "x": 82,
      "legend_size": "0",
      "type": "timeseries",
      "legend": false
    }
  ],
  "template_variables": [],
  "id": XXXXX1,
  "width": null
}

APIの直実行

同じJSON定義でAPIを直接実行してみましたが、同様の結果となりました。 API側の問題になりそうです。

$ curl -X POST -H "Content-type: application/json" \
> -d '@SampleScreenBoard.post.single.json' \
> "https://app.datadoghq.com/api/v1/screen?api_key=${api_key}&application_key=${app_key}"
{"board_id":XXXX6,"read_only":false,"title_size":13,"title":true,"id": XXXXX7,"title_align":"left","modified":"yyyy-mm-ddThh:mm:ss.495185+00:00","title_text":"CPU utilization by name (top 10)","height":21,"tile_def":{"viz":"timeseries","requests":[{"q":"top(avg:aws.ec2.cpuutilization{$scope,$region,$availability-zone} by {name},10,'mean','desc')","aggregator":"avg","style":{"palette":"warm"},"type":"line","conditional_formats":[]}]},"width":42,"created":"yyyy-mm-ddThh:mm:ss.495175+00:00","timeframe":"4h","y":0,"x":82,"legend_size":"0","type":"timeseries","legend":false}$

API Reference 上のサンプルをそのまま実行してみます。また違う結果になりましたが、やはり正常に動作していないように見えます。

> "https://app.datadoghq.com/api/v1/screen?api_key=${api_key}&application_key=${app_key}"
{"board_title":"dogapi test","read_only":false,"created":"yyyy-mm-ddThh:mm:ss.329178+00:00","modified":"yyyy-mm-ddThh:mm:ss.329191+00:00","height":768,"width":1024,"widgets":[{"url":"https://path/to/image.jpg","height":20,"width":32,"y":7,"x":32,"type":"image"}],"id": XXXXX9}$

f:id:htnosm:20170323212203p:plain

一部修正、template_variables、width、height オプション

オプション付与で実行してみた所、オプションは有効なようです。

$ dog screenboard post --template_variables "$(cat TEMPLATE_VARIABLES.json)" --width 1024 --height 768 "sb1" "ScreenBoard Test 1" "$(cat SampleScreenBoard.post.single.json)" | jq '.'
{
  "read_only": false,
  "description": "ScreenBoard Test 1",
  "title": "sb1",
  "created": "yyyy-mm-ddThh:mm:ss.222671+00:00",
  "modified": "yyyy-mm-ddThh:mm:ss.222682+00:00",
  "height": 768,
  "graphs": [
    {
      "board_id": XXXX6,
      "title_size": 13,
      "title": true,
      "title_align": "left",
      "title_text": "CPU utilization by name (top 10)",
      "height": 21,
      "tile_def": {
        "viz": "timeseries",
        "requests": [
          {
            "q": "top(avg:aws.ec2.cpuutilization{$scope,$region,$availability-zone} by {name},10,'mean','desc')",
            "aggregator": "avg",
            "style": {
              "palette": "warm"
            },
            "type": "line",
            "conditional_formats": []
          }
        ]
      },
      "width": 42,
      "timeframe": "4h",
      "y": 0,
      "x": 82,
      "legend_size": "0",
      "type": "timeseries",
      "legend": false
    }
  ],
  "template_variables": [
    {
      "default": "*",
      "prefix": "host",
      "name": "host"
    },
    {
      "default": "region:ap-northeast-1",
      "prefix": "region",
      "name": "region"
    }
  ],
  "id": XXXXX1,
  "width": 1024
}

f:id:htnosm:20170323212204p:plain

update

スクリーンボードを更新します。 post とほぼ同じ構文で、対象の screenboard_id を指定します。

usage: dog screenboard update [-h] [--template_variables TEMPLATE_VARIABLES]
                              [--width WIDTH] [--height HEIGHT]
                              screenboard_id title description [graphs]

意図した動作となりません
処理は正常終了しているように見えますが、指定値が反映されません。

pull

usage: dog screenboard pull [-h] screenboard_id filename

positional arguments:

引数 説明
screenboard_id スクリーンボードID
filename 出力ファイル名

実行例

JSON形式で出力されます。

$ board_id=169723
$ dog screenboard pull ${board_id} pull_${board_id}.json
XXXXX3 pull_XXXXX3.json
# 出力結果
$ cat pull_XXXXX3.json
{
  "board_title": "SampleScreenBoard",
  "read_only": false,
  "isIntegration": false,
  "board_bgtype": "board_graph",
  "created": "2017-03-23T16:57:56.454510+00:00",
  "original_title": "SampleScreenBoard",
  "modified": "2017-03-23T16:59:49.634253+00:00",
  "disableEditing": false,
  "height": 80,
  "width": "100%",
  "template_variables": [
    {
      "default": "*",
      "prefix": null,
      "name": "scope"
    },
・・・略
    }
  ],
  "templated": true,
  "widgets": [
    {
      "metric": "aws.ec2.host_ok",
      "text_align": "center",
      "query": "sum:aws.ec2.host_ok{$zone,$region,$account}",
      "text_size": "auto",
      "autoscale": true,
      "title": true,
      "aggregator": "max",
      "title_align": "left",
      "custom_unit": null,
      "width": 18,
      "timeframe": "1h",
      "wrapped": true,
      "legend_size": "0",
      "type": "query_value",
      "tags": [
        "$zone",
        "$region",
        "$account"
      ],
      "precision": 2,
      "title_text": "Active EC2 instances (max)",
      "padding": 8,
      "x": 20,
      "metric_type": "standard",
      "title_size": 13,
      "height": 8,
      "legend": false,
      "conditional_formats": [],
      "is_valid_query": true,
      "tile_def": {
        "text_align": "center",
        "autoscale": true,
        "custom_unit": null,
        "precision": 2,
        "viz": "query_value",
        "requests": [
          {
            "q": "sum:aws.ec2.host_ok{$scope,$region,$availability-zone}",
            "aggregator": "max",
            "conditional_formats": []
          }
        ]
      },
      "res_calc_func": "raw",
      "aggr": "sum",
      "y": 13,
      "calc_func": "raw"
    },
・・・略
    }
  ],
  "disableCog": false,
  "id": XXXXX3,
  "title_edited": false,
  "isShared": false
}$

push

JSON (pull した結果) を基に更新します。

positional arguments:

引数 説明
file 入力ファイル名。JSON

optional arguments:

ロングオプション 説明
–append_auto_text 対象タイムボードの description に日時とファイル名を追記します

append_auto_text はヘルプ上に記載はありますが、利用できません。 スクリーンボードはWebUI上 description が参照できないため、不要なオプションなのだと思います。

実行例

$ ls *${board_id}*
pull_XXXXX3.json  pull_XXXXX3.json.org
$ diff -w pull_XXXXX3.json.org pull_XXXXX3.json
22,26d21
<     },
<     {
<       "default": "*",
<       "prefix": "availability-zone",
<       "name": "availability-zone"
69c64
<             "q": "sum:aws.ec2.host_ok{$scope,$region,$availability-zone}",
---
>             "q": "sum:aws.ec2.host_ok{$scope,$region}",
104c99
<       "bgcolor": "gray",
---
>       "bgcolor": "blue",
134,135c129
<           "$region",
<           "$availability-zone"
---
>           "$region"
139c133
<             "q": "avg:aws.ec2.cpuutilization{$scope,$region,$availability-zone} by {host}",
---
>             "q": "avg:aws.ec2.cpuutilization{$scope,$region} by {host}",
166c160
<             "q": "top(avg:aws.ec2.cpuutilization{$scope,$region,$availability-zone} by {name},10,'mean','desc')",
---
>             "q": "top(avg:aws.ec2.cpuutilization{$scope,$region} by {name},10,'mean','desc')",
$ dog screenboard push pull_${board_id}.json | jq '.'
{
  "board_title": "SampleScreenBoard",
・・・略
  "id": XXXXX3,
  "title_edited": false,
  "isShared": false
}

f:id:htnosm:20170323212205p:plain

append_auto_text オプション

pull 結果に description が含まれていないため失敗します。

$ dog screenboard push --append_auto_text pull_${board_id}.json | jq '.'
Traceback (most recent call last):
  File "/usr/bin/dog", line 9, in <module>
    load_entry_point('datadog==0.15.0', 'console_scripts', 'dog')()
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/__init__.py", line 69, in main
    args.func(args)
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/screenboard.py", line 119, in _push
    screen_obj["description"] += auto_text
KeyError: 'description'
$ grep -c 'description'  pull_${board_id}.json
0

description を追記すれば動作します。また、 description を追加した状態で pull すると結果ファイルに description が含まれます。
ですが、WebUI上で作成した物には付与されないので使用しない方が良いかと思います。

$ diff pull_${board_id}.json pull_${board_id}_add_description.json
1a2
>   "description": "test",
$ dog screenboard push --append_auto_text pull_${board_id}_add_description.json | jq '.'
{
  "board_title": "SampleScreenBoard",
  "read_only": false,
  "isIntegration": false,
  "description": "test<br/>\nUpdated at mm/dd/yy hh:mm:dd from pull_XXXXX3_add_description.json (XXXXX3) on XXXXX.local",
・・・略
  "isShared": false
}
# 更新後にpull
$ dog screenboard pull ${board_id} pull_${board_id}_after.json
XXXXX3 pull_XXXXX3_after.json
$ grep -c description pull_XXXXX3.json pull_XXXXX3_after.json
pull_XXXXX3.json:0
pull_XXXXX3_after.json:1

new_file

新規でダッシュボードおよびpush用のファイルを作成します。

usage: dog screenboard new_file [-h] filename [graphs]

positional arguments:

引数 説明
filename 出力ファイル名。タイムボード名も兼ねる(説明にも記載される)。JSON
graphs グラフ定義JSON。標準入力から読み込ませる事も可能。

実行例

post して pull する動作となり、post と同じ問題が出てくるため省きます。

delete

スクリーンボードを削除します。

usage: dog screenboard delete [-h] screenboard_id

実行例

成功時のレスポンスはありません。

$ board_id=XXXXX1
$ dog screenboard delete ${board_id}
# 存在しない(削除済み) ID を指定
$ dog screenboard show ${board_id}
ERROR: Unable to find Screenboard for id XXXXX1

share | revoke

Public URL の払い出しと削除を行います。

# share
usage: dog screenboard share [-h] screenboard_id
# revoke
usage: dog screenboard revoke [-h] screenboard_id

実行例

share

PublicURL が払い出されます。再実行しても PublicURL の更新はされません。

$ board_id=XXXXX9
$ dog screenboard share ${board_id}
{"board_id": XXXXX9, "public_url": "https://p.datadoghq.com/sb/XXXXXXXXX-YYYYY5b001"}
$ dog screenboard share ${board_id}
{"board_id": XXXXX9, "public_url": "https://p.datadoghq.com/sb/XXXXXXXXX-YYYYY5b001"}

f:id:htnosm:20170323212206p:plain

ダッシュボードリスト(Dashboards) 上は share が表示されます。

f:id:htnosm:20170323212207p:plain

revoke

払い出し済みの PublicURL を削除します。
削除後に再度払い出し(share)を行うと別URLが払い出されます。

$ dog screenboard revoke ${board_id}
null
$ dog screenboard revoke ${board_id}
{"errors": ["Unable to find shared Screenboard for id XXXXX9"]}
# 再払い出し
$ dog screenboard share ${board_id}
{"board_id": XXXXX9, "public_url": "https://p.datadoghq.com/sb/XXXXXXXXX-YYYYY5c178"}
$

screenboard編まとめ

指定しているグラフの定義が悪いのか、想定した動作を確認できませんでした。
pull -> push の流れは利用できるので、現状はWebUIで作成したスクリーンボードを用意した後、定義のコード管理を行うことになりそうです。

Datadog (dogコマンド) timeboard編

Datadog

Datadog公式のツール dog 使用方法まとめ timeboard 編です。

f:id:htnosm:20170323212147p:plain


目次


timeboard Modes

ダッシュボード(TimeBoard) 操作を行います。

f:id:htnosm:20170323212148p:plain

サブコマンド 説明
show タイムボード情報出力
show_all タイムボードリスト出力
post タイムボード新規作成
update タイムボード更新
pull タイムボード定義取得
pull_all 全タイムボードの定義取得
push タイムボード更新
new_file タイムボードの新規作成と定義取得 (post後にpull)
web_view タイムボードを規定ブラウザで開く
delete タイムボードの削除

JSON形式で定義することになりますが、 1からJSONを作るのは中々難しいため、 参照用のタイムボードを用意して確認します。

  • サンプルタイムボード

f:id:htnosm:20170323212149p:plain

show

タイムボード定義を出力します。JSON形式で出力されます。

usage: dog timeboard show [-h] timeboard_id

実行結果

$ dash_id=XXXXXX
$ dog timeboard show ${dash_id} | jq '.'
{
  "dash": {
    "read_only": false,
    "description": "sample timeboard",
    "title": "SampleTimeBoard",
    "created": "yyyy-mm-ddThh:mm:ss.549586+00:00",
    "modified": "yyyy-mm-ddThh:mm:ss.731078+00:00",
    "graphs": [
      {
        "definition": {
          "viz": "timeseries",
          "requests": [
            {
              "q": "max:system.cpu.user{*} by {host}",
              "conditional_formats": [],
              "type": "line"
            }
          ],
          "autoscale": true
        },
        "title": "system.cpu.user"
      },
・・・略
      }
    ],
    "id": XXXXXX
  },
  "url": "/dash/XXXXXX/sampletimeboard",
  "resource": "/api/v1/dash/XXXXXX"
}

show_all

タイムボードリストを出力します。全タイムボードが対象となり、絞り込みのオプションはありません。

usage: dog timeboard show_all [-h]

実行結果

JSON形式で出力したい場合は raw オプションを使用します。

$ dog timeboard show_all
XXXXX8  /api/v1/dash/XXXXX8 Hoge's TimeBoard    created by user@example.com
XXXXX9  /api/v1/dash/XXXXX9 SampleTimeBoard sample timeboard
# rawオプション
$ dog --raw timeboard show_all | jq '.'
{
  "dashes": [
    {
      "read_only": false,
      "resource": "/api/v1/dash/XXXXX8",
      "description": "created by user@example.com",
      "created": "yyyy-mm-ddThh:mm:ss.111559+00:00",
      "title": "Hoge's TimeBoard",
      "modified": "yyyy-mm-ddThh:mm:ss.062052+00:00",
      "id": "XXXXX8"
    },
・・・略
    }
  ]
}

post

タイムボードを作成します。

usage: dog timeboard post [-h] [--template_variables TEMPLATE_VARIABLES]
                          title description [graphs]

(恐らく)複数グラフ未対応です
オブジェクトをそのまま連ねた場合、 JSON 読み込み時点でエラー、 配列化して JSON としては正しい状態にした場合、api呼び出し時点でエラーとなるようです。

positional arguments:

引数 説明
title タイムボード名
description タイムボードの説明
graphs グラフ定義JSON。標準入力から読み込ませる事も可能。

optional arguments:

ロングオプション 説明
–template_variables テンプレート変数定義JSON

実行例(エラー)

show コマンド結果JSONの使用

show コマンドで出力した結果をそのまま使用してもエラーとなります。graphs 以外の不要な key が含まれているためだと思います。

$ dog --raw timeboard post "tb1" "TimeBoard Test 1" "$(cat SampleTimeBoard.json)"
ERROR: The 'title' parameter is required for all graphs

show コマンド結果JSONの使用(graphs配下)

graphs 配下を抜き出した物を使用してみた所、JSONのパースエラーとなりました。

$ dash_id=XXXXXX 
$ dog timeboard show ${dash_id} > SampleTimeBoard.json
$ dog timeboard post "tb1" "TimeBoard Test 1" "$(cat SampleTimeBoard.post.json)"
Traceback (most recent call last):
  File "/usr/bin/dog", line 9, in <module>
    load_entry_point('datadog==0.15.0', 'console_scripts', 'dog')()
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/__init__.py", line 69, in main
    args.func(args)
  File "/usr/lib/python2.7/site-packages/datadog/dogshell/timeboard.py", line 236, in _post
    raise Exception('bad json parameter')
Exception: bad json parameter
  • 使用したファイル抜粋
      {
        "definition": {
          "viz": "timeseries",
          "requests": [
            {
              "q": "max:system.cpu.user{*} by {host}",
              "conditional_formats": [],
              "type": "line"
            }
          ],
          "autoscale": true
        },
        "title": "system.cpu.user"
      },
      {
        "definition": {
・・・略
      },

show コマンド結果JSONの使用 + 配列

オブジェクトが並ぶ形式で JSON として不正なため、配列としてみた所、 ‘title’ パラメータが無い旨のエラーメッセージとなりました。

$ dog timeboard post "tb1" "TimeBoard Test 1" "$(cat SampleTimeBoard.post.array.json)"
ERROR: The 'title' parameter is required for all graphs
  • 使用したファイル抜粋
      [{
        "definition": {
          "viz": "timeseries",
          "requests": [
            {
              "q": "max:system.cpu.user{*} by {host}",
              "conditional_formats": [],
              "type": "line"
            }
          ],
          "autoscale": true
        },
        "title": "system.cpu.user"
      },
      {
        "definition": {
・・・略
      }]

実行例

複数グラフを指定すると上手く動作しないようなので、グラフを1つにして実行した所、成功しました。
レスポンスは JSON 形式です。

$ dog timeboard post "tb1" "TimeBoard Test 1" "$(cat SampleTimeBoard.post.single.json)"
{"dash": {"read_only": false, "description": "TimeBoard Test 1", "title": "tb1", "created": "yyyy-mm-ddThh:mm:ss.260935+00:00", "modified": "yyyy-mm-ddThh:mm:ss.321740+00:00", "graphs": [{"definition": {"viz": "timeseries", "requests": [{"q": "max:system.cpu.user{*} by {host}", "conditional_formats": [], "type": "line"}], "autoscale": true}, "title": "system.cpu.user"}], "id": XXXXX6}, "url": "/dash/XXXXX6/tb1", "resource": "/api/v1/dash/XXXXX6"}
  • 使用したファイル
      {
        "definition": {
          "viz": "timeseries",
          "requests": [
            {
              "q": "max:system.cpu.user{*} by {host}",
              "conditional_formats": [],
              "type": "line"
            }
          ],
          "autoscale": true
        },
        "title": "system.cpu.user"
      }

f:id:htnosm:20170323212150p:plain

template_variables

テンプレート定義変数を付与できます。JSONのファイルを使用した実行例です。

$ cat TEMPLATE_VARIABLES.json
[{
  "name": "host",
  "prefix": "host",
  "default": "*"
},
{
  "name": "region",
  "prefix": "region",
  "default": "region:ap-northeast-1"
}]
$ dog timeboard post --template_variables "$(cat TEMPLATE_VARIABLES.json)" "tb2" "TimeBoard Test 2" "$(cat SampleTimeBoard.post.single.json)" | jq '.'
{
  "dash": {
    "read_only": false,
    "description": "TimeBoard Test 2",
    "title": "tb2",
    "created": "yyyy-mm-ddThh:mm:ss.444179+00:00",
    "modified": "yyyy-mm-ddThh:mm:ss.497676+00:00",
    "graphs": [
      {
        "definition": {
          "viz": "timeseries",
          "requests": [
            {
              "q": "max:system.cpu.user{*} by {host}",
              "conditional_formats": [],
              "type": "line"
            }
          ],
          "autoscale": true
        },
        "title": "system.cpu.user"
      }
    ],
    "template_variables": [
      {
        "default": "*",
        "prefix": "host",
        "name": "host"
      },
      {
        "default": "region:ap-northeast-1",
        "prefix": "region",
        "name": "region"
      }
    ],
    "id": XXXXX9
  },
  "url": "/dash/XXXXX9/tb2",
  "resource": "/api/v1/dash/XXXXX9"
}

f:id:htnosm:20170323212151p:plain

update

タイムボードを更新します。 post とほぼ同じ構文で、対象の timeboard_id を指定します。

usage: dog timeboard update [-h] [--template_variables TEMPLATE_VARIABLES]
                            timeboard_id title description [graphs]

変更がない場合でも title, description の指定は必須です。(idのみにして欲しい所ではあります)
graphs は post ではエラーとなりましたが、 update は複数指定が成功します。(後述)

実行例(エラー)

post コマンドで利用したJSON

show コマンドで出力した結果をそのまま使用してもエラーとなりました。

$ dog timeboard update --template_variables "$(cat TEMPLATE_VARIABLES.json)" ${dash_id} "tb1" "TimeBoard Test 1 Add graph" "$(cat SampleTimeBoard.post.single.json)" | jq '.'
ERROR: The 'graphs' parameter is required to be a list

実行例

post コマンドで利用したJSON + 配列[]

JSONを配列化した所、成功しました。 post と update で何故か受け付ける形式が異なります。

$ dash_id=XXXXX6
$ dog timeboard update --template_variables "$(cat TEMPLATE_VARIABLES.json)" ${dash_id} "tb1" "TimeBoard Test 1 Add graph" "$(cat SampleTimeBoard.update.json)" | jq '.'
{
  "dash": {
    "read_only": false,
    "description": "TimeBoard Test 1 Add graph",
    "title": "tb1",
    "created": "yyyy-mm-ddThh:mm:ss.260935+00:00",
    "modified": "yyyy-mm-ddThh:mm:ss.797204+00:00",
    "graphs": [
      {
        "definition": {
          "viz": "query_value",
          "requests": [
            {
              "q": "avg:system.load.5{*}",
              "aggregator": "max",
              "conditional_formats": [
                {
                  "palette": "white_on_yellow",
                  "value": "5",
                  "comparator": ">"
                },
                {
                  "palette": "white_on_red",
                  "value": "10",
                  "comparator": ">"
                }
              ]
            }
          ],
          "autoscale": true,
          "text_align": "right",
          "precision": "1"
        },
        "title": "system.load.5"
      }
    ],
    "template_variables": [
      {
        "default": "*",
        "prefix": "host",
        "name": "host"
      },
      {
        "default": "region:ap-northeast-1",
        "prefix": "region",
        "name": "region"
      }
    ],
    "id": XXXXX6
  },
  "url": "/dash/XXXXX6/tb1",
  "resource": "/api/v1/dash/XXXXX6"
}
  • 使用したファイル
$ cat SampleTimeBoard.update.json
      [{
        "definition": {
          "viz": "query_value",
          "requests": [
            {
              "q": "avg:system.load.5{*}",
              "aggregator": "max",
              "conditional_formats": [
                {
                  "palette": "white_on_yellow",
                  "value": "5",
                  "comparator": ">"
                },
                {
                  "palette": "white_on_red",
                  "value": "10",
                  "comparator": ">"
                }
              ]
            }
          ],
          "autoscale": true,
          "text_align": "right",
          "precision": "1"
        },
        "title": "system.load.5"
      }]

f:id:htnosm:20170323212152p:plain

show コマンド結果JSONの使用 + 配列[]

配列形式が受け付けられたので複数グラフも試した所、成功しました。

$ dog timeboard update ${dash_id} "tb1" "TimeBoard Test 1 Add graph array" "$(cat SampleTimeBoard.post.array.json)" | jq '.'
{
  "dash": {
    "read_only": false,
    "description": "TimeBoard Test 1 Add graph array",
    "title": "tb1",
    "created": "yyyy-mm-ddThh:mm:ss.260935+00:00",
    "modified": "yyyy-mm-ddThh:mm:ss.343722+00:00",
    "graphs": [
      {
        "definition": {
          "viz": "timeseries",
          "requests": [
            {
              "q": "max:system.cpu.user{*} by {host}",
              "conditional_formats": [],
              "type": "line"
            }
          ],
          "autoscale": true
        },
        "title": "system.cpu.user"
      },
・・・略
      }
    ],
    "template_variables": [],
    "id": XXXXX6
  },
  "url": "/dash/XXXXX6/tb1",
  "resource": "/api/v1/dash/XXXXX6"
}

f:id:htnosm:20170323212153p:plain

pull

usage: dog timeboard pull [-h] timeboard_id filename

positional arguments:

引数 説明
timeboard_id タイムボードID
filename 出力ファイル名

実行例

JSON形式で出力されます。

$ dash_id=XXXXX9
$ dog timeboard pull ${dash_id} pull_${dash_id}.json
XXXXX9 pull_XXXXX9.txt
  • 出力結果
$ cat pull_${dash_id}.txt
{
  "read_only": false,
  "description": "TimeBoard Test 2",
  "title": "tb2",
  "created": "yyyy-mm-ddThh:mm:ss.444179+00:00",
  "modified": "yyyy-mm-ddThh:mm:ss.497676+00:00",
  "graphs": [
    {
      "definition": {
        "viz": "timeseries",
        "requests": [
          {
            "q": "max:system.cpu.user{*} by {host}",
            "conditional_formats": [],
            "type": "line"
          }
        ],
        "autoscale": true
      },
      "title": "system.cpu.user"
    }
  ],
  "template_variables": [
    {
      "default": "*",
      "prefix": "host",
      "name": "host"
    },
    {
      "default": "region:ap-northeast-1",
      "prefix": "region",
      "name": "region"
    }
  ],
  "id": XXXXX9
}

pull_all

usage: dog timeboard pull_all [-h] pull_dir

positional arguments:

引数 説明
pull_dir 出力ディレクトリ名

実行例

指定ディレクトリへ各タイムボードの JSON を出力します。
ディレクトリは存在しない場合作成、存在する場合は上書きされます。

$ dog timeboard pull_all out_dir
XXXXX8 out_dir/hoge.json
XXXXX9 out_dir/sampletimeboard.json
XXXXX6 out_dir/tb1.json
XXXXX9 out_dir/tb2.json

push

JSON (pull した結果) を基に更新します。

usage: dog timeboard push [-h] [--append_auto_text] file [file ...]

positional arguments:

引数 説明
file 入力ファイル名。JSON

optional arguments:

ロングオプション 説明
–append_auto_text 対象タイムボードの description に日時とファイル名を追記します

実行例

pull 結果ファイルを push

pull で出力した JSON を編集して、そのまま push できます。

$ dog timeboard push pull_XXXXX9.json | jq '.'
{
  "dash": {
    "read_only": false,
    "description": "TimeBoard Test 2 push",
    "title": "tb2",
    "created": "yyyy-mm-ddThh:mm:ss.444179+00:00",
    "modified": "yyyy-mm-ddThh:mm:ss.050260+00:00",
    "graphs": [
      {
        "definition": {
          "viz": "timeseries",
          "requests": [
            {
              "q": "max:system.cpu.user{*} by {host}",
              "conditional_formats": [],
              "type": "line"
            }
          ],
          "autoscale": true
        },
        "title": "system.cpu.user"
      }
    ],
    "template_variables": [
      {
        "default": "*",
        "prefix": "host",
        "name": "host"
      },
      {
        "default": "region:ap-northeast-1",
        "prefix": "region",
        "name": "region"
      }
    ],
    "id": XXXXX9
  },
  "url": "/dash/XXXXX9/tb2",
  "resource": "/api/v1/dash/XXXXX9"
}

f:id:htnosm:20170323212154p:plain

append_auto_text オプション

description に更新日時とファイル名、実行ホストが追記されます。 改行の <br> は改行として認識されていないようです。

$ dog timeboard push --append_auto_text pull_XXXXX9.json | jq '.'

f:id:htnosm:20170323212155p:plain

new_file

新規でダッシュボードおよびpush用のファイルを作成します。

usage: dog timeboard new_file [-h] filename [graphs]

positional arguments:

引数 説明
filename 出力ファイル名。タイムボード名も兼ねる(説明にも記載される)。JSON
graphs グラフ定義JSON。標準入力から読み込ませる事も可能。

実行例

post して pull する動作です。
タイムボード作成処理は post と同様の処理となっているため、グラフを1つにしたJSONで実行します。 filename で指定した JSON ファイルが生成されます。

$ dog timeboard new_file NewFile.json "$(cat SampleTimeBoard.post.single.json)"
XXXXX3 NewFile.json
{"dash": {"read_only": false, "description": "Description for NewFile.json", "title": "NewFile.json", "created": "yyyy-mm-ddThh:mm:ss.957193+00:00", "modified": "yyyy-mm-ddThh:mm:ss.028761+00:00", "graphs": [{"definition": {"viz": "timeseries", "requests": [{"q": "max:system.cpu.user{*} by {host}", "conditional_formats": [], "type": "line"}], "autoscale": true}, "title": "system.cpu.user"}], "id": XXXXX3}, "url": "/dash/XXXXX3/newfilejson", "resource": "/api/v1/dash/XXXXX3"}
$ cat NewFile.json
{
  "read_only": false,
  "description": "Description for NewFile.json",
  "title": "NewFile.json",
  "created": "yyyy-mm-ddThh:mm:ss.957193+00:00",
  "modified": "yyyy-mm-ddThh:mm:ss.028761+00:00",
  "graphs": [
    {
      "definition": {
        "viz": "timeseries",
        "requests": [
          {
            "q": "max:system.cpu.user{*} by {host}",
            "conditional_formats": [],
            "type": "line"
          }
        ],
        "autoscale": true
      },
      "title": "system.cpu.user"
    }
  ],
  "id": XXXXX3
}

タイムボード件名と説明には filename が使用されます。

f:id:htnosm:20170323212156p:plain

web_view

ブラウザでダッシュボードを開きます。

usage: dog timeboard web_view [-h] file

positional arguments:

引数 説明
file 入力ファイル名。JSON

json.load(file)['id']timeboard_id が取得できれば良いので、下のような形式のJSONがあれば実行可能です。

'{ "id": XXXXX3 }'

実行例

レスポンスはありません。規定のブラウザでタイムボードのURLを開きます。

$ dog --raw timeboard web_view NewFile.json
$
# 存在しない id 指定
% diff NewFile.json NewFile_noid.json
23c23
<   "id": XXXXX3
---
>   "id": 200003
$ dog --raw timeboard web_view NewFile_noid.json
$
  • 存在するID

f:id:htnosm:20170323212157p:plain

  • 存在しないID

f:id:htnosm:20170323212158p:plain

delete

タイムボードを削除します。

usage: dog timeboard delete [-h] timeboard_id

実行例

成功時のレスポンスはありません。

$ dash_id=265413
$ dog --raw timeboard delete ${dash_id}
# 存在しない(削除済み) ID を指定
$ dog timeboard delete ${dash_id}
ERROR: No dashboard matches that dash_id.

timeboard編まとめ

pull -> push の流れを利用すると定義のコード管理が行いやすいと思います。
似たような名前のサブコマンドが多く困惑しました。 dog コマンドとしては show[all],pull[all],push,delete だけに絞っても、必要十分なのではと思います。