From a39543ce1924e7d16b27c43d66bbbc5eb0a7ca29 Mon Sep 17 00:00:00 2001 From: Shantanu Singh Date: Mon, 17 Jun 2019 15:38:19 -0700 Subject: [PATCH] Add support for specifying a pull policy for modules (#1233) Add support for specifying an image pull policy for modules --- THIRDPARTYNOTICES | 13 ++ .../IModule.cs | 14 ++ .../UnknownModule.cs | 5 + .../DockerCommandFactory.cs | 32 +++-- .../DockerDesiredModule.cs | 3 +- .../DockerEnvironment.cs | 5 +- .../DockerModule.cs | 8 ++ .../DockerRuntimeModule.cs | 6 +- .../EdgeAgentDockerModule.cs | 4 +- .../EdgeAgentDockerRuntimeModule.cs | 4 + .../EdgeHubDockerModule.cs | 3 +- .../EdgeHubDockerRuntimeModule.cs | 5 + .../commands/CreateOrUpdateCommand.cs | 2 +- .../commands/PrepareUpdateCommand.cs | 2 +- .../models/ModuleSpec.cs | 10 +- .../ModuleManagementHttpClient.cs | 29 ++++- .../generatedCode/EdgeletHttpClient.cs | 15 +++ .../AgentTests.cs | 18 +-- .../DeploymentConfigInfoTest.cs | 8 ++ .../DeploymentConfigTest.cs | 41 +++++- .../DiffTest.cs | 12 +- .../ModuleSetTest.cs | 32 ++--- .../OrderedPlanRunnerTest.cs | 30 ++--- .../TestModule.cs | 26 ++-- .../TestModuleTest.cs | 48 +++++-- .../TestRuntimeModule.cs | 4 +- .../TestRuntimeModuleTest.cs | 3 +- .../commands/GroupCommandTest.cs | 10 +- .../commands/LoggingCommandFactoryTest.cs | 4 +- .../commands/NullCommandFactoryTest.cs | 4 +- .../commands/ParallelGroupCommandTest.cs | 10 +- .../FileBackupConfigSourceTest.cs | 6 +- .../configsources/FileConfigSourceTest.cs | 25 ++-- .../planners/HealthRestartPlannerTest.cs | 120 ++++++++++++++---- .../planners/RestartPlannerTest.cs | 18 +-- .../AgentTests.cs | 52 ++++++++ .../ImagePullPolicyTestConfig.cs | 22 ++++ .../RunCommandValidator.cs | 4 +- .../TestConfig.cs | 24 ++++ .../test-config-x64.json | 48 +++++++ .../DockerEnvironmentTest.cs | 12 +- .../DockerModuleTest.cs | 43 ++++--- .../DockerRuntimeModuleTest.cs | 76 +++++++---- .../EdgeAgentDockerModuleTest.cs | 20 +-- .../EdgeAgentDockerRuntimeModuleTest.cs | 3 + .../EdgeHubDockerRuntimeModuleTest.cs | 7 + .../RuntimeInfoProviderTest.cs | 4 +- .../commands/CreateCommandTest.cs | 14 +- .../ModuleIdentityLifecycleManagerTest.cs | 26 ++-- .../ModuleManagementHttpClientTest.cs | 16 ++- .../EdgeAgentConnectionTest.cs | 10 +- .../ModuleIdentityLifecycleManagerTest.cs | 22 ++-- .../reporters/IoTHubReporterTest.cs | 39 ++++-- edgelet/Cargo.lock | 31 +++-- edgelet/api/managementVersion_2019_01_30.yaml | 6 + edgelet/edgelet-config/Cargo.toml | 2 +- edgelet/edgelet-core/src/error.rs | 9 +- edgelet/edgelet-core/src/lib.rs | 2 +- edgelet/edgelet-core/src/module.rs | 75 ++++++++++- edgelet/edgelet-core/src/watchdog.rs | 13 +- edgelet/edgelet-docker/src/runtime.rs | 3 +- edgelet/edgelet-docker/tests/runtime.rs | 5 +- .../src/server/module/create.rs | 117 ++++++++++++----- .../src/server/module/mod.rs | 14 +- .../src/server/module/prepare_update.rs | 64 ++++++++-- .../src/server/module/update.rs | 61 +++++++-- edgelet/edgelet-kube/src/convert/to_k8s.rs | 9 +- edgelet/edgelet-kube/src/runtime.rs | 4 +- edgelet/iotedged/src/lib.rs | 1 + edgelet/management/src/models/module_spec.rs | 20 +++ 70 files changed, 1114 insertions(+), 343 deletions(-) create mode 100644 edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/ImagePullPolicyTestConfig.cs diff --git a/THIRDPARTYNOTICES b/THIRDPARTYNOTICES index 4a30268a7f0..4127e7dffc9 100644 --- a/THIRDPARTYNOTICES +++ b/THIRDPARTYNOTICES @@ -3121,6 +3121,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *** +zonyitoo/rust-ini +The MIT License (MIT) + +Copyright (c) 2014 Y. T. CHUNG + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*** + fizyk20/generic-array The MIT License (MIT) Copyright (c) 2015 Bartlomiej Kaminski diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/IModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/IModule.cs index 58407adb61d..25875eecf45 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/IModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/IModule.cs @@ -3,6 +3,7 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Core { using System; using System.Collections.Generic; + using System.ComponentModel; using System.Runtime.Serialization; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -81,6 +82,16 @@ public enum RestartPolicy Unknown } + [JsonConverter(typeof(StringEnumConverter))] + public enum ImagePullPolicy + { + [EnumMember(Value = "on-create")] + OnCreate = 0, + + [EnumMember(Value = "never")] + Never = 1, + } + public interface IModule : IEquatable { [JsonIgnore] @@ -98,6 +109,9 @@ public interface IModule : IEquatable [JsonProperty(PropertyName = "restartPolicy")] RestartPolicy RestartPolicy { get; } + [JsonProperty(PropertyName = "imagePullPolicy")] + ImagePullPolicy ImagePullPolicy { get; } + [JsonIgnore] ConfigurationInfo ConfigurationInfo { get; } diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/UnknownModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/UnknownModule.cs index 108ddd8d9a8..18fe1336227 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/UnknownModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Core/UnknownModule.cs @@ -21,6 +21,8 @@ public virtual string Name public virtual RestartPolicy RestartPolicy => RestartPolicy.Never; + public virtual ImagePullPolicy ImagePullPolicy => ImagePullPolicy.OnCreate; + public virtual ConfigurationInfo ConfigurationInfo => new ConfigurationInfo(); public IDictionary Env { get; } = ImmutableDictionary.Empty; @@ -58,6 +60,9 @@ public class UnknownEdgeAgentModule : UnknownModule, IEdgeAgentModule [JsonIgnore] public override RestartPolicy RestartPolicy => RestartPolicy.Never; + [JsonIgnore] + public override ImagePullPolicy ImagePullPolicy => ImagePullPolicy.OnCreate; + [JsonIgnore] public override ModuleStatus DesiredStatus => ModuleStatus.Unknown; diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerCommandFactory.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerCommandFactory.cs index 375912e5f87..1c256d6b941 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerCommandFactory.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerCommandFactory.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. namespace Microsoft.Azure.Devices.Edge.Agent.Docker { + using System.Collections.Generic; using System.Threading.Tasks; using global::Docker.DotNet; using Microsoft.Azure.Devices.Edge.Agent.Core; @@ -30,9 +31,15 @@ public async Task CreateAsync(IModuleWithIdentity module, IRuntimeInfo if (module.Module is DockerModule dockerModule) { CombinedDockerConfig combinedDockerConfig = this.combinedConfigProvider.GetCombinedConfig(dockerModule, runtimeInfo); - return new GroupCommand( - new PullCommand(this.client, combinedDockerConfig), - await CreateCommand.BuildAsync(this.client, dockerModule, module.ModuleIdentity, this.dockerLoggerConfig, this.configSource, module.Module is EdgeHubDockerModule)); + + var commands = new List(); + if (module.Module.ImagePullPolicy != ImagePullPolicy.Never) + { + commands.Add(new PullCommand(this.client, combinedDockerConfig)); + } + + commands.Add(await CreateCommand.BuildAsync(this.client, dockerModule, module.ModuleIdentity, this.dockerLoggerConfig, this.configSource, module.Module is EdgeHubDockerModule)); + return new GroupCommand(commands.ToArray()); } return NullCommand.Instance; @@ -43,11 +50,20 @@ public async Task UpdateAsync(IModule current, IModuleWithIdentity nex if (current is DockerModule currentDockerModule && next.Module is DockerModule nextDockerModule) { CombinedDockerConfig combinedDockerConfig = this.combinedConfigProvider.GetCombinedConfig(nextDockerModule, runtimeInfo); - return new GroupCommand( - new PullCommand(this.client, combinedDockerConfig), - new StopCommand(this.client, currentDockerModule), - new RemoveCommand(this.client, currentDockerModule), - await CreateCommand.BuildAsync(this.client, nextDockerModule, next.ModuleIdentity, this.dockerLoggerConfig, this.configSource, next.Module is EdgeHubDockerModule)); + var commands = new List(); + if (next.Module.ImagePullPolicy != ImagePullPolicy.Never) + { + commands.Add(new PullCommand(this.client, combinedDockerConfig)); + } + + commands.AddRange( + new ICommand[] + { + new StopCommand(this.client, currentDockerModule), + new RemoveCommand(this.client, currentDockerModule), + await CreateCommand.BuildAsync(this.client, nextDockerModule, next.ModuleIdentity, this.dockerLoggerConfig, this.configSource, next.Module is EdgeHubDockerModule) + }); + return new GroupCommand(commands.ToArray()); } return NullCommand.Instance; diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerDesiredModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerDesiredModule.cs index d552861f35e..a09d5544dc7 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerDesiredModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerDesiredModule.cs @@ -16,9 +16,10 @@ public class DockerDesiredModule : DockerModule RestartPolicy restartPolicy, string type, DockerConfig settings, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env) - : base(string.Empty, version, desiredStatus, restartPolicy, settings, configuration, env) + : base(string.Empty, version, desiredStatus, restartPolicy, settings, imagePullPolicy, configuration, env) { Preconditions.CheckArgument(type?.Equals("docker") ?? false); this.DesiredStatus = Preconditions.CheckIsDefined(desiredStatus); diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerEnvironment.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerEnvironment.cs index 36a7310db3e..58cda3fb979 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerEnvironment.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerEnvironment.cs @@ -61,7 +61,7 @@ public async Task GetModulesAsync(CancellationToken token) if (!moduleSet.Modules.TryGetValue(dockerRuntimeInfo.Name, out IModule configModule) || !(configModule is DockerModule dockerModule)) { - dockerModule = new DockerModule(dockerRuntimeInfo.Name, string.Empty, ModuleStatus.Unknown, Core.RestartPolicy.Unknown, new DockerConfig(Constants.UnknownImage, new CreateContainerParameters()), new ConfigurationInfo(), null); + dockerModule = new DockerModule(dockerRuntimeInfo.Name, string.Empty, ModuleStatus.Unknown, Core.RestartPolicy.Unknown, new DockerConfig(Constants.UnknownImage, new CreateContainerParameters()), ImagePullPolicy.OnCreate, new ConfigurationInfo(), null); } Option moduleStateOption = await this.moduleStateStore.Get(moduleRuntimeInfo.Name); @@ -89,6 +89,7 @@ public async Task GetModulesAsync(CancellationToken token) moduleState.RestartCount, moduleState.LastRestartTimeUtc, moduleRuntimeStatus, + dockerModule.ImagePullPolicy, dockerModule.ConfigurationInfo, dockerModule.Env); break; @@ -101,6 +102,7 @@ public async Task GetModulesAsync(CancellationToken token) dockerRuntimeInfo.Description, dockerRuntimeInfo.StartTime.GetOrElse(DateTime.MinValue), lastExitTime, + dockerModule.ImagePullPolicy, dockerModule.ConfigurationInfo, dockerModule.Env); break; @@ -119,6 +121,7 @@ public async Task GetModulesAsync(CancellationToken token) moduleState.RestartCount, moduleState.LastRestartTimeUtc, moduleRuntimeStatus, + dockerModule.ImagePullPolicy, dockerModule.ConfigurationInfo, dockerModule.Env); break; diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerModule.cs index e69c156dda6..5e4856574d4 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerModule.cs @@ -17,6 +17,7 @@ public DockerModule( ModuleStatus desiredStatus, RestartPolicy restartPolicy, DockerConfig config, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configurationInfo, IDictionary env) { @@ -25,6 +26,7 @@ public DockerModule( this.DesiredStatus = Preconditions.CheckIsDefined(desiredStatus); this.Config = Preconditions.CheckNotNull(config, nameof(config)); this.RestartPolicy = Preconditions.CheckIsDefined(restartPolicy); + this.ImagePullPolicy = Preconditions.CheckIsDefined(imagePullPolicy); this.ConfigurationInfo = configurationInfo ?? new ConfigurationInfo(string.Empty); this.Env = env?.ToImmutableDictionary() ?? ImmutableDictionary.Empty; } @@ -41,6 +43,9 @@ public DockerModule( [JsonProperty(PropertyName = "restartPolicy")] public virtual RestartPolicy RestartPolicy { get; } + [JsonProperty(PropertyName = "imagePullPolicy")] + public virtual ImagePullPolicy ImagePullPolicy { get; } + [JsonProperty(Required = Required.Always, PropertyName = "type")] public virtual string Type => "docker"; @@ -75,6 +80,7 @@ public virtual bool Equals(IModule other) this.DesiredStatus == other.DesiredStatus && this.Config.Equals(other.Config) && this.RestartPolicy == other.RestartPolicy && + this.ImagePullPolicy == other.ImagePullPolicy && EnvDictionaryComparer.Equals(this.Env, other.Env); } @@ -87,6 +93,7 @@ public virtual bool OnlyModuleStatusChanged(IModule other) this.DesiredStatus != other.DesiredStatus && this.Config.Equals(dockerModule.Config) && this.RestartPolicy == other.RestartPolicy && + this.ImagePullPolicy == other.ImagePullPolicy && EnvDictionaryComparer.Equals(this.Env, other.Env); } @@ -104,6 +111,7 @@ public override int GetHashCode() hashCode = (hashCode * 397) ^ (int)this.DesiredStatus; hashCode = (hashCode * 397) ^ (this.Config != null ? this.Config.GetHashCode() : 0); hashCode = (hashCode * 397) ^ this.RestartPolicy.GetHashCode(); + hashCode = (hashCode * 397) ^ this.ImagePullPolicy.GetHashCode(); hashCode = (hashCode * 397) ^ EnvDictionaryComparer.GetHashCode(this.Env); return hashCode; } diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerRuntimeModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerRuntimeModule.cs index eef376d35db..7e4e4d8c1d9 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerRuntimeModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/DockerRuntimeModule.cs @@ -22,9 +22,10 @@ public DockerRuntimeModule( int restartCount, DateTime lastRestartTime, ModuleStatus runtimeStatus, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env) - : base(name, version, desiredStatus, restartPolicy, config, configuration, env) + : base(name, version, desiredStatus, restartPolicy, config, imagePullPolicy, configuration, env) { this.ExitCode = exitCode; this.StatusDescription = statusDescription; @@ -50,6 +51,7 @@ public DockerRuntimeModule( int restartCount, DateTime lastRestartTimeUtc, ModuleStatus runtimeStatus, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configurationInfo, IDictionary env) : this( @@ -65,6 +67,7 @@ public DockerRuntimeModule( restartCount, lastRestartTimeUtc, runtimeStatus, + imagePullPolicy, configurationInfo, env) { @@ -153,6 +156,7 @@ public override int GetHashCode() this.RestartCount, this.LastRestartTimeUtc, newStatus, + this.ImagePullPolicy, this.ConfigurationInfo, this.Env); } diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerModule.cs index e3e4bd561e3..8f92d0081ac 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerModule.cs @@ -9,8 +9,8 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Docker public class EdgeAgentDockerModule : DockerModule, IEdgeAgentModule { [JsonConstructor] - public EdgeAgentDockerModule(string type, DockerConfig settings, ConfigurationInfo configuration, IDictionary env, string version = "") - : base(Core.Constants.EdgeAgentModuleName, version, ModuleStatus.Running, RestartPolicy.Always, settings, configuration, env) + public EdgeAgentDockerModule(string type, DockerConfig settings, ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env, string version = "") + : base(Core.Constants.EdgeAgentModuleName, version, ModuleStatus.Running, RestartPolicy.Always, settings, imagePullPolicy, configuration, env) { Preconditions.CheckArgument(type?.Equals("docker") ?? false); } diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerRuntimeModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerRuntimeModule.cs index 34fb991b2ca..11df7a031ca 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerRuntimeModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeAgentDockerRuntimeModule.cs @@ -4,6 +4,7 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Docker using System; using System.Collections.Generic; using Microsoft.Azure.Devices.Edge.Agent.Core; + using Microsoft.Azure.Devices.Edge.Util; using Newtonsoft.Json; public class EdgeAgentDockerRuntimeModule : DockerRuntimeModule, IEdgeAgentModule @@ -16,6 +17,7 @@ public EdgeAgentDockerRuntimeModule( string statusDescription, DateTime lastStartTimeUtc, DateTime lastExitTime, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env, string version = "") @@ -32,6 +34,7 @@ public EdgeAgentDockerRuntimeModule( 0, DateTime.MinValue, runtimeStatus, + imagePullPolicy, configuration, env) { @@ -70,6 +73,7 @@ public EdgeAgentDockerRuntimeModule( this.StatusDescription, this.LastStartTimeUtc, this.LastExitTimeUtc, + this.ImagePullPolicy, this.ConfigurationInfo, this.Env, this.Version); diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerModule.cs index d9eddfa071c..9bcc4a356f6 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerModule.cs @@ -15,10 +15,11 @@ public EdgeHubDockerModule( ModuleStatus status, RestartPolicy restartPolicy, DockerConfig settings, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env, string version = "") - : base(Core.Constants.EdgeHubModuleName, version, status, restartPolicy, settings, configuration, env) + : base(Core.Constants.EdgeHubModuleName, version, status, restartPolicy, settings, imagePullPolicy, configuration, env) { Preconditions.CheckArgument(type?.Equals("docker") ?? false); this.DesiredStatus = Preconditions.CheckIsDefined(status); diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerRuntimeModule.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerRuntimeModule.cs index 887d6fdeeff..4d9dca98aca 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerRuntimeModule.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Docker/EdgeHubDockerRuntimeModule.cs @@ -21,6 +21,7 @@ public EdgeHubDockerRuntimeModule( int restartCount, DateTime lastRestartTime, ModuleStatus runtimeStatus, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env, string version = "") @@ -37,6 +38,7 @@ public EdgeHubDockerRuntimeModule( restartCount, lastRestartTime, runtimeStatus, + imagePullPolicy, configuration, env) { @@ -63,6 +65,7 @@ public EdgeHubDockerRuntimeModule( int restartCount, DateTime lastRestartTimeUtc, ModuleStatus runtimeStatus, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configurationInfo, IDictionary env, string version = "") @@ -77,6 +80,7 @@ public EdgeHubDockerRuntimeModule( restartCount, lastRestartTimeUtc, runtimeStatus, + imagePullPolicy, configurationInfo, env, version) @@ -105,6 +109,7 @@ public EdgeHubDockerRuntimeModule( this.RestartCount, this.LastRestartTimeUtc, newStatus, + this.ImagePullPolicy, this.ConfigurationInfo, this.Env); } diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/CreateOrUpdateCommand.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/CreateOrUpdateCommand.cs index eb5206ad62c..c7e6ed87219 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/CreateOrUpdateCommand.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/CreateOrUpdateCommand.cs @@ -87,7 +87,7 @@ public string Show() static ModuleSpec BuildModuleSpec(IModule module, IEnumerable envVars, object settings) { - return new ModuleSpec(module.Name, module.Type, settings, envVars); + return new ModuleSpec(module.Name, module.Type, module.ImagePullPolicy, settings, envVars); } static IEnumerable GetEnvVars(IDictionary moduleEnvVars, IModuleIdentity identity, IConfigSource configSource) diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/PrepareUpdateCommand.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/PrepareUpdateCommand.cs index e8b158468b5..087f5150c56 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/PrepareUpdateCommand.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/commands/PrepareUpdateCommand.cs @@ -31,7 +31,7 @@ public Task ExecuteAsync(CancellationToken token) static ModuleSpec BuildModuleSpec(IModule module, object settings) { - return new ModuleSpec(module.Name, module.Type, settings); + return new ModuleSpec(module.Name, module.Type, module.ImagePullPolicy, settings); } } } diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/models/ModuleSpec.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/models/ModuleSpec.cs index efd91517247..9627f4daa98 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/models/ModuleSpec.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/models/ModuleSpec.cs @@ -2,17 +2,19 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Edgelet.Models { using System.Collections.Generic; + using Microsoft.Azure.Devices.Edge.Agent.Core; using Microsoft.Azure.Devices.Edge.Util; public class ModuleSpec { - public ModuleSpec(string name, string type, object settings) - : this(name, type, settings, new List()) + public ModuleSpec(string name, string type, ImagePullPolicy imagePullPolicy, object settings) + : this(name, type, imagePullPolicy, settings, new List()) { } - public ModuleSpec(string name, string type, object settings, IEnumerable environmentVariables) + public ModuleSpec(string name, string type, ImagePullPolicy imagePullPolicy, object settings, IEnumerable environmentVariables) { + this.ImagePullPolicy = imagePullPolicy; this.Name = Preconditions.CheckNonWhiteSpace(name, nameof(name)); this.Type = Preconditions.CheckNonWhiteSpace(type, nameof(type)); this.Settings = Preconditions.CheckNotNull(settings, nameof(settings)); @@ -26,5 +28,7 @@ public ModuleSpec(string name, string type, object settings, IEnumerable public object Settings { get; } public IEnumerable EnvironmentVariables { get; } + + public ImagePullPolicy ImagePullPolicy { get; } } } diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/ModuleManagementHttpClient.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/ModuleManagementHttpClient.cs index 315d5cbda17..60247163262 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/ModuleManagementHttpClient.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/ModuleManagementHttpClient.cs @@ -93,7 +93,7 @@ public override async Task CreateModuleAsync(ModuleSpec moduleSpec) using (HttpClient httpClient = HttpClientHelper.GetHttpClient(this.ManagementUri)) { var edgeletHttpClient = new EdgeletHttpClient(httpClient) { BaseUrl = HttpClientHelper.GetBaseUrl(this.ManagementUri) }; - await this.Execute(() => edgeletHttpClient.CreateModuleAsync(this.Version.Name, this.MapToModuleSpec(moduleSpec)), $"Create module {moduleSpec.Name}"); + await this.Execute(() => edgeletHttpClient.CreateModuleAsync(this.Version.Name, MapToModuleSpec(moduleSpec)), $"Create module {moduleSpec.Name}"); } } @@ -164,7 +164,7 @@ public override async Task UpdateModuleAsync(ModuleSpec moduleSpec) using (HttpClient httpClient = HttpClientHelper.GetHttpClient(this.ManagementUri)) { var edgeletHttpClient = new EdgeletHttpClient(httpClient) { BaseUrl = HttpClientHelper.GetBaseUrl(this.ManagementUri) }; - await this.Execute(() => edgeletHttpClient.UpdateModuleAsync(this.Version.Name, moduleSpec.Name, null, this.MapToModuleSpec(moduleSpec)), $"update module {moduleSpec.Name}"); + await this.Execute(() => edgeletHttpClient.UpdateModuleAsync(this.Version.Name, moduleSpec.Name, null, MapToModuleSpec(moduleSpec)), $"update module {moduleSpec.Name}"); } } @@ -173,7 +173,7 @@ public override async Task UpdateAndStartModuleAsync(ModuleSpec moduleSpec) using (HttpClient httpClient = HttpClientHelper.GetHttpClient(this.ManagementUri)) { var edgeletHttpClient = new EdgeletHttpClient(httpClient) { BaseUrl = HttpClientHelper.GetBaseUrl(this.ManagementUri) }; - await this.Execute(() => edgeletHttpClient.UpdateModuleAsync(this.Version.Name, moduleSpec.Name, true, this.MapToModuleSpec(moduleSpec)), $"update and start module {moduleSpec.Name}"); + await this.Execute(() => edgeletHttpClient.UpdateModuleAsync(this.Version.Name, moduleSpec.Name, true, MapToModuleSpec(moduleSpec)), $"update and start module {moduleSpec.Name}"); } } @@ -182,7 +182,7 @@ public override async Task PrepareUpdateAsync(ModuleSpec moduleSpec) using (HttpClient httpClient = HttpClientHelper.GetHttpClient(this.ManagementUri)) { var edgeletHttpClient = new EdgeletHttpClient(httpClient) { BaseUrl = HttpClientHelper.GetBaseUrl(this.ManagementUri) }; - await this.Execute(() => edgeletHttpClient.PrepareUpdateModuleAsync(this.Version.Name, moduleSpec.Name, this.MapToModuleSpec(moduleSpec)), $"prepare update for module module {moduleSpec.Name}"); + await this.Execute(() => edgeletHttpClient.PrepareUpdateModuleAsync(this.Version.Name, moduleSpec.Name, MapToModuleSpec(moduleSpec)), $"prepare update for module module {moduleSpec.Name}"); } } @@ -209,12 +209,13 @@ protected override void HandleException(Exception exception, string operation) } } - GeneratedCode.ModuleSpec MapToModuleSpec(ModuleSpec moduleSpec) + static GeneratedCode.ModuleSpec MapToModuleSpec(ModuleSpec moduleSpec) { return new GeneratedCode.ModuleSpec() { Name = moduleSpec.Name, Type = moduleSpec.Type, + ImagePullPolicy = ToGeneratedCodePullPolicy(moduleSpec.ImagePullPolicy), Config = new Config() { Env = new ObservableCollection( @@ -229,6 +230,24 @@ GeneratedCode.ModuleSpec MapToModuleSpec(ModuleSpec moduleSpec) }; } + internal static GeneratedCode.ImagePullPolicy ToGeneratedCodePullPolicy(Core.ImagePullPolicy imagePullPolicy) + { + GeneratedCode.ImagePullPolicy resultantPullPolicy; + switch (imagePullPolicy) + { + case Core.ImagePullPolicy.OnCreate: + resultantPullPolicy = GeneratedCode.ImagePullPolicy.OnCreate; + break; + case Core.ImagePullPolicy.Never: + resultantPullPolicy = GeneratedCode.ImagePullPolicy.Never; + break; + default: + throw new InvalidOperationException("Translation of this image pull policy type is not configured."); + } + + return resultantPullPolicy; + } + Identity MapFromIdentity(GeneratedCode.Identity identity) { return new Identity(identity.ModuleId, identity.GenerationId, identity.ManagedBy); diff --git a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/generatedCode/EdgeletHttpClient.cs b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/generatedCode/EdgeletHttpClient.cs index 18b46b39872..211ff652f65 100644 --- a/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/generatedCode/EdgeletHttpClient.cs +++ b/edge-agent/src/Microsoft.Azure.Devices.Edge.Agent.Edgelet/version_2019_01_30/generatedCode/EdgeletHttpClient.cs @@ -1704,6 +1704,10 @@ public partial class ModuleSpec [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] public string Type { get; set; } + [Newtonsoft.Json.JsonProperty("imagePullPolicy", Required = Newtonsoft.Json.Required.Default, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] + public ImagePullPolicy? ImagePullPolicy { get; set; } + [Newtonsoft.Json.JsonProperty("config", Required = Newtonsoft.Json.Required.Always)] public Config Config { get; set; } = new Config(); @@ -1957,6 +1961,17 @@ public static ErrorResponse FromJson(string data) } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "9.13.2.0 (Newtonsoft.Json v11.0.0.0)")] + public enum ImagePullPolicy + { + [System.Runtime.Serialization.EnumMember(Value = @"OnCreate")] + OnCreate = 0, + + [System.Runtime.Serialization.EnumMember(Value = @"Never")] + Never = 1, + + } + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "9.13.2.0 (Newtonsoft.Json v11.0.0.0)")] public enum IdentityAuthType { diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/AgentTests.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/AgentTests.cs index d261c1de5e7..836d33104b3 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/AgentTests.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/AgentTests.cs @@ -109,7 +109,7 @@ public async void ReconcileAsyncOnEmptyPlan() new SystemModules(null, null), new Dictionary { - { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null) } + { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null) } }); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); ModuleSet desiredModuleSet = deploymentConfig.GetModuleSet(); @@ -263,7 +263,7 @@ public async void ReconcileAsyncAbortsWhenModuleIdentityLifecycleManagerThrows() new SystemModules(null, null), new Dictionary { - { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null) } + { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null) } }); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); ModuleSet desiredModuleSet = deploymentConfig.GetModuleSet(); @@ -308,9 +308,9 @@ public async void ReconcileAsyncReportsFailedWhenEncryptProviderThrows() new SystemModules(null, null), new Dictionary { - { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null) } + { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null) } }); - var desiredModule = new TestModule("desired", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null); + var desiredModule = new TestModule("desired", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); var recordKeeper = Option.Some(new TestPlanRecorder()); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); ModuleSet desiredModuleSet = deploymentConfig.GetModuleSet(); @@ -350,8 +350,8 @@ public async void ReconcileAsyncReportsFailedWhenEncryptProviderThrows() [Unit] public async void ReconcileAsyncOnSetPlan() { - var desiredModule = new TestModule("desired", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null); - var currentModule = new TestModule("current", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null); + var desiredModule = new TestModule("desired", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); + var currentModule = new TestModule("current", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); var recordKeeper = Option.Some(new TestPlanRecorder()); var moduleExecutionList = new List { @@ -489,7 +489,7 @@ public async Task ReportShutdownAsyncConfigTest() new SystemModules(null, null), new Dictionary { - { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null) } + { "mod1", new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null) } }); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); var token = new CancellationToken(); @@ -513,8 +513,8 @@ public async Task HandleShutdownTest() // Arrange var mockConfigSource = new Mock(); - IModule mod1 = new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null); - IModule mod2 = new TestModule("mod2", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null); + IModule mod1 = new TestModule("mod1", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); + IModule mod2 = new TestModule("mod2", "1.0", "docker", ModuleStatus.Running, new TestConfig("boo"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); var modules = new Dictionary { [mod1.Name] = mod1, diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigInfoTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigInfoTest.cs index 0309dd78b17..33b6f8b96dc 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigInfoTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigInfoTest.cs @@ -11,6 +11,7 @@ public class DeploymentConfigInfoTest "edgeAgent", "docker", new TestConfig("microsoft/edgeAgent:1.0"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -18,6 +19,7 @@ public class DeploymentConfigInfoTest "edgeAgent", "docker", new TestConfig("microsoft/edgeAgent:1.0"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -27,6 +29,7 @@ public class DeploymentConfigInfoTest ModuleStatus.Running, new TestConfig("microsoft/edgeHub:1.0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -36,6 +39,7 @@ public class DeploymentConfigInfoTest ModuleStatus.Running, new TestConfig("microsoft/edgeHub:1.0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -46,6 +50,7 @@ public class DeploymentConfigInfoTest ModuleStatus.Running, new TestConfig("mod1:v0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -56,6 +61,7 @@ public class DeploymentConfigInfoTest ModuleStatus.Running, new TestConfig("mod1:v0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -66,6 +72,7 @@ public class DeploymentConfigInfoTest ModuleStatus.Running, new TestConfig("mod2:v0"), RestartPolicy.Always, + ImagePullPolicy.Never, new ConfigurationInfo(), new Dictionary()); @@ -76,6 +83,7 @@ public class DeploymentConfigInfoTest ModuleStatus.Running, new TestConfig("mod2:v0"), RestartPolicy.Always, + ImagePullPolicy.Never, new ConfigurationInfo(), new Dictionary()); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigTest.cs index d10aa6ce330..264372a48ff 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DeploymentConfigTest.cs @@ -14,6 +14,7 @@ public class DeploymentConfigTest "edgeAgent", "docker", new TestConfig("microsoft/edgeAgent:1.0"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -21,6 +22,7 @@ public class DeploymentConfigTest "edgeAgent", "docker", new TestConfig("microsoft/edgeAgent:1.0"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -28,6 +30,7 @@ public class DeploymentConfigTest "edgeAgent", "docker", new TestConfig("microsoft/edgeAgent:2.0"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -35,6 +38,7 @@ public class DeploymentConfigTest "edgeAgent", "rkt", new TestConfig("microsoft/edgeAgent:1.0"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -44,6 +48,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("microsoft/edgeHub:1.0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -53,6 +58,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("microsoft/edgeHub:1.0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -62,6 +68,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("microsoft/edgeHub:2.0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -71,6 +78,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("microsoft/edgeHub:1.0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -81,6 +89,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("mod1:v0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -91,6 +100,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("mod1:v0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -101,6 +111,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("mod1:v2"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -111,6 +122,7 @@ public class DeploymentConfigTest ModuleStatus.Stopped, new TestConfig("mod1:v0"), RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); @@ -121,6 +133,18 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("mod1:v0"), RestartPolicy.OnFailure, + ImagePullPolicy.OnCreate, + new ConfigurationInfo(), + new Dictionary()); + + static readonly IModule TestModule1_5 = new TestModule( + "mod1", + string.Empty, + "docker", + ModuleStatus.Running, + new TestConfig("mod1:v0"), + RestartPolicy.Always, + ImagePullPolicy.Never, new ConfigurationInfo(), new Dictionary()); @@ -131,6 +155,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("mod2:v0"), RestartPolicy.Always, + ImagePullPolicy.Never, new ConfigurationInfo(), new Dictionary()); @@ -141,6 +166,7 @@ public class DeploymentConfigTest ModuleStatus.Running, new TestConfig("mod2:v0"), RestartPolicy.Always, + ImagePullPolicy.Never, new ConfigurationInfo(), new Dictionary()); @@ -299,6 +325,16 @@ public class DeploymentConfigTest ["mod2"] = TestModule2 }); + static readonly DeploymentConfig Config16 = new DeploymentConfig( + "1.0", + new TestRuntimeInfo("docker"), + new SystemModules(TestEdgeAgent1, TestEdgeHub1), + new Dictionary + { + ["mod1"] = TestModule1_5, + ["mod2"] = TestModule2 + }); + public static IEnumerable EqualityTestData() { yield return new object[] { Config1, Config1_1, true }; @@ -316,6 +352,7 @@ public static IEnumerable EqualityTestData() yield return new object[] { Config1, Config13, false }; yield return new object[] { Config1, Config14, false }; yield return new object[] { Config1, Config15, false }; + yield return new object[] { Config1, Config16, false }; } [Fact] @@ -325,8 +362,8 @@ public void BasicTest() var edgeHubModule = Mock.Of(m => m.Name == "edgeHub"); var systemModules = new SystemModules(edgeAgentModule, edgeHubModule); - var mod1 = new TestModule(null, string.Empty, "test", ModuleStatus.Running, new TestConfig("mod1"), RestartPolicy.Always, new ConfigurationInfo(), null); - var mod2 = new TestModule(null, string.Empty, "test", ModuleStatus.Running, new TestConfig("mod2"), RestartPolicy.Always, new ConfigurationInfo(), null); + var mod1 = new TestModule(null, string.Empty, "test", ModuleStatus.Running, new TestConfig("mod1"), RestartPolicy.Always, ImagePullPolicy.OnCreate, new ConfigurationInfo(), null); + var mod2 = new TestModule(null, string.Empty, "test", ModuleStatus.Running, new TestConfig("mod2"), RestartPolicy.Always, ImagePullPolicy.OnCreate, new ConfigurationInfo(), null); var modules = new Dictionary { diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DiffTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DiffTest.cs index 8cbd7cb0eec..9e3d0b42534 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DiffTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/DiffTest.cs @@ -11,12 +11,12 @@ public class DiffTest static readonly IDictionary EnvVars = new Dictionary(); static readonly TestConfig Config1 = new TestConfig("image1"); static readonly TestConfig Config2 = new TestConfig("image2"); - static readonly IModule Module1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), EnvVars); - static readonly IModule Module1A = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), EnvVars); - static readonly IModule Module2 = new TestModule("mod2", "version2", "type2", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), EnvVars); - static readonly IModule Module2A = new TestModule("mod2", "version2", "type2", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), EnvVars); - static readonly IModule Module2B = new TestModule("mod2", "version2", "type2", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), EnvVars); - static readonly IModule Module3 = new TestModule("mod3", "version3", "type3", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), EnvVars); + static readonly IModule Module1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), EnvVars); + static readonly IModule Module1A = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), EnvVars); + static readonly IModule Module2 = new TestModule("mod2", "version2", "type2", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), EnvVars); + static readonly IModule Module2A = new TestModule("mod2", "version2", "type2", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), EnvVars); + static readonly IModule Module2B = new TestModule("mod2", "version2", "type2", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), EnvVars); + static readonly IModule Module3 = new TestModule("mod3", "version3", "type3", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), EnvVars); [Fact] [Unit] diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/ModuleSetTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/ModuleSetTest.cs index fdffd84fd52..019f93f6a69 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/ModuleSetTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/ModuleSetTest.cs @@ -15,13 +15,13 @@ public class ModuleSetTest static readonly TestConfig Config1 = new TestConfig("image1"); static readonly TestConfig Config2 = new TestConfig("image2"); - static readonly IModule Module1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module2 = new TestModule("mod2", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module3 = new TestModule("mod3", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module4 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module2 = new TestModule("mod2", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module3 = new TestModule("mod3", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.Never, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module4 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); - static readonly TestModule Module5 = new TestModule("mod5", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module6 = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + static readonly TestModule Module5 = new TestModule("mod5", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module6 = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); static readonly ModuleSet ModuleSet1 = ModuleSet.Create(Module1); static readonly ModuleSet ModuleSet2 = ModuleSet.Create(Module5, Module3); @@ -39,16 +39,16 @@ public void TestDiff(ModuleSet start, ModuleSet end, Diff expected) [Unit] public void TestDeserialize() { - string validJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; - string validJsonAllLower = "{\"modules\":{\"mod1\":{\"version\":\"version1\",\"type\":\"test\",\"status\":\"running\",\"settings\":{\"image\":\"image1\"},\"restartpolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"version\":\"version1\",\"type\":\"test\",\"status\":\"running\",\"settings\":{\"image\":\"image1\"},\"restartpolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; - string validJsonAllCap = "{\"MODULES\":{\"mod1\":{\"NAME\":\"mod1\",\"VERSION\":\"version1\",\"TYPE\":\"test\",\"STATUS\":\"RUNNING\",\"SETTINGS\":{\"IMAGE\":\"image1\"},\"RESTARTPOLICY\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"NAME\":\"mod2\",\"VERSION\":\"version1\",\"TYPE\":\"test\",\"STATUS\":\"RUNNING\",\"SETTINGS\":{\"IMAGE\":\"image1\"},\"RESTARTPOLICY\":\"on-unhealthy\",\"CONFIGURATION\":{\"id\":\"1\"}}}}"; - - string noVersionJson = "{\"Modules\":{\"mod1\":{\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; - string noTypeJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Status\":\"Running\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; - string noStatusJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; - string noConfigJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"RestartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; - string noConfigImageJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; - string notATestType = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"not_a_test\",\"Status\":\"Running\",\"Settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}}}"; + string validJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; + string validJsonAllLower = "{\"modules\":{\"mod1\":{\"version\":\"version1\",\"type\":\"test\",\"status\":\"running\",\"settings\":{\"image\":\"image1\"},\"restartpolicy\":\"on-unhealthy\",\"imagepullpolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"version\":\"version1\",\"type\":\"test\",\"status\":\"running\",\"settings\":{\"image\":\"image1\"},\"restartpolicy\":\"on-unhealthy\",\"imagepullpolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; + string validJsonAllCap = "{\"MODULES\":{\"mod1\":{\"NAME\":\"mod1\",\"VERSION\":\"version1\",\"TYPE\":\"test\",\"STATUS\":\"RUNNING\",\"SETTINGS\":{\"IMAGE\":\"image1\"},\"RESTARTPOLICY\":\"on-unhealthy\",\"IMAGEPULLPOLICY\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"NAME\":\"mod2\",\"VERSION\":\"version1\",\"TYPE\":\"test\",\"STATUS\":\"RUNNING\",\"SETTINGS\":{\"IMAGE\":\"image1\"},\"RESTARTPOLICY\":\"on-unhealthy\",\"IMAGEPULLPOLICY\":\"on-create\",\"CONFIGURATION\":{\"id\":\"1\"}}}}"; + + string noVersionJson = "{\"Modules\":{\"mod1\":{\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; + string noTypeJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Status\":\"Running\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; + string noStatusJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"settings\":{\"image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; + string noConfigJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{\"Image\":\"image1\"},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; + string noConfigImageJson = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"Settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; + string notATestType = "{\"Modules\":{\"mod1\":{\"Version\":\"version1\",\"Type\":\"not_a_test\",\"Status\":\"Running\",\"Settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"Configuration\":{\"id\":\"1\"}},\"mod2\":{\"Version\":\"version1\",\"Type\":\"test\",\"Status\":\"Running\",\"settings\":{},\"RestartPolicy\":\"on-unhealthy\",\"ImagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}}}"; var serializerInputTable = new Dictionary() { { "Test", typeof(TestModule) } }; var myModuleSetSerde = new ModuleSetSerde(serializerInputTable); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/OrderedPlanRunnerTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/OrderedPlanRunnerTest.cs index a719a4fec35..bec3f4e9165 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/OrderedPlanRunnerTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/OrderedPlanRunnerTest.cs @@ -24,11 +24,11 @@ public async void TestPlanExecution() Option recordKeeper = Option.Some(new TestPlanRecorder()); var moduleExecutionList = new List { - new TestRecordType(TestCommandType.TestCreate, new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestCreate, new TestModule("module2", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image2"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestCreate, new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestCreate, new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestCreate, new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestCreate, new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestCreate, new TestModule("module2", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image2"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestCreate, new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestCreate, new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestCreate, new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), }; var commandList = new List { @@ -69,11 +69,11 @@ public async void TestPlanFactoryCommands() var runtimeInfo = Mock.Of(); var moduleExecutionList = new List { - new TestRecordType(TestCommandType.TestCreate, new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestUpdate, new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestRemove, new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestStart, new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestStop, new TestModule("module6", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image6"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestCreate, new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestUpdate, new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestRemove, new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestStart, new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestStop, new TestModule("module6", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image6"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), }; var identity = new Mock(); var commandList = new List @@ -108,11 +108,11 @@ public async void TestPlanContinueOnFailure() var failureFactory = new TestCommandFailureFactory(); var moduleExecutionList = new List { - new TestRecordType(TestCommandType.TestCreate, new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestUpdate, new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestRemove, new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestStart, new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), - new TestRecordType(TestCommandType.TestStop, new TestModule("module6", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image6"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestCreate, new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestUpdate, new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestRemove, new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestStart, new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, ImagePullPolicy.Never, DefaultConfigurationInfo, EnvVars)), + new TestRecordType(TestCommandType.TestStop, new TestModule("module6", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image6"), RestartPolicy.OnUnhealthy, ImagePullPolicy.Never, DefaultConfigurationInfo, EnvVars)), }; var identity = new Mock(); var commandList = new List diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModule.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModule.cs index fe5647d57ef..ad267c2b18a 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModule.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModule.cs @@ -4,6 +4,7 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Core.Test using System; using System.Collections.Generic; using System.Collections.Immutable; + using System.ComponentModel; using Microsoft.Azure.Devices.Edge.Util; using Newtonsoft.Json; @@ -55,6 +56,7 @@ public TestModuleBase( ModuleStatus desiredStatus, TConfig config, RestartPolicy restartPolicy, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env) { @@ -64,6 +66,7 @@ public TestModuleBase( this.DesiredStatus = Preconditions.CheckNotNull(desiredStatus, nameof(desiredStatus)); this.Config = Preconditions.CheckNotNull(config, nameof(config)); this.RestartPolicy = Preconditions.CheckIsDefined(restartPolicy); + this.ImagePullPolicy = Preconditions.CheckIsDefined(imagePullPolicy); this.ConfigurationInfo = configuration ?? new ConfigurationInfo(); this.Env = env?.ToImmutableDictionary() ?? ImmutableDictionary.Empty; } @@ -83,6 +86,9 @@ public TestModuleBase( [JsonProperty(Required = Required.Always, PropertyName = "restartPolicy")] public virtual RestartPolicy RestartPolicy { get; } + [JsonProperty(Required = Required.Always, PropertyName = "imagePullPolicy")] + public virtual ImagePullPolicy ImagePullPolicy { get; } + [JsonProperty(Required = Required.Always, PropertyName = "status")] public virtual ModuleStatus DesiredStatus { get; } @@ -99,7 +105,8 @@ other is TestModuleBase testModuleBase && string.Equals(this.Type, other.Type) && this.DesiredStatus != other.DesiredStatus && this.Config.Equals(testModuleBase.Config) && - this.RestartPolicy == other.RestartPolicy; + this.RestartPolicy == other.RestartPolicy && + this.ImagePullPolicy == other.ImagePullPolicy; public override bool Equals(object obj) => this.Equals(obj as TestModuleBase); @@ -122,7 +129,8 @@ public virtual bool Equals(IModule other) string.Equals(this.Type, other.Type) && this.DesiredStatus == other.DesiredStatus && this.Config.Equals(other.Config) && - this.RestartPolicy == other.RestartPolicy; + this.RestartPolicy == other.RestartPolicy && + this.ImagePullPolicy == other.ImagePullPolicy; } public override int GetHashCode() @@ -138,6 +146,7 @@ public override int GetHashCode() hashCode = (hashCode * 397) ^ (int)this.DesiredStatus; hashCode = (hashCode * 397) ^ (this.Config != null ? this.Config.GetHashCode() : 0); hashCode = (hashCode * 397) ^ this.RestartPolicy.GetHashCode(); + hashCode = (hashCode * 397) ^ this.ImagePullPolicy.GetHashCode(); return hashCode; } } @@ -152,22 +161,23 @@ public TestModule( ModuleStatus desiredStatus, TestConfig config, RestartPolicy restartPolicy, + ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env) - : base(name, version, type, desiredStatus, config, restartPolicy, configuration, env) + : base(name, version, type, desiredStatus, config, restartPolicy, imagePullPolicy, configuration, env) { } public TestModule CloneWithImage(string image) { - return new TestModule(this.Name, this.Version, this.Type, this.DesiredStatus, new TestConfig(image), this.RestartPolicy, this.ConfigurationInfo, this.Env); + return new TestModule(this.Name, this.Version, this.Type, this.DesiredStatus, new TestConfig(image), this.RestartPolicy, this.ImagePullPolicy, this.ConfigurationInfo, this.Env); } } public class TestAgentModule : TestModule, IEdgeAgentModule { - public TestAgentModule(string name, string type, TestConfig config, ConfigurationInfo configuration, IDictionary env) - : base(name ?? Constants.EdgeAgentModuleName, string.Empty, type, ModuleStatus.Running, config, RestartPolicy.Always, configuration, env) + public TestAgentModule(string name, string type, TestConfig config, ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env) + : base(name ?? Constants.EdgeAgentModuleName, string.Empty, type, ModuleStatus.Running, config, RestartPolicy.Always, imagePullPolicy, configuration, env) { this.Version = string.Empty; this.RestartPolicy = RestartPolicy.Always; @@ -191,8 +201,8 @@ public virtual IModule WithRuntimeStatus(ModuleStatus newStatus) public class TestHubModule : TestModule, IEdgeHubModule { - public TestHubModule(string name, string type, ModuleStatus desiredStatus, TestConfig config, RestartPolicy restartPolicy, ConfigurationInfo configuration, IDictionary env) - : base(name ?? Constants.EdgeHubModuleName, string.Empty, type, desiredStatus, config, restartPolicy, configuration, env) + public TestHubModule(string name, string type, ModuleStatus desiredStatus, TestConfig config, RestartPolicy restartPolicy, ImagePullPolicy imagePullPolicy, ConfigurationInfo configuration, IDictionary env) + : base(name ?? Constants.EdgeHubModuleName, string.Empty, type, desiredStatus, config, restartPolicy, imagePullPolicy, configuration, env) { this.Version = string.Empty; } diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModuleTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModuleTest.cs index afc4ab09b19..fb0119e1f92 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModuleTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestModuleTest.cs @@ -21,17 +21,17 @@ public class TestModuleTest static readonly TestConfig Config2 = new TestConfig("image2"); static readonly TestConfig Config3 = new TestConfig("image1"); - static readonly IModule Module1 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module2 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module3 = new TestModule("mod3", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module4 = new TestModule("mod1", "version2", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module5 = new TestModule("mod1", "version1", "type2", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module6 = new TestModule("mod1", "version1", "type1", ModuleStatus.Unknown, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module7 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly TestModule Module8 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module1 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module2 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module3 = new TestModule("mod3", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module4 = new TestModule("mod1", "version2", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module5 = new TestModule("mod1", "version1", "type2", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module6 = new TestModule("mod1", "version1", "type1", ModuleStatus.Unknown, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module7 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly TestModule Module8 = new TestModule("mod1", "version1", "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); - static readonly IModule ValidJsonModule = new TestModule("", "", "docker", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly string serializedModule = "{\"version\":\"version1\",\"type\":\"type1\",\"status\":\"running\",\"settings\":{\"image\":\"image1\"},\"restartPolicy\":\"on-unhealthy\",\"configuration\":{\"id\":\"1\"}}"; + static readonly IModule ValidJsonModule = new TestModule("", "", "docker", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly string serializedModule = "{\"version\":\"version1\",\"type\":\"type1\",\"status\":\"running\",\"settings\":{\"image\":\"image1\"},\"restartPolicy\":\"on-unhealthy\",\"imagePullPolicy\":\"on-create\",\"configuration\":{\"id\":\"1\"}}"; static readonly JObject TestJsonInputs = JsonConvert.DeserializeObject( @" @@ -42,6 +42,7 @@ public class TestModuleTest ""Type"": ""docker"", ""Status"": ""running"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"": { ""Image"": ""image1"" }, @@ -54,6 +55,7 @@ public class TestModuleTest ""type"": ""docker"", ""status"": ""running"", ""restartpolicy"": ""on-unhealthy"", + ""imagepullpolicy"": ""on-create"", ""settings"": { ""image"": ""image1"" }, @@ -66,6 +68,7 @@ public class TestModuleTest ""TYPE"": ""docker"", ""STATUS"": ""RUNNING"", ""RESTARTPOLICY"": ""on-unhealthy"", + ""IMAGEPULLPOLICY"": ""on-create"", ""SETTINGS"": { ""IMAGE"": ""image1"" }, @@ -80,6 +83,7 @@ public class TestModuleTest ""Type"": ""docker"", ""Status"": ""stopped"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"": { ""Image"": """" }, @@ -92,6 +96,7 @@ public class TestModuleTest ""Type"": ""docker"", ""Status"": ""Unknown"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"": { ""Image"": """" }, @@ -105,6 +110,7 @@ public class TestModuleTest ""Version"": """", ""Type"": ""docker"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"": { ""Image"": """" }, @@ -116,6 +122,7 @@ public class TestModuleTest ""Type"": ""docker"", ""Status"": ""running"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"": { ""Image"": """" }, @@ -127,6 +134,7 @@ public class TestModuleTest ""Version"": """", ""Status"": ""running"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"": { ""Image"": """" }, @@ -139,6 +147,7 @@ public class TestModuleTest ""Type"": ""docker"", ""Settings"": ""running"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Configuration"": { ""id"":""1"" } @@ -148,6 +157,7 @@ public class TestModuleTest ""Type"": ""docker"", ""Status"": ""running"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"": {}, ""Configuration"": { ""id"":""1"" @@ -158,6 +168,7 @@ public class TestModuleTest ""Type"": ""docker"", ""Status"": """", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""never"", ""Settings"": { ""Image"": """" }, @@ -170,6 +181,17 @@ public class TestModuleTest ""Type"": ""docker"", ""Status"": """", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""never"", + ""Settings"": { + ""Image"": """" + } + }, + { + ""Version"": """", + ""Type"": ""docker"", + ""Status"": """", + ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": """", ""Settings"": { ""Image"": """" } @@ -191,9 +213,9 @@ public static IEnumerable GetExceptionJsonInputs() [Unit] public void TestConstructor() { - Assert.Throws(() => new TestModule("mod1", null, "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)); - Assert.Throws(() => new TestModule("mod1", "version1", null, ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)); - Assert.Throws(() => new TestModule("mod1", "version1", "type1", ModuleStatus.Running, null, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new TestModule("mod1", null, "type1", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new TestModule("mod1", "version1", null, ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new TestModule("mod1", "version1", "type1", ModuleStatus.Running, null, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); } [Fact] diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModule.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModule.cs index a16abc49499..04147909dd1 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModule.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModule.cs @@ -21,9 +21,10 @@ public TestRuntimeModule( int restartCount, DateTime lastRestartTimeUtc, ModuleStatus runtimeStatus, + ImagePullPolicy imagePullPolicy = ImagePullPolicy.OnCreate, ConfigurationInfo deploymentInfo = null, IDictionary env = null) - : base(name, version, type, desiredStatus, config, restartPolicy, deploymentInfo, env) + : base(name, version, type, desiredStatus, config, restartPolicy, imagePullPolicy, deploymentInfo, env) { this.ExitCode = exitCode; this.StatusDescription = statusDescription; @@ -114,6 +115,7 @@ public override int GetHashCode() this.RestartCount, this.LastRestartTimeUtc, newStatus, + this.ImagePullPolicy, this.ConfigurationInfo); } } diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModuleTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModuleTest.cs index 60f3f88fc06..514a20e98cf 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModuleTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/TestRuntimeModuleTest.cs @@ -11,7 +11,7 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Core.Test public class TestRuntimeModuleTest { static readonly TestConfig Config1 = new TestConfig("image1"); - public static TestModule TestModule1 = new TestModule("name", "version", "type", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, new ConfigurationInfo("1"), null); + public static TestModule TestModule1 = new TestModule("name", "version", "type", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); static readonly DateTime lastStartTime = DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind); static readonly DateTime lastExitTime = lastStartTime.AddDays(1); @@ -96,6 +96,7 @@ public static void TestWithRuntimeStatus() Assert.Equal(reportedModule.Name, updatedModule.Name); Assert.Equal(reportedModule.RestartCount, updatedModule.RestartCount); Assert.Equal(reportedModule.RestartPolicy, updatedModule.RestartPolicy); + Assert.Equal(reportedModule.ImagePullPolicy, updatedModule.ImagePullPolicy); Assert.Equal(reportedModule.StatusDescription, updatedModule.StatusDescription); Assert.Equal(reportedModule.Type, updatedModule.Type); Assert.Equal(reportedModule.Version, updatedModule.Version); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/GroupCommandTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/GroupCommandTest.cs index 4f7ef6a86db..67afe861f2f 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/GroupCommandTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/GroupCommandTest.cs @@ -114,11 +114,11 @@ public static IEnumerable CreateTestData() }; var tm = new List { - new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module2", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image2"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars) + new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module2", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image2"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars) }; (Option recorder, List moduleExecutionList, List commandList)[] testInputRecords = { diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/LoggingCommandFactoryTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/LoggingCommandFactoryTest.cs index bca0da1adb5..c2e3d593aff 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/LoggingCommandFactoryTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/LoggingCommandFactoryTest.cs @@ -35,8 +35,8 @@ public class LoggingCommandFactoryTest { static readonly ConfigurationInfo DefaultConfigurationInfo = new ConfigurationInfo("1"); static readonly IDictionary EnvVars = new Dictionary(); - static readonly TestModule TestModule = new TestModule("module", "version", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - static readonly TestModule UpdateModule = new TestModule("module", "version", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + static readonly TestModule TestModule = new TestModule("module", "version", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly TestModule UpdateModule = new TestModule("module", "version", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); static readonly TestCommand WrapTargetCommand = new TestCommand(TestCommandType.TestCreate, TestModule); [Fact] diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/NullCommandFactoryTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/NullCommandFactoryTest.cs index 6ed90a6739d..fae36ef78e6 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/NullCommandFactoryTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/NullCommandFactoryTest.cs @@ -17,8 +17,8 @@ public async void NullCommandFactoryAllTestAsync() NullCommandFactory nf = NullCommandFactory.Instance; var moduleIdentity = new Mock(); var runtimeInfo = Mock.Of(); - var nm = new TestModule("null", "version_null", "null", ModuleStatus.Running, new TestConfig("null"), RestartPolicy.OnUnhealthy, new ConfigurationInfo(), envVars); - var nmn = new TestModule("next", "version_null", "null", ModuleStatus.Running, new TestConfig("null"), RestartPolicy.OnUnhealthy, new ConfigurationInfo(), envVars); + var nm = new TestModule("null", "version_null", "null", ModuleStatus.Running, new TestConfig("null"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo(), envVars); + var nmn = new TestModule("next", "version_null", "null", ModuleStatus.Running, new TestConfig("null"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo(), envVars); ICommand createCommand = await nf.CreateAsync(new ModuleWithIdentity(nm, moduleIdentity.Object), runtimeInfo); ICommand updateCommand = await nf.UpdateAsync(nm, new ModuleWithIdentity(nmn, moduleIdentity.Object), runtimeInfo); ICommand removeCommand = await nf.RemoveAsync(nm); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/ParallelGroupCommandTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/ParallelGroupCommandTest.cs index 3355b23e993..d46831aa485 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/ParallelGroupCommandTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/commands/ParallelGroupCommandTest.cs @@ -173,11 +173,11 @@ public static IEnumerable CreateTestData() var tm = new List { - new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module2", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image2"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars), - new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, defaultConfigurationInfo, envVars) + new TestModule("module1", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image1"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module2", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image2"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module3", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image3"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module4", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image4"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars), + new TestModule("module5", "version1", "type1", ModuleStatus.Stopped, new TestConfig("image5"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, defaultConfigurationInfo, envVars) }; (Option recorder, List moduleExecutionList, List commandList)[] testInputRecords = diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileBackupConfigSourceTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileBackupConfigSourceTest.cs index 66b22701b6e..93a84cd4d90 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileBackupConfigSourceTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileBackupConfigSourceTest.cs @@ -18,11 +18,11 @@ public class FileBackupConfigSourceTest : IDisposable const string TestType = "test"; static readonly IDictionary EnvVars = new Dictionary(); static readonly ConfigurationInfo ConfigurationInfo = new ConfigurationInfo(); - static readonly IEdgeAgentModule EdgeAgentModule = new TestAgentModule("edgeAgent", "test", new TestConfig("edge-agent"), ConfigurationInfo, EnvVars); + static readonly IEdgeAgentModule EdgeAgentModule = new TestAgentModule("edgeAgent", "test", new TestConfig("edge-agent"), ImagePullPolicy.OnCreate, ConfigurationInfo, EnvVars); static readonly TestRuntimeInfo TestRuntimeInfo = new TestRuntimeInfo("test"); static readonly TestConfig Config1 = new TestConfig("image1"); - static readonly IModule ValidModule1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ConfigurationInfo, EnvVars); - static readonly IEdgeHubModule EdgeHubModule = new TestHubModule("edgeHub", "test", ModuleStatus.Running, new TestConfig("edge-hub:latest"), RestartPolicy.Always, ConfigurationInfo, EnvVars); + static readonly IModule ValidModule1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, ConfigurationInfo, EnvVars); + static readonly IEdgeHubModule EdgeHubModule = new TestHubModule("edgeHub", "test", ModuleStatus.Running, new TestConfig("edge-hub:latest"), RestartPolicy.Always, ImagePullPolicy.OnCreate, ConfigurationInfo, EnvVars); static readonly IDictionary Modules1 = new Dictionary { ["mod1"] = ValidModule1 }; static readonly IDictionary Modules2 = new Dictionary { ["mod2"] = ValidModule1 }; static readonly DeploymentConfig ValidConfig1 = new DeploymentConfig("1.0", TestRuntimeInfo, new SystemModules(EdgeAgentModule, EdgeHubModule), Modules1); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileConfigSourceTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileConfigSourceTest.cs index 70e14d57381..06e908f841d 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileConfigSourceTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/configsources/FileConfigSourceTest.cs @@ -28,7 +28,8 @@ public class FileConfigSourceTest : IDisposable }, ""systemModules"": { ""edgeAgent"": { - ""type"": ""test"", + ""type"": ""test"", + ""imagePullPolicy"": ""on-create"", ""settings"": { ""image"": ""edge-agent"" }, @@ -39,7 +40,8 @@ public class FileConfigSourceTest : IDisposable ""edgeHub"": { ""type"": ""test"", ""status"": ""running"", - ""restartPolicy"": ""always"", + ""restartPolicy"": ""always"", + ""imagePullPolicy"": ""on-create"", ""settings"": { ""image"": ""edge-hub:latest"" }, @@ -54,6 +56,7 @@ public class FileConfigSourceTest : IDisposable ""type"": ""test"", ""status"": ""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""never"", ""settings"": { ""image"": ""image1"" }, @@ -78,7 +81,8 @@ public class FileConfigSourceTest : IDisposable }, ""systemModules"": { ""edgeAgent"": { - ""type"": ""test"", + ""type"": ""test"", + ""imagePullPolicy"": ""on-create"", ""settings"": { ""image"": ""edge-agent"" }, @@ -89,7 +93,8 @@ public class FileConfigSourceTest : IDisposable ""edgeHub"": { ""type"": ""test"", ""status"": ""running"", - ""restartPolicy"": ""always"", + ""restartPolicy"": ""always"", + ""imagePullPolicy"": ""on-create"", ""settings"": { ""image"": ""edge-hub:latest"" }, @@ -104,6 +109,7 @@ public class FileConfigSourceTest : IDisposable ""type"": ""test"", ""status"": ""stopped"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""never"", ""settings"": { ""image"": ""image1"" }, @@ -116,6 +122,7 @@ public class FileConfigSourceTest : IDisposable ""type"": ""test"", ""status"": ""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"": { ""image"": ""image1"" }, @@ -133,19 +140,19 @@ public class FileConfigSourceTest : IDisposable static readonly TestConfig Config1 = new TestConfig("image1"); - static readonly IModule ValidModule1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ConfigurationInfo, EnvVars); + static readonly IModule ValidModule1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.Never, ConfigurationInfo, EnvVars); - static readonly IEdgeHubModule EdgeHubModule = new TestHubModule("edgeHub", "test", ModuleStatus.Running, new TestConfig("edge-hub:latest"), RestartPolicy.Always, ConfigurationInfo, EnvVars); + static readonly IEdgeHubModule EdgeHubModule = new TestHubModule("edgeHub", "test", ModuleStatus.Running, new TestConfig("edge-hub:latest"), RestartPolicy.Always, ImagePullPolicy.OnCreate, ConfigurationInfo, EnvVars); - static readonly IEdgeAgentModule EdgeAgentModule = new TestAgentModule("edgeAgent", "test", new TestConfig("edge-agent"), ConfigurationInfo, null); + static readonly IEdgeAgentModule EdgeAgentModule = new TestAgentModule("edgeAgent", "test", new TestConfig("edge-agent"), ImagePullPolicy.OnCreate, ConfigurationInfo, null); static readonly IDictionary Modules1 = new Dictionary { ["mod1"] = ValidModule1 }; static readonly ModuleSet ValidSet1 = new ModuleSet(new Dictionary(Modules1) { [EdgeHubModule.Name] = EdgeHubModule, [EdgeAgentModule.Name] = EdgeAgentModule }); - static readonly IModule UpdatedModule1 = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, ConfigurationInfo, EnvVars); + static readonly IModule UpdatedModule1 = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.Never, ConfigurationInfo, EnvVars); - static readonly IModule ValidModule2 = new TestModule("mod2", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ConfigurationInfo, EnvVars); + static readonly IModule ValidModule2 = new TestModule("mod2", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, ConfigurationInfo, EnvVars); static readonly IDictionary Modules2 = new Dictionary { ["mod1"] = UpdatedModule1, ["mod2"] = ValidModule2 }; diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/HealthRestartPlannerTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/HealthRestartPlannerTest.cs index f3a7e9cc2e7..ed830ccbc62 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/HealthRestartPlannerTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/HealthRestartPlannerTest.cs @@ -61,7 +61,7 @@ public async void TestAddRunningModule() { (TestCommandFactory factory, _, _, HealthRestartPlanner planner) = CreatePlanner(); - IModule addModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule addModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary moduleIdentities = GetModuleIdentities(new List() { addModule }); ModuleSet addRunning = ModuleSet.Create(addModule); var addExecutionList = new List @@ -82,7 +82,7 @@ public async void TestAddStoppedModule() { (TestCommandFactory factory, _, _, HealthRestartPlanner planner) = CreatePlanner(); - IModule addModule = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule addModule = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary moduleIdentities = GetModuleIdentities(new List() { addModule }); ModuleSet addRunning = ModuleSet.Create(addModule); var addExecutionList = new List @@ -116,7 +116,7 @@ public async void TestUpdateModule() 0, DateTime.MinValue, ModuleStatus.Running); - IModule desiredModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule desiredModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary moduleIdentities = GetModuleIdentities(new List() { desiredModule }); ModuleSet currentSet = ModuleSet.Create(currentModule); ModuleSet desiredSet = ModuleSet.Create(desiredModule); @@ -472,8 +472,8 @@ public async Task CreateShutdownPlanTest() // Arrange (TestCommandFactory factory, _, _, HealthRestartPlanner planner) = CreatePlanner(); - IModule module1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - IModule edgeAgentModule = new TestModule(Constants.EdgeAgentModuleName, "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule module1 = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + IModule edgeAgentModule = new TestModule(Constants.EdgeAgentModuleName, "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); var modules = new List { module1, @@ -814,9 +814,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -833,9 +834,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule2", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule2", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -852,9 +854,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Unhealthy, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule3", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule3", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -871,9 +874,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule4", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule4", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -890,9 +894,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Failed, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule5", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule5", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), // OnUnhealthy @@ -911,9 +916,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule6", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule6", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -930,9 +936,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule7", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule7", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -949,9 +956,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Unhealthy, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule8", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule8", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -968,9 +976,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule9", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule9", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -987,9 +996,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Failed, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule10", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule10", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), // OnFailure @@ -1008,9 +1018,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule11", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule11", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1027,9 +1038,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule12", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule12", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1046,9 +1058,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Unhealthy, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule13", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule13", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1065,9 +1078,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule14", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule14", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1084,9 +1098,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Failed, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule15", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule15", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnFailure, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), // Never @@ -1105,9 +1120,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule16", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule16", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1124,9 +1140,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule17", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule17", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1143,9 +1160,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Unhealthy, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule18", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule18", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1162,9 +1180,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule19", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule19", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), ( new TestRuntimeModule( @@ -1181,9 +1200,10 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Failed, + ImagePullPolicy.OnCreate, null, EnvVars), - new TestModule("updateDeployModule20", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, DefaultConfigurationInfo, EnvVars) + new TestModule("updateDeployModule20", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.Never, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), }; @@ -1205,6 +1225,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1214,6 +1235,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Running, Config1, RestartPolicy.Always, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1234,6 +1256,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1243,6 +1266,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1263,6 +1287,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1272,6 +1297,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Running, Config1, RestartPolicy.OnFailure, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1292,6 +1318,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1301,6 +1328,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Running, Config1, RestartPolicy.Never, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1321,6 +1349,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1330,6 +1359,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Running, Config1, RestartPolicy.Never, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ) @@ -1353,6 +1383,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1362,6 +1393,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Always, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1380,6 +1412,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1389,6 +1422,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Always, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1407,6 +1441,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1416,6 +1451,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Running, Config1, RestartPolicy.Always, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1434,6 +1470,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1443,6 +1480,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Always, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1461,6 +1499,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Failed, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1470,6 +1509,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Always, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1490,6 +1530,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1499,6 +1540,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1517,6 +1559,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1526,6 +1569,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1544,6 +1588,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Unhealthy, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1553,6 +1598,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1571,6 +1617,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1580,6 +1627,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1598,6 +1646,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Failed, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1607,6 +1656,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1627,6 +1677,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1636,6 +1687,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnFailure, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1654,6 +1706,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1663,6 +1716,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnFailure, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1681,6 +1735,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Unhealthy, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1690,6 +1745,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnFailure, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1708,6 +1764,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1717,6 +1774,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.OnFailure, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1735,6 +1793,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1744,6 +1803,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Running, Config1, RestartPolicy.OnFailure, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1764,6 +1824,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1773,6 +1834,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Never, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1791,6 +1853,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1800,6 +1863,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Never, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1818,6 +1882,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Unhealthy, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1827,6 +1892,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Never, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1845,6 +1911,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Stopped, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1854,6 +1921,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Never, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), @@ -1872,6 +1940,7 @@ public async Task CreateShutdownPlanTest() 0, DateTime.MinValue, ModuleStatus.Failed, + ImagePullPolicy.OnCreate, null, EnvVars), new TestModule( @@ -1881,6 +1950,7 @@ public async Task CreateShutdownPlanTest() ModuleStatus.Stopped, Config1, RestartPolicy.Never, + ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) ), diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/RestartPlannerTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/RestartPlannerTest.cs index cb306785e3a..187beef560e 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/RestartPlannerTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Core.Test/planners/RestartPlannerTest.cs @@ -42,7 +42,7 @@ public async void RestartPlannerAdd1RunningModule() { var factory = new TestCommandFactory(); - IModule addModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule addModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary moduleIdentities = GetModuleIdentities(new List() { addModule }); @@ -68,7 +68,7 @@ public async void RestartPlannerAdd1StoppedModule() { var factory = new TestCommandFactory(); - IModule stoppedModule = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule stoppedModule = new TestModule("mod1", "version1", "test", ModuleStatus.Stopped, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); ModuleSet addStopped = ModuleSet.Create(stoppedModule); IImmutableDictionary moduleIdentities = GetModuleIdentities(new List() { stoppedModule }); @@ -92,8 +92,8 @@ public async void RestartPlannerUpdate1Module() { var factory = new TestCommandFactory(); - IModule currentModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - IModule desiredModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule currentModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + IModule desiredModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config2, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary moduleIdentities = GetModuleIdentities(new List() { desiredModule }); var planner = new RestartPlanner(factory); @@ -122,7 +122,7 @@ public async void RestartPlannerRemove1Module() var planner = new RestartPlanner(factory); var token = new CancellationToken(); - IModule removeModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + IModule removeModule = new TestModule("mod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); ModuleSet removeRunning = ModuleSet.Create(removeModule); var removeExecutionList = new List { @@ -154,10 +154,10 @@ public async void RestartPlannerAddRemoveUpdate() }; var desiredModules = new List { - new TestModule("NewMod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars), - new TestModule("NewMod2", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars), - new TestModule("UpdateMod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars), - new TestModule("UpdateMod2", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars) + new TestModule("NewMod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars), + new TestModule("NewMod2", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars), + new TestModule("UpdateMod1", "version1", "test", ModuleStatus.Running, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars), + new TestModule("UpdateMod2", "version1", "test", ModuleStatus.Stopped, Config1, RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars) }; IImmutableDictionary moduleIdentities = GetModuleIdentities(desiredModules); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/AgentTests.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/AgentTests.cs index 2564f85b240..0c763fd6e7e 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/AgentTests.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/AgentTests.cs @@ -40,10 +40,15 @@ public static IEnumerable GenerateStartTestData() // "version": "1.0", // "image": "mongo:3.4.4", // "imageCreateOptions": "{\"HostConfig\": {\"PortBindings\": {\"80/tcp\": [{\"HostPort\": \"8080\"}]}}}", + // "imagePullPolicyTestConfig": { + // "imagePullPolicy": "on-create", + // "pullImage": "false" + // }, // "validator": { // "$type": "RunCommandValidator", // "command": "docker", // "args": "run --rm --link mongo-server:mongo-server mongo:3.4.4 sh -c \"exec mongo --quiet --eval 'db.serverStatus().version' mongo-server:27017/test\"", + // "exitCode": 0, // "outputEquals": "3.4.4" // } // } @@ -53,6 +58,11 @@ public static IEnumerable GenerateStartTestData() // We provide the mapping from the value of "$type" to a fully qualified .NET type name by providing // a "serialization binder" - in our case this is an instance of TypeNameSerializationBinder. The JSON // deserializer consults the TypeNameSerializationBinder instance to determine what type to instantiate. + // + // The "pullPolicyTestConfig" configuration is optional. It's intended for cases where we wish to test + // the behavior of the Agent based on the pull policy specified for a module. + // + // The "exitCode" configuration is optional. By default it's expected value is assumed to be 0. Type agentTestsType = typeof(AgentTests); string format = $"{agentTestsType.Namespace}.{{0}}, {agentTestsType.Assembly.GetName().Name}"; var settings = new JsonSerializerSettings() @@ -91,11 +101,17 @@ public async Task AgentStartsUpModules(TestConfig testConfig) // from previous test runs. await RemoveContainer(client, testConfig); + // Remove old images and pull a new image if specified in the test config. + await PullImage(client, testConfig); + // Initialize docker configuration for this module. DockerConfig dockerConfig = testConfig.ImageCreateOptions != null ? new DockerConfig(testConfig.Image, testConfig.ImageCreateOptions) : new DockerConfig(testConfig.Image); + ImagePullPolicy imagePullPolicy = ImagePullPolicy.OnCreate; + testConfig.ImagePullPolicyTestConfig.ForEach(p => imagePullPolicy = p.ImagePullPolicy); + // Initialize an Edge Agent module object. var dockerModule = new DockerModule( testConfig.Name, @@ -103,6 +119,7 @@ public async Task AgentStartsUpModules(TestConfig testConfig) ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, dockerConfig, + imagePullPolicy, null, null); var modules = new Dictionary { [testConfig.Name] = dockerModule }; @@ -216,5 +233,40 @@ static async Task RemoveContainer(IDockerClient client, TestConfig testConfig) }; await Task.WhenAll(toBeRemoved.Select(c => client.Containers.RemoveContainerAsync(c.ID, removeParams))); } + + static async Task PullImage(IDockerClient client, TestConfig testConfig) + { + // First, delete the image if it's already present. + IList images = await client.Images.ListImagesAsync( + new ImagesListParameters + { + MatchName = testConfig.Image, + }); + + foreach (ImagesListResponse image in images) + { + await client.Images.DeleteImageAsync( + image.ID, + new ImageDeleteParameters + { + Force = true, + }); + } + + bool pullImage = false; + testConfig.ImagePullPolicyTestConfig.ForEach(p => pullImage = p.PullImage); + + // Pull the image if the test config specifies that the image should be pulled. + if (pullImage) + { + await client.Images.CreateImageAsync( + new ImagesCreateParameters + { + FromImage = testConfig.Image, + }, + new AuthConfig(), + new Progress()); + } + } } } diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/ImagePullPolicyTestConfig.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/ImagePullPolicyTestConfig.cs new file mode 100644 index 00000000000..9199fc655ca --- /dev/null +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/ImagePullPolicyTestConfig.cs @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +namespace Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test +{ + using Microsoft.Azure.Devices.Edge.Agent.Core; + using Newtonsoft.Json; + + public class ImagePullPolicyTestConfig + { + [JsonConstructor] + public ImagePullPolicyTestConfig(ImagePullPolicy imagePullPolicy, bool pullImage) + { + this.ImagePullPolicy = imagePullPolicy; + this.PullImage = pullImage; + } + + [JsonProperty("imagePullPolicy")] + public ImagePullPolicy ImagePullPolicy { get; set; } + + [JsonProperty("pullImage")] + public bool PullImage { get; set; } + } +} diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/RunCommandValidator.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/RunCommandValidator.cs index 97f2b157a7c..c5f59eca23f 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/RunCommandValidator.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/RunCommandValidator.cs @@ -16,6 +16,8 @@ public RunCommandValidator() public string OutputEquals { get; set; } + public int ExitCode { get; set; } + public override bool Validate() { var process = new Process @@ -34,7 +36,7 @@ public override bool Validate() process.BeginOutputReadLine(); process.WaitForExit(); - return process.ExitCode == 0 && output == this.OutputEquals; + return process.ExitCode == this.ExitCode && output == this.OutputEquals; } } } diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/TestConfig.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/TestConfig.cs index f2783466272..7eeb964176e 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/TestConfig.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/TestConfig.cs @@ -1,16 +1,40 @@ // Copyright (c) Microsoft. All rights reserved. namespace Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test { + using Microsoft.Azure.Devices.Edge.Util; + using Microsoft.Azure.Devices.Edge.Util.Json; + using Newtonsoft.Json; + public class TestConfig { + [JsonConstructor] + public TestConfig(string name, string version, string image, string imageCreateOptions, Validator validator, ImagePullPolicyTestConfig imagePullPolicyTestConfig) + { + this.Name = name; + this.Version = version; + this.Image = image; + this.ImageCreateOptions = imageCreateOptions; + this.Validator = validator; + this.ImagePullPolicyTestConfig = Option.Maybe(imagePullPolicyTestConfig); + } + + [JsonProperty(PropertyName = "name")] public string Name { get; set; } + [JsonProperty(PropertyName = "version")] public string Version { get; set; } + [JsonProperty(PropertyName = "image")] public string Image { get; set; } + [JsonProperty(PropertyName = "imageCreateOptions")] public string ImageCreateOptions { get; set; } + [JsonProperty(PropertyName = "validator")] public Validator Validator { get; set; } + + [JsonProperty(PropertyName = "imagePullPolicyTestConfig")] + [JsonConverter(typeof(OptionConverter))] + public Option ImagePullPolicyTestConfig { get; set; } } } diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/test-config-x64.json b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/test-config-x64.json index bf31204ae2a..05383f73cc3 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/test-config-x64.json +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.E2E.Test/test-config-x64.json @@ -21,5 +21,53 @@ "args": "run --rm --link nginx-server:nginx-server appropriate/curl curl -s -o /dev/null -w '%{http_code}' http://nginx-server", "outputEquals": "'200'" } + }, + { + "name": "bash", + "version": "1.0", + "image": "bash:latest", + "imagePullPolicyTestConfig": { + "imagePullPolicy": "never", + "pullImage": "false" + }, + "validator": { + "$type": "RunCommandValidator", + "command": "curl", + "args": "-X GET -s -o /dev/null -w \"%{http_code}\" --unix-socket /var/run/docker.sock http://docker/containers/bash/json", + "exitCode" : 23, + "outputEquals": "404" + } + }, + { + "name": "bash", + "version": "1.0", + "image": "bash:latest", + "imagePullPolicyTestConfig": { + "imagePullPolicy": "never", + "pullImage": "true" + }, + "validator": { + "$type": "RunCommandValidator", + "command": "curl", + "args": "-X GET -s -o /dev/null -w \"%{http_code}\" --unix-socket /var/run/docker.sock http://docker/containers/bash/json", + "exitCode" : 23, + "outputEquals": "200" + } + }, + { + "name": "bash", + "version": "1.0", + "image": "bash:latest", + "imagePullPolicyTestConfig": { + "imagePullPolicy": "on-create", + "pullImage": "false" + }, + "validator": { + "$type": "RunCommandValidator", + "command": "curl", + "args": "-X GET -s -o /dev/null -w \"%{http_code}\" --unix-socket /var/run/docker.sock http://docker/containers/bash/json", + "exitCode" : 23, + "outputEquals": "200" + } } ] \ No newline at end of file diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerEnvironmentTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerEnvironmentTest.cs index 4ec28c81744..7e50c6940e7 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerEnvironmentTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerEnvironmentTest.cs @@ -149,10 +149,10 @@ public async Task GetModulesTest() string minDockerVersion = "20"; string dockerLoggingOptions = "dummy logging options"; - var module1 = new DockerModule("module1", "v1", ModuleStatus.Stopped, RestartPolicy.Always, new DockerConfig("mod1:v1", "{\"Env\":[\"foo=bar\"]}"), new ConfigurationInfo(), null); - var module2 = new DockerModule("module2", "v2", ModuleStatus.Running, RestartPolicy.OnUnhealthy, new DockerConfig("mod2:v2", "{\"Env\":[\"foo2=bar2\"]}"), new ConfigurationInfo(), null); - var edgeHubModule = new EdgeHubDockerModule("docker", ModuleStatus.Running, RestartPolicy.Always, new DockerConfig("edgehub:v1", "{\"Env\":[\"foo3=bar3\"]}"), new ConfigurationInfo(), null); - var edgeAgentModule = new EdgeAgentDockerModule("docker", new DockerConfig("edgeAgent:v1", string.Empty), new ConfigurationInfo(), null); + var module1 = new DockerModule("module1", "v1", ModuleStatus.Stopped, RestartPolicy.Always, new DockerConfig("mod1:v1", "{\"Env\":[\"foo=bar\"]}"), ImagePullPolicy.OnCreate, new ConfigurationInfo(), null); + var module2 = new DockerModule("module2", "v2", ModuleStatus.Running, RestartPolicy.OnUnhealthy, new DockerConfig("mod2:v2", "{\"Env\":[\"foo2=bar2\"]}"), ImagePullPolicy.Never, new ConfigurationInfo(), null); + var edgeHubModule = new EdgeHubDockerModule("docker", ModuleStatus.Running, RestartPolicy.Always, new DockerConfig("edgehub:v1", "{\"Env\":[\"foo3=bar3\"]}"), ImagePullPolicy.OnCreate, new ConfigurationInfo(), null); + var edgeAgentModule = new EdgeAgentDockerModule("docker", new DockerConfig("edgeAgent:v1", string.Empty), ImagePullPolicy.OnCreate, new ConfigurationInfo(), null); var deploymentConfig = new DeploymentConfig( "1.0", new DockerRuntimeInfo("docker", new DockerRuntimeConfig(minDockerVersion, dockerLoggingOptions)), @@ -177,6 +177,7 @@ public async Task GetModulesTest() Assert.Equal("v1", receivedDockerModule1.Version); Assert.Equal(ModuleStatus.Stopped, receivedDockerModule1.DesiredStatus); Assert.Equal(RestartPolicy.Always, receivedDockerModule1.RestartPolicy); + Assert.Equal(ImagePullPolicy.OnCreate, receivedDockerModule1.ImagePullPolicy); Assert.Equal("mod1:v1", receivedDockerModule1.Config.Image); Assert.Equal("{\"Env\":[\"foo=bar\"]}", JsonConvert.SerializeObject(receivedDockerModule1.Config.CreateOptions)); Assert.Equal(ModuleStatus.Stopped, receivedDockerModule1.RuntimeStatus); @@ -194,6 +195,7 @@ public async Task GetModulesTest() Assert.Equal("v2", receivedDockerModule2.Version); Assert.Equal(ModuleStatus.Running, receivedDockerModule2.DesiredStatus); Assert.Equal(RestartPolicy.OnUnhealthy, receivedDockerModule2.RestartPolicy); + Assert.Equal(ImagePullPolicy.Never, receivedDockerModule2.ImagePullPolicy); Assert.Equal("mod2:v2", receivedDockerModule2.Config.Image); Assert.Equal("{\"Env\":[\"foo2=bar2\"]}", JsonConvert.SerializeObject(receivedDockerModule2.Config.CreateOptions)); Assert.Equal(ModuleStatus.Failed, receivedDockerModule2.RuntimeStatus); @@ -211,6 +213,7 @@ public async Task GetModulesTest() Assert.Equal(string.Empty, receivedDockerEdgeHub.Version); Assert.Equal(ModuleStatus.Running, receivedDockerEdgeHub.DesiredStatus); Assert.Equal(RestartPolicy.Always, receivedDockerEdgeHub.RestartPolicy); + Assert.Equal(ImagePullPolicy.OnCreate, receivedDockerEdgeHub.ImagePullPolicy); Assert.Equal("edgehub:v1", receivedDockerEdgeHub.Config.Image); Assert.Equal("{\"Env\":[\"foo3=bar3\"]}", JsonConvert.SerializeObject(receivedDockerEdgeHub.Config.CreateOptions)); Assert.Equal(ModuleStatus.Running, receivedDockerEdgeHub.RuntimeStatus); @@ -227,6 +230,7 @@ public async Task GetModulesTest() Assert.Equal("edgeAgent", receivedDockerEdgeAgent.Name); Assert.Equal(string.Empty, receivedDockerEdgeAgent.Version); Assert.Equal(ModuleStatus.Running, receivedDockerEdgeAgent.RuntimeStatus); + Assert.Equal(ImagePullPolicy.OnCreate, receivedDockerEdgeAgent.ImagePullPolicy); Assert.Equal("edgeAgent:v1", receivedDockerEdgeAgent.Config.Image); Assert.Equal("{}", JsonConvert.SerializeObject(receivedDockerEdgeAgent.Config.CreateOptions)); Assert.Equal(new DateTime(2017, 10, 10), receivedDockerEdgeAgent.LastStartTimeUtc); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerModuleTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerModuleTest.cs index a946484c283..e494c141eb8 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerModuleTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerModuleTest.cs @@ -15,22 +15,23 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Docker.Test [ExcludeFromCodeCoverage] public class DockerModuleTest { - const string SerializedModule = @"{""version"":""version1"",""type"":""docker"",""status"":""running"",""restartPolicy"":""on-unhealthy"",""settings"":{""image"":""image1:42"", ""createOptions"": {""HostConfig"": {""PortBindings"": {""43/udp"": [{""HostPort"": ""43""}], ""42/tcp"": [{""HostPort"": ""42""}]}}}},""configuration"":{""id"":""1""},""env"":{""Env1"": {""value"":""Val1""}}}"; + const string SerializedModule = @"{""version"":""version1"",""type"":""docker"",""status"":""running"",""restartPolicy"":""on-unhealthy"",""imagePullPolicy"":""on-create"",""settings"":{""image"":""image1:42"", ""createOptions"": {""HostConfig"": {""PortBindings"": {""43/udp"": [{""HostPort"": ""43""}], ""42/tcp"": [{""HostPort"": ""42""}]}}}},""configuration"":{""id"":""1""},""env"":{""Env1"": {""value"":""Val1""}}}"; static readonly ConfigurationInfo DefaultConfigurationInfo = null; static readonly DockerConfig Config1 = new DockerConfig("image1:42", @"{""HostConfig"": {""PortBindings"": {""43/udp"": [{""HostPort"": ""43""}], ""42/tcp"": [{""HostPort"": ""42""}]}}}"); static readonly DockerConfig Config2 = new DockerConfig("image2:42", @"{""HostConfig"": {""PortBindings"": {""43/udp"": [{""HostPort"": ""43""}], ""42/tcp"": [{""HostPort"": ""42""}]}}}"); static readonly IDictionary DefaultEnvVals = new Dictionary { ["Env1"] = new EnvVal("Val1") }; - static readonly IModule Module1 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, DefaultEnvVals); - static readonly IModule Module2 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, DefaultEnvVals); - static readonly IModule Module3 = new DockerModule("mod3", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, DefaultEnvVals); - static readonly IModule Module4 = new DockerModule("mod1", "version2", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, DefaultEnvVals); - static readonly IModule Module6 = new DockerModule("mod1", "version1", ModuleStatus.Unknown, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, DefaultEnvVals); - static readonly IModule Module7 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config2, DefaultConfigurationInfo, DefaultEnvVals); - static readonly DockerModule Module8 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, DefaultEnvVals); - static readonly IModule Module9 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.Always, Config1, DefaultConfigurationInfo, DefaultEnvVals); - static readonly IModule Module10 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, new Dictionary { ["Env1"] = new EnvVal("Val2") }); - static readonly IModule ModuleWithConfig = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.Always, Config1, new ConfigurationInfo("c1"), DefaultEnvVals); - static readonly DockerModule ValidJsonModule = new DockerModule("", "", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module1 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module2 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module3 = new DockerModule("mod3", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module4 = new DockerModule("mod1", "version2", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module6 = new DockerModule("mod1", "version1", ModuleStatus.Unknown, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module7 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config2, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly DockerModule Module8 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module9 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule Module10 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, new Dictionary { ["Env1"] = new EnvVal("Val2") }); + static readonly IModule Module11 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.Never, DefaultConfigurationInfo, DefaultEnvVals); + static readonly IModule ModuleWithConfig = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.Always, Config1, ImagePullPolicy.OnCreate, new ConfigurationInfo("c1"), DefaultEnvVals); + static readonly DockerModule ValidJsonModule = new DockerModule("", "", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, DefaultEnvVals); static readonly JObject TestJsonInputs = JsonConvert.DeserializeObject( @" @@ -85,6 +86,7 @@ public class DockerModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-failure"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"", ""createoptions"":{ @@ -103,6 +105,7 @@ public class DockerModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""always"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"", ""createoptions"":{ @@ -118,6 +121,7 @@ public class DockerModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"", ""createoptions"":{ @@ -133,6 +137,7 @@ public class DockerModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""never"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"", }, @@ -147,6 +152,7 @@ public class DockerModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"": ""on-unhealthy"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"", ""CreateOptions"": { @@ -180,6 +186,7 @@ public class DockerModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:42"", ""createoptions"": { @@ -213,6 +220,7 @@ public class DockerModuleTest ""TYPE"":""docker"", ""STATUS"":""running"", ""RESTARTPOLICY"": ""on-unhealthy"", + ""IMAGEPULLPOLICY"": ""on-create"", ""SETTINGS"":{ ""IMAGE"":""image1:42"", ""CREATEOPTIONS"": { @@ -308,9 +316,10 @@ public static IEnumerable GetExceptionJsonInputs() [Unit] public void TestConstructor() { - Assert.Throws(() => new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, null, null, null)); - Assert.Throws(() => new DockerModule("mod1", "version1", (ModuleStatus)int.MaxValue, RestartPolicy.OnUnhealthy, Config1, null, null)); - Assert.Throws(() => new DockerModule("mod1", "version1", ModuleStatus.Running, (RestartPolicy)int.MaxValue, Config1, null, null)); + Assert.Throws(() => new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, null, ImagePullPolicy.OnCreate, null, null)); + Assert.Throws(() => new DockerModule("mod1", "version1", (ModuleStatus)int.MaxValue, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, null, null)); + Assert.Throws(() => new DockerModule("mod1", "version1", ModuleStatus.Running, (RestartPolicy)int.MaxValue, Config1, ImagePullPolicy.OnCreate, null, null)); + Assert.Throws(() => new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, (ImagePullPolicy)int.MaxValue, null, null)); } [Fact] @@ -322,6 +331,7 @@ public void TestEquality() Assert.Equal(Module8, Module8); Assert.NotEqual(Module1, Module3); Assert.NotEqual(Module1, Module9); + Assert.NotEqual(Module1, Module11); Assert.NotEqual(Module1, Module4); Assert.NotEqual(Module1, Module6); Assert.NotEqual(Module1, Module7); @@ -346,6 +356,7 @@ public void TestEquality() Assert.Equal(Module1.GetHashCode(), Module2.GetHashCode()); Assert.NotEqual(Module1.GetHashCode(), Module3.GetHashCode()); Assert.NotEqual(Module1.GetHashCode(), Module9.GetHashCode()); + Assert.NotEqual(Module1.GetHashCode(), Module11.GetHashCode()); } [Theory] @@ -410,7 +421,7 @@ public void TestSerializeContainerCreateConfig() // Arrange string createOptions = @"{""Env"": [""k1=v1"",""k2=v2""]}"; var config = new DockerConfig("ubuntu:latest", createOptions); - var module = new DockerModule("testser", "1.0", ModuleStatus.Running, RestartPolicy.OnUnhealthy, config, null, null); + var module = new DockerModule("testser", "1.0", ModuleStatus.Running, RestartPolicy.OnUnhealthy, config, ImagePullPolicy.OnCreate, null, null); // Act string json = ModuleSerde.Instance.Serialize(module); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerRuntimeModuleTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerRuntimeModuleTest.cs index a6c23335c70..8c11e302bc9 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerRuntimeModuleTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/DockerRuntimeModuleTest.cs @@ -17,31 +17,32 @@ namespace Microsoft.Azure.Devices.Edge.Agent.Docker.Test [Unit] public class DockerRuntimeModuleTest { - const string SerializedModule1 = @"{""version"":""version1"",""type"":""docker"",""status"":""running"",""restartPolicy"":""on-unhealthy"",""exitcode"":0,""restartcount"":0,""lastrestarttimeutc"":""0001-01-01T00:00:00Z"",""runtimestatus"":""running"",""settings"":{""image"":""image1:42"",""createOptions"":{""HostConfig"":{""PortBinding"":{""42/tcp"":[{""HostPort"":""42""}],""43/udp"":[{""HostPort"":""43""}]}}}},""configuration"":{""id"":""1""}}"; - const string SerializedModule2 = @"{""version"":""version1"",""type"":""docker"",""status"":""running"",""restartPolicy"":""on-unhealthy"",""exitcode"":0,""statusdescription"":""Running 1 minute"",""laststarttimeutc"":""2017-08-04T17:52:13.0419502Z"",""lastexittimeutc"":""0001-01-01T00:00:00Z"",""restartcount"":0,""lastrestarttimeutc"":""0001-01-01T00:00:00Z"",""runtimestatus"":""running"",""settings"":{""image"":""image1:42"",""createOptions"":{""HostConfig"":{""PortBinding"":{""42/tcp"":[{""HostPort"":""42""}],""43/udp"":[{""HostPort"":""43""}]}}}},""configuration"":{""id"":""1""}}"; + const string SerializedModule1 = @"{""version"":""version1"",""type"":""docker"",""status"":""running"",""restartPolicy"":""on-unhealthy"",""imagePullPolicy"":""on-create"",""exitcode"":0,""restartcount"":0,""lastrestarttimeutc"":""0001-01-01T00:00:00Z"",""runtimestatus"":""running"",""settings"":{""image"":""image1:42"",""createOptions"":{""HostConfig"":{""PortBinding"":{""42/tcp"":[{""HostPort"":""42""}],""43/udp"":[{""HostPort"":""43""}]}}}},""configuration"":{""id"":""1""}}"; + const string SerializedModule2 = @"{""version"":""version1"",""type"":""docker"",""status"":""running"",""restartPolicy"":""on-unhealthy"",""imagePullPolicy"":""on-create"",""exitcode"":0,""statusdescription"":""Running 1 minute"",""laststarttimeutc"":""2017-08-04T17:52:13.0419502Z"",""lastexittimeutc"":""0001-01-01T00:00:00Z"",""restartcount"":0,""lastrestarttimeutc"":""0001-01-01T00:00:00Z"",""runtimestatus"":""running"",""settings"":{""image"":""image1:42"",""createOptions"":{""HostConfig"":{""PortBinding"":{""42/tcp"":[{""HostPort"":""42""}],""43/udp"":[{""HostPort"":""43""}]}}}},""configuration"":{""id"":""1""}}"; static readonly ConfigurationInfo DefaultConfigurationInfo = null; static readonly IDictionary EnvVars = new Dictionary(); static readonly DockerConfig Config1 = new DockerReportedConfig("image1:42", @"{""HostConfig"": {""PortBinding"": {""42/tcp"": [{""HostPort"": ""42""}], ""43/udp"": [{""HostPort"": ""43""}]}}}", "foo"); static readonly DockerConfig Config2 = new DockerReportedConfig("image2:42", @"{""HostConfig"": {""PortBinding"": {""42/tcp"": [{""HostPort"": ""42""}], ""43/udp"": [{""HostPort"": ""43""}]}}}", "foo"); - static readonly IModule Module1 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, null, DateTime.MinValue, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module1A = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, null, DateTime.MinValue, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module2 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module2A = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module3 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config2, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module4 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, -1, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module5 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 35 minutes", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module6 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-07-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module7 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.Parse("2017-08-05T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module8 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly DockerModule Module9 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module10 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnFailure, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module11 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 1, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - static readonly IModule Module12 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Stopped, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module1 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, null, DateTime.MinValue, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module1A = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, null, DateTime.MinValue, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module2 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module2A = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module3 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config2, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module4 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, -1, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module5 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 35 minutes", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module6 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-07-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module7 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.Parse("2017-08-05T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module8 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly DockerModule Module9 = new DockerModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module10 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnFailure, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module11 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 1, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module12 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Stopped, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + static readonly IModule Module13 = new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.Never, DefaultConfigurationInfo, EnvVars); static readonly DockerConfig ValidConfig = new DockerReportedConfig("image1:42", (string)null, "sha256:75"); - static readonly DockerRuntimeModule ValidJsonModule = new DockerRuntimeModule("", "", ModuleStatus.Running, RestartPolicy.OnFailure, ValidConfig, 0, "", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.Parse("2017-08-05T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), 1, DateTime.Parse("2017-08-06T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); + static readonly DockerRuntimeModule ValidJsonModule = new DockerRuntimeModule("", "", ModuleStatus.Running, RestartPolicy.OnFailure, ValidConfig, 0, "", DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), DateTime.Parse("2017-08-05T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), 1, DateTime.Parse("2017-08-06T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind), ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); static readonly JObject TestJsonInputs = JsonConvert.DeserializeObject( @" @@ -52,6 +53,7 @@ public class DockerRuntimeModuleTest ""type"": ""docker"", ""status"": ""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"": { ""image"": ""image1:ver1"" }, @@ -65,6 +67,7 @@ public class DockerRuntimeModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"" }, @@ -78,6 +81,7 @@ public class DockerRuntimeModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"" }, @@ -91,6 +95,7 @@ public class DockerRuntimeModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"" }, @@ -106,6 +111,7 @@ public class DockerRuntimeModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"" }, @@ -119,6 +125,7 @@ public class DockerRuntimeModuleTest ""type"":""docker"", ""status"":""running"", ""restartPolicy"": ""on-unhealthy"", + ""imagePullPolicy"": ""on-create"", ""settings"":{ ""image"":""image1:ver1"", }, @@ -186,6 +193,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:ver1"", }, @@ -202,6 +210,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"", }, @@ -218,6 +227,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"", }, @@ -234,6 +244,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"", }, @@ -250,6 +261,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:ver1"" }, @@ -294,6 +306,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""unknown"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"" }, @@ -313,6 +326,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""stopped"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"" }, @@ -332,6 +346,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""backoff"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"" }, @@ -351,6 +366,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""unhealthy"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"" }, @@ -370,6 +386,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"" }, @@ -389,6 +406,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""failed"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"" }, @@ -410,6 +428,7 @@ public class DockerRuntimeModuleTest ""Type"":""docker"", ""Status"":""running"", ""RestartPolicy"":""on-failure"", + ""ImagePullPolicy"": ""on-create"", ""Settings"":{ ""Image"":""image1:42"" }, @@ -429,6 +448,7 @@ public class DockerRuntimeModuleTest ""type"":""docker"", ""status"":""running"", ""restartpolicy"":""on-failure"", + ""imagepullpolicy"": ""on-create"", ""exitcode"": 0, ""statusdescription"" : """", ""laststarttimeutc"" : ""2017-08-04T17:52:13.0419502Z"", @@ -452,6 +472,7 @@ public class DockerRuntimeModuleTest ""TYPE"":""docker"", ""STATUS"":""RUNNING"", ""RESTARTPOLICY"":""on-failure"", + ""IMAGEPULLPOLICY"": ""on-create"", ""SETTINGS"":{ ""IMAGE"":""image1:42"" }, @@ -512,23 +533,26 @@ public void TestConstructor() DateTime lastStartTime = DateTime.Parse("2017-08-04T17:52:13.0419502Z", null, DateTimeStyles.RoundtripKind); // null docker config - Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, null, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, null, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); // bad desired status - Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", (ModuleStatus)int.MaxValue, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", (ModuleStatus)int.MaxValue, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); // bad restart policy - Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, (RestartPolicy)int.MaxValue, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, (RestartPolicy)int.MaxValue, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); // bad runtime status - Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, (ModuleStatus)int.MaxValue, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, (ModuleStatus)int.MaxValue, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); // bad restart count - Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, -1, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars)); + Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, -1, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars)); - var env1 = new DockerRuntimeModule("name", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, null, lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - var env2 = new DockerRuntimeModule("name", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.MinValue, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); - var env3 = new DockerRuntimeModule("name", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, DefaultConfigurationInfo, EnvVars); + // bad pull policy + Assert.Throws(() => new DockerRuntimeModule("mod1", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, (ImagePullPolicy)int.MaxValue, DefaultConfigurationInfo, EnvVars)); + + var env1 = new DockerRuntimeModule("name", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, null, lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + var env2 = new DockerRuntimeModule("name", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", DateTime.MinValue, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + var env3 = new DockerRuntimeModule("name", "version1", ModuleStatus.Running, RestartPolicy.OnUnhealthy, Config1, 0, "Running 1 minute", lastStartTime, DateTime.MinValue, 0, DateTime.MinValue, ModuleStatus.Running, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); Assert.NotNull(env1); Assert.NotNull(env2); Assert.NotNull(env3); @@ -553,6 +577,7 @@ public void TestEquality() Assert.NotEqual(Module8, Module10); Assert.NotEqual(Module8, Module11); Assert.NotEqual(Module8, Module12); + Assert.NotEqual(Module8, Module13); Assert.False(Module1.Equals(null)); Assert.False(Module2.Equals(null)); @@ -685,6 +710,7 @@ public void TestWithRuntimeStatus() Assert.Equal(m2.Name, newM2.Name); Assert.Equal(m2.RestartCount, newM2.RestartCount); Assert.Equal(m2.RestartPolicy, newM2.RestartPolicy); + Assert.Equal(m2.ImagePullPolicy, newM2.ImagePullPolicy); Assert.Equal(m2.StatusDescription, newM2.StatusDescription); Assert.Equal(m2.Type, newM2.Type); Assert.Equal(m2.Version, newM2.Version); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerModuleTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerModuleTest.cs index ebfb8b39698..b484b8eff41 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerModuleTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerModuleTest.cs @@ -12,36 +12,36 @@ public static IEnumerable GetEaModules() { yield return new object[] { - new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), null, null), - new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), null, null), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), ImagePullPolicy.OnCreate, null, null), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), ImagePullPolicy.OnCreate, null, null), true }; yield return new object[] { - new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), new ConfigurationInfo("c1"), new Dictionary { ["Env1"] = new EnvVal("EnvVal1") }, "version1"), - new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), null, null), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), ImagePullPolicy.Never, new ConfigurationInfo("c1"), new Dictionary { ["Env1"] = new EnvVal("EnvVal1") }, "version1"), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), ImagePullPolicy.Never, null, null), true }; yield return new object[] { - new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), new ConfigurationInfo("c1"), new Dictionary { ["Env1"] = new EnvVal("EnvVal1") }, "version1"), - new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), new ConfigurationInfo("c2"), new Dictionary { ["Env2"] = new EnvVal("EnvVal2") }, "version2"), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), ImagePullPolicy.OnCreate, new ConfigurationInfo("c1"), new Dictionary { ["Env1"] = new EnvVal("EnvVal1") }, "version1"), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), ImagePullPolicy.OnCreate, new ConfigurationInfo("c2"), new Dictionary { ["Env2"] = new EnvVal("EnvVal2") }, "version2"), true }; yield return new object[] { - new EdgeAgentDockerModule("docker", new DockerConfig("Foo", "{}"), new ConfigurationInfo("c1"), new Dictionary { ["Env1"] = new EnvVal("EnvVal1") }, "version1"), - new EdgeAgentDockerModule("docker", new DockerConfig("Foo", "{\"HostConfig\":{\"PortBindings\":{\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"), new ConfigurationInfo("c2"), new Dictionary { ["Env2"] = new EnvVal("EnvVal2") }, "version2"), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo", "{}"), ImagePullPolicy.OnCreate, new ConfigurationInfo("c1"), new Dictionary { ["Env1"] = new EnvVal("EnvVal1") }, "version1"), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo", "{\"HostConfig\":{\"PortBindings\":{\"8883/tcp\":[{\"HostPort\":\"8883\"}],\"443/tcp\":[{\"HostPort\":\"443\"}]}}}"), ImagePullPolicy.OnCreate, new ConfigurationInfo("c2"), new Dictionary { ["Env2"] = new EnvVal("EnvVal2") }, "version2"), true }; yield return new object[] { - new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), null, null), - new EdgeAgentDockerModule("docker", new DockerConfig("Bar"), null, null), + new EdgeAgentDockerModule("docker", new DockerConfig("Foo"), ImagePullPolicy.OnCreate, null, null), + new EdgeAgentDockerModule("docker", new DockerConfig("Bar"), ImagePullPolicy.OnCreate, null, null), false }; } diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerRuntimeModuleTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerRuntimeModuleTest.cs index 0ae73885fbd..11743cab176 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerRuntimeModuleTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeAgentDockerRuntimeModuleTest.cs @@ -26,6 +26,7 @@ public void TestJsonSerialize() string.Empty, lastStartTimeUtc, lastExitTimeUtc, + ImagePullPolicy.OnCreate, null, new Dictionary()); @@ -42,6 +43,7 @@ public void TestJsonSerialize() lastExitTimeUtc = lastExitTimeUtc, statusDescription = string.Empty, type = "docker", + imagePullPolicy = "on-create", settings = new { image = "booyah:latest", @@ -136,6 +138,7 @@ public void TestWithRuntimeStatus() string.Empty, lastStartTimeUtc, lastExitTimeUtc, + ImagePullPolicy.OnCreate, new ConfigurationInfo("bing"), new Dictionary()); var updatedModule1 = (EdgeAgentDockerRuntimeModule)module.WithRuntimeStatus(ModuleStatus.Running); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeHubDockerRuntimeModuleTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeHubDockerRuntimeModuleTest.cs index 062377b064d..72fe03ece32 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeHubDockerRuntimeModuleTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/EdgeHubDockerRuntimeModuleTest.cs @@ -27,6 +27,7 @@ public void TestJsonSerialize() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.Never, new ConfigurationInfo("1"), new Dictionary()); @@ -39,6 +40,7 @@ public void TestJsonSerialize() { ""status"": ""running"", ""restartPolicy"": ""always"", + ""imagePullPolicy"": ""never"", ""exitCode"": 0, ""statusDescription"": """", ""lastStartTimeUtc"": ""0001-01-01T00:00:00"", @@ -67,6 +69,7 @@ public void TestJsonDeerialize() { ""status"": ""running"", ""restartPolicy"": ""always"", + ""imagePullPolicy"": ""never"", ""exitCode"": 0, ""statusDescription"": """", ""lastStartTimeUtc"": ""0001-01-01T00:00:00"", @@ -96,6 +99,7 @@ public void TestJsonDeerialize() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.Never, null, new Dictionary()); @@ -113,6 +117,7 @@ public void EqualsTest() ModuleStatus.Running, RestartPolicy.Always, new DockerConfig(image), + ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), new Dictionary()); @@ -127,6 +132,7 @@ public void EqualsTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), new Dictionary()); @@ -152,6 +158,7 @@ public void TestWithRuntimeStatus() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), new Dictionary()); var updatedModule1 = (EdgeHubDockerRuntimeModule)module.WithRuntimeStatus(ModuleStatus.Running); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/RuntimeInfoProviderTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/RuntimeInfoProviderTest.cs index 58e296c3baf..5ee872c431b 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/RuntimeInfoProviderTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/RuntimeInfoProviderTest.cs @@ -79,7 +79,7 @@ public async Task TestFilters() var loggingConfig = new DockerLoggingConfig("json-file"); var config = new DockerConfig(Image); - var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, null, null); + var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, ImagePullPolicy.OnCreate, null, null); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary @@ -145,7 +145,7 @@ public async Task TestEnvVars() string createOptions = @"{""Env"": [ ""k1=v1"", ""k2=v2""]}"; var config = new DockerConfig(Image, createOptions); var loggingConfig = new DockerLoggingConfig("json-file"); - var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, null, null); + var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, ImagePullPolicy.OnCreate, null, null); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/commands/CreateCommandTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/commands/CreateCommandTest.cs index 221f5179591..1808efbe541 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/commands/CreateCommandTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Docker.Test/commands/CreateCommandTest.cs @@ -53,7 +53,7 @@ public async Task SmokeTest() // Logging options will be derived from these default logging options var loggingConfig = new DockerLoggingConfig("json-file", dockerLoggingOptions); var config = new DockerConfig(Image, @"{""Env"": [""k1=v1"", ""k2=v2""], ""HostConfig"": {""PortBindings"": {""8080/tcp"": [{""HostPort"": ""80""}]}}}"); - var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, null, EnvVars); + var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, ImagePullPolicy.OnCreate, null, EnvVars); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary @@ -124,7 +124,7 @@ public async Task TestUdpModuleConfig() var loggingConfig = new DockerLoggingConfig("json-file"); var config = new DockerConfig(Image, @"{""HostConfig"": {""PortBindings"": {""42/udp"": [{""HostPort"": ""42""}]}}}"); - var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, null, EnvVars); + var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, ImagePullPolicy.OnCreate, null, EnvVars); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary @@ -201,7 +201,7 @@ public async Task EdgeHubLaunch() // Logging options will be derived from module options. var config = new DockerConfig(Image, @"{""Env"": [""k1=v1"", ""k2=v2""], ""HostConfig"": {""LogConfig"": {""Type"":""none""}, ""PortBindings"": {""8080/tcp"": [{""HostPort"": ""80""}],""443/tcp"": [{""HostPort"": ""11443""}]}}}"); var configurationInfo = new ConfigurationInfo(); - var module = new EdgeHubDockerModule("docker", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, config, configurationInfo, EnvVars); + var module = new EdgeHubDockerModule("docker", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, config, ImagePullPolicy.Never, configurationInfo, EnvVars); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary @@ -288,7 +288,7 @@ public async Task EdgeHubLaunchWithBadLogOptions() var loggingConfig = new DockerLoggingConfig("json-file", dockerLoggingOptions); var config = new DockerConfig(Image, @"{""Env"": [""k1=v1"", ""k2=v2""]}"); var configurationInfo = new ConfigurationInfo("43"); - var module = new EdgeHubDockerModule("docker", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, config, configurationInfo, EnvVars); + var module = new EdgeHubDockerModule("docker", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, config, ImagePullPolicy.OnCreate, configurationInfo, EnvVars); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary @@ -399,6 +399,7 @@ public async Task TestMountEdgeHubVolume() ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, new DockerConfig("image1"), + ImagePullPolicy.OnCreate, new ConfigurationInfo("1234"), EnvVars), moduleIdentity.Object, @@ -470,6 +471,7 @@ public async Task TestMountModuleVolume() ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, new DockerConfig("image1"), + ImagePullPolicy.OnCreate, new ConfigurationInfo("1234"), EnvVars), moduleIdentity.Object, @@ -672,7 +674,7 @@ public async Task UpstreamProtocolTest() // Logging options will be derived from these default logging options var loggingConfig = new DockerLoggingConfig("json-file", dockerLoggingOptions); var config = new DockerConfig(Image, @"{""Env"": [""k1=v1"", ""k2=v2""], ""HostConfig"": {""PortBindings"": {""8080/tcp"": [{""HostPort"": ""80""}]}}}"); - var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, null, EnvVars); + var module = new DockerModule(Name, "1.0", ModuleStatus.Running, global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.OnUnhealthy, config, ImagePullPolicy.OnCreate, null, EnvVars); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary @@ -730,6 +732,7 @@ public async Task UpstreamProtocolTest() Constants.EdgeAgentModuleName, "docker", new TestConfig("EdgeAgentImage"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), EnvVars); @@ -739,6 +742,7 @@ public async Task UpstreamProtocolTest() ModuleStatus.Running, new TestConfig("EdgeAgentImage"), global::Microsoft.Azure.Devices.Edge.Agent.Core.RestartPolicy.Always, + ImagePullPolicy.OnCreate, new ConfigurationInfo(), EnvVars); } diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleIdentityLifecycleManagerTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleIdentityLifecycleManagerTest.cs index c55910aa8ec..8a91c5163da 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleIdentityLifecycleManagerTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleIdentityLifecycleManagerTest.cs @@ -48,10 +48,10 @@ public async Task TestGetModulesIdentity_IIdentityManagerException_ShouldReturnE var moduleIdentityLifecycleManager = new ModuleIdentityLifecycleManager(identityManager, ModuleIdentityProviderServiceBuilder, EdgeletUri); var envVar = new Dictionary(); - var module1 = new TestModule("mod1", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var module2 = new TestModule("mod2", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var module3 = new TestModule("mod3", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var module4 = new TestModule("$edgeHub", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); + var module1 = new TestModule("mod1", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var module2 = new TestModule("mod2", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var module3 = new TestModule("mod3", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var module4 = new TestModule("$edgeHub", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); ModuleSet desired = ModuleSet.Create(module1, module4); ModuleSet current = ModuleSet.Create(module2, module3, module4); @@ -80,7 +80,7 @@ public async Task TestGetModulesIdentity_WithNewModules_ShouldCreateIdentities() m.CreateIdentityAsync(Name, Constants.ModuleIdentityEdgeManagedByValue) == Task.FromResult(identity)); var moduleIdentityLifecycleManager = new ModuleIdentityLifecycleManager(identityManager, ModuleIdentityProviderServiceBuilder, EdgeletUri); - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, new Dictionary()); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, new Dictionary()); // Act IImmutableDictionary modulesIdentities = await moduleIdentityLifecycleManager.GetModuleIdentitiesAsync( @@ -128,11 +128,11 @@ public async Task TestGetModulesIdentity_WithUpdatedModules_ShouldUpdateIdentiti var moduleIdentityLifecycleManager = new ModuleIdentityLifecycleManager(identityManager, ModuleIdentityProviderServiceBuilder, EdgeletUri); var envVar = new Dictionary(); - var module1 = new TestModule(Module1, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var module2 = new TestModule(Module2, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var module3 = new TestModule(Module3, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var module4 = new TestModule(Module4, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var module5 = new TestModule(Module5, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); + var module1 = new TestModule(Module1, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var module2 = new TestModule(Module2, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var module3 = new TestModule(Module3, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var module4 = new TestModule(Module4, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var module5 = new TestModule(Module5, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); ModuleSet desired = ModuleSet.Create(module1, module2.CloneWithImage("image2"), module3.CloneWithImage("image2"), module4.CloneWithImage("image2"), module5.CloneWithImage("image2")); ModuleSet current = ModuleSet.Create(module2, module3, module4, module5); @@ -175,9 +175,9 @@ public async Task TestGetModulesIdentity_WithRemovedModules_ShouldRemove() var moduleIdentityLifecycleManager = new ModuleIdentityLifecycleManager(identityManager, ModuleIdentityProviderServiceBuilder, EdgeletUri); var envVar = new Dictionary(); - var desiredModule = new TestModule(Module1, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var currentModule1 = new TestModule(Module2, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); - var currentModule2 = new TestModule(Module3, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, envVar); + var desiredModule = new TestModule(Module1, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var currentModule1 = new TestModule(Module2, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); + var currentModule2 = new TestModule(Module3, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, envVar); ModuleSet desired = ModuleSet.Create(new IModule[] { desiredModule }); ModuleSet current = ModuleSet.Create(new IModule[] { currentModule1, currentModule2 }); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleManagementHttpClientTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleManagementHttpClientTest.cs index 8cb614bd80a..40a12adb974 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleManagementHttpClientTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.Edgelet.Test/ModuleManagementHttpClientTest.cs @@ -148,7 +148,7 @@ public async Task ModulesTest(string serverApiVersion, string clientApiVersion) { // Arrange IModuleManager client = new ModuleManagementHttpClient(this.serverUrl, serverApiVersion, clientApiVersion); - var moduleSpec = new ModuleSpec("Module1", "Docker", JObject.Parse("{ \"image\": \"testimage\" }"), new ObservableCollection { new EnvVar("E1", "P1") }); + var moduleSpec = new ModuleSpec("Module1", "Docker", ImagePullPolicy.OnCreate, JObject.Parse("{ \"image\": \"testimage\" }"), new ObservableCollection { new EnvVar("E1", "P1") }); // Act await client.CreateModuleAsync(moduleSpec); @@ -229,6 +229,7 @@ public async Task Test_PrepareUpdate_ShouldSucceed(string serverApiVersion, stri var moduleSpec = new ModuleSpec( "Module1", "Docker", + ImagePullPolicy.OnCreate, JObject.Parse("{ \"image\": \"testimage\" }"), new ObservableCollection { new EnvVar("E1", "P1") }); IModuleManager client = new ModuleManagementHttpClient(this.serverUrl, serverApiVersion, clientApiVersion); @@ -255,6 +256,19 @@ public async Task ModuleLogsTest(string serverApiVersion, string clientApiVersio Assert.Equal(buffer.Length, bytesRead); } + [Fact] + public void ImagePullPolicyTest() + { + Assert.Equal( + Version_2019_01_30.GeneratedCode.ImagePullPolicy.OnCreate, + Version_2019_01_30.ModuleManagementHttpClient.ToGeneratedCodePullPolicy(ImagePullPolicy.OnCreate)); + Assert.Equal( + Version_2019_01_30.GeneratedCode.ImagePullPolicy.Never, + Version_2019_01_30.ModuleManagementHttpClient.ToGeneratedCodePullPolicy(ImagePullPolicy.Never)); + + Assert.Throws(() => Version_2019_01_30.ModuleManagementHttpClient.ToGeneratedCodePullPolicy((ImagePullPolicy)int.MaxValue)); + } + [Fact] public async Task ExecuteTimeoutTest_Version_2018_06_28() { diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/EdgeAgentConnectionTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/EdgeAgentConnectionTest.cs index 209992150b2..e7569873d39 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/EdgeAgentConnectionTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/EdgeAgentConnectionTest.cs @@ -1054,12 +1054,13 @@ public async Task EdgeAgentConnectionRefreshTest() ISerde serde = new TypeSpecificSerDe(deserializerTypes); var runtimeInfo = new DockerRuntimeInfo("docker", new DockerRuntimeConfig("1.0", null)); - var edgeAgentDockerModule = new EdgeAgentDockerModule("docker", new DockerConfig("image", string.Empty), null, null); + var edgeAgentDockerModule = new EdgeAgentDockerModule("docker", new DockerConfig("image", string.Empty), ImagePullPolicy.OnCreate, null, null); var edgeHubDockerModule = new EdgeHubDockerModule( "docker", ModuleStatus.Running, RestartPolicy.Always, new DockerConfig("image", string.Empty), + ImagePullPolicy.OnCreate, null, null); var deploymentConfig = new DeploymentConfig( @@ -1126,12 +1127,13 @@ public async Task GetTwinFailureDoesNotUpdateState() ISerde serde = new TypeSpecificSerDe(deserializerTypes); var runtimeInfo = new DockerRuntimeInfo("docker", new DockerRuntimeConfig("1.0", null)); - var edgeAgentDockerModule = new EdgeAgentDockerModule("docker", new DockerConfig("image", string.Empty), null, null); + var edgeAgentDockerModule = new EdgeAgentDockerModule("docker", new DockerConfig("image", string.Empty), ImagePullPolicy.OnCreate, null, null); var edgeHubDockerModule = new EdgeHubDockerModule( "docker", ModuleStatus.Running, RestartPolicy.Always, new DockerConfig("image", string.Empty), + ImagePullPolicy.OnCreate, null, null); var deploymentConfig = new DeploymentConfig( @@ -1217,12 +1219,13 @@ public async Task GetTwinRetryLogicGetsNewClient() ISerde serde = new TypeSpecificSerDe(deserializerTypes); var runtimeInfo = new DockerRuntimeInfo("docker", new DockerRuntimeConfig("1.0", null)); - var edgeAgentDockerModule = new EdgeAgentDockerModule("docker", new DockerConfig("image", string.Empty), null, null); + var edgeAgentDockerModule = new EdgeAgentDockerModule("docker", new DockerConfig("image", string.Empty), ImagePullPolicy.OnCreate, null, null); var edgeHubDockerModule = new EdgeHubDockerModule( "docker", ModuleStatus.Running, RestartPolicy.Always, new DockerConfig("image", string.Empty), + ImagePullPolicy.OnCreate, null, null); var deploymentConfig = new DeploymentConfig( @@ -1238,6 +1241,7 @@ public async Task GetTwinRetryLogicGetsNewClient() ModuleStatus.Running, RestartPolicy.Always, new DockerConfig("image2", string.Empty), + ImagePullPolicy.OnCreate, null, null); var deploymentConfig2 = new DeploymentConfig( diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/ModuleIdentityLifecycleManagerTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/ModuleIdentityLifecycleManagerTest.cs index c51e263ca94..dd681e16649 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/ModuleIdentityLifecycleManagerTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/ModuleIdentityLifecycleManagerTest.cs @@ -58,7 +58,7 @@ public async Task TestGetModulesIdentity_WithUpdatedModules_NoServiceIdentity_Sh // ReSharper disable PossibleMultipleEnumeration serviceClient.Setup(sc => sc.CreateModules(It.Is>(m => m.Count() == 1 && m.First() == Name))).Returns(Task.FromResult(updatedServiceIdentities)); // ReSharper restore PossibleMultipleEnumeration - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(new IModule[] { module }), ModuleSet.Empty); @@ -98,7 +98,7 @@ public async Task TestGetModulesIdentity_WithUpdatedModules_NoAccessKey_ShouldUp } }).Returns(Task.FromResult(serviceIdentities)); - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(new IModule[] { module }), ModuleSet.Empty); @@ -134,7 +134,7 @@ public async Task TestGetModulesIdentity_WithUpdatedModules_AuthTypeNull_ShouldU } }).Returns(Task.FromResult(serviceIdentities)); - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(new IModule[] { module }), ModuleSet.Empty); @@ -181,7 +181,7 @@ public async Task TestGetModulesIdentity_WithUpdatedModules_AuthTypeNotSas_Shoul } }).Returns(Task.FromResult(serviceIdentities)); - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(new IModule[] { module }), ModuleSet.Empty); @@ -223,7 +223,7 @@ public async Task TestGetModulesIdentity_WithUpdatedModules_SymmKeyNull_ShouldUp } }).Returns(Task.FromResult(serviceIdentities)); - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(new IModule[] { module }), ModuleSet.Empty); @@ -260,7 +260,7 @@ public async Task TestGetModulesIdentity_WithUpdatedModules_HasAccessKey_ShouldN serviceClient.Setup(sc => sc.CreateModules(It.Is>(m => !m.Any()))).Returns(Task.FromResult(new Module[0])); serviceClient.Setup(sc => sc.UpdateModules(It.Is>(m => !m.Any()))).Returns(Task.FromResult(new Module[0])); - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(module), ModuleSet.Empty); @@ -278,7 +278,7 @@ public async Task TestGetModulesIdentity_WithRemovedModules_ShouldRemove() // Use Json to create module because managedBy property can't has private set on Module object const string ModuleJson = "{\"moduleId\":\"test-filters\",\"deviceId\":\"device1\",\"authentication\":{\"symmetricKey\":{\"primaryKey\":\"cHJpbWFyeVN5bW1ldHJpY0tleQ == \",\"secondaryKey\":\"c2Vjb25kYXJ5U3ltbWV0cmljS2V5\"},\"x509Thumbprint\":{\"primaryThumbprint\":null,\"secondaryThumbprint\":null},\"type\":\"sas\"},\"managedBy\":\"iotEdge\"}"; var serviceModuleIdentity = JsonConvert.DeserializeObject(ModuleJson); - var currentModule = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var currentModule = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); var serviceClient = new Mock(); string hostname = "hostname"; @@ -309,7 +309,7 @@ public async Task TestGetModulesIdentity_WithRemovedModules_NotEdgeHubManaged_Sh // Use Json to create module because managedBy property can't has private set on Module object const string ModuleJson = "{\"moduleId\":\"test-filters\",\"deviceId\":\"device1\",\"authentication\":{\"symmetricKey\":{\"primaryKey\":\"cHJpbWFyeVN5bW1ldHJpY0tleQ == \",\"secondaryKey\":\"c2Vjb25kYXJ5U3ltbWV0cmljS2V5\"},\"x509Thumbprint\":{\"primaryThumbprint\":null,\"secondaryThumbprint\":null},\"type\":\"sas\"},\"managedBy\":null}"; var serviceModuleIdentity = JsonConvert.DeserializeObject(ModuleJson); - var currentModule = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var currentModule = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); var serviceClient = new Mock(); string hostname = "hostname"; @@ -363,8 +363,8 @@ public async Task TestGetModulesIdentity_EdgeHubTest() serviceClient.Setup(sc => sc.CreateModules(It.Is>(m => !m.Any()))).Returns(Task.FromResult(new Module[0])); serviceClient.Setup(sc => sc.UpdateModules(It.Is>(m => !m.Any()))).Returns(Task.FromResult(new Module[0])); - var testMod = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); - var edgeHubMod = new TestModule(Constants.EdgeHubModuleName, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.Always, DefaultConfigurationInfo, EnvVars); + var testMod = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); + var edgeHubMod = new TestModule(Constants.EdgeHubModuleName, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.Always, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(testMod, edgeHubMod), ModuleSet.Empty); @@ -403,7 +403,7 @@ public async Task TestGetModuleIdentities_WhenOffline_ReturnsEmptyList() // ReSharper disable PossibleMultipleEnumeration serviceClient.Setup(sc => sc.CreateModules(It.Is>(m => m.Count() == 1 && m.First() == Name))).ThrowsAsync(new InvalidOperationException()); // ReSharper restore PossibleMultipleEnumeration - var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, DefaultConfigurationInfo, EnvVars); + var module = new TestModule(Name, "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, DefaultConfigurationInfo, EnvVars); IImmutableDictionary modulesIdentities = await new ModuleIdentityLifecycleManager(serviceClient.Object, hostname, deviceId, gatewayHostName) .GetModuleIdentitiesAsync(ModuleSet.Create(module), ModuleSet.Empty); diff --git a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/reporters/IoTHubReporterTest.cs b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/reporters/IoTHubReporterTest.cs index 901519f1c1a..db621b93718 100644 --- a/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/reporters/IoTHubReporterTest.cs +++ b/edge-agent/test/Microsoft.Azure.Devices.Edge.Agent.IoTHub.Test/reporters/IoTHubReporterTest.cs @@ -230,7 +230,8 @@ public async void ClearAndGenerateNewReportedInfoIfDeserializeFails() settings = new { image = "EdgeAgentImage" - } + }, + imagePullPolicy = "on-create" } }, modules = new Dictionary @@ -400,7 +401,8 @@ public async void ReportedPatchTest() settings = new { image = "EdgeAgentImage" - } + }, + imagePullPolicy = "on-create" } }, modules = new Dictionary @@ -578,7 +580,8 @@ public async void ReportedPatchNoneStatusTest() settings = new { image = "EdgeAgentImage" - } + }, + imagePullPolicy = "on-create" } }, modules = new Dictionary @@ -771,7 +774,8 @@ public async void ReportedPatchTestStripMetadata() settings = new { image = "EdgeAgentImage" - } + }, + imagePullPolicy = "on-create" } }, modules = new Dictionary @@ -1125,11 +1129,13 @@ public async void ReportedPatchIncludesEdgeHubInSystemModulesTest() ModuleStatus.Running, RestartPolicy.Always, new DockerConfig("edge.azurecr.io/edgeHub:1.0"), + ImagePullPolicy.Never, new ConfigurationInfo("1"), new Dictionary()); var edgeAgentDesiredModule = new EdgeAgentDockerModule( "docker", new DockerConfig("edge.azurecr.io/edgeAgent:1.0"), + ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), new Dictionary()); var deploymentConfig = new DeploymentConfig( @@ -1163,6 +1169,7 @@ public async void ReportedPatchIncludesEdgeHubInSystemModulesTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.Never, new ConfigurationInfo("1"), new Dictionary { ["foo"] = new EnvVal("Bar") }); ModuleSet currentModuleSet = ModuleSet.Create( @@ -1180,7 +1187,8 @@ public async void ReportedPatchIncludesEdgeHubInSystemModulesTest() DateTime.MinValue, 0, DateTime.MinValue, - ModuleStatus.Backoff), + ModuleStatus.Backoff, + ImagePullPolicy.OnCreate), new TestRuntimeModule( "mod2", "1.0", @@ -1194,7 +1202,8 @@ public async void ReportedPatchIncludesEdgeHubInSystemModulesTest() DateTime.MinValue, 0, DateTime.MinValue, - ModuleStatus.Running), + ModuleStatus.Running, + ImagePullPolicy.Never), edgeHubRuntimeModule); var agentStateSerde = new Mock>(); @@ -1249,7 +1258,8 @@ public async void ReportedPatchIncludesEdgeHubInSystemModulesTest() settings = new { image = "EdgeAgentImage" - } + }, + imagePullPolicy = "on-create" } }, modules = new @@ -1361,8 +1371,8 @@ public async void ReportShutdown() var versionInfo = new VersionInfo("v1", "b1", "c1"); DateTime lastStartTimeUtc = DateTime.Parse("2017-11-13T23:44:35.127381Z", null, DateTimeStyles.RoundtripKind); - IEdgeAgentModule edgeAgent = new EdgeAgentDockerRuntimeModule(new DockerReportedConfig("image", string.Empty, "hash"), ModuleStatus.Running, 0, string.Empty, lastStartTimeUtc, DateTime.MinValue, new ConfigurationInfo("id"), new Dictionary()); - IEdgeHubModule edgeHub = new EdgeHubDockerRuntimeModule(ModuleStatus.Running, RestartPolicy.Always, new DockerReportedConfig("hubimage", string.Empty, "hash"), 0, string.Empty, DateTime.Now, DateTime.Now, 0, DateTime.Now, ModuleStatus.Running, new ConfigurationInfo("hub"), new Dictionary()); + IEdgeAgentModule edgeAgent = new EdgeAgentDockerRuntimeModule(new DockerReportedConfig("image", string.Empty, "hash"), ModuleStatus.Running, 0, string.Empty, lastStartTimeUtc, DateTime.MinValue, ImagePullPolicy.OnCreate, new ConfigurationInfo("id"), new Dictionary()); + IEdgeHubModule edgeHub = new EdgeHubDockerRuntimeModule(ModuleStatus.Running, RestartPolicy.Always, new DockerReportedConfig("hubimage", string.Empty, "hash"), 0, string.Empty, DateTime.Now, DateTime.Now, 0, DateTime.Now, ModuleStatus.Running, ImagePullPolicy.OnCreate, new ConfigurationInfo("hub"), new Dictionary()); // prepare IEdgeAgentConnection mock var edgeAgentConnection = new Mock(); @@ -1506,7 +1516,7 @@ public async void ReportShutdownWithOnlyEdgeAgentInState() var versionInfo = new VersionInfo("v1", "b1", "c1"); DateTime lastStartTimeUtc = DateTime.Parse("2017-11-13T23:44:35.127381Z", null, DateTimeStyles.RoundtripKind); - IEdgeAgentModule edgeAgent = new EdgeAgentDockerRuntimeModule(new DockerReportedConfig("image", string.Empty, "hash"), ModuleStatus.Running, 0, string.Empty, lastStartTimeUtc, DateTime.MinValue, new ConfigurationInfo("id"), new Dictionary()); + IEdgeAgentModule edgeAgent = new EdgeAgentDockerRuntimeModule(new DockerReportedConfig("image", string.Empty, "hash"), ModuleStatus.Running, 0, string.Empty, lastStartTimeUtc, DateTime.MinValue, ImagePullPolicy.OnCreate, new ConfigurationInfo("id"), new Dictionary()); // prepare IEdgeAgentConnection mock var edgeAgentConnection = new Mock(); @@ -1681,6 +1691,7 @@ public async void ReportedPatchWithEnvVarsTest() 0, DateTime.MinValue, ModuleStatus.Backoff, + ImagePullPolicy.Never, null, new Dictionary { ["e1"] = new EnvVal("e1Val") }), new TestRuntimeModule( @@ -1697,6 +1708,7 @@ public async void ReportedPatchWithEnvVarsTest() 0, DateTime.MinValue, ModuleStatus.Running, + ImagePullPolicy.OnCreate, null, new Dictionary { ["e2"] = new EnvVal("e2Val") })); @@ -1759,7 +1771,8 @@ public async void ReportedPatchWithEnvVarsTest() settings = new { image = "EdgeAgentImage" - } + }, + imagePullPolicy = "on-create" } }, modules = new Dictionary @@ -1775,7 +1788,8 @@ public async void ReportedPatchWithEnvVarsTest() { value = "e1Val" } - } + }, + imagePullPolicy = "never" } }, { currentModuleSet.Modules["mod2"].Name, currentModuleSet.Modules["mod2"] }, @@ -1791,6 +1805,7 @@ public async void ReportedPatchWithEnvVarsTest() Constants.EdgeAgentModuleName, "docker", new TestConfig("EdgeAgentImage"), + ImagePullPolicy.OnCreate, new ConfigurationInfo(), new Dictionary()); } diff --git a/edgelet/Cargo.lock b/edgelet/Cargo.lock index c72f27dc8d6..8acd1c578cf 100755 --- a/edgelet/Cargo.lock +++ b/edgelet/Cargo.lock @@ -189,11 +189,12 @@ dependencies = [ [[package]] name = "config" -version = "0.8.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)", "serde-hjson 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -330,7 +331,7 @@ name = "edgelet-config" version = "0.1.0" dependencies = [ "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "config 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "edgelet-core 0.1.0", "edgelet-docker 0.1.0", "edgelet-utils 0.1.0", @@ -1154,14 +1155,6 @@ name = "matches" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "memchr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "memchr" version = "2.0.1" @@ -1310,10 +1303,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "nom" -version = "3.2.1" +version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1547,6 +1541,11 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-ini" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rustc-demangle" version = "0.1.7" @@ -2303,7 +2302,7 @@ dependencies = [ "checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c" -"checksum config 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e595d1735d8ab6b04906bbdcfc671cce2a5e609b6f8e92865e67331cc2f41ba4" +"checksum config 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f9107d78ed62b3fa5a86e7d18e647abed48cfd8f8fab6c72f4cdb982d196f7e6" "checksum consistenttime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a079bddaa385eab2a88dc5816a378921852ab3af6646748da14681b2facf502" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" @@ -2354,7 +2353,6 @@ dependencies = [ "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" -"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd" @@ -2368,7 +2366,7 @@ dependencies = [ "checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" +"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" @@ -2394,6 +2392,7 @@ dependencies = [ "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" "checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" +"checksum rust-ini 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" diff --git a/edgelet/api/managementVersion_2019_01_30.yaml b/edgelet/api/managementVersion_2019_01_30.yaml index fecb218dc07..0034240bacc 100644 --- a/edgelet/api/managementVersion_2019_01_30.yaml +++ b/edgelet/api/managementVersion_2019_01_30.yaml @@ -482,6 +482,12 @@ definitions: type: type: string example: docker + imagePullPolicy: + type: string + enum: + - OnCreate + - Never + example: "OnCreate" config: $ref: '#/definitions/Config' required: diff --git a/edgelet/edgelet-config/Cargo.toml b/edgelet/edgelet-config/Cargo.toml index d7a76b3ad2b..244b3667539 100644 --- a/edgelet/edgelet-config/Cargo.toml +++ b/edgelet/edgelet-config/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" [dependencies] base64 = "0.9" -config = "0.8" +config = "0.9.2" failure = "0.1" log = "0.4" regex = "0.2" diff --git a/edgelet/edgelet-core/src/error.rs b/edgelet/edgelet-core/src/error.rs index 75a7c69aaa3..72eaa249c01 100644 --- a/edgelet/edgelet-core/src/error.rs +++ b/edgelet/edgelet-core/src/error.rs @@ -54,12 +54,12 @@ pub enum ErrorKind { #[fail(display = "An identity manager error occurred.")] IdentityManager, + #[fail(display = "Invalid image pull policy configuration {:?}", _0)] + InvalidImagePullPolicy(String), + #[fail(display = "Invalid or unsupported certificate issuer.")] InvalidIssuer, - #[fail(display = "An error occurred in the key store.")] - KeyStore, - #[fail(display = "Invalid log tail {:?}", _0)] InvalidLogTail(String), @@ -72,6 +72,9 @@ pub enum ErrorKind { #[fail(display = "Invalid URL {:?}", _0)] InvalidUrl(String), + #[fail(display = "An error occurred in the key store.")] + KeyStore, + #[fail(display = "Item not found.")] KeyStoreItemNotFound, diff --git a/edgelet/edgelet-core/src/lib.rs b/edgelet/edgelet-core/src/lib.rs index 1eb1070edb1..659643a4e3a 100644 --- a/edgelet/edgelet-core/src/lib.rs +++ b/edgelet/edgelet-core/src/lib.rs @@ -31,7 +31,7 @@ pub use crypto::{ pub use error::{Error, ErrorKind}; pub use identity::{AuthType, Identity, IdentityManager, IdentityOperation, IdentitySpec}; pub use module::{ - LogOptions, LogTail, Module, ModuleOperation, ModuleRegistry, ModuleRuntime, + ImagePullPolicy, LogOptions, LogTail, Module, ModuleOperation, ModuleRegistry, ModuleRuntime, ModuleRuntimeErrorReason, ModuleRuntimeState, ModuleSpec, ModuleStatus, ModuleTop, RegistryOperation, RuntimeOperation, SystemInfo, }; diff --git a/edgelet/edgelet-core/src/module.rs b/edgelet/edgelet-core/src/module.rs index 2e2a17bd9e9..15a7d022980 100644 --- a/edgelet/edgelet-core/src/module.rs +++ b/edgelet/edgelet-core/src/module.rs @@ -146,6 +146,9 @@ pub struct ModuleSpec { #[serde(default = "HashMap::new")] #[serde(serialize_with = "serialize_ordered")] env: HashMap, + #[serde(default)] + #[serde(rename = "imagePullPolicy")] + image_pull_policy: ImagePullPolicy, } impl Clone for ModuleSpec @@ -158,6 +161,7 @@ where type_: self.type_.clone(), config: self.config.clone(), env: self.env.clone(), + image_pull_policy: self.image_pull_policy, } } } @@ -168,6 +172,7 @@ impl ModuleSpec { type_: String, config: T, env: HashMap, + image_pull_policy: ImagePullPolicy, ) -> Result { ensure_not_empty_with_context(&name, || ErrorKind::InvalidModuleName(name.clone()))?; ensure_not_empty_with_context(&type_, || ErrorKind::InvalidModuleType(type_.clone()))?; @@ -177,6 +182,7 @@ impl ModuleSpec { type_, config, env, + image_pull_policy, }) } @@ -223,6 +229,15 @@ impl ModuleSpec { self.env = env; self } + + pub fn image_pull_policy(&self) -> ImagePullPolicy { + self.image_pull_policy + } + + pub fn with_image_pull_policy(mut self, image_pull_policy: ImagePullPolicy) -> Self { + self.image_pull_policy = image_pull_policy; + self + } } #[derive(Clone, Copy, Debug, PartialEq)] @@ -493,6 +508,34 @@ impl fmt::Display for RuntimeOperation { } } +#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum ImagePullPolicy { + #[serde(rename = "on-create")] + OnCreate, + Never, +} + +impl Default for ImagePullPolicy { + fn default() -> Self { + ImagePullPolicy::OnCreate + } +} + +impl FromStr for ImagePullPolicy { + type Err = Error; + + fn from_str(s: &str) -> StdResult { + match s.to_lowercase().as_str() { + "on-create" => Ok(ImagePullPolicy::OnCreate), + "never" => Ok(ImagePullPolicy::Never), + _ => Err(Error::from(ErrorKind::InvalidImagePullPolicy( + s.to_string(), + ))), + } + } +} + #[cfg(test)] mod tests { use super::*; @@ -531,7 +574,13 @@ mod tests { #[test] fn module_config_empty_name_fails() { let name = "".to_string(); - match ModuleSpec::new(name.clone(), "docker".to_string(), 10_i32, HashMap::new()) { + match ModuleSpec::new( + name.clone(), + "docker".to_string(), + 10_i32, + HashMap::new(), + ImagePullPolicy::default(), + ) { Ok(_) => panic!("Expected error"), Err(err) => { if let ErrorKind::InvalidModuleName(s) = err.kind() { @@ -546,7 +595,13 @@ mod tests { #[test] fn module_config_white_space_name_fails() { let name = " ".to_string(); - match ModuleSpec::new(name.clone(), "docker".to_string(), 10_i32, HashMap::new()) { + match ModuleSpec::new( + name.clone(), + "docker".to_string(), + 10_i32, + HashMap::new(), + ImagePullPolicy::default(), + ) { Ok(_) => panic!("Expected error"), Err(err) => { if let ErrorKind::InvalidModuleName(s) = err.kind() { @@ -561,7 +616,13 @@ mod tests { #[test] fn module_config_empty_type_fails() { let type_ = " ".to_string(); - match ModuleSpec::new("m1".to_string(), type_.clone(), 10_i32, HashMap::new()) { + match ModuleSpec::new( + "m1".to_string(), + type_.clone(), + 10_i32, + HashMap::new(), + ImagePullPolicy::default(), + ) { Ok(_) => panic!("Expected error"), Err(err) => { if let ErrorKind::InvalidModuleType(s) = err.kind() { @@ -576,7 +637,13 @@ mod tests { #[test] fn module_config_white_space_type_fails() { let type_ = " ".to_string(); - match ModuleSpec::new("m1".to_string(), type_.clone(), 10_i32, HashMap::new()) { + match ModuleSpec::new( + "m1".to_string(), + type_.clone(), + 10_i32, + HashMap::new(), + ImagePullPolicy::default(), + ) { Ok(_) => panic!("Expected error"), Err(err) => { if let ErrorKind::InvalidModuleType(s) = err.kind() { diff --git a/edgelet/edgelet-core/src/watchdog.rs b/edgelet/edgelet-core/src/watchdog.rs index c01d56f1760..d90a92675f1 100644 --- a/edgelet/edgelet-core/src/watchdog.rs +++ b/edgelet/edgelet-core/src/watchdog.rs @@ -16,7 +16,8 @@ use edgelet_utils::log_failure; use crate::error::{Error, ErrorKind}; use crate::identity::{Identity, IdentityManager, IdentitySpec}; use crate::module::{ - Module, ModuleRegistry, ModuleRuntime, ModuleRuntimeErrorReason, ModuleSpec, ModuleStatus, + ImagePullPolicy, Module, ModuleRegistry, ModuleRuntime, ModuleRuntimeErrorReason, ModuleSpec, + ModuleStatus, }; // Time to allow EdgeAgent to gracefully shutdown (including stopping all modules, and updating reported properties) @@ -287,9 +288,13 @@ where id.generation_id().to_string(), ); let spec = spec.with_env(env); - runtime - .registry() - .pull(spec.clone().config()) + + let pull_future = match spec.image_pull_policy() { + ImagePullPolicy::Never => Either::A(future::ok(())), + ImagePullPolicy::OnCreate => Either::B(runtime.registry().pull(spec.clone().config())), + }; + + pull_future .and_then(move |_| runtime.create(spec)) .and_then(move |_| runtime_copy.start(&module_name)) .map_err(|e| Error::from(e.context(ErrorKind::ModuleRuntime))) diff --git a/edgelet/edgelet-docker/src/runtime.rs b/edgelet/edgelet-docker/src/runtime.rs index 94bf2d6b6b0..47e534eb012 100644 --- a/edgelet/edgelet-docker/src/runtime.rs +++ b/edgelet/edgelet-docker/src/runtime.rs @@ -859,7 +859,7 @@ mod tests { use url::Url; use docker::models::ContainerCreateBody; - use edgelet_core::{ModuleId, ModuleRegistry, ModuleTop}; + use edgelet_core::{ImagePullPolicy, ModuleId, ModuleRegistry, ModuleTop}; use crate::error::{Error, ErrorKind}; @@ -987,6 +987,7 @@ mod tests { DockerConfig::new("nginx:latest".to_string(), ContainerCreateBody::new(), None) .unwrap(), HashMap::new(), + ImagePullPolicy::default(), ) .unwrap(); diff --git a/edgelet/edgelet-docker/tests/runtime.rs b/edgelet/edgelet-docker/tests/runtime.rs index 894c0ad9c7f..23563ede20c 100644 --- a/edgelet/edgelet-docker/tests/runtime.rs +++ b/edgelet/edgelet-docker/tests/runtime.rs @@ -24,7 +24,9 @@ use docker::models::{ ContainerCreateBody, ContainerHostConfig, ContainerNetworkSettings, ContainerSummary, HostConfig, HostConfigPortBindings, ImageDeleteResponseItem, }; -use edgelet_core::{LogOptions, LogTail, Module, ModuleRegistry, ModuleRuntime, ModuleSpec}; +use edgelet_core::{ + ImagePullPolicy, LogOptions, LogTail, Module, ModuleRegistry, ModuleRuntime, ModuleSpec, +}; use edgelet_docker::{DockerConfig, DockerModuleRuntime}; use edgelet_test_utils::{get_unused_tcp_port, run_tcp_server}; @@ -657,6 +659,7 @@ fn container_create_succeeds() { "docker".to_string(), DockerConfig::new("nginx:latest".to_string(), create_options, None).unwrap(), env, + ImagePullPolicy::default(), ) .unwrap(); diff --git a/edgelet/edgelet-http-mgmt/src/server/module/create.rs b/edgelet/edgelet-http-mgmt/src/server/module/create.rs index 5a5fb3136e9..5b05dd2250b 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/create.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/create.rs @@ -1,14 +1,18 @@ // Copyright (c) Microsoft. All rights reserved. -use failure::{Fail, ResultExt}; +use failure::ResultExt; +use futures::future::Either; use futures::{Future, Stream}; use hyper::header::{CONTENT_LENGTH, CONTENT_TYPE}; use hyper::{Body, Request, Response, StatusCode}; +use log::debug; use serde::de::DeserializeOwned; use serde::Serialize; use serde_json; -use edgelet_core::{Module, ModuleRegistry, ModuleRuntime, ModuleStatus, RuntimeOperation}; +use edgelet_core::{ + ImagePullPolicy, Module, ModuleRegistry, ModuleRuntime, ModuleStatus, RuntimeOperation, +}; use edgelet_http::route::{Handler, Parameters}; use edgelet_http::Error as HttpError; use management::models::*; @@ -50,38 +54,62 @@ where }) .and_then(move |(spec, core_spec)| { let module_name = spec.name().to_string(); - runtime - .registry() - .pull(core_spec.config()) - .then(move |result| match result { - Ok(_) => Ok(runtime.create(core_spec).then( - move |result| -> Result<_, Error> { + let image_pull_policy = core_spec.image_pull_policy(); + + let pull_future = match image_pull_policy { + ImagePullPolicy::OnCreate => { + let name = module_name.clone(); + Either::A(runtime.registry().pull(core_spec.config()).then( + move |result| { result.with_context(|_| { ErrorKind::RuntimeOperation(RuntimeOperation::CreateModule( - module_name.clone(), - )) - })?; - let details = spec_to_details(&spec, ModuleStatus::Stopped); - let b = serde_json::to_string(&details).with_context(|_| { - ErrorKind::RuntimeOperation(RuntimeOperation::CreateModule( - module_name.clone(), + name.clone(), )) })?; - let response = Response::builder() - .status(StatusCode::CREATED) - .header(CONTENT_TYPE, "application/json") - .header(CONTENT_LENGTH, b.len().to_string().as_str()) - .body(b.into()) - .context(ErrorKind::RuntimeOperation( - RuntimeOperation::CreateModule(module_name), - ))?; - Ok(response) + Ok((name, true)) }, - )), - Err(err) => Err(Error::from(err.context(ErrorKind::RuntimeOperation( - RuntimeOperation::CreateModule(module_name), - )))), - }) + )) + } + ImagePullPolicy::Never => { + Either::B(futures::future::ok((module_name.clone(), false))) + } + }; + + pull_future.and_then(move |(name, image_pulled)| -> Result<_, Error> { + if image_pulled { + debug!("Successfully pulled new image for module {}", name) + } else { + debug!( + "Skipped pulling image for module {} as per pull policy", + name + ) + } + + Ok(runtime + .create(core_spec) + .then(move |result| -> Result<_, Error> { + result.with_context(|_| { + ErrorKind::RuntimeOperation(RuntimeOperation::CreateModule( + name.clone(), + )) + })?; + let details = spec_to_details(&spec, ModuleStatus::Stopped); + let b = serde_json::to_string(&details).with_context(|_| { + ErrorKind::RuntimeOperation(RuntimeOperation::CreateModule( + name.clone(), + )) + })?; + let response = Response::builder() + .status(StatusCode::CREATED) + .header(CONTENT_TYPE, "application/json") + .header(CONTENT_LENGTH, b.len().to_string().as_str()) + .body(b.into()) + .context(ErrorKind::RuntimeOperation( + RuntimeOperation::CreateModule(name), + ))?; + Ok(response) + })) + }) }) .flatten() .or_else(|e| Ok(e.into_response())); @@ -124,7 +152,8 @@ mod tests { fn success() { let handler = CreateModule::new(RUNTIME.clone()); let config = Config::new(json!({"image":"microsoft/test-image"})); - let spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + let mut spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + spec.set_image_pull_policy("on-create".to_string()); let request = Request::post("http://localhost/modules") .body(serde_json::to_string(&spec).unwrap().into()) .unwrap(); @@ -245,4 +274,32 @@ mod tests { .wait() .unwrap(); } + + #[test] + fn bad_image_pull_policy() { + let handler = CreateModule::new(RUNTIME.clone()); + let config = Config::new(json!({"image":"microsoft/test-image"})); + let mut spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + spec.set_image_pull_policy("what".to_string()); + let request = Request::post("http://localhost/modules") + .body(serde_json::to_string(&spec).unwrap().into()) + .unwrap(); + + // act + let response = handler.handle(request, Parameters::new()).wait().unwrap(); + + // assert + assert_eq!(StatusCode::BAD_REQUEST, response.status()); + response + .into_body() + .concat2() + .and_then(|b| { + let error_response: ErrorResponse = serde_json::from_slice(&b).unwrap(); + let expected = "Request body is malformed\n\tcaused by: Invalid image pull policy configuration \"what\""; + assert_eq!(expected, error_response.message()); + Ok(()) + }) + .wait() + .unwrap(); + } } diff --git a/edgelet/edgelet-http-mgmt/src/server/module/mod.rs b/edgelet/edgelet-http-mgmt/src/server/module/mod.rs index 244e778528a..91aaf585539 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/mod.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/mod.rs @@ -7,7 +7,9 @@ use serde::de::DeserializeOwned; use serde::Serialize; use serde_json; -use edgelet_core::{Module, ModuleRuntime, ModuleSpec as CoreModuleSpec, ModuleStatus}; +use edgelet_core::{ + ImagePullPolicy, Module, ModuleRuntime, ModuleSpec as CoreModuleSpec, ModuleStatus, +}; use management::models::*; use crate::error::{Error, ErrorKind}; @@ -55,7 +57,15 @@ where Err(err) => return Err(Error::from(err.context(context))), }; - let module_spec = match CoreModuleSpec::new(name, type_, config, env) { + let image_pull_policy = match spec + .image_pull_policy() + .map_or(Ok(ImagePullPolicy::default()), str::parse) + { + Ok(image_pull_policy) => image_pull_policy, + Err(err) => return Err(Error::from(err.context(context))), + }; + + let module_spec = match CoreModuleSpec::new(name, type_, config, env, image_pull_policy) { Ok(module_spec) => module_spec, Err(err) => return Err(Error::from(err.context(context))), }; diff --git a/edgelet/edgelet-http-mgmt/src/server/module/prepare_update.rs b/edgelet/edgelet-http-mgmt/src/server/module/prepare_update.rs index cc5cdda7716..6e776813daa 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/prepare_update.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/prepare_update.rs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use failure::ResultExt; +use futures::future::Either; use futures::{Future, Stream}; use hyper::{Body, Request, Response, StatusCode}; use log::debug; @@ -8,7 +9,7 @@ use serde::de::DeserializeOwned; use serde::Serialize; use serde_json; -use edgelet_core::{Module, ModuleRegistry, ModuleRuntime}; +use edgelet_core::{ImagePullPolicy, Module, ModuleRegistry, ModuleRuntime}; use edgelet_http::route::{Handler, Parameters}; use edgelet_http::Error as HttpError; @@ -49,13 +50,32 @@ where }) .and_then(|(core_spec, runtime)| { let name = core_spec.name().to_string(); - runtime.registry().pull(core_spec.config()).then(|result| { - result.with_context(|_| ErrorKind::PrepareUpdateModule(name.clone()))?; - Ok(name) - }) + let image_pull_policy = core_spec.image_pull_policy(); + match image_pull_policy { + ImagePullPolicy::OnCreate => Either::A( + runtime + .registry() + .pull(core_spec.config()) + .then(move |result| { + result.with_context(|_| { + ErrorKind::PrepareUpdateModule(name.clone()) + })?; + Ok((name, true)) + }), + ), + ImagePullPolicy::Never => Either::B(futures::future::ok((name, false))), + } }) - .and_then(|name| -> Result<_, Error> { - debug!("Successfully pulled new image for module {}", name); + .and_then(|(name, image_pulled)| -> Result<_, Error> { + if image_pulled { + debug!("Successfully pulled new image for module {}", name) + } else { + debug!( + "Skipped pulling image for module {} as per pull policy", + name + ) + } + let response = Response::builder() .status(StatusCode::NO_CONTENT) .body(Body::default()) @@ -100,7 +120,8 @@ mod tests { fn success() { let handler = PrepareUpdateModule::new(RUNTIME.clone()); let config = Config::new(json!({"image":"microsoft/test-image-2"})); - let spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + let mut spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + spec.set_image_pull_policy("never".to_string()); let request = Request::post("http://localhost/modules/test-module/prepareupdate") .body(serde_json::to_string(&spec).unwrap().into()) .unwrap(); @@ -198,4 +219,31 @@ mod tests { .wait() .unwrap(); } + + #[test] + fn bad_image_pull_policy() { + let handler = PrepareUpdateModule::new(RUNTIME.clone()); + let config = Config::new(json!({"image":"microsoft/test-image-2"})); + let mut spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + spec.set_image_pull_policy("what".to_string()); + let request = Request::post("http://localhost/modules/test-module/prepareupdate") + .body(serde_json::to_string(&spec).unwrap().into()) + .unwrap(); + + // act + let response = handler.handle(request, Parameters::new()).wait().unwrap(); + + // assert + assert_eq!(StatusCode::BAD_REQUEST, response.status()); + response + .into_body() + .concat2() + .and_then(|b| { + let error: ErrorResponse = serde_json::from_slice(&b).unwrap(); + assert_eq!("Request body is malformed\n\tcaused by: Invalid image pull policy configuration \"what\"", error.message()); + Ok(()) + }) + .wait() + .unwrap(); + } } diff --git a/edgelet/edgelet-http-mgmt/src/server/module/update.rs b/edgelet/edgelet-http-mgmt/src/server/module/update.rs index 47e10d6027e..de5da9a45f6 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/update.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/update.rs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use failure::ResultExt; +use futures::future::Either; use futures::{future, Future, Stream}; use hyper::header::{CONTENT_LENGTH, CONTENT_TYPE}; use hyper::{Body, Request, Response, StatusCode}; @@ -11,7 +12,7 @@ use serde::Serialize; use serde_json; use url::form_urlencoded::parse as parse_query; -use edgelet_core::{Module, ModuleRegistry, ModuleRuntime, ModuleStatus}; +use edgelet_core::{ImagePullPolicy, Module, ModuleRegistry, ModuleRuntime, ModuleStatus}; use edgelet_http::route::{Handler, Parameters}; use edgelet_http::Error as HttpError; @@ -77,13 +78,29 @@ where }) .and_then(|(core_spec, spec, name, runtime)| { debug!("Removed existing module {}", name); - runtime.registry().pull(core_spec.config()).then(|result| { - result.with_context(|_| ErrorKind::UpdateModule(name.clone()))?; - Ok((core_spec, spec, name, runtime)) - }) + + match core_spec.image_pull_policy() { + ImagePullPolicy::OnCreate => { + Either::A(runtime.registry().pull(core_spec.config()).then(|result| { + result.with_context(|_| ErrorKind::UpdateModule(name.clone()))?; + Ok((core_spec, spec, name, runtime, true)) + })) + } + ImagePullPolicy::Never => { + Either::B(futures::future::ok((core_spec, spec, name, runtime, false))) + } + } }) - .and_then(|(core_spec, spec, name, runtime)| { - debug!("Successfully pulled new image for module {}", name); + .and_then(|(core_spec, spec, name, runtime, image_pulled)| { + if image_pulled { + debug!("Successfully pulled new image for module {}", name) + } else { + debug!( + "Skipped pulling image for module {} as per pull policy", + name + ) + } + runtime.create(core_spec).then(|result| { result.with_context(|_| ErrorKind::UpdateModule(name.clone()))?; Ok((name, spec, runtime)) @@ -190,7 +207,8 @@ mod tests { fn success_start() { let handler = UpdateModule::new(RUNTIME.clone()); let config = Config::new(json!({"image":"microsoft/test-image"})); - let spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + let mut spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + spec.set_image_pull_policy("on-create".to_string()); let request = Request::put("http://localhost/modules/test-module?start") .body(serde_json::to_string(&spec).unwrap().into()) .unwrap(); @@ -311,4 +329,31 @@ mod tests { .wait() .unwrap(); } + + #[test] + fn bad_image_pull_policy() { + let handler = UpdateModule::new(RUNTIME.clone()); + let config = Config::new(json!({"image":"microsoft/test-image"})); + let mut spec = ModuleSpec::new("test-module".to_string(), "docker".to_string(), config); + spec.set_image_pull_policy("what".to_string()); + let request = Request::put("http://localhost/modules/test-module") + .body(serde_json::to_string(&spec).unwrap().into()) + .unwrap(); + + // act + let response = handler.handle(request, Parameters::new()).wait().unwrap(); + + // assert + assert_eq!(StatusCode::BAD_REQUEST, response.status()); + response + .into_body() + .concat2() + .and_then(|b| { + let error: ErrorResponse = serde_json::from_slice(&b).unwrap(); + assert_eq!("Request body is malformed\n\tcaused by: Invalid image pull policy configuration \"what\"", error.message()); + Ok(()) + }) + .wait() + .unwrap(); + } } diff --git a/edgelet/edgelet-kube/src/convert/to_k8s.rs b/edgelet/edgelet-kube/src/convert/to_k8s.rs index 9f8e28d91e9..4411a07d64f 100644 --- a/edgelet/edgelet-kube/src/convert/to_k8s.rs +++ b/edgelet/edgelet-kube/src/convert/to_k8s.rs @@ -420,7 +420,7 @@ mod tests { use docker::models::ContainerCreateBody; use docker::models::HostConfig; use docker::models::Mount; - use edgelet_core::ModuleSpec; + use edgelet_core::{ImagePullPolicy, ModuleSpec}; use edgelet_docker::DockerConfig; use k8s_openapi::apimachinery::pkg::apis::meta::v1 as api_meta; use serde_json; @@ -562,6 +562,7 @@ mod tests { env.insert(String::from("C"), String::from("D")); env }, + ImagePullPolicy::default(), ) .unwrap() } @@ -600,7 +601,7 @@ mod tests { String::from("proxy:latest"), String::from("/etc/traefik"), String::from("device1-iotedged-proxy-config"), - String::from("IfNotPresent"), + String::from("OnCreate"), String::from("iotedge"), Url::parse("http://localhost:35000").unwrap(), Url::parse("http://localhost:35001").unwrap(), @@ -642,7 +643,7 @@ mod tests { assert_eq!(module.env.as_ref().map(Vec::len).unwrap(), 3); assert_eq!(module.volume_mounts.as_ref().map(Vec::len).unwrap(), 7); assert_eq!(module.image.as_ref().unwrap(), "my-image:v1.0"); - assert_eq!(module.image_pull_policy.as_ref().unwrap(), "IfNotPresent"); + assert_eq!(module.image_pull_policy.as_ref().unwrap(), "OnCreate"); } if let Some(proxy) = podspec .containers @@ -653,7 +654,7 @@ mod tests { assert_eq!(proxy.env.as_ref().map(Vec::len).unwrap(), 3); assert_eq!(proxy.volume_mounts.as_ref().map(Vec::len).unwrap(), 1); assert_eq!(proxy.image.as_ref().unwrap(), "proxy:latest"); - assert_eq!(proxy.image_pull_policy.as_ref().unwrap(), "IfNotPresent"); + assert_eq!(proxy.image_pull_policy.as_ref().unwrap(), "OnCreate"); } assert_eq!(podspec.service_account_name.as_ref().unwrap(), "iotedge"); assert!(podspec.image_pull_secrets.is_some()); diff --git a/edgelet/edgelet-kube/src/runtime.rs b/edgelet/edgelet-kube/src/runtime.rs index 64897a0315d..d7d4cb16d4e 100644 --- a/edgelet/edgelet-kube/src/runtime.rs +++ b/edgelet/edgelet-kube/src/runtime.rs @@ -581,7 +581,7 @@ mod tests { let proxy_image = String::from("proxy-image"); let proxy_config_path = String::from("proxy-confg-path"); let proxy_config_map_name = String::from("config-volume"); - let image_pull_policy = String::from("IfNotPresent"); + let image_pull_policy = String::from("OnCreate"); let service_account_name = String::from("iotedge"); let workload_uri = Url::from_str("http://localhost:35000").unwrap(); let management_uri = Url::from_str("http://localhost:35001").unwrap(); @@ -877,7 +877,7 @@ mod tests { let proxy_image = String::from("proxy-image"); let proxy_config_path = String::from("proxy-confg-path"); let proxy_config_map_name = String::from("config-volume"); - let image_pull_policy = String::from("IfNotPresent"); + let image_pull_policy = String::from("OnCreate"); let service_account_name = String::from("iotedge"); let workload_uri = Url::from_str("http://localhost:35000").unwrap(); let management_uri = Url::from_str("http://localhost:35001").unwrap(); diff --git a/edgelet/iotedged/src/lib.rs b/edgelet/iotedged/src/lib.rs index 53936c834d7..7d3168c79ad 100644 --- a/edgelet/iotedged/src/lib.rs +++ b/edgelet/iotedged/src/lib.rs @@ -960,6 +960,7 @@ where spec.type_().to_string(), spec.config().clone(), env, + spec.image_pull_policy(), ) .context(ErrorKind::Initialize(InitializeErrorReason::EdgeRuntime))?; diff --git a/edgelet/management/src/models/module_spec.rs b/edgelet/management/src/models/module_spec.rs index 4d5029a504b..c4165953498 100644 --- a/edgelet/management/src/models/module_spec.rs +++ b/edgelet/management/src/models/module_spec.rs @@ -21,6 +21,8 @@ pub struct ModuleSpec { type_: String, #[serde(rename = "config")] config: crate::models::Config, + #[serde(rename = "imagePullPolicy", skip_serializing_if = "Option::is_none")] + image_pull_policy: Option, } impl ModuleSpec { @@ -29,6 +31,7 @@ impl ModuleSpec { name, type_, config, + image_pull_policy: None, } } @@ -70,4 +73,21 @@ impl ModuleSpec { pub fn config(&self) -> &crate::models::Config { &self.config } + + pub fn set_image_pull_policy(&mut self, image_pull_policy: String) { + self.image_pull_policy = Some(image_pull_policy); + } + + pub fn with_image_pull_policy(mut self, image_pull_policy: String) -> Self { + self.image_pull_policy = Some(image_pull_policy); + self + } + + pub fn image_pull_policy(&self) -> Option<&str> { + self.image_pull_policy.as_ref().map(AsRef::as_ref) + } + + pub fn reset_image_pull_policy(&mut self) { + self.image_pull_policy = None; + } }