Amazon Performance Metrics DataSource

Amazon.AmazonWebServices.CloudWatchMetricsDiscoveryDataSource (DataSourceModuleType)

Data provider for Amazon performance metrics discovery.

Element properties:

TypeDataSourceModuleType
IsolationAny
AccessibilityInternal
RunAsDefault
OutputTypeSystem.Discovery.Data

Member Modules:

ID Module Type TypeId RunAs 
DS DataSource Amazon.AmazonWebServices.ScriptedDiscoveryClientQueryDataSource Default

Overrideable Parameters:

IDParameterTypeSelectorDisplay NameDescription
IntervalSecondsint$Config/IntervalSeconds$Interval (sec)
SyncTimestring$Config/SyncTime$SyncTime
TimeoutSecondsint$Config/TimeoutSeconds$Timeout (sec)
EnableLoggingbool$Config/EnableLogging$Verbose log messages

Source Code:

<DataSourceModuleType ID="Amazon.AmazonWebServices.CloudWatchMetricsDiscoveryDataSource" Accessibility="Internal">
<Configuration>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="IntervalSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="SyncTime" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="TimeoutSeconds" type="xsd:integer"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="NamespaceFilter" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="WatcherNodeName" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="ParentObjectNameFormat" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="RelationshipTypeId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="ParentTypeId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="ParentKeyPropertyId" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="Guid" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="Region" type="xsd:string"/>
<xsd:element xmlns:xsd="http://www.w3.org/2001/XMLSchema" minOccurs="1" maxOccurs="1" name="EnableLogging" type="xsd:boolean"/>
</Configuration>
<OverrideableParameters>
<OverrideableParameter ID="IntervalSeconds" Selector="$Config/IntervalSeconds$" ParameterType="int"/>
<OverrideableParameter ID="SyncTime" Selector="$Config/SyncTime$" ParameterType="string"/>
<OverrideableParameter ID="TimeoutSeconds" Selector="$Config/TimeoutSeconds$" ParameterType="int"/>
<OverrideableParameter ID="EnableLogging" Selector="$Config/EnableLogging$" ParameterType="bool"/>
</OverrideableParameters>
<ModuleImplementation>
<Composite>
<MemberModules>
<DataSource ID="DS" TypeID="Amazon.AmazonWebServices.ScriptedDiscoveryClientQueryDataSource">
<IntervalSeconds>$Config/IntervalSeconds$</IntervalSeconds>
<SyncTime>$Config/SyncTime$</SyncTime>
<TimeoutSeconds>$Config/TimeoutSeconds$</TimeoutSeconds>
<ScriptName>AmazonMetricsDiscovery.ps1</ScriptName>
<ScriptBody><Script>param(
$PackElement, $TargetID,
$AWSAccessKey, $AWSSecretKey,
$NamespaceFilter, $WatcherNodeName, $ParentObjectNameFormat,
$RelationshipTypeId, $ParentTypeId, $ParentKeyPropertyId, $Guid, $Region, $EnableLogging)

#TODO: Discuss event id
$SCRIPT_EVENT_ID = 4102

#Event Severity values
$INFORMATION_EVENT_TYPE = 0
$ERROR_EVENT_TYPE = 1
$SERVICE_URL = "https://{0}.{1}.amazonaws.com"
$ELB_ADDRESS = "elasticloadbalancing"
$EC2_ADDRESS = "ec2"
$CLOUDWATCH_ADDRESS = "monitoring"

