Skip to content

Commit

Permalink
Manage distributed settings per-device
Browse files Browse the repository at this point in the history
  • Loading branch information
anusapan committed Mar 3, 2020
1 parent 8fdd7ed commit 712145c
Show file tree
Hide file tree
Showing 19 changed files with 1,933 additions and 17 deletions.
40 changes: 40 additions & 0 deletions src/IotHub/IotHub.Test/ScenarioTests/IotHubDPTracingTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------------

using Microsoft.Azure.ServiceManagement.Common.Models;
using Microsoft.WindowsAzure.Commands.ScenarioTest;
using Microsoft.WindowsAzure.Commands.Test.Utilities.Common;
using Xunit;
using Xunit.Abstractions;

namespace Microsoft.Azure.Commands.IotHub.Test.ScenarioTests
{
public class IotHubDPTracingTests : RMTestBase
{
public XunitTracingInterceptor _logger;

public IotHubDPTracingTests(ITestOutputHelper output)
{
_logger = new XunitTracingInterceptor(output);
XunitTracingInterceptor.AddToContext(_logger);
}

[Fact]
[Trait(Category.AcceptanceType, Category.LiveOnly)]
public void TestAzureIotHubTracing()
{
IotHubController.NewInstance.RunPsTest(_logger, "Test-AzureRmIotHubTracing");
}
}
}
60 changes: 60 additions & 0 deletions src/IotHub/IotHub.Test/ScenarioTests/IotHubDPTracingTests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# ----------------------------------------------------------------------------------
#
# Copyright Microsoft Corporation
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------------


#################################
## IotHub Tracing Cmdlets ##
#################################

<#
.SYNOPSIS
Test all iothub device tracing cmdlets
#>
function Test-AzureRmIotHubTracing
{
$Location = Get-Location "Microsoft.Devices" "IotHubs" "WEST US 2"
$IotHubName = getAssetName
$ResourceGroupName = getAssetName
$Sku = "S1"
$device1 = getAssetName

# Create Resource Group
$resourceGroup = New-AzResourceGroup -Name $ResourceGroupName -Location $Location

# Create Iot Hub
$iothub = New-AzIotHub -Name $IotHubName -ResourceGroupName $ResourceGroupName -Location $Location -SkuName $Sku -Units 1

# Add iot device
$newDevice1 = Add-AzIotHubDevice -ResourceGroupName $ResourceGroupName -IotHubName $IotHubName -DeviceId $device1 -AuthMethod 'shared_private_key'
Assert-True { $newDevice1.Id -eq $device1 }
Assert-False { $newDevice1.Capabilities.IotEdge }

# Get device tracing detail
$deviceTracing = Get-AzIotHubDistributedTracing -ResourceGroupName $ResourceGroupName -IotHubName $IotHubName -DeviceId $device1
Assert-True { $deviceTracing.DeviceId -eq $device1}
Assert-True { $deviceTracing.TracingOption.SamplingMode -eq 'Disabled'}
Assert-True { $deviceTracing.TracingOption.SamplingRate -eq ''}
Assert-False { $deviceTracing.IsSynced}

# Set device tracing option
$updatedDeviceTracing = Set-AzIotHubDistributedTracing -ResourceGroupName $ResourceGroupName -IotHubName $IotHubName -DeviceId $device1 -mode 'Enabled' -rate 45
Assert-True { $updatedDeviceTracing.DeviceId -eq $device1}
Assert-True { $updatedDeviceTracing.TracingOption.SamplingMode -eq 'Enabled'}
Assert-True { $updatedDeviceTracing.TracingOption.SamplingRate -eq 45}
Assert-False { $updatedDeviceTracing.IsSynced}

# Delete all devices
$result = Remove-AzIotHubDevice -ResourceGroupName $ResourceGroupName -IotHubName $IotHubName -Passthru
Assert-True { $result }
}

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions src/IotHub/IotHub/Az.IotHub.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ CmdletsToExport = 'Add-AzIotHubKey', 'Get-AzIotHubEventHubConsumerGroup',
'Set-AzIotHubModule', 'Get-AzIotHubDeviceConnectionString',
'Get-AzIotHubModuleConnectionString', 'Get-AzIotHubDeviceParent',
'Set-AzIotHubDeviceParent', 'Add-AzIotHubDeviceChildren',
'Remove-AzIotHubDeviceChildren', 'Get-AzIotHubDeviceChildren'
'Remove-AzIotHubDeviceChildren', 'Get-AzIotHubDeviceChildren',
'Get-AzIotHubDistributedTracing', 'Set-AzIotHubDistributedTracing'
# Variables to export from this module
# VariablesToExport = @()

