-
Notifications
You must be signed in to change notification settings - Fork 459
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[k8s][EdgeAgent] Planners and commands for Kubernetes (#1442)
* Pulled code in from POC Planners, commands and other useful classes going from edge deployment to CRD. * Cleaned up and added tests. * Command Factory, ImagePullSecret and CombinedConfig tests
- Loading branch information
Showing
14 changed files
with
1,387 additions
and
4 deletions.
There are no files selected for viewing
111 changes: 111 additions & 0 deletions
111
...ent/src/Microsoft.Azure.Devices.Edge.Agent.Kubernetes/CombinedKubernetesConfigProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
namespace Microsoft.Azure.Devices.Edge.Agent.Kubernetes | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.IO; | ||
using System.Runtime.InteropServices; | ||
using global::Docker.DotNet.Models; | ||
using Microsoft.Azure.Devices.Edge.Agent.Core; | ||
using Microsoft.Azure.Devices.Edge.Agent.Docker; | ||
using Microsoft.Azure.Devices.Edge.Util; | ||
using Microsoft.Extensions.Configuration; | ||
using Newtonsoft.Json; | ||
|
||
public class CombinedKubernetesConfigProvider : CombinedDockerConfigProvider | ||
{ | ||
readonly IConfigSource configSource; | ||
|
||
public CombinedKubernetesConfigProvider(IEnumerable<AuthConfig> authConfigs, IConfigSource configSource) | ||
: base(authConfigs) | ||
{ | ||
this.configSource = Preconditions.CheckNotNull(configSource, nameof(configSource)); | ||
} | ||
|
||
static CreateContainerParameters CloneOrCreateParams(CreateContainerParameters createOptions) => | ||
createOptions != null | ||
? JsonConvert.DeserializeObject<CreateContainerParameters>(JsonConvert.SerializeObject(createOptions)) | ||
: new CreateContainerParameters(); | ||
|
||
public override CombinedDockerConfig GetCombinedConfig(IModule module, IRuntimeInfo runtimeInfo) | ||
{ | ||
CombinedDockerConfig combinedConfig = base.GetCombinedConfig(module, runtimeInfo); | ||
|
||
// if the workload URI is a Unix domain socket then volume mount it into the container | ||
CreateContainerParameters createOptions = CloneOrCreateParams(combinedConfig.CreateOptions); | ||
this.MountSockets(module, createOptions); | ||
this.InjectNetworkAliases(module, createOptions); | ||
|
||
return new CombinedDockerConfig(combinedConfig.Image, createOptions, combinedConfig.AuthConfig); | ||
} | ||
|
||
void InjectNetworkAliases(IModule module, CreateContainerParameters createOptions) | ||
{ | ||
if (createOptions.NetworkingConfig?.EndpointsConfig == null) | ||
{ | ||
string networkId = this.configSource.Configuration.GetValue<string>(Core.Constants.NetworkIdKey); | ||
string edgeDeviceHostName = this.configSource.Configuration.GetValue<string>(Core.Constants.EdgeDeviceHostNameKey); | ||
|
||
if (!string.IsNullOrWhiteSpace(networkId)) | ||
{ | ||
var endpointSettings = new EndpointSettings(); | ||
if (module.Name.Equals(Core.Constants.EdgeHubModuleName, StringComparison.OrdinalIgnoreCase) | ||
&& !string.IsNullOrWhiteSpace(edgeDeviceHostName)) | ||
{ | ||
endpointSettings.Aliases = new List<string> | ||
{ | ||
edgeDeviceHostName | ||
}; | ||
} | ||
|
||
IDictionary<string, EndpointSettings> endpointsConfig = new Dictionary<string, EndpointSettings> | ||
{ | ||
[networkId] = endpointSettings | ||
}; | ||
createOptions.NetworkingConfig = new NetworkingConfig | ||
{ | ||
EndpointsConfig = endpointsConfig | ||
}; | ||
} | ||
} | ||
} | ||
|
||
void MountSockets(IModule module, CreateContainerParameters createOptions) | ||
{ | ||
var workloadUri = new Uri(this.configSource.Configuration.GetValue<string>(Core.Constants.EdgeletWorkloadUriVariableName)); | ||
if (string.Equals(workloadUri.Scheme, "unix", StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
SetMountOptions(createOptions, workloadUri); | ||
} | ||
|
||
// If Management URI is Unix domain socket, and the module is the EdgeAgent, then mount it ino the container. | ||
var managementUri = new Uri(this.configSource.Configuration.GetValue<string>(Core.Constants.EdgeletManagementUriVariableName)); | ||
if (string.Equals(managementUri.Scheme, "unix", StringComparison.OrdinalIgnoreCase) | ||
&& module.Name.Equals(Core.Constants.EdgeAgentModuleName, StringComparison.OrdinalIgnoreCase)) | ||
{ | ||
SetMountOptions(createOptions, managementUri); | ||
} | ||
} | ||
|
||
static void SetMountOptions(CreateContainerParameters createOptions, Uri uri) | ||
{ | ||
HostConfig hostConfig = createOptions.HostConfig ?? new HostConfig(); | ||
IList<string> binds = hostConfig.Binds ?? new List<string>(); | ||
string path = BindPath(uri); | ||
binds.Add($"{path}:{path}"); | ||
|
||
hostConfig.Binds = binds; | ||
createOptions.HostConfig = hostConfig; | ||
} | ||
|
||
static string BindPath(Uri uri) | ||
{ | ||
// On Windows we need to bind to the parent folder. We can't bind | ||
// directly to the socket file. | ||
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) | ||
? Path.GetDirectoryName(uri.LocalPath) | ||
: uri.AbsolutePath; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
77 changes: 77 additions & 0 deletions
77
edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Kubernetes/ImagePullSecret.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
namespace Microsoft.Azure.Devices.Edge.Agent.Kubernetes | ||
{ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Text; | ||
using global::Docker.DotNet.Models; | ||
using Newtonsoft.Json; | ||
|
||
public class ImagePullSecret | ||
{ | ||
class AuthEntry | ||
{ | ||
[JsonProperty(Required = Required.Always, PropertyName = "username")] | ||
public readonly string Username; | ||
[JsonProperty(Required = Required.Always, PropertyName = "password")] | ||
public readonly string Password; | ||
[JsonProperty(Required = Required.Always, PropertyName = "auth")] | ||
public readonly string Auth; | ||
|
||
public AuthEntry(string username, string password) | ||
{ | ||
this.Username = username; | ||
this.Password = password; | ||
byte[] auth = Encoding.UTF8.GetBytes($"{username}:{password}"); | ||
this.Auth = Convert.ToBase64String(auth); | ||
} | ||
} | ||
|
||
class Auth | ||
{ | ||
[JsonProperty(Required = Required.Always, PropertyName = "auths")] | ||
public Dictionary<string, AuthEntry> Auths; | ||
|
||
public Auth() | ||
{ | ||
this.Auths = new Dictionary<string, AuthEntry>(); | ||
} | ||
|
||
public Auth(string registry, AuthEntry entry) | ||
: this() | ||
{ | ||
this.Auths.Add(registry, entry); | ||
} | ||
} | ||
|
||
public string Name { get; } | ||
|
||
readonly AuthConfig dockerAuth; | ||
|
||
public string GenerateSecret() | ||
{ | ||
// JSON struct is | ||
// { "auths": | ||
// { "<registry>" : | ||
// { "username":"<user>", | ||
// "password":"<password>", | ||
// "email":"<email>" (not needed) | ||
// "auth":"<base 64 of '<user>:<password>'>" | ||
// } | ||
// } | ||
// } | ||
var auths = new Auth( | ||
this.dockerAuth.ServerAddress, | ||
new AuthEntry(this.dockerAuth.Username, this.dockerAuth.Password)); | ||
string authString = JsonConvert.SerializeObject(auths); | ||
return authString; | ||
} | ||
|
||
public ImagePullSecret(AuthConfig dockerAuth) | ||
{ | ||
this.dockerAuth = dockerAuth; | ||
this.Name = $"{dockerAuth.Username.ToLower()}-{dockerAuth.ServerAddress.ToLower()}"; | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Kubernetes/InvalidModuleException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
namespace Microsoft.Azure.Devices.Edge.Agent.Kubernetes | ||
{ | ||
using System; | ||
|
||
[Serializable] | ||
public class InvalidModuleException : Exception | ||
{ | ||
public InvalidModuleException(string message) | ||
: base(message) | ||
{ | ||
} | ||
|
||
public InvalidModuleException(string message, Exception inner) | ||
: base(message, inner) | ||
{ | ||
} | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Kubernetes/KubernetesCommandFactory.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
namespace Microsoft.Azure.Devices.Edge.Agent.Kubernetes | ||
{ | ||
using System.Threading.Tasks; | ||
using Microsoft.Azure.Devices.Edge.Agent.Core; | ||
using Microsoft.Azure.Devices.Edge.Agent.Core.Commands; | ||
|
||
public class KubernetesCommandFactory : ICommandFactory | ||
{ | ||
public KubernetesCommandFactory() | ||
{ | ||
} | ||
|
||
public Task<ICommand> UpdateEdgeAgentAsync(IModuleWithIdentity module, IRuntimeInfo runtimeInfo) => Task.FromResult(NullCommand.Instance as ICommand); | ||
|
||
public Task<ICommand> CreateAsync(IModuleWithIdentity module, IRuntimeInfo runtimeInfo) => | ||
Task.FromResult((ICommand)NullCommand.Instance); | ||
|
||
public Task<ICommand> UpdateAsync(IModule current, IModuleWithIdentity next, IRuntimeInfo runtimeInfo) => | ||
Task.FromResult((ICommand)NullCommand.Instance); | ||
|
||
public Task<ICommand> RemoveAsync(IModule module) => | ||
Task.FromResult((ICommand)NullCommand.Instance); | ||
|
||
public Task<ICommand> StartAsync(IModule module) => | ||
Task.FromResult((ICommand)NullCommand.Instance); | ||
|
||
public Task<ICommand> StopAsync(IModule module) => | ||
Task.FromResult((ICommand)NullCommand.Instance); | ||
|
||
public Task<ICommand> RestartAsync(IModule module) => | ||
Task.FromResult((ICommand)NullCommand.Instance); | ||
|
||
public Task<ICommand> WrapAsync(ICommand command) => Task.FromResult(command); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
3 changes: 2 additions & 1 deletion
3
edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Kubernetes/KubernetesModuleIdentity.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.