はじめに

こんにちは、そしてこんばんは。
クラウドインテグレーション事業部の大嵩です。

今回は、私がNew RelicにてWindowsServerのNTPオフセット監視を実装しようとしたときに、調査してわかった実装方法を紹介いたします!

前提

  • OSがWindowsであること
  • New Relic Agentがインストール済みであること

1. NTPオフセットを出力するためのスクリプトを作成

まず、New Relic側にNR-Flexを用いてオリジナルのメトリクスを送信するためのスクリプトを作成します。
こちらはなんと公式リポジトリに記載がありますので、そのまま持ってきてしまいます。
https://github.com/newrelic/nri-flex/blob/master/examples/windows/windows-clock-drift-ntp-script.ps1
もちろんファイル名はお好みでも大丈夫です。

#region Top of Script

#requires -version 3

<#
.SYNOPSIS
    Tests clock drift from target NTP server
.DESCRIPTION
  This script uses the "w32tm" tool from Windows.
  There is the option to use a hard-coded time server (see like 24-26), or as in most enterprise
  settings where a primary domain controller serves as the time server, the option to have the
  $ntpServer variable set dynamically based on the source of the NTP configuration.  It should be
  noted however, that if more than one time server is set, either manually or through group policy
  this dynamic option will not work.
.NOTES
    Version:        1.0
    Author:         Zack Mutchler
    Creation Date:  09/24/2020
    Purpose/Change: Initial script development
#>

#endregion Top of Script

#####-----------------------------------------------------------------------------------------#####

#region Execution

# Target NTP Server
# Hard coded option
# $ntpServer = 'time.windows.com'

# Target NTP Server
# Dynamic option to pickup configured NTP Server on local machine
$server = [Net.Dns]::GetHostName()
$ntpServer = w32tm /query /computer:$server /source | Out-String

# REGEX to find Skew later
$findSkew = [regex]"(?:NTP\: )(?<Value>/?[^s]+)"

# Grab the local server time in Epoch
$localEpoch = [int64](Get-Date -UFormat %s)

# Query the current skew using the w32tm tool
$ntpQuery = Invoke-Expression "w32tm /monitor /computers:$ntpServer" | Out-String

# Check to see if there is a match
If ( $ntpQuery -match $findSkew ) {

    # Extract the skew from the resulting string match
    $ntpSkew = [decimal]$Matches['Value']

    # Set the results object, making sure we pass the +/- sign to show the direction of skew from NTP
    If( $ntpSkew -lt 0 ) {
        $skewValue = [math]::Abs( $ntpSkew )
        $skewSign = "-"
        $results = New-Object -TypeName psobject
        $results | Add-Member -MemberType NoteProperty -Name 'ntpServer' -Value $ntpServer
        $results | Add-Member -MemberType NoteProperty -Name 'localTime' -Value $localEpoch
        $results | Add-Member -MemberType NoteProperty -Name 'skewString' -Value $ntpSkew.ToString()
        $results | Add-Member -MemberType NoteProperty -Name 'skewSign' -Value $skewSign
        $results | Add-Member -MemberType NoteProperty -Name 'skewValue' -Value $skewValue
    }
    Else {
        $skewValue = [math]::Abs( $ntpSkew )
        $skewSign = "+"
        $results = New-Object -TypeName psobject
        $results | Add-Member -MemberType NoteProperty -Name 'ntpServer' -Value $ntpServer
        $results | Add-Member -MemberType NoteProperty -Name 'localTime' -Value $localEpoch
        $results | Add-Member -MemberType NoteProperty -Name 'skewString' -Value $ntpSkew.ToString()
        $results | Add-Member -MemberType NoteProperty -Name 'skewSign' -Value $skewSign
        $results | Add-Member -MemberType NoteProperty -Name 'skewValue' -Value $skewValue
    }
}
# Otherwise exit with the $nulls
Else {
    $results = New-Object -TypeName psobject
    $results | Add-Member -MemberType NoteProperty -Name 'ntpServer' -Value $ntpServer
    $results | Add-Member -MemberType NoteProperty -Name 'localTime' -Value $localEpoch
    $results | Add-Member -MemberType NoteProperty -Name 'skewString' -Value "Error Collecting NTP Skew Value"
    $results | Add-Member -MemberType NoteProperty -Name 'skewSign' -Value $null
    $results | Add-Member -MemberType NoteProperty -Name 'skewValue' -Value $null
}

# Print the results to STDOUT in JSON for Flex to pickup
$results | ConvertTo-Json

#endregion Execution

記述の中で値が取れなかった場合の処理もあるため、エラーが発生した場合はすぐに対応することも可能となっております!

# Otherwise exit with the $nulls
Else {
    $results = New-Object -TypeName psobject
    $results | Add-Member -MemberType NoteProperty -Name 'ntpServer' -Value $ntpServer
    $results | Add-Member -MemberType NoteProperty -Name 'localTime' -Value $localEpoch
    $results | Add-Member -MemberType NoteProperty -Name 'skewString' -Value "Error Collecting NTP Skew Value"
    $results | Add-Member -MemberType NoteProperty -Name 'skewSign' -Value $null
    $results | Add-Member -MemberType NoteProperty -Name 'skewValue' -Value $null
}

$results | ConvertTo-Json

なお、New Relicに値を渡すときはJSON形式にする必要があるため、最後の行で変換を挟みます。

2. スクリプトを実行するAgentの設定ファイルを作成

次に作成したスクリプトを実行させて、New Relicにメトリクスを送信するAgentの設定ファイルを作成します。
こちらも同様に公式リポジトリからそのまま使用します。
https://github.com/newrelic/nri-flex/blob/master/examples/windows/windows-clock-drift-ntp.yml

# This config will execute a script to measure clock drift from a target NTP server
# Use forward slashes on Windows paths as Flex handles these more gracefully
# Note we have manually created a 'flexAssets' directory to hold scripts and lookup files
---
integrations:
  - name: nri-flex
    config:
      name: ntpCheck
      apis:
        - event_type: ntpCheck
          shell: powershell
          commands:
            - run: "& \"C:/Program Files/New Relic/newrelic-infra/integrations.d/flexAssets/ntpCheck.ps1\""

event_type: ntpCheck

ここでNew Relic側で扱うイベント名を定義します。

commands:
– run: “& \”C:/Program Files/New Relic/newrelic-infra/integrations.d/flexAssets/ntpCheck.ps1\””

さらにcommandsの中で先程のシェルスクリプトを指定して、Agentに実行させます。

3. 送信されたメトリクスを確認する

最後に、設定したNTPオフセットのオリジナルメトリクスをNRQLで取得したいと思います。
まずはテーブル形式ですべての内容を見てみます。

SELECT * FROM ntpCheck

するとスクリプトで定義した結果が出力されていることが確認できます!

# スクリプトの該当部分
$results | Add-Member -MemberType NoteProperty -Name 'skewString' -Value $ntpSkew.ToString()
$results | Add-Member -MemberType NoteProperty -Name 'skewSign' -Value $skewSign
$results | Add-Member -MemberType NoteProperty -Name 'skewValue' -Value $skewValue

さらに以下のように記述することで、プラス方向とマイナス方向のNTPオフセットを取得することができます!!

SELECT latest(skewString) FROM ntpCheck TIMESERIES AUTO

まとめ

  • WindowsでのNTPオフセット監視は公式リポジトリから引用することで簡単に実装が可能。
  • オリジナルメトリクスを用いてNRQLを使用すればすぐに監視ができる。

この記事がどなたかの監視実装の手助けになりますと幸いです!!