Expand All @@ -109,7 +110,8 @@ AliasesToExport = 'Get-AzIotHubEHCG', 'Add-AzIotHubEHCG', 'Remove-AzIotHubEHCG',
'Set-AzIotHubVC', 'Get-AzIotHubCVC', 'Add-AzIotHubMsgEnrich',
'Get-AzIotHubMsgEnrich', 'Remove-AzIotHubMsgEnrich',
'Set-AzIotHubMsgEnrich', 'Get-AzIotHubDCS', 'Get-AzIotHubMCS',
'Add-AzIotHubDCL', 'Remove-AzIotHubDCL', 'Get-AzIotHubDCL'
'Add-AzIotHubDCL', 'Remove-AzIotHubDCL', 'Get-AzIotHubDCL',
'Get-AzIotHubTracing', 'Set-AzIotHubTracing'

# DSC resources to export from this module
# DscResourcesToExport = @()
Expand Down
8 changes: 7 additions & 1 deletion src/IotHub/IotHub/ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,13 @@
* Add support to get/set parent device of an IoT device. New Cmdlets are:
- Get-AzIotHubDeviceParent
- Set-AzIotHubDeviceParent
* Add support to manage device parent-child relationship.
* Add support to manage device parent-child relationship. New Cmdlets are:
- Add-AzIotHubDeviceChildren
- Get-AzIotHubDeviceChildren
- Remove-AzIotHubDeviceChildren
* Add support to manage distributed settings per-device. New Cmdlets are:
- Get-AzIotHubDistributedTracing
- Set-AzIotHubDistributedTracing

## Version 2.1.0
* Added support to manage devices in an Iot Hub. New Cmdlets are:
Expand Down
51 changes: 51 additions & 0 deletions src/IotHub/IotHub/Common/IotHubDataPlaneUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,22 @@

