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

did wrong - ignore #172

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all 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
4 changes: 2 additions & 2 deletions src/all.sln
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "devhostAgent.restorationjob
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "routingmanager.tests", "routingmanager.tests\routingmanager.tests.csproj", "{49DF73FE-1E7D-4AF6-87B5-194BF4A35ADB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "endpointmanagerlauncher", "endpointmanagerlauncher\endpointmanagerlauncher.csproj", "{B406D9B1-35B1-42CC-B39C-9E6E691EB99E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "endpointmanagerlauncher", "EndpointManagerLauncher\endpointmanagerlauncher.csproj", "{B406D9B1-35B1-42CC-B39C-9E6E691EB99E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "localagent", "LocalAgent\localagent.csproj", "{C3F0EE30-9187-43D8-B2C7-86CD61635561}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "localagent", "LocalAgent\LocalAgent.csproj", "{C3F0EE30-9187-43D8-B2C7-86CD61635561}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dsc.tests", "dsc.tests\dsc.tests.csproj", "{C3753974-9857-4AF1-B06B-DD53F963108B}"
EndProject
Expand Down
2 changes: 1 addition & 1 deletion src/common/Kubernetes/KubernetesConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public static class TypeStrings

public static class Protocols
{
public const string Tcp = "TCP";
public const string Tcp = "tcp";
}
}
}
36 changes: 25 additions & 11 deletions src/common/Models/Settings/PortPair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,28 @@ public class PortPair : ICloneable
/// <param name="localPort"></param>
/// <param name="remotePort"></param>
/// <param name="protocol"></param>
/// <param name="name"></param>
[JsonConstructor]
public PortPair(int localPort, int remotePort, string protocol = KubernetesConstants.Protocols.Tcp)
public PortPair(int localPort, int remotePort, string protocol = KubernetesConstants.Protocols.Tcp, string name = null)
{
this.LocalPort = localPort;
this.RemotePort = remotePort;
this.Protocol = protocol;
LocalPort = localPort;
RemotePort = remotePort;
Protocol = protocol;
Name = name;
}

/// <summary>
/// Constructor
/// </summary>
/// <param name="remotePort"></param>
/// <param name="protocol"></param>
public PortPair(int remotePort, string protocol = KubernetesConstants.Protocols.Tcp)
/// <param name="name"></param>
public PortPair(int remotePort, string protocol = KubernetesConstants.Protocols.Tcp, string name = null)
{
this.LocalPort = Constants.IP.PortPlaceHolder;
this.RemotePort = remotePort;
this.Protocol = protocol;
LocalPort = Constants.IP.PortPlaceHolder;
RemotePort = remotePort;
Protocol = protocol;
Name = name;
}

