* NetworkController linux implementation
This commit is contained in:
Anca Antochi 2019-12-11 17:13:15 -08:00 коммит произвёл GitHub
Родитель 7a5d9017da
Коммит c51606d21d
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
35 изменённых файлов: 1041 добавлений и 19 удалений

Просмотреть файл

@ -207,6 +207,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "modules", "modules", "{F921
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestResultCoordinator", "test\modules\TestResultCoordinator\TestResultCoordinator.csproj", "{8181EB49-62CE-495B-8078-08DCF8C30541}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "connectivity", "connectivity", "{F3B989E5-E7F5-4A07-AEA1-84B63040A190}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetworkController", "test\connectivity\modules\NetworkController\NetworkController.csproj", "{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
CheckInBuild|Any CPU = CheckInBuild|Any CPU
@ -671,6 +675,14 @@ Global
{8181EB49-62CE-495B-8078-08DCF8C30541}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8181EB49-62CE-495B-8078-08DCF8C30541}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8181EB49-62CE-495B-8078-08DCF8C30541}.Release|Any CPU.Build.0 = Release|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.CheckInBuild|Any CPU.ActiveCfg = CheckInBuild|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.CheckInBuild|Any CPU.Build.0 = CheckInBuild|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.CodeCoverage|Any CPU.ActiveCfg = CheckInBuild|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.CodeCoverage|Any CPU.Build.0 = CheckInBuild|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -751,6 +763,8 @@ Global
{C1FDA6CF-7EF6-4C3F-81E7-4C13EE399BF1} = {69157D2B-2AD3-4EE0-A837-6AD9329EDDC3}
{F921339B-32F9-4BF3-B364-2DB01FA2F1A1} = {2300ED4C-1D5A-460F-8691-7C85E1162E0C}
{8181EB49-62CE-495B-8078-08DCF8C30541} = {F921339B-32F9-4BF3-B364-2DB01FA2F1A1}
{F3B989E5-E7F5-4A07-AEA1-84B63040A190} = {2300ED4C-1D5A-460F-8691-7C85E1162E0C}
{9DB94B1F-D773-4D17-9CD7-54EE5DD3F84B} = {F3B989E5-E7F5-4A07-AEA1-84B63040A190}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {D71830F5-3AF5-46B4-8A9E-1DCE4F2253AC}

Просмотреть файл

@ -243,6 +243,13 @@ jobs:
name: Relayer
imageName: azureiotedge-relayer
project: Relayer
# Network Controller
- template: templates/image-linux.yaml
parameters:
name: Network Controller
imageName: azureiotedge-network-controller
project: NetworkController
# TestResultCoordinator
- template: templates/image-linux.yaml

Просмотреть файл

@ -82,7 +82,7 @@
"value": "mqtt"
},
"outputName": {
"value": "output2"
"value": "output2"
}
},
"settings": {
@ -118,30 +118,37 @@
"value": "mqtt"
},
"inputName": {
"value": "input2"
}
},
"settings": {
"value": "input2"
},
"image": "<Container_Registry>/microsoft/azureiotedge-relayer:<Build.BuildNumber>-linux-<Architecture>",
"createOptions": ""
},
"networkController": {
"version": "1.0",
"type": "docker",
"status": "running",
"restartPolicy": "always",
"settings": {
"image": "<Container_Registry>/microsoft/azureiotedge-network-controller:<Build.BuildNumber>-linux-<Architecture>",
"createOptions": "{\"HostConfig\":{\"Privileged\":\"true\",\"NetworkMode\":\"host\",\"Binds\":[\"/var/run/docker.sock:/var/run/docker.sock\"]},\"NetworkingConfig\":{\"EndpointsConfig\":{\"host\":{}}}}"
}
}
}
}
}
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.0",
"routes": {
},
"$edgeHub": {
"properties.desired": {
"schemaVersion": "1.0",
"routes": {
"loadGen1ToRelayer1": "FROM /messages/modules/loadGen1/outputs/output1 INTO BrokeredEndpoint(\"/modules/relayer1/inputs/input1\")",
"relayer1ToCloud": "FROM /messages/modules/relayer1/outputs/output1 INTO $upstream",
"loadGen2ToRelayer2": "FROM /messages/modules/loadGen2/outputs/output2 INTO BrokeredEndpoint(\"/modules/relayer2/inputs/input2\")",
"relayer2ToCloud": "FROM /messages/modules/relayer2/outputs/output2 INTO $upstream"
},
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
"relayer1ToCloud": "FROM /messages/modules/relayer1/outputs/output1 INTO $upstream",
"loadGen2ToRelayer2": "FROM /messages/modules/loadGen2/outputs/output2 INTO BrokeredEndpoint(\"/modules/relayer2/inputs/input2\")",
"relayer2ToCloud": "FROM /messages/modules/relayer2/outputs/output2 INTO $upstream"
},
"storeAndForwardConfiguration": {
"timeToLiveSecs": 86400
}
}
}
}
}
}
}