function Main {
param(
$PackElement, $TargetID,
$AWSAccessKey, $AWSSecretKey,
$NamespaceFilter, $WatcherNodeName, $ParentObjectNameFormat,
$RelationshipTypeId, $ParentTypeId, $ParentKeyPropertyId, $Guid, $Region, $EnableLogging)

#
# Parse boolean param
#
switch($EnableLogging)
{
"true" { $EnableLogging = $true }
"false" { $EnableLogging = $false }
}

#
# Prepare MOM API and property bag object
#
$api = New-Object -comObject "MOM.ScriptAPI"
$discoveryData = $api.CreateDiscoveryData(0, $PackElement, $TargetID)

try
{
#
# Define Regions
#
$regionName = $Region

#
# Access Amazon EC2 via SDK
#
$cloudWatchConfig = New-Object Amazon.CloudWatch.AmazonCloudWatchConfig;
$cloudWatchConfig.ServiceURL = $SERVICE_URL -f $CLOUDWATCH_ADDRESS, $regionName
$cloudWatchClient = [Amazon.AWSClientFactory]::CreateAmazonCloudWatchClient($AWSAccessKey, $AWSSecretKey, $cloudWatchConfig)

# Get List of available parent objects
$parentObjects = $null
switch ($NamespaceFilter) {
'AWS/ELB' { $parentObjects = GetElbs $AWSAccessKey $AWSSecretKey $regionName }
'AWS/EBS' { $parentObjects = GetVolumes $AWSAccessKey $AWSSecretKey $regionName }
'AWS/EC2' { $parentObjects = GetEc2Instances $AWSAccessKey $AWSSecretKey $regionName }
default { $parentObjects = @{} }
}

$metrics = @()
$null = GetMetrics $cloudWatchClient $NamespaceFilter $null ([ref]$metrics)
foreach ($metric in $metrics) {
$parentEntityId = $null
# Try get parent entity Id as first dimension
# TODO: Verify if there metrics with more than one dimension filter?
if ($metric.Dimensions -ne $null -and $metric.Dimensions.Count -gt 0) {
$parentEntityId = $metric.Dimensions[0].Value
}
If (!$parentEntityId) { continue; }

$metricId = "{0}:{1}:{2}" -f $metric.Namespace, $parentEntityId, $metric.MetricName

# Create Metric instance
$metricEntity = $discoveryData.CreateClassInstance("$MPElement[Name='Amazon.AmazonWebServices.CloudWatchMetric']$")
$metricEntity.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", $metric.MetricName)
$metricEntity.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $WatcherNodeName)
$metricEntity.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.WatcherNode']/Guid$", $Guid)
$metricEntity.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.CloudWatchMetric']/Id$", $metricId)
$metricEntity.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.CloudWatchMetric']/Namespace$", $metric.Namespace)
$metricEntity.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.CloudWatchMetric']/ParentObjectName$", ("$ParentObjectNameFormat" -f $parentEntityId))
$metricEntity.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.Component']/RegionName$", $regionName)

$discoveryData.AddInstance($metricEntity)

# Do not create relationship if no parent exists
if (!$parentObjects.ContainsKey($parentEntityId)) { continue; }

# Ensure parent object created
$parentEntity = $parentObjects.Get_Item($parentEntityId)
if ($parentEntity -eq $null) {
$parentEntity = $discoveryData.CreateClassInstance("$ParentTypeId")
$parentEntity.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $WatcherNodeName)
$parentEntity.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.WatcherNode']/Guid$", $Guid)
$parentEntity.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.DiscoveredGroupBase']/Region$", $regionName)
$parentEntity.AddProperty("$ParentKeyPropertyId", $parentEntityId)
$parentObjects.Set_Item($parentEntityId, $parentEntity)
}

# Connect parent object with the metric
$relationship = $discoveryData.CreateRelationshipInstance("$RelationshipTypeId")
$relationship.Source = $parentEntity
$relationship.Target = $metricEntity
$discoveryData.AddInstance($relationship)
}


# Create discovery spore
$discoverySpore = $discoveryData.CreateClassInstance("$MPElement[Name='Amazon.AmazonWebServices.CloudWatchMetricsDiscoverySpore']$")
$discoverySpore.AddProperty("$MPElement[Name='System!System.Entity']/DisplayName$", ("Metrics Discovery Spore for '{0}'" -f $NamespaceFilter))
$discoverySpore.AddProperty("$MPElement[Name='Windows!Microsoft.Windows.Computer']/PrincipalName$", $WatcherNodeName)
$discoverySpore.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.WatcherNode']/Guid$", $Guid)
$discoverySpore.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.CloudWatchMetricsDiscoverySpore']/NamespaceFilter$", $NamespaceFilter)
$discoverySpore.AddProperty("$MPElement[Name='Amazon.AmazonWebServices.DiscoveredGroupBase']/Region$", $regionName)
$discoveryData.AddInstance($discoverySpore)

$discoveryData
if ($EnableLogging) {
$header = "Metrics discovery successfully completed for '$NamespaceFilter' namespace in '$Region' region."
$api.LogScriptEvent($header, $SCRIPT_EVENT_ID, $INFORMATION_EVENT_TYPE, $msg)
}
}
catch
{
$header = "Managegement Group: $Target/ManagementGroup/Name$. Script: {0}" -f ($MyInvocation.MyCommand).Name.ToString()
$msg += "Error occured during Amazon Metrics discovery for '$NamespaceFilter' namespace in '{3}' region.{0}Computer:{1} {0}Reason: {2}" -f [Environment]::NewLine, $env:COMPUTERNAME, $_.Exception.Message, $Region
$api.LogScriptEvent($header, $SCRIPT_EVENT_ID, $ERROR_EVENT_TYPE, $msg)
$discoveryData = $api.CreateDiscoveryData(0, $PackElement, $TargetID)
$discoveryData.IsSnapshot = $false
}
}

function GetElbs($AWSAccessKey, $AWSSecretKey, $regionName) {
$elbConfig = New-Object Amazon.ElasticLoadBalancing.AmazonElasticLoadBalancingConfig;
$elbConfig.ServiceURL = $SERVICE_URL -f $ELB_ADDRESS, $regionName
$elbClient = [Amazon.AWSClientFactory]::CreateAmazonElasticLoadBalancingClient($AWSAccessKey, $AWSSecretKey, $elbConfig)
$elbRequest = New-Object Amazon.ElasticLoadBalancing.Model.DescribeLoadBalancersRequest;
$elbResponse = $elbClient.DescribeLoadBalancers($elbRequest);

$balancers = @{}
foreach ($elbDescription in $elbResponse.DescribeLoadBalancersResult.LoadBalancerDescriptions) {
$balancers.Add($elbDescription.LoadBalancerName, $null)
}
return $balancers
}

