Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to Quickstart for testing devices behind an HTTP proxy. #446

Merged
merged 5 commits into from
Oct 17, 2018
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion smoke/IotEdgeQuickstart/IotEdgeQuickstart.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.2.0-*" />
<PackageReference Include="Microsoft.Azure.Devices" Version="1.17.1" />
<PackageReference Include="Microsoft.Azure.EventHubs" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.EventHubs" Version="2.2.1" />
<PackageReference Include="Microsoft.CodeCoverage" Version="1.0.3" />
<PackageReference Include="RunProcessAsTask" Version="1.2.3" />
<PackageReference Include="YamlDotNet" Version="4.3.2" />
Expand Down
32 changes: 30 additions & 2 deletions smoke/IotEdgeQuickstart/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Option Environment variable
--registry registryAddress
--tag imageTag
--username registryUser
--proxy https_proxy

Defaults:
All options to this command have defaults. If an option is not specified and
Expand Down Expand Up @@ -55,6 +56,7 @@ Option Default value
--deployment deployment json file
--runtime-log-level debug
--clean_up_existing_device false
--proxy No proxy is used
"
)]
[HelpOption]
Expand Down Expand Up @@ -129,6 +131,12 @@ class Program
[Option("--clean_up_existing_device <true/false>", CommandOptionType.SingleValue, Description = "Clean up existing device on success.")]
public bool CleanUpExistingDeviceOnSuccess { get; } = false;

[Option("--proxy <value>", CommandOptionType.SingleValue, Description = "Proxy for IoT Hub connections.")]
public (bool useProxy, string proxyUrl) Proxy { get; } = (false, string.Empty);

[Option("--upstream-protocol <value>", CommandOptionType.SingleValue, Description = "Upstream protocol for IoT Hub connections.")]
public (bool overrideUpstreamProtocol, UpstreamProtocolType upstreamProtocol) UpstreamProtocol { get; } = (false, UpstreamProtocolType.Amqp);

// ReSharper disable once UnusedMember.Local
async Task<int> OnExecuteAsync()
{
Expand All @@ -152,17 +160,28 @@ async Task<int> OnExecuteAsync()
{
case BootstrapperType.Iotedged:
{
(bool useProxy, string proxyUrl) = this.Proxy;
Option<string> proxy = useProxy
? Option.Some(proxyUrl)
: Option.Maybe(Environment.GetEnvironmentVariable("https_proxy"));

if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
bootstrapper = new IotedgedWindows(this.BootstrapperArchivePath, credentials);
bootstrapper = new IotedgedWindows(this.BootstrapperArchivePath, credentials, proxy);
}
else
{
(bool useHttp, string hostname) = this.UseHttp;
Option<HttpUris> uris = useHttp
? Option.Some(string.IsNullOrEmpty(hostname) ? new HttpUris() : new HttpUris(hostname))
: Option.None<HttpUris>();
bootstrapper = new IotedgedLinux(this.BootstrapperArchivePath, credentials, uris);

(bool overrideUpstreamProtocol, UpstreamProtocolType upstreamProtocol) = this.UpstreamProtocol;
Option<UpstreamProtocolType> upstreamProtocolOption = overrideUpstreamProtocol
? Option.Some(upstreamProtocol)
: Option.None<UpstreamProtocolType>();

bootstrapper = new IotedgedLinux(this.BootstrapperArchivePath, credentials, uris, proxy, upstreamProtocolOption);
}
}
break;
Expand All @@ -188,6 +207,7 @@ async Task<int> OnExecuteAsync()
credentials,
connectionString,
endpoint,
this.UpstreamProtocol.Item2,
tag,
this.DeviceId,
this.EdgeHostname,
Expand Down Expand Up @@ -246,4 +266,12 @@ public enum LogLevel
Info,
Debug
}