Просмотреть файл

@ -256,6 +256,7 @@ publish_app "ModuleRestarter"
publish_app "TwinTester"
publish_app "Relayer"
publish_app "TestResultCoordinator"
publish_app "NetworkController"
publish_lib "Microsoft.Azure.WebJobs.Extensions.EdgeHub"
publish_lib "EdgeHubTriggerCSharp"

Просмотреть файл

@ -0,0 +1,3 @@
# Connectivity tests

Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Runtime.Serialization;
[Serializable]
class CommandExecutionException : Exception
{
public CommandExecutionException()
{
}
public CommandExecutionException(string message)
: base(message)
{
}
public CommandExecutionException(string message, Exception innerException)
: base(message, innerException)
{
}
protected CommandExecutionException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

Просмотреть файл

@ -0,0 +1,37 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
using RunProcessAsTask;
class CommandExecutor
{
static readonly ILogger Log = Logger.Factory.CreateLogger<CommandExecutor>();
public static async Task<string> Execute(string commandName, string args, CancellationToken cs)
{
var info = new ProcessStartInfo
{
FileName = commandName,
Arguments = args
};
using (ProcessResults result = await ProcessEx.RunAsync(info, cs))
{
if (result.ExitCode != 0)
{
string errorMessage = $"{commandName} result: {result.StandardError.Join(" ")}";
Log.LogError(errorMessage);
throw new CommandExecutionException(errorMessage);
}
Log.LogDebug($"{commandName} result: {result.StandardOutput.Join(" ")}");
return result.StandardOutput.Join(" ");
}
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
class CountedTaskExecutor
{
readonly TimeSpan interval;
readonly ILogger logger;
readonly string operationName;
readonly int runCount;
readonly TimeSpan startAfter;
readonly Func<CancellationToken, Task> work;
public CountedTaskExecutor(
Func<CancellationToken, Task> work,
TimeSpan startAfter,
TimeSpan interval,
int runsCount,
ILogger logger,
string operationName)
{
this.startAfter = startAfter;
this.interval = interval;
this.runCount = runsCount;
this.work = work;
this.logger = logger;
this.operationName = operationName;
}
public async Task Schedule(CancellationToken cancellationToken)
{
await Task.Delay(this.startAfter, cancellationToken);
for (int i = 0; i < this.runCount; i++)
{
if (cancellationToken.IsCancellationRequested)
{
return;
}
try
{
this.logger.LogInformation($"Starting operation {this.operationName} run number {i}...");
await this.work(cancellationToken);
this.logger.LogInformation($"Successfully completed operation {this.operationName} run number {i}");
await Task.Delay(this.interval, cancellationToken);
}
catch (Exception e)
{
this.logger.LogError(e, $"Failed to run {this.operationName} scheduled task run number {i}");
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Net.NetworkInformation;
using Docker.DotNet;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
class DockerHelper
{
const int DockerNetworkInterfaceNameLenght = 12;
const int DockerNetworkInterfaceStartIndex = 0;
const string DockerNetworkInterfaceSuffix = "br-";
static readonly ILogger Log = Logger.Factory.CreateLogger<DockerHelper>();
public static Option<string> GetDockerInterfaceName()
{
var client = new DockerClientConfiguration(new Uri(Settings.Current.DockerUri)).CreateClient();
var networkId = client.Networks.InspectNetworkAsync(Settings.Current.NetworkId).Result.ID;
string interfaceName = GetInterfaceNameFromNetworkId(networkId);
Log.LogInformation($"{Settings.Current.NetworkId} network has id {networkId}");
foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
{
if (item.Name.Equals(interfaceName, StringComparison.OrdinalIgnoreCase))
{
Log.LogInformation($"Found network interface {item.Name}");
return Option.Some(item.Name);
}
}
Log.LogInformation($"No network interface found for docker network id {Settings.Current.NetworkId}");
return Option.None<string>();
}
static string GetInterfaceNameFromNetworkId(string networkId)
{
// TODO: this is on linux, windows might be different
// Network interface name has by default first chars form networkId
return string.Format($"{DockerNetworkInterfaceSuffix}{networkId.Substring(DockerNetworkInterfaceStartIndex, DockerNetworkInterfaceNameLenght)}");
}
}
}

Просмотреть файл

@ -0,0 +1,68 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
class FirewallOfflineController : IController
{
static readonly ILogger Log = Logger.Factory.CreateLogger<FirewallOfflineController>();
readonly IFirewallCommands networkCommands;
public FirewallOfflineController(string networkInterfaceName)
{
Preconditions.CheckNonWhiteSpace(networkInterfaceName, nameof(networkInterfaceName));
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
this.networkCommands = new WindowsFirewallCommands(networkInterfaceName);
}
else
{
this.networkCommands = new LinuxFirewallCommands(networkInterfaceName);
}
}
public string Description => "FirewallOffline";
public async Task<NetworkStatus> GetStatus(CancellationToken cs) => await this.networkCommands.GetStatus(cs);
public Task<bool> SetStatus(NetworkStatus status, CancellationToken cs)
{
switch (status)
{
case NetworkStatus.Restricted:
return this.AddNetworkControllingRule(cs);
case NetworkStatus.Default:
return this.RemoveNetworkControllingRule(cs);
default:
Log.LogDebug($"Status not set {status}");
throw new NotSupportedException($"Status is not supported {status}");
}
}
async Task<bool> AddNetworkControllingRule(CancellationToken cs)
{
bool result = await this.networkCommands.AddDropRule(cs);
NetworkStatus status = await this.GetStatus(cs);
Log.LogInformation($"Command AddDropRule execution success {result}, network status {status}");
return result && status == NetworkStatus.Restricted;
}
async Task<bool> RemoveNetworkControllingRule(CancellationToken cs)
{
bool result = await this.networkCommands.RemoveDropRule(cs);
NetworkStatus status = await this.GetStatus(cs);
Log.LogInformation($"Command RemoveDropRule execution success {result}, network status {status}");
return result && status == NetworkStatus.Default;
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System.Threading;
using System.Threading.Tasks;
interface IController
{
string Description { get; }
Task<bool> SetStatus(NetworkStatus status, CancellationToken cs);
Task<NetworkStatus> GetStatus(CancellationToken cs);
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System.Threading;
using System.Threading.Tasks;
interface IFirewallCommands
{
Task<bool> RemoveDropRule(CancellationToken cs);
Task<bool> AddDropRule(CancellationToken cs);
Task<NetworkStatus> GetStatus(CancellationToken cs);
}
}

Просмотреть файл

@ -0,0 +1,13 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System.Threading;
using System.Threading.Tasks;
interface INetworkInterfaceCommands
{
Task<bool> Enable(CancellationToken token);
Task<bool> Disable(CancellationToken token);
}
}

Просмотреть файл

@ -0,0 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System.Threading.Tasks;
interface INetworkStatusReporter
{
Task ReportNetworkStatus(NetworkControllerOperation settingRule, NetworkStatus status, string description, bool success = true);
}
}

Просмотреть файл

@ -0,0 +1,82 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
class LinuxFirewallCommands : IFirewallCommands
{
static readonly ILogger Log = Logger.Factory.CreateLogger<LinuxFirewallCommands>();
readonly string networkInterfaceName;
public LinuxFirewallCommands(string networkInterfaceName)
{
this.networkInterfaceName = networkInterfaceName;
}
public async Task<NetworkStatus> GetStatus(CancellationToken cs)
{
try
{
string output = await CommandExecutor.Execute(
"tc",
$"qdisc show dev {this.networkInterfaceName}",
cs);
// parse output to see if online or offline
if (output.Contains("qdisc noqueue"))
{
return NetworkStatus.Default;
}
else
{
return NetworkStatus.Restricted;
}
}
catch (Exception e)
{
Log.LogError(e, "Failed to get network status");
return NetworkStatus.Unknown;
}
}
public async Task<bool> RemoveDropRule(CancellationToken cs)
{
try
{
string output = await CommandExecutor.Execute(
"tc",
$"qdisc delete dev {this.networkInterfaceName} root netem loss 100%",
cs);
return true;
}
catch (Exception e)
{
Log.LogError(e, "Failed to set accept rule");
return false;
}
}
public async Task<bool> AddDropRule(CancellationToken cs)
{
try
{
string output = await CommandExecutor.Execute(
"tc",
$"qdisc add dev {this.networkInterfaceName} root netem loss 100%",
cs);
return true;
}
catch (Exception e)
{
Log.LogError(e, "Failed to set drop rule");
return false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
class LinuxNetworkInterfaceCommands : INetworkInterfaceCommands
{
static readonly ILogger Log = Logger.Factory.CreateLogger<LinuxNetworkInterfaceCommands>();
readonly string interfaceName;
public LinuxNetworkInterfaceCommands(string interfaceName)
{
this.interfaceName = interfaceName;
}
public async Task<bool> Disable(CancellationToken token)
{
try
{
string output = await CommandExecutor.Execute("ifconfig", $"{this.interfaceName} down", token);
Log.LogInformation($"Disabled {this.interfaceName}");
return true;
}
catch (Exception e)
{
Log.LogError(e, "Failed to disable");
return false;
}
}
public async Task<bool> Enable(CancellationToken token)
{
try
{
var exitCode = await CommandExecutor.Execute("ifconfig", $"{this.interfaceName} up", token);
Log.LogInformation($"Enabled {this.interfaceName}");
return true;
}
catch (Exception e)
{
Log.LogError(e, "Failed to disable");
return false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup Condition="'$(DotNet_Runtime)' != 'netcoreapp3.0'">
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(OS)|$(DotNet_Runtime)' == 'Unix|netcoreapp3.0'">
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<LangVersion>latest</LangVersion>
<Configurations>Debug;Release;CheckInBuild</Configurations>
<HighEntropyVA>true</HighEntropyVA>
</PropertyGroup>
<ItemGroup>
<None Remove="docker\linux\amd64\Dockerfile" />
<None Remove="docker\linux\arm32v7\Dockerfile" />
<None Remove="docker\linux\arm64v8\Dockerfile" />
<None Remove="docker\windows\amd64\Dockerfile" />
<None Remove="docker\windows\arm32v7\Dockerfile" />
</ItemGroup>
<ItemGroup>
<Content Include="docker*/**/*.*" CopyToPublishDirectory="Always" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Docker.DotNet" Version="3.125.2" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
<PackageReference Include="RunProcessAsTask" Version="1.2.4" />
</ItemGroup>
<ItemGroup>
<None Update="config\settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="..\..\..\..\stylecop.json" Link="stylecop.json" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\edge-util\src\Microsoft.Azure.Devices.Edge.Util\Microsoft.Azure.Devices.Edge.Util.csproj" />
</ItemGroup>
<PropertyGroup>
<CodeAnalysisRuleSet>..\..\..\..\stylecop.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<Import Project="..\..\..\..\stylecop.props" />
</Project>

Просмотреть файл

@ -0,0 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
enum NetworkControllerMode
{
OfflineNetworkInterface = 0,
OfflineTrafficController,
SatelliteTrafficController
}
}

Просмотреть файл

@ -0,0 +1,9 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
enum NetworkControllerOperation
{
SettingRule,
RuleSet
}
}

Просмотреть файл

@ -0,0 +1,95 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
class NetworkInterfaceOfflineController : IController
{
static readonly ILogger Log = Logger.Factory.CreateLogger<NetworkInterfaceOfflineController>();
readonly INetworkInterfaceCommands networkCommands;
readonly string networkInterfaceName;
public NetworkInterfaceOfflineController(string dockerInterfaceName)
{
this.networkInterfaceName =
Preconditions.CheckNonWhiteSpace(dockerInterfaceName, nameof(dockerInterfaceName));
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
this.networkCommands = new WindowsNetworkInterfaceCommands();
}
else
{
this.networkCommands = new LinuxNetworkInterfaceCommands(this.networkInterfaceName);
}
}
public string Description => "NetworkInterfaceOffline";
public Task<NetworkStatus> GetStatus(CancellationToken cs)
{
OperationalStatus status = this.GetNetworkInterfaceStatus();
switch (status)
{
case OperationalStatus.Up:
return Task.FromResult(NetworkStatus.Default);
case OperationalStatus.Unknown:
return Task.FromResult(NetworkStatus.Unknown);
default:
return Task.FromResult(NetworkStatus.Restricted);
}
}
public async Task<bool> AddNetworkControllingRule(CancellationToken cs)
{
bool result = await this.networkCommands.Disable(cs);
NetworkStatus status = await this.GetStatus(cs);
Log.LogInformation($"Command AddNetworkControllingRule success {result}, network status {status}");
return result && status == NetworkStatus.Restricted;
}
public async Task<bool> RemoveNetworkControllingRule(CancellationToken cs)
{
bool result = await this.networkCommands.Enable(cs);
NetworkStatus status = await this.GetStatus(cs);
Log.LogInformation($"Command RemoveNetworkControllingRule execution success {result}, network status {status}");
return result && status == NetworkStatus.Default;
}
public Task<bool> SetStatus(NetworkStatus status, CancellationToken cs)
{
switch (status)
{
case NetworkStatus.Restricted:
return this.AddNetworkControllingRule(cs);
case NetworkStatus.Default:
return this.RemoveNetworkControllingRule(cs);
default:
Log.LogDebug($"Status not set {status}");
throw new NotSupportedException($"Status '{status}' is not supported.");
}
}
OperationalStatus GetNetworkInterfaceStatus()
{
foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
{
if (item.Name.Equals(this.networkInterfaceName))
{
return item.OperationalStatus;
}
}
return OperationalStatus.Unknown;
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System.Threading.Tasks;
class NetworkReporter : INetworkStatusReporter
{
public Task ReportNetworkStatus(NetworkControllerOperation settingRule, NetworkStatus status, string description, bool success = true)
{
// TODO: send to analyzer
return Task.CompletedTask;
}
}
}

Просмотреть файл

@ -0,0 +1,10 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
enum NetworkStatus
{
Unknown = 0,
Restricted,
Default
}
}

Просмотреть файл

@ -0,0 +1,116 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Logging;
class Program
{
static readonly ILogger Log = Logger.Factory.CreateLogger<Program>();
static async Task Main()
{
(CancellationTokenSource cts, ManualResetEventSlim completed, Option<object> handler) = ShutdownHandler.Init(TimeSpan.FromSeconds(5), Log);
Log.LogInformation($"Starting with {Settings.Current.NetworkControllerMode}");
var networkInterfaceName = DockerHelper.GetDockerInterfaceName();
if (networkInterfaceName.HasValue)
{
await networkInterfaceName.ForEachAsync(
async name =>
{
var nic = new NetworkInterfaceOfflineController(name);
var firewall = new FirewallOfflineController(name);
var satellite = new SatelliteController(name);
var controllers = new List<IController>() { nic, firewall, satellite };
await RemoveAllControllingRules(controllers, cts.Token);
switch (Settings.Current.NetworkControllerMode)
{
case NetworkControllerMode.OfflineNetworkInterface:
await StartAsync(nic, cts.Token);
break;
case NetworkControllerMode.OfflineTrafficController:
await StartAsync(firewall, cts.Token);
break;
case NetworkControllerMode.SatelliteTrafficController:
await StartAsync(satellite, cts.Token);
break;
}
});
await cts.Token.WhenCanceled();
completed.Set();
handler.ForEach(h => GC.KeepAlive(h));
}
else
{
Log.LogError($"No network interface found for docker network {Settings.Current.NetworkId}");
}
}
static async Task StartAsync(IController controller, CancellationToken cancellationToken)
{
var delay = Settings.Current.StartAfter;
INetworkStatusReporter reporter = new NetworkReporter();
foreach (Frequency item in Settings.Current.Frequencies)
{
Log.LogInformation($"Schedule task with {controller.Description} to start after {delay} Offline frequency {item.OfflineFrequency} Online frequency {item.OnlineFrequency} Run times {item.RunsCount}");
var taskExecutor = new CountedTaskExecutor(
async cs =>
{
await SetNetworkStatus(controller, NetworkStatus.Restricted, reporter, cs);
await Task.Delay(item.OfflineFrequency, cs);
await SetNetworkStatus(controller, NetworkStatus.Default, reporter, cs);
},
delay,
item.OfflineFrequency,
item.RunsCount,
Log,
"restrict/default");
await taskExecutor.Schedule(cancellationToken);
// Only needs to set the start delay for first frequency, after that reset to 0
delay = TimeSpan.FromSeconds(0);
}
}
static async Task SetNetworkStatus(IController controller, NetworkStatus status, INetworkStatusReporter reporter, CancellationToken cs)
{
await reporter.ReportNetworkStatus(NetworkControllerOperation.SettingRule, status, controller.Description);
bool success = await controller.SetStatus(status, cs);
await reporter.ReportNetworkStatus(NetworkControllerOperation.RuleSet, status, controller.Description, success);
}
static async Task RemoveAllControllingRules(IList<IController> controllerList, CancellationToken cancellationToken)
{
var reporter = new NetworkReporter();
foreach (var controller in controllerList)
{
NetworkStatus status = await controller.GetStatus(cancellationToken);
if (status != NetworkStatus.Default)
{
Log.LogInformation($"Network is {status} with {controller.Description}, setting default");
bool online = await controller.SetStatus(NetworkStatus.Default, cancellationToken);
if (!online)
{
Log.LogError($"Failed to ensure it starts with default values.");
throw new TestInitializationException();
}
}
}
Log.LogInformation($"Network is online");
await reporter.ReportNetworkStatus(NetworkControllerOperation.RuleSet, NetworkStatus.Default, "All", true);
}
}
}

Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System.Threading;
using System.Threading.Tasks;
// TODO: implement satellite
class SatelliteController : IController
{
string name;
public SatelliteController(string name)
{
this.name = name;
}
public string Description => "Satellite";
public Task<bool> SetStatus(NetworkStatus status, CancellationToken cs)
{
return Task.FromResult(true);
}
public Task<NetworkStatus> GetStatus(CancellationToken cs)
{
return Task.FromResult(NetworkStatus.Default);
}
}
}

Просмотреть файл

@ -0,0 +1,73 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Azure.Devices.Edge.Util;
using Microsoft.Extensions.Configuration;
class Settings
{
const string StartAfterPropertyName = "StartAfter";
const string DockerUriPropertyName = "DockerUri";
const string FrequencyPropertyName = "RunFrequencies";
const string NetworkIdPropertyName = "NetworkId";
const string NetworkControllerModePropertyName = "NetworkControllerMode";
static readonly Lazy<Settings> Setting = new Lazy<Settings>(
() =>
{
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("config/settings.json")
.AddEnvironmentVariables()
.Build();
var result = new List<Frequency>();
configuration.GetSection(FrequencyPropertyName).Bind(result);
return new Settings(
configuration.GetValue<TimeSpan>(StartAfterPropertyName),
configuration.GetValue<string>(DockerUriPropertyName),
configuration.GetValue<string>(NetworkIdPropertyName),
result,
configuration.GetValue<NetworkControllerMode>(NetworkControllerModePropertyName));
});
Settings(
TimeSpan startAfter,
string dockerUri,
string networkId,
IList<Frequency> frequencies,
NetworkControllerMode mode)
{
this.StartAfter = startAfter;
this.Frequencies = frequencies;
this.DockerUri = Preconditions.CheckNonWhiteSpace(dockerUri, nameof(dockerUri));
this.NetworkId = Preconditions.CheckNonWhiteSpace(networkId, nameof(networkId));
this.NetworkControllerMode = mode;
}
public static Settings Current => Setting.Value;
public TimeSpan StartAfter { get; }
public IList<Frequency> Frequencies { get; }
public string DockerUri { get; }
public string NetworkId { get; }
public NetworkControllerMode NetworkControllerMode { get; }
}
class Frequency
{
public TimeSpan OfflineFrequency { get; set; }
public TimeSpan OnlineFrequency { get; set; }
public int RunsCount { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,29 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Runtime.Serialization;
[Serializable]
class TestInitializationException : Exception
{
public TestInitializationException()
{
}
public TestInitializationException(string message)
: base(message)
{
}
public TestInitializationException(string message, Exception innerException)
: base(message, innerException)
{
}
protected TestInitializationException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
}

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.Devices.Edge.Util;
class WindowsFirewallCommands : IFirewallCommands
{
readonly string networkInterfaceName;
public WindowsFirewallCommands(string networkInterfaceName)
{
this.networkInterfaceName =
Preconditions.CheckNonWhiteSpace(networkInterfaceName, nameof(networkInterfaceName));
}
public Task<NetworkStatus> GetStatus(CancellationToken cs)
{
throw new NotImplementedException();
}
public Task<bool> RemoveDropRule(CancellationToken cs) => throw new NotImplementedException();
public Task<bool> AddDropRule(CancellationToken cs) => throw new NotImplementedException();
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) Microsoft. All rights reserved.
namespace NetworkController
{
using System;
using System.Threading;
using System.Threading.Tasks;
class WindowsNetworkInterfaceCommands : INetworkInterfaceCommands
{
public Task<bool> Disable(CancellationToken token) =>
throw new NotImplementedException();
public Task<bool> Enable(CancellationToken token) => throw new NotImplementedException();
}
}

Просмотреть файл

@ -0,0 +1,13 @@
{
"StartAfter": "00:05:00",
"DockerUri": "unix:///var/run/docker.sock",
"NetworkId": "azure-iot-edge",
"NetworkControllerMode": "OfflineTrafficController",
"RunFrequencies": [
{
"OfflineFrequency": "00:05:00",
"OnlineFrequency": "00:05:00",
"RunsCount": "6"
}
]
}

Просмотреть файл

@ -0,0 +1,16 @@
ARG base_tag=2.1.13-alpine3.10
FROM mcr.microsoft.com/dotnet/core/runtime:${base_tag}
ARG EXE_DIR=.
RUN apk update && \
apk add --no-cache iproute2
ENV MODULE_NAME "NetworkController.dll"
WORKDIR /app
COPY $EXE_DIR/ ./
CMD echo "$(date --utc +"[%Y-%m-%d %H:%M:%S %:z]"): Starting Module" && \
exec /usr/bin/dotnet NetworkController.dll

Просмотреть файл

@ -0,0 +1,13 @@
ARG base_tag=1.0.0-linux-arm32v7
FROM azureiotedge/azureiotedge-networkcontroller-module-base:${base_tag}
ARG EXE_DIR=.
ENV MODULE_NAME "NetworkController.dll"
WORKDIR /app
COPY $EXE_DIR/ ./
CMD echo "$(date --utc +"[%Y-%m-%d %H:%M:%S %:z]"): Starting Module" && \
exec /usr/bin/dotnet NetworkController.dll

Просмотреть файл

@ -0,0 +1,4 @@
ARG base_tag=2.1.13-bionic-arm32v7
FROM mcr.microsoft.com/dotnet/core/runtime:${base_tag}
RUN apt-get update && apt-get install -y --no-install-recommends iproute2 net-tools

Просмотреть файл

@ -0,0 +1,13 @@
ARG base_tag=1.0.3-linux-arm64v8
FROM azureiotedge/azureiotedge-module-base:${base_tag}
ARG EXE_DIR=.
ENV MODULE_NAME "NetworkController.dll"
WORKDIR /app
COPY $EXE_DIR/ ./
CMD echo "$(date --utc +"%Y-%m-%d %H:%M:%S %:z") Starting Module" && \
exec /usr/bin/dotnet NetworkController.dll

Просмотреть файл

@ -0,0 +1,10 @@
ARG base_tag=2.1.13-nanoserver-1809
FROM mcr.microsoft.com/dotnet/core/runtime:${base_tag}
ARG EXE_DIR=.
WORKDIR /app
COPY $EXE_DIR/ ./
CMD ["dotnet", "NetworkController.dll"]

Просмотреть файл

@ -0,0 +1,11 @@
ARG base_tag=1.0.3-windows-arm32v7
ARG base_registry
FROM ${base_registry}/azureiotedge/azureiotedge-module-base:${base_tag}
ARG EXE_DIR=.
WORKDIR /app
COPY $EXE_DIR/ ./
CMD ["dotnet", "NetworkController.dll"]