function GetVolumes($AWSAccessKey, $AWSSecretKey, $regionName) {
$ec2client = CreateEc2Client $AWSAccessKey $AWSSecretKey $regionName
$request = New-Object Amazon.EC2.Model.DescribeVolumesRequest;
$response = $ec2client.DescribeVolumes($request);

$volumes = @{}
if (!$response.IsSetDescribeVolumesResult -or !$response.DescribeVolumesResult.IsSetVolume) { return $volumes; }

foreach ($volume in $response.DescribeVolumesResult.Volume) {
$volumes.Add($volume.VolumeId, $null)
}
return $volumes
}

function GetEc2Instances($AWSAccessKey, $AWSSecretKey, $regionName) {
$ec2client = CreateEc2Client $AWSAccessKey $AWSSecretKey $regionName
$request = New-Object Amazon.EC2.Model.DescribeInstancesRequest;
$response = $ec2client.DescribeInstances($request);
$instances = @{}
foreach ($reservation in $response.DescribeInstancesResult.Reservation) {
foreach ($instance in $reservation.RunningInstance) {
$instances.Add($instance.InstanceId, $null)
}
}
return $instances
}

function CreateEc2Client($AWSAccessKey, $AWSSecretKey, $regionName) {
$ec2Config = New-Object Amazon.EC2.AmazonEC2Config;
$ec2Config.ServiceURL = $SERVICE_URL -f $EC2_ADDRESS, $regionName
return [Amazon.AWSClientFactory]::CreateAmazonEC2Client($AWSAccessKey, $AWSSecretKey, $ec2Config)
}

function GetMetrics {
param(
$cloudWatchClient,
$NamespaceFilter,
$NextToken,
[ref] $Metrics
)
$listMetricsRequest = New-Object Amazon.CloudWatch.Model.ListMetricsRequest;
if ($NextToken) {
$listMetricsRequest = $listMetricsRequest.WithNextToken($NextToken)
}

# Filter on required object type
$listMetricsRequest.WithNamespace("$NamespaceFilter")

$response = $cloudWatchClient.ListMetrics($listMetricsRequest);

if ($response.ListMetricsResult -ne $null) {
foreach ($metric in $response.ListMetricsResult.Metrics) {
$Metrics.Value += $metric
}
$NextToken = $response.ListMetricsResult.NextToken
}

if ($NextToken) {
$null = GetMetrics $cloudWatchClient $NamespaceFilter $NextToken $Metrics
}
}

Main $PackElement $TargetID $AWSAccessKey $AWSSecretKey $NamespaceFilter $WatcherNodeName $ParentObjectNameFormat $RelationshipTypeId $ParentTypeId $ParentKeyPropertyId $Guid $Region $EnableLogging
</Script></ScriptBody>
<Parameters>
<Parameter>
<Name>PackElement</Name>
<Value>$MPElement$</Value>
</Parameter>
<Parameter>
<Name>TargetID</Name>
<Value>$Target/Id$</Value>
</Parameter>
<Parameter>
<Name>AWSAccessKey</Name>
<Value>$RunAs[Name="Amazon.AmazonWebServices.RunAsProfile.AwsKeys"]/UserName$</Value>
</Parameter>
<Parameter>
<Name>AWSSecretKey</Name>
<Value>$RunAs[Name="Amazon.AmazonWebServices.RunAsProfile.AwsKeys"]/Password$</Value>
</Parameter>
<Parameter>
<Name>NamespaceFilter</Name>
<Value>$Config/NamespaceFilter$</Value>
</Parameter>
<Parameter>
<Name>WatcherNodeName</Name>
<Value>$Config/WatcherNodeName$</Value>
</Parameter>
<Parameter>
<Name>ParentObjectNameFormat</Name>
<Value>$Config/ParentObjectNameFormat$</Value>
</Parameter>
<Parameter>
<Name>RelationshipTypeId</Name>
<Value>$Config/RelationshipTypeId$</Value>
</Parameter>
<Parameter>
<Name>ParentTypeId</Name>
<Value>$Config/ParentTypeId$</Value>
</Parameter>
<Parameter>
<Name>ParentKeyPropertyId</Name>
<Value>$Config/ParentKeyPropertyId$</Value>
</Parameter>
<Parameter>
<Name>Guid</Name>
<Value>$Config/Guid$</Value>
</Parameter>
<Parameter>
<Name>Region</Name>
<Value>$Config/Region$</Value>
</Parameter>
<Parameter>
<Name>EnableLogging</Name>
<Value>$Config/EnableLogging$</Value>
</Parameter>
</Parameters>
</DataSource>
</MemberModules>
<Composition>
<Node ID="DS"/>
</Composition>
</Composite>
</ModuleImplementation>
<OutputType>System!System.Discovery.Data</OutputType>
</DataSourceModuleType>