/// <summary>
Expand All @@ -53,18 +57,28 @@ public PortPair(int remotePort, string protocol = KubernetesConstants.Protocols.
public int RemotePort { get; set; }

/// <summary>
/// Procol used when comunicating on this port (usually TCP)
/// Protocol used when communicating on this port (usually TCP)
/// </summary>
[JsonProperty("protocol")]
public string Protocol { get; set; }

/// <summary>
/// Name metadata corresponding to named ports in service resource in Kubernetes
/// </summary>
/// <remarks>
/// Service resources with multiple ports must be given names so that they are unambiguous.
/// https://kubernetes.io/docs/concepts/services-networking/service/#multi-port-services
/// </remarks>
[JsonProperty("name")]
public string Name { get; set; }

/// <summary>
/// Create a clone of this object
/// </summary>
/// <returns></returns>
public object Clone()
{
return new PortPair(LocalPort, RemotePort, Protocol);
return new PortPair(LocalPort, RemotePort, Protocol, Name);
}
}
}
}
214 changes: 163 additions & 51 deletions src/library.tests/LocalEnvironmentManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
// Licensed under the MIT license.
// --------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using Autofac;
using FluentAssertions;
using Microsoft.BridgeToKubernetes.Common.Models;
using Microsoft.BridgeToKubernetes.Common.Models.Settings;
using Microsoft.BridgeToKubernetes.Library.Connect;
using Microsoft.BridgeToKubernetes.Library.Models;
using Microsoft.BridgeToKubernetes.TestHelpers;
Expand All @@ -17,61 +18,172 @@ namespace Microsoft.BridgeToKubernetes.Library.Tests
{
public class LocalEnvironmentManagerTests : TestsBase
{
private ILocalEnvironmentManager _localEnvironmentManager;
private readonly ILocalEnvironmentManager _localEnvironmentManager;

public LocalEnvironmentManagerTests()
{
var remoteContainerConnectionDetails = new AsyncLazy<RemoteContainerConnectionDetails>(async () => _autoFake.Resolve<RemoteContainerConnectionDetails>());
_localEnvironmentManager = _autoFake.Resolve<LocalEnvironmentManager>(new NamedParameter("useKubernetesServiceEnvironmentVariables", true));
}
public LocalEnvironmentManagerTests() =>
_localEnvironmentManager =
_autoFake.Resolve<LocalEnvironmentManager>(new NamedParameter(
"useKubernetesServiceEnvironmentVariables",
true));

[Fact]
public async void GetLocalEnvironment_GoodPath()
public static IEnumerable<object[]> TestData()
{
// Prepare test
WorkloadInfo workloadInfo = new WorkloadInfo();
Common.Models.EndpointInfo endpointInfo1 = new Common.Models.EndpointInfo();
endpointInfo1.DnsName = Common.Constants.ManagedIdentity.TargetServiceNameOnLocalMachine;
endpointInfo1.LocalIP = System.Net.IPAddress.Parse("127.0.0.1");
endpointInfo1.Ports = new Common.Models.Settings.PortPair[] {new Common.Models.Settings.PortPair(5050, 80)};
Common.Models.EndpointInfo endpointInfo2 = new Common.Models.EndpointInfo();
endpointInfo2.DnsName = "foo";
endpointInfo2.LocalIP = System.Net.IPAddress.Parse("127.0.0.2");
endpointInfo2.Ports = new Common.Models.Settings.PortPair[] { new Common.Models.Settings.PortPair(5049, 80)};
Common.Models.EndpointInfo endpointInfo3 = new Common.Models.EndpointInfo();
endpointInfo3.DnsName = "kubernetes.default";
endpointInfo3.LocalIP = System.Net.IPAddress.Parse("127.0.0.3");
endpointInfo3.Ports = new Common.Models.Settings.PortPair[] { new Common.Models.Settings.PortPair(5048, 80)};
// single basic endpoint
yield return new object[]
{
new[] {
new EndpointInfo
{
DnsName = "foo",
LocalIP = System.Net.IPAddress.Parse("127.0.0.1"),
Ports = new[] { new PortPair(5050, 80) }
}
},
new Dictionary<string, string>
{
// backwards-compatible ports
["FOO_SERVICE_HOST"] = "127.0.0.1",
["FOO_SERVICE_PORT"] = "5050",
["FOO_PORT"] = "tcp://127.0.0.1:5050",
// named ports
["FOO_PORT_5050_TCP_PROTO"] = "tcp",
["FOO_PORT_5050_TCP"] = "tcp://127.0.0.1:5050",
["FOO_PORT_5050_TCP_PORT"] = "5050",
["FOO_PORT_5050_TCP_ADDR"] = "127.0.0.1",
}
};

workloadInfo.ReachableEndpoints = new List<Common.Models.EndpointInfo>{endpointInfo1, endpointInfo2, endpointInfo3};
workloadInfo.EnvironmentVariables = new Dictionary<string, string>();
// single endpoint with multiple named ports
yield return new object[]
{
new[]
{
new EndpointInfo
{
DnsName = "foo",
LocalIP = System.Net.IPAddress.Parse("127.0.0.1"),
Ports = new[]
{
new PortPair(5050, 80, "tcp", "http"),
new PortPair(5051, 443, "tcp", "tls")
}
}
},
new Dictionary<string, string>
{
// backwards-compatible ports
["FOO_SERVICE_HOST"] = "127.0.0.1",
["FOO_SERVICE_PORT"] = "5050",
["FOO_PORT"] = "tcp://127.0.0.1:5050",
// named ports for first port pair
["FOO_PORT_5050_TCP_PROTO"] = "tcp",
["FOO_PORT_5050_TCP"] = "tcp://127.0.0.1:5050",
["FOO_PORT_5050_TCP_PORT"] = "5050",
["FOO_PORT_5050_TCP_ADDR"] = "127.0.0.1",
["FOO_SERVICE_PORT_HTTP"] = "5050",
// named ports for second port pair
["FOO_PORT_5051_TCP_PROTO"] = "tcp",
["FOO_PORT_5051_TCP"] = "tcp://127.0.0.1:5051",
["FOO_PORT_5051_TCP_PORT"] = "5051",
["FOO_PORT_5051_TCP_ADDR"] = "127.0.0.1",
["FOO_SERVICE_PORT_TLS"] = "5051",
}
};

// Execute
IDictionary<string, string> result = _localEnvironmentManager.CreateEnvVariablesForK8s(workloadInfo);

// Validate
// We should add 8 entries per each service
// Since one of the services is managed identity for bridge to kubernetes we should also add/update msi_enpoint variable
Assert.Equal(8*3 + 1, result.Count());
ValidateService("foo", result, "tcp", "5049", "127.0.0.2");
ValidateService(Common.Constants.ManagedIdentity.TargetServiceNameOnLocalMachine, result, "tcp", "5050", "127.0.0.1");
ValidateService("kubernetes", result, "tcp", "5048", "");
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[ManagedIdentity.MSI_ENDPOINT_EnvironmentVariable], "http://127.0.0.1:5050/metadata/identity/oauth2/token"));

}
// multiple endpoints with simple and named ports
yield return new object[]
{
new[]
{
new EndpointInfo
{
DnsName = "foo",
LocalIP = System.Net.IPAddress.Parse("127.0.0.1"),
Ports = new[]
{
new PortPair(5050, 80, "tcp", "http"),
new PortPair(5051, 443, "tcp", "tls")
}
},
new EndpointInfo
{
DnsName = "bar",
LocalIP = System.Net.IPAddress.Parse("127.0.0.2"),
Ports = new[] { new PortPair(5050, 80) }
}
},
new Dictionary<string, string>
{
// first endpoints backwards-compatible ports
["FOO_SERVICE_HOST"] = "127.0.0.1",
["FOO_SERVICE_PORT"] = "5050",
["FOO_PORT"] = "tcp://127.0.0.1:5050",
// first endpoints named ports for first port pair
["FOO_PORT_5050_TCP_PROTO"] = "tcp",
["FOO_PORT_5050_TCP"] = "tcp://127.0.0.1:5050",
["FOO_PORT_5050_TCP_PORT"] = "5050",
["FOO_PORT_5050_TCP_ADDR"] = "127.0.0.1",
["FOO_SERVICE_PORT_HTTP"] = "5050",
// first endpoints named ports for second port pair
["FOO_PORT_5051_TCP_PROTO"] = "tcp",
["FOO_PORT_5051_TCP"] = "tcp://127.0.0.1:5051",
["FOO_PORT_5051_TCP_PORT"] = "5051",
["FOO_PORT_5051_TCP_ADDR"] = "127.0.0.1",
["FOO_SERVICE_PORT_TLS"] = "5051",
// second endpoints backwards-compatible ports
["BAR_SERVICE_HOST"] = "127.0.0.2",
["BAR_SERVICE_PORT"] = "5050",
["BAR_PORT"] = "tcp://127.0.0.2:5050",
// second endpoints named ports for first port pair
["BAR_PORT_5050_TCP_PROTO"] = "tcp",
["BAR_PORT_5050_TCP"] = "tcp://127.0.0.2:5050",
["BAR_PORT_5050_TCP_PORT"] = "5050",
["BAR_PORT_5050_TCP_ADDR"] = "127.0.0.2",
}
};