public enum UpstreamProtocolType
{
Amqp,
AmqpWs,
Mqtt,
MqttWs
}
}
3 changes: 2 additions & 1 deletion smoke/IotEdgeQuickstart/Quickstart.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public Quickstart(
Option<RegistryCredentials> credentials,
string iothubConnectionString,
string eventhubCompatibleEndpointWithEntityPath,
UpstreamProtocolType upstreamProtocol,
string imageTag,
string deviceId,
string hostname,
Expand All @@ -34,7 +35,7 @@ public Quickstart(
bool optimizedForPerformance,
LogLevel runtimeLogLevel,
bool cleanUpExistingDeviceOnSuccess) :
base(bootstrapper, credentials, iothubConnectionString, eventhubCompatibleEndpointWithEntityPath, imageTag, deviceId, hostname, deploymentFileName, deviceCaCert, deviceCaPk, deviceCaCerts, optimizedForPerformance, runtimeLogLevel, cleanUpExistingDeviceOnSuccess)
base(bootstrapper, credentials, iothubConnectionString, eventhubCompatibleEndpointWithEntityPath, upstreamProtocol, imageTag, deviceId, hostname, deploymentFileName, deviceCaCert, deviceCaPk, deviceCaCerts, optimizedForPerformance, runtimeLogLevel, cleanUpExistingDeviceOnSuccess)
{
this.leaveRunning = leaveRunning;
this.noDeployment = noDeployment;
Expand Down
33 changes: 29 additions & 4 deletions smoke/IotEdgeQuickstart/details/Details.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ namespace IotEdgeQuickstart.Details
using Microsoft.Azure.EventHubs;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using EventHubClientTransportType = Microsoft.Azure.EventHubs.TransportType;
using ServiceClientTransportType = Microsoft.Azure.Devices.TransportType;

public class Details
{
readonly IBootstrapper bootstrapper;
readonly Option<RegistryCredentials> credentials;
readonly string iothubConnectionString;
readonly string eventhubCompatibleEndpointWithEntityPath;
readonly ServiceClientTransportType serviceClientTransportType;
readonly EventHubClientTransportType eventHubClientTransportType;
readonly string imageTag;
readonly string deviceId;
readonly string hostname;
Expand All @@ -40,6 +44,7 @@ protected Details(
Option<RegistryCredentials> credentials,
string iothubConnectionString,
string eventhubCompatibleEndpointWithEntityPath,
UpstreamProtocolType upstreamProtocol,
string imageTag,
string deviceId,
string hostname,
Expand All @@ -56,6 +61,25 @@ bool cleanUpExistingDeviceOnSuccess
this.credentials = credentials;
this.iothubConnectionString = iothubConnectionString;
this.eventhubCompatibleEndpointWithEntityPath = eventhubCompatibleEndpointWithEntityPath;

switch (upstreamProtocol)
{
case UpstreamProtocolType.Amqp:
case UpstreamProtocolType.Mqtt:
this.serviceClientTransportType = ServiceClientTransportType.Amqp;
this.eventHubClientTransportType = EventHubClientTransportType.Amqp;
break;

case UpstreamProtocolType.AmqpWs:
case UpstreamProtocolType.MqttWs:
this.serviceClientTransportType = ServiceClientTransportType.Amqp_WebSocket_Only;
this.eventHubClientTransportType = EventHubClientTransportType.AmqpWebSockets;
break;

default:
throw new Exception($"Unexpected upstream protocol type {upstreamProtocol}");
}

this.imageTag = imageTag;
this.deviceId = deviceId;
this.hostname = hostname;
Expand Down Expand Up @@ -147,7 +171,7 @@ protected async Task VerifyEdgeAgentIsConnectedToIotHub()
try
{
ServiceClient serviceClient =
ServiceClient.CreateFromConnectionString(this.context.IotHubConnectionString);
ServiceClient.CreateFromConnectionString(this.context.IotHubConnectionString, this.serviceClientTransportType);

while (true)
{
Expand Down Expand Up @@ -196,6 +220,7 @@ protected Task DeployToEdgeDevice()
protected async Task VerifyDataOnIoTHub(string moduleId)
{
var builder = new EventHubsConnectionStringBuilder(this.eventhubCompatibleEndpointWithEntityPath);
builder.TransportType = this.eventHubClientTransportType;

Console.WriteLine($"Receiving events from device '{this.context.Device.Id}' on Event Hub '{builder.EntityPath}'");

Expand All @@ -207,7 +232,7 @@ protected async Task VerifyDataOnIoTHub(string moduleId)
EventHubPartitionKeyResolver.ResolveToPartition(
this.context.Device.Id,
(await eventHubClient.GetRuntimeInformationAsync()).PartitionCount),
DateTime.Now);
EventPosition.FromEnd());

var result = new TaskCompletionSource<bool>();
using (var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3)))
Expand All @@ -216,8 +241,8 @@ protected async Task VerifyDataOnIoTHub(string moduleId)
{
eventHubReceiver.SetReceiveHandler(new PartitionReceiveHandler(eventData =>
{
eventData.Properties.TryGetValue("iothub-connection-device-id", out object devId);
eventData.Properties.TryGetValue("iothub-connection-module-id", out object modId);
eventData.SystemProperties.TryGetValue("iothub-connection-device-id", out object devId);
eventData.SystemProperties.TryGetValue("iothub-connection-module-id", out object modId);
arsing marked this conversation as resolved.
Show resolved Hide resolved

if (devId != null && devId.ToString().Equals(this.context.Device.Id) &&
modId != null && modId.ToString().Equals(moduleId))
Expand Down
10 changes: 9 additions & 1 deletion smoke/IotEdgeQuickstart/details/IotedgedLinux.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,16 @@ class IotedgedLinux : IBootstrapper
readonly string archivePath;
readonly Option<RegistryCredentials> credentials;
readonly Option<HttpUris> httpUris;
readonly Option<string> proxy;
readonly Option<UpstreamProtocolType> upstreamProtocol;

public IotedgedLinux(string archivePath, Option<RegistryCredentials> credentials, Option<HttpUris> httpUris)
public IotedgedLinux(string archivePath, Option<RegistryCredentials> credentials, Option<HttpUris> httpUris, Option<string> proxy, Option<UpstreamProtocolType> upstreamProtocol)
{
this.archivePath = archivePath;
this.credentials = credentials;
this.httpUris = httpUris;
this.proxy = proxy;
this.upstreamProtocol = upstreamProtocol;
}

public async Task VerifyNotActive()
Expand Down Expand Up @@ -198,6 +202,10 @@ public async Task Configure(string connectionString, string image, string hostna
doc.ReplaceOrAdd("certificates.trusted_ca_certs", deviceCaCerts);
}

this.proxy.ForEach(proxy => doc.ReplaceOrAdd("agent.env.https_proxy", proxy));

this.upstreamProtocol.ForEach(upstreamProtocol => doc.ReplaceOrAdd("agent.env.UpstreamProtocol", upstreamProtocol.ToString()));

string result = doc.ToString();


Expand Down
8 changes: 7 additions & 1 deletion smoke/IotEdgeQuickstart/details/IotedgedWindows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ class IotedgedWindows : IBootstrapper
{
readonly string archivePath;
readonly Option<RegistryCredentials> credentials;
readonly Option<string> proxy;
string scriptDir;

public IotedgedWindows(string archivePath, Option<RegistryCredentials> credentials)
public IotedgedWindows(string archivePath, Option<RegistryCredentials> credentials, Option<string> proxy)
{
this.archivePath = archivePath;
this.credentials = credentials;
this.proxy = proxy;
}

public async Task VerifyNotActive()
Expand Down Expand Up @@ -115,6 +117,10 @@ await Process.RunAsync("powershell",
args += $" -Username '{c.User}' -Password (ConvertTo-SecureString '{c.Password}' -AsPlainText -Force)";
}

this.proxy.ForEach(proxy => {
args += $" -Proxy '{proxy}'";
});

if (this.archivePath != null)
{
args += $" -ArchivePath '{this.archivePath}'";
Expand Down
2 changes: 1 addition & 1 deletion smoke/IotEdgeQuickstart/details/PartitionReceiveHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ public Task ProcessEventsAsync(IEnumerable<EventData> events)
return Task.CompletedTask;
}
public Task ProcessErrorAsync(Exception error) => throw error;
public int MaxBatchSize { get; } = 10;
public int MaxBatchSize { get; set; }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who uses this setter?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interface requires it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There doesn't seem to be any reason why they changed it to require a setter. The IPartitionReceiver impl in the SDK only gets its value.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@
"image": "edgebuilds.azurecr.io/microsoft/azureiotedge-direct-method-receiver:<Build.BuildNumber>-linux-<Architecture>",
"createOptions": ""
}
},

}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
"image": "edgebuilds.azurecr.io/microsoft/azureiotedge-hub:<Build.BuildNumber>-linux-<Architecture>",
"createOptions": "{\"HostConfig\": {\"PortBindings\": {\"8883/tcp\": [{\"HostPort\": \"8883\"}],\"443/tcp\": [{\"HostPort\": \"443\"}],\"5671/tcp\": [{\"HostPort\": \"5671\"}]}}}"
},
"env": {
"OptimizeForPerformance": {
"value": "<OptimizeForPerformance>"
}
},
"env": {
"OptimizeForPerformance": {
"value": "<OptimizeForPerformance>"
}
},
"status": "running",
"restartPolicy": "always"
}
Expand Down Expand Up @@ -65,8 +65,7 @@
"image": "edgebuilds.azurecr.io/microsoft/azureiotedge-temperature-filter:<Build.BuildNumber>-linux-<Architecture>",
"createOptions": ""
}
},

}
}
}
},
Expand Down