namespace Microsoft.Azure.Commands.Management.IotHub.Common
{
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Azure.Commands.Management.IotHub.Models;
using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Shared;
using Newtonsoft.Json;

public static class IotHubDataPlaneUtils
{
public const string DEVICE_DEVICESCOPE_PREFIX = "ms-azure-iot-edge://";
public const string TRACING_ALLOWED_FOR_SKU = "standard";
public const string TRACING_PROPERTY = "azureiot*com^dtracing^1";

public static readonly string[] TRACING_ALLOWED_FOR_LOCATION = { "northeurope", "westus2", "west us 2", "southeastasia" };

public static string GetEdgeDevices()
{
return "select * from devices where capabilities.iotEdge=true";
Expand Down Expand Up @@ -60,5 +69,47 @@ public static IEnumerable<PSModules> ToPSModules(IEnumerable<Module> modules)
{
return IotHubUtils.ConvertObject<IEnumerable<Module>, IEnumerable<PSModules>>(modules.ToList());
}

public static void Validate_Device_Tracing(string DeviceId, string Sku, string Location, bool IsEdgeDevice)
{
if (!TRACING_ALLOWED_FOR_LOCATION.Any(location => location.Equals(Location, StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException($"Distributed tracing isn\'t supported for the hub located at \"{Location}\"");
}
if (!TRACING_ALLOWED_FOR_SKU.Equals(Sku, StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"Distributed tracing isn\'t supported for the hub belongs to \"{Sku}\" sku tier.");
}
if (IsEdgeDevice)
{
throw new ArgumentException($"The device \"{DeviceId}\" should be non-edge device.");
}
}

public static PSDeviceTracing GetDeviceTracing(string DeviceId, Twin deviceTwin)
{
PSDeviceTracing psDeviceTracing = new PSDeviceTracing
{
DeviceId = DeviceId,
TracingOption = new PSDistributedTracing() { SamplingMode = PSDistributedTracingSamplingMode.Disabled, SamplingRate = 0 },
IsSynced = false
};

if (deviceTwin.Properties.Desired.Contains(TRACING_PROPERTY))
{
psDeviceTracing.TracingOption = JsonConvert.DeserializeObject<PSDistributedTracing>(deviceTwin.Properties.Desired[TRACING_PROPERTY].ToString());
}

if (deviceTwin.Properties.Reported.Contains(TRACING_PROPERTY))
{
PSDistributedTracing psReportedDistributedTracing = JsonConvert.DeserializeObject<PSDistributedTracing>(deviceTwin.Properties.Reported[TRACING_PROPERTY].ToString());
if (psReportedDistributedTracing != null)
{
psDeviceTracing.IsSynced = (psDeviceTracing.TracingOption.SamplingMode.Equals(psReportedDistributedTracing.SamplingMode) && psDeviceTracing.TracingOption.SamplingRate.Equals(psReportedDistributedTracing.SamplingRate));
}
}

return psDeviceTracing;
}
}
}
30 changes: 30 additions & 0 deletions src/IotHub/IotHub/IotHub.format.ps1xml
Original file line number Diff line number Diff line change
Expand Up @@ -898,5 +898,35 @@
</TableRowEntries>
</TableControl>
</View>
<View>
<Name>
Microsoft.Azure.Commands.Management.IotHub.Models.PSDeviceTracing
</Name>
<ViewSelectedBy>
<TypeName>Microsoft.Azure.Commands.Management.IotHub.Models.PSDeviceTracing</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>DeviceId</PropertyName>
</ListItem>
<ListItem>
<Label>Sampling Mode</Label>
<ScriptBlock>$_.TracingOption.SamplingMode</ScriptBlock>
</ListItem>
<ListItem>
<Label>Sampling Rate</Label>
<ScriptBlock>if($_.TracingOption.SamplingMode.value__ -eq 1) { "$($_.TracingOption.SamplingRate)%" } else { "" }</ScriptBlock>
</ListItem>
<ListItem>
<PropertyName>IsSynced</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
</ViewDefinitions>
</Configuration>
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ public override void ExecuteCmdlet()
{
throw new ArgumentException($"The entered device \"{this.DeviceId}\" doesn\'t support parent device functionality.");
}

string parentDeviceId = childDevice.Scope.Substring(Properties.Resources.DEVICE_DEVICESCOPE_PREFIX.Length, childDevice.Scope.LastIndexOf("-") - Properties.Resources.DEVICE_DEVICESCOPE_PREFIX.Length);
string parentDeviceId = childDevice.Scope.Substring(IotHubDataPlaneUtils.DEVICE_DEVICESCOPE_PREFIX.Length, childDevice.Scope.LastIndexOf("-") - IotHubDataPlaneUtils.DEVICE_DEVICESCOPE_PREFIX.Length);

this.WriteObject(IotHubDataPlaneUtils.ToPSDevice(registryManager.GetDeviceAsync(parentDeviceId).GetAwaiter().GetResult()));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// ----------------------------------------------------------------------------------
//
// Copyright Microsoft Corporation
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------------------------------------------------------------

namespace Microsoft.Azure.Commands.Management.IotHub
{
using System;
using System.Collections.Generic;
using System.Management.Automation;
using Microsoft.Azure.Commands.Management.IotHub.Common;
using Microsoft.Azure.Commands.Management.IotHub.Models;
using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Shared;
using Microsoft.Azure.Management.IotHub;
using Microsoft.Azure.Management.IotHub.Models;
using ResourceManager.Common.ArgumentCompleters;

[Cmdlet("Get", ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "IotHubDistributedTracing", DefaultParameterSetName = ResourceParameterSet)]
[Alias("Get-" + ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "IotHubTracing")]
[OutputType(typeof(PSDeviceTracing))]
public class GetAzIotHubDistributedTracing : IotHubBaseCmdlet
{
private const string ResourceIdParameterSet = "ResourceIdSet";
private const string ResourceParameterSet = "ResourceSet";
private const string InputObjectParameterSet = "InputObjectSet";

[Parameter(Position = 0, Mandatory = true, ParameterSetName = InputObjectParameterSet, ValueFromPipeline = true, HelpMessage = "IotHub object")]
[ValidateNotNullOrEmpty]
public PSIotHub InputObject { get; set; }

[Parameter(Position = 0, Mandatory = true, ParameterSetName = ResourceParameterSet, HelpMessage = "Name of the Resource Group")]
[ValidateNotNullOrEmpty]
[ResourceGroupCompleter]
public string ResourceGroupName { get; set; }

[Parameter(Position = 0, Mandatory = true, ParameterSetName = ResourceIdParameterSet, ValueFromPipelineByPropertyName = true, HelpMessage = "IotHub Resource Id")]
[ValidateNotNullOrEmpty]
[ResourceIdCompleter("Microsoft.Devices/IotHubs")]
public string ResourceId { get; set; }

[Parameter(Position = 1, Mandatory = true, ParameterSetName = ResourceParameterSet, HelpMessage = "Name of the Iot Hub")]
[ValidateNotNullOrEmpty]
public string IotHubName { get; set; }

[Parameter(Position = 1, Mandatory = true, ParameterSetName = InputObjectParameterSet, HelpMessage = "Target Device Id.")]
[Parameter(Position = 1, Mandatory = true, ParameterSetName = ResourceIdParameterSet, HelpMessage = "Target Device Id.")]
[Parameter(Position = 2, Mandatory = true, ParameterSetName = ResourceParameterSet, HelpMessage = "Target Device Id.")]
[ValidateNotNullOrEmpty]
public string DeviceId { get; set; }

public override void ExecuteCmdlet()
{
IotHubDescription iotHubDescription;
if (ParameterSetName.Equals(InputObjectParameterSet))
{
this.ResourceGroupName = this.InputObject.Resourcegroup;
this.IotHubName = this.InputObject.Name;
iotHubDescription = IotHubUtils.ConvertObject<PSIotHub, IotHubDescription>(this.InputObject);
}
else
{
if (ParameterSetName.Equals(ResourceIdParameterSet))
{
this.ResourceGroupName = IotHubUtils.GetResourceGroupName(this.ResourceId);
this.IotHubName = IotHubUtils.GetIotHubName(this.ResourceId);
}

iotHubDescription = this.IotHubClient.IotHubResource.Get(this.ResourceGroupName, this.IotHubName);
}

IEnumerable<SharedAccessSignatureAuthorizationRule> authPolicies = this.IotHubClient.IotHubResource.ListKeys(this.ResourceGroupName, this.IotHubName);
SharedAccessSignatureAuthorizationRule policy = IotHubUtils.GetPolicy(authPolicies, PSAccessRights.RegistryWrite);
PSIotHubConnectionString psIotHubConnectionString = IotHubUtils.ToPSIotHubConnectionString(policy, iotHubDescription.Properties.HostName);
RegistryManager registryManager = RegistryManager.CreateFromConnectionString(psIotHubConnectionString.PrimaryConnectionString);

Twin deviceTwin = registryManager.GetTwinAsync(this.DeviceId).GetAwaiter().GetResult();

if (deviceTwin == null)
{
throw new ArgumentException($"The entered non-edge device \"{this.DeviceId}\" doesn't exist.");
}

IotHubDataPlaneUtils.Validate_Device_Tracing(this.DeviceId, iotHubDescription.Sku.Tier.Value.ToString(), iotHubDescription.Location, deviceTwin.Capabilities.IotEdge);

this.WriteObject(IotHubDataPlaneUtils.GetDeviceTracing(this.DeviceId, deviceTwin));
}
}
}
Loading

0 comments on commit 712145c

Please sign in to comment.