public void ValidateService(string serviceName, IDictionary<string, string> result, string protocol, string port, string host) {
var protocolUpper = protocol.ToUpperInvariant();
serviceName = serviceName.ToUpperInvariant();
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_PORT"], $"{protocol}://{host}:{port}"));
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_SERVICE_PORT_{protocolUpper}"], port.ToString()));
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_PORT_{port}_{protocolUpper}_PROTO"], protocol));
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_PORT_{port}_{protocolUpper}"], $"{protocol}://{host}:{port}"));
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_PORT_{port}_{protocolUpper}_PORT"], port.ToString()));
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_SERVICE_PORT"], port.ToString()));
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_PORT_{port}_{protocolUpper}_ADDR"], host));
Assert.True(StringComparer.OrdinalIgnoreCase.Equals(result[$"{serviceName}_SERVICE_HOST"], host));
// managed identity
yield return new object[]
{
new[]
{
new EndpointInfo
{
DnsName = ManagedIdentity.TargetServiceNameOnLocalMachine,
LocalIP = System.Net.IPAddress.Parse("127.0.0.1"),
Ports = new[] { new PortPair(5050, 80, "tcp") }
}
},
new Dictionary<string, string>
{
// backwards-compatible ports
["MANAGEDIDENTITYFORBRIDGETOKUBERNETES_SERVICE_HOST"] = "127.0.0.1",
["MANAGEDIDENTITYFORBRIDGETOKUBERNETES_SERVICE_PORT"] = "5050",
["MANAGEDIDENTITYFORBRIDGETOKUBERNETES_PORT"] = "tcp://127.0.0.1:5050",
// named ports
["MANAGEDIDENTITYFORBRIDGETOKUBERNETES_PORT_5050_TCP_PROTO"] = "tcp",
["MANAGEDIDENTITYFORBRIDGETOKUBERNETES_PORT_5050_TCP"] = "tcp://127.0.0.1:5050",
["MANAGEDIDENTITYFORBRIDGETOKUBERNETES_PORT_5050_TCP_PORT"] = "5050",
["MANAGEDIDENTITYFORBRIDGETOKUBERNETES_PORT_5050_TCP_ADDR"] = "127.0.0.1",
// specific use case for managed identity
[ManagedIdentity.MSI_ENDPOINT_EnvironmentVariable] = "http://127.0.0.1:5050/metadata/identity/oauth2/token",
}
};
}

[Theory]
[MemberData(nameof(TestData))]
public void CreateEnvVariablesForK8s_Returns_ExactlyTheExpectedResults(IEnumerable<EndpointInfo> endpoints, Dictionary<string, string> expected)
{
var workloadInfo = new WorkloadInfo
{
ReachableEndpoints = new List<EndpointInfo>(endpoints),
EnvironmentVariables = new Dictionary<string, string>()
};

var result = _localEnvironmentManager.CreateEnvVariablesForK8s(workloadInfo);

result.Should().Equal(expected);
}
}
}
}
Loading