public async void ChangeFileAndSeeChange() { // Set up initial config file and create `FileConfigSource` File.WriteAllText(this.tempFileName, ValidJson1); Diff validDiff1To2 = ValidSet2.Diff(ValidSet1); using (FileConfigSource configSource = await FileConfigSource.Create(this.tempFileName, this.config, this.serde)) { Assert.NotNull(configSource); DeploymentConfigInfo deploymentConfigInfo = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(deploymentConfigInfo); ModuleSet initialModuleSet = deploymentConfigInfo.DeploymentConfig.GetModuleSet(); Diff emptyDiff = ValidSet1.Diff(initialModuleSet); Assert.True(emptyDiff.IsEmpty); // Modify the config file by writing new content. File.WriteAllText(this.tempFileName, ValidJson2); await Task.Delay(TimeSpan.FromSeconds(20)); DeploymentConfigInfo updatedAgentConfig = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(updatedAgentConfig); ModuleSet updatedModuleSet = updatedAgentConfig.DeploymentConfig.GetModuleSet(); Diff newDiff = updatedModuleSet.Diff(initialModuleSet); Assert.False(newDiff.IsEmpty); Assert.Equal(newDiff, validDiff1To2); } }
async Task <DeploymentConfigInfo> ReadFromBackup() { try { if (!File.Exists(this.configFilePath)) { Events.BackupFileDoesNotExist(this.configFilePath); } else { using (await this.sync.LockAsync()) { string encryptedJson = await DiskFile.ReadAllAsync(this.configFilePath); string json = await this.encryptionProvider.DecryptAsync(encryptedJson); DeploymentConfigInfo deploymentConfigInfo = this.serde.Deserialize(json); Events.ObtainedDeploymentFromBackup(this.configFilePath); return(deploymentConfigInfo); } } } catch (Exception e) { Events.GetBackupFailed(e, this.configFilePath); } return(DeploymentConfigInfo.Empty); }
public static void RestoringFromBackup(DeploymentConfigInfo deploymentConfig, string filename) { string reason = deploymentConfig.Exception.Map(e => $"Error getting edge agent config - {e}") .GetOrElse("Empty edge agent config was received"); Log.LogWarning((int)EventIds.RestoringFromBackup, $"{reason}. Attempting to read config from backup file ({filename}) instead"); }
public async Task <DeploymentConfigInfo> GetDeploymentConfigInfoAsync() { try { DeploymentConfigInfo deploymentConfig = await this.underlying.GetDeploymentConfigInfoAsync(); if (deploymentConfig == DeploymentConfigInfo.Empty) { Events.RestoringFromBackup(deploymentConfig, this.configFilePath); deploymentConfig = await this.ReadFromBackup(); } else if (!deploymentConfig.Exception.HasValue) { // TODO - Backing up the config every time for now, probably should optimize this. await this.BackupDeploymentConfig(deploymentConfig); } return(deploymentConfig); } catch (Exception ex) { Events.RestoringFromBackup(ex, this.configFilePath); return(await this.ReadFromBackup()); } }
protected override async Task <Option <object> > HandleRequestInternal(Option <RestartRequest> payloadOption, CancellationToken cancellationToken) { RestartRequest payload = payloadOption.Expect(() => new ArgumentException("Request payload not found")); if (ExpectedSchemaVersion.CompareMajorVersion(payload.SchemaVersion, "restart module request schema") != 0) { Events.MismatchedMinorVersions(payload.SchemaVersion, ExpectedSchemaVersion); } Events.ProcessingRequest(payload); DeploymentConfigInfo deploymentConfigInfo = await this.configSource.GetDeploymentConfigInfoAsync(); IEnvironment environment = this.environmentProvider.Create(deploymentConfigInfo.DeploymentConfig); ModuleSet modules = await environment.GetModulesAsync(cancellationToken); if (!modules.TryGetModule(payload.Id, out IModule module)) { throw new InvalidOperationException($"Module {payload.Id} not found in the current environment"); } Events.RestartingModule(payload.Id); ICommand restartCommand = await this.commandFactory.RestartAsync(module); await restartCommand.ExecuteAsync(cancellationToken); Events.RestartedModule(payload.Id); return(Option.None <object>()); }
public async void ReadsBackupOnce() { DeploymentConfigInfo configInfo = SetupNonEmptyDeployment(); var underlying = new Mock <IConfigSource>(); underlying.Setup(u => u.GetDeploymentConfigInfoAsync()).ThrowsAsync(new NullException("failure")); var backup = new Mock <IDeploymentBackupSource>(); backup.SetupGet(b => b.Name).Returns("backup"); backup.SetupSequence(b => b.ReadFromBackupAsync()) .ReturnsAsync(configInfo) .ReturnsAsync(DeploymentConfigInfo.Empty); var backupSource = new BackupConfigSource(backup.Object, underlying.Object); var result1 = await backupSource.GetDeploymentConfigInfoAsync(); var result2 = await backupSource.GetDeploymentConfigInfoAsync(); Assert.Equal(configInfo, result1); Assert.Equal(configInfo, result2); underlying.VerifyAll(); backup.Verify(b => b.ReadFromBackupAsync(), Times.Once); }
public async void FileBackupSuccessCallsEncrypt() { if (File.Exists(this.tempFileName)) { File.Delete(this.tempFileName); } var underlying = new Mock <IConfigSource>(); underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync()) .ReturnsAsync(ValidConfigInfo1); ISerde <DeploymentConfigInfo> serde = this.GetSerde(); var encryptionProvider = new Mock <IEncryptionProvider>(); encryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>())) .ReturnsAsync(serde.Serialize(ValidConfigInfo1)); using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, encryptionProvider.Object)) { DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(config1); Assert.True(File.Exists(this.tempFileName)); string backupJson = await DiskFile.ReadAllAsync(this.tempFileName); string returnedJson = serde.Serialize(config1); Assert.Equal(backupJson, returnedJson, true); encryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>())); } }
public async void FileBackupReadFromBackupCallsEncryptDecrypt() { if (File.Exists(this.tempFileName)) { File.Delete(this.tempFileName); } ISerde <DeploymentConfigInfo> serde = this.GetSerde(); var encryptionProvider = new Mock <IEncryptionProvider>(); encryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>())) .ReturnsAsync(serde.Serialize(ValidConfigInfo1)); encryptionProvider.Setup(ep => ep.DecryptAsync(It.IsAny <string>())) .ReturnsAsync(serde.Serialize(ValidConfigInfo1)); IDeploymentBackupSource fileBackup = new DeploymentFileBackup(this.tempFileName, serde, encryptionProvider.Object); await fileBackup.BackupDeploymentConfigAsync(ValidConfigInfo1); DeploymentConfigInfo config1 = await fileBackup.ReadFromBackupAsync(); Assert.NotNull(config1); Assert.True(File.Exists(this.tempFileName)); string backupJson = await DiskFile.ReadAllAsync(this.tempFileName); string returnedJson = serde.Serialize(config1); string expectedJson = serde.Serialize(ValidConfigInfo1); Assert.Equal(expectedJson, backupJson, ignoreCase: true); Assert.Equal(expectedJson, returnedJson, ignoreCase: true); encryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>())); encryptionProvider.Verify(ep => ep.DecryptAsync(It.IsAny <string>())); }
public async void ReconcileAsyncAbortsWhenEnvironmentSourceThrows() { // Arrange var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockPlanner = new Mock <IPlanner>(); var mockPlanRunner = new Mock <IPlanRunner>(); var mockReporter = new Mock <IReporter>(); var token = default(CancellationToken); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var configStore = Mock.Of <IEntityStore <string, string> >(); var mockEnvironmentProvider = Mock.Of <IEnvironmentProvider>(m => m.Create(It.IsAny <DeploymentConfig>()) == mockEnvironment.Object); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var encryptionDecryptionProvider = Mock.Of <IEncryptionProvider>(); var deploymentConfig = new DeploymentConfig("1.0", Mock.Of <IRuntimeInfo>(), new SystemModules(null, null), new Dictionary <string, IModule>()); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(env => env.GetModulesAsync(token)).Throws <InvalidOperationException>(); mockReporter.Setup(r => r.ReportAsync(token, null, It.IsAny <IRuntimeInfo>(), It.IsAny <long>(), It.Is <DeploymentStatus>(s => s.Code == DeploymentStatusCode.Failed))) .Returns(Task.CompletedTask); var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider, mockPlanner.Object, mockPlanRunner.Object, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider); // Act // Assert await agent.ReconcileAsync(token); mockPlanner.Verify(p => p.PlanAsync(It.IsAny <ModuleSet>(), It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), It.IsAny <ImmutableDictionary <string, IModuleIdentity> >()), Times.Never); mockReporter.VerifyAll(); mockPlanRunner.Verify(r => r.ExecuteAsync(1, It.IsAny <Plan>(), token), Times.Never); }
public async void FileBackupDoesNotThrowWhenEncryptFails() { if (File.Exists(this.tempFileName)) { File.Delete(this.tempFileName); } var underlying = new Mock <IConfigSource>(); underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync()) .ReturnsAsync(ValidConfigInfo1); ISerde <DeploymentConfigInfo> serde = this.GetSerde(); var encryptionProvider = new Mock <IEncryptionProvider>(); encryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>())) .ThrowsAsync(new IoTEdgedException("failed", 404, "", null, null)); using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, encryptionProvider.Object)) { DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(config1); Assert.Equal(ValidConfigInfo1, config1); encryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>())); } }
public async void FileBackupSuccessWhenFileNotExists() { if (File.Exists(this.tempFileName)) { File.Delete(this.tempFileName); } var underlying = new Mock <IConfigSource>(); underlying.SetupSequence(t => t.GetDeploymentConfigInfoAsync()) .ReturnsAsync(ValidConfigInfo1) .ThrowsAsync(new InvalidOperationException()); ISerde <DeploymentConfigInfo> serde = this.GetSerde(); using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance)) { DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(config1); Assert.True(File.Exists(this.tempFileName)); string backupJson = await DiskFile.ReadAllAsync(this.tempFileName); string returnedJson = serde.Serialize(config1); Assert.True(string.Equals(backupJson, returnedJson, StringComparison.OrdinalIgnoreCase)); DeploymentConfigInfo config2 = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(config2); Assert.Equal(serde.Serialize(config1), serde.Serialize(config2)); } }
public async Task DesiredIsNotNullBecauseCurrentThrew() { // Arrange var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockPlanner = new Mock <IPlanner>(); var mockPlanRunner = new Mock <IPlanRunner>(); var mockReporter = new Mock <IReporter>(); var runtimeInfo = new Mock <IRuntimeInfo>(); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var token = default(CancellationToken); var configStore = Mock.Of <IEntityStore <string, string> >(); var mockEnvironmentProvider = Mock.Of <IEnvironmentProvider>(m => m.Create(It.IsAny <DeploymentConfig>()) == mockEnvironment.Object); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var encryptionDecryptionProvider = Mock.Of <IEncryptionProvider>(); var deploymentConfigInfo = new DeploymentConfigInfo(1, new DeploymentConfig("1.0", runtimeInfo.Object, new SystemModules(null, null), ImmutableDictionary <string, IModule> .Empty)); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(e => e.GetModulesAsync(token)) .Throws <InvalidOperationException>(); // Act var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider, mockPlanner.Object, mockPlanRunner.Object, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider); await agent.ReconcileAsync(token); // Assert mockReporter.Verify(r => r.ReportAsync(token, null, It.IsAny <IRuntimeInfo>(), It.IsAny <long>(), It.Is <DeploymentStatus>(s => s.Code == DeploymentStatusCode.Failed))); mockPlanRunner.Verify(r => r.ExecuteAsync(1, It.IsAny <Plan>(), token), Times.Never); }
public async Task ReportShutdownAsyncConfigTest() { // Arrange var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockPlanner = new Mock <IPlanner>(); var mockPlanRunner = new Mock <IPlanRunner>(); var mockReporter = new Mock <IReporter>(); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var configStore = Mock.Of <IEntityStore <string, string> >(); var mockEnvironmentProvider = Mock.Of <IEnvironmentProvider>(m => m.Create(It.IsAny <DeploymentConfig>()) == mockEnvironment.Object); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var encryptionDecryptionProvider = Mock.Of <IEncryptionProvider>(); var deploymentConfig = new DeploymentConfig( "1.0", Mock.Of <IRuntimeInfo>(), new SystemModules(null, null), new Dictionary <string, IModule> { { "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 = default(CancellationToken); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(e => e.GetModulesAsync(token)) .ReturnsAsync(ModuleSet.Empty); var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider, mockPlanner.Object, mockPlanRunner.Object, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider); await agent.ReportShutdownAsync(token); // Assert mockReporter.Verify(r => r.ReportShutdown(It.IsAny <DeploymentStatus>(), token)); }
public async void ReconcileAsyncOnSetPlan() { 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 <TestRecordType> { new TestRecordType(TestCommandType.TestCreate, desiredModule), new TestRecordType(TestCommandType.TestRemove, currentModule) }; var commandList = new List <ICommand> { new TestCommand(TestCommandType.TestCreate, desiredModule, recordKeeper), new TestCommand(TestCommandType.TestRemove, currentModule, recordKeeper) }; var testPlan = new Plan(commandList); var token = new CancellationToken(); var runtimeInfo = Mock.Of <IRuntimeInfo>(); var deploymentConfig = new DeploymentConfig("1.0", runtimeInfo, new SystemModules(null, null), new Dictionary <string, IModule> { ["desired"] = desiredModule }); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); ModuleSet desiredSet = deploymentConfig.GetModuleSet(); ModuleSet currentSet = ModuleSet.Create(currentModule); var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockPlanner = new Mock <IPlanner>(); var planRunner = new OrderedPlanRunner(); var mockReporter = new Mock <IReporter>(); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var configStore = Mock.Of <IEntityStore <string, string> >(); var mockEnvironmentProvider = Mock.Of <IEnvironmentProvider>(m => m.Create(It.IsAny <DeploymentConfig>()) == mockEnvironment.Object); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var encryptionDecryptionProvider = Mock.Of <IEncryptionProvider>(); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(env => env.GetModulesAsync(token)) .ReturnsAsync(currentSet); mockModuleIdentityLifecycleManager.Setup(m => m.GetModuleIdentitiesAsync(desiredSet, currentSet)) .ReturnsAsync(ImmutableDictionary <string, IModuleIdentity> .Empty); mockPlanner.Setup(pl => pl.PlanAsync(It.IsAny <ModuleSet>(), currentSet, runtimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty)) .Returns(Task.FromResult(testPlan)); mockModuleIdentityLifecycleManager.Setup(m => m.GetModuleIdentitiesAsync(It.IsAny <ModuleSet>(), currentSet)) .Returns(Task.FromResult((IImmutableDictionary <string, IModuleIdentity>)ImmutableDictionary <string, IModuleIdentity> .Empty)); mockReporter.Setup(r => r.ReportAsync(token, It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), It.IsAny <long>(), Option.Some(DeploymentStatus.Success))) .Returns(Task.CompletedTask); var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider, mockPlanner.Object, planRunner, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider); await agent.ReconcileAsync(token); mockEnvironment.Verify(env => env.GetModulesAsync(token), Times.Exactly(1)); mockPlanner.Verify(pl => pl.PlanAsync(It.IsAny <ModuleSet>(), currentSet, runtimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty), Times.Once); mockReporter.VerifyAll(); recordKeeper.ForEach(r => Assert.Equal(moduleExecutionList, r.ExecutionList)); }
public async Task TestEnvVars() { const string Image = "hello-world:latest"; const string Name = "test-env"; string sharedAccessKey = Convert.ToBase64String(Encoding.UTF8.GetBytes("deviceKey")); string fakeConnectionString = $"Hostname=fakeiothub;Deviceid=test;SharedAccessKey={sharedAccessKey}"; try { using (var cts = new CancellationTokenSource(Timeout)) { await Client.CleanupContainerAsync(Name, Image); 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); IConfigurationRoot configRoot = new ConfigurationBuilder().AddInMemoryCollection( new Dictionary <string, string> { { "EdgeDeviceConnectionString", fakeConnectionString } }).Build(); var deploymentConfigModules = new Dictionary <string, IModule> { [Name] = module }; var systemModules = new SystemModules(null, null); var deploymentConfigInfo = new DeploymentConfigInfo(1, new DeploymentConfig("1.0", new DockerRuntimeInfo("docker", new DockerRuntimeConfig("1.25", string.Empty)), systemModules, deploymentConfigModules)); var configSource = new Mock <IConfigSource>(); configSource.Setup(cs => cs.Configuration).Returns(configRoot); configSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()).ReturnsAsync(deploymentConfigInfo); var credential = new ConnectionStringCredentials("fake"); var identity = new Mock <IModuleIdentity>(); identity.Setup(id => id.Credentials).Returns(credential); ICommand create = await CreateCommand.BuildAsync(Client, module, identity.Object, loggingConfig, configSource.Object, false); await Client.PullImageAsync(Image, cts.Token); // create module using command await create.ExecuteAsync(cts.Token); // check that the environment variables are being returned RuntimeInfoProvider runtimeInfoProvider = await RuntimeInfoProvider.CreateAsync(Client); IEnumerable <ModuleRuntimeInfo> modules = await runtimeInfoProvider.GetModules(cts.Token); var returnedModule = modules.First(m => m.Name == Name) as ModuleRuntimeInfo <DockerReportedConfig>; Assert.NotNull(returnedModule); } } finally { await Client.CleanupContainerAsync(Name, Image); await Client.CleanupContainerAsync("test-filters-external", Image); } }
public async void FileBackupDoesNotThrowWhenBackupFileDoesNotExist() { if (File.Exists(this.tempFileName)) { File.Delete(this.tempFileName); } // Arrange var underlying = new Mock <IConfigSource>(); underlying.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(DeploymentConfigInfo.Empty); ISerde <DeploymentConfigInfo> serde = this.GetSerde(); // Act using (IConfigSource configSource = new FileBackupConfigSource(this.tempFileName, underlying.Object, serde, NullEncryptionProvider.Instance)) { // this call should fetch the config properly DeploymentConfigInfo config1 = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(config1); Assert.Equal(DeploymentConfigInfo.Empty, config1); } }
public async void ConfigBacksUpEachTimeItChanges() { DeploymentConfigInfo configInfo1 = SetupNonEmptyDeployment(); DeploymentConfigInfo configInfo2 = SetupNonEmptyDeployment("new-module"); var underlying = new Mock <IConfigSource>(); underlying.SetupSequence(u => u.GetDeploymentConfigInfoAsync()) .ReturnsAsync(configInfo1) .ReturnsAsync(configInfo2); var backup = new Mock <IDeploymentBackupSource>(); backup.SetupGet(b => b.Name).Returns("backup"); backup.Setup(b => b.BackupDeploymentConfigAsync(configInfo1)).Returns(TaskEx.Done); backup.Setup(b => b.BackupDeploymentConfigAsync(configInfo2)).Returns(TaskEx.Done); var backupSource = new BackupConfigSource(backup.Object, underlying.Object); var result1 = await backupSource.GetDeploymentConfigInfoAsync(); var result2 = await backupSource.GetDeploymentConfigInfoAsync(); Assert.Equal(configInfo1, result1); Assert.Equal(configInfo2, result2); underlying.VerifyAll(); backup.Verify(b => b.BackupDeploymentConfigAsync(configInfo1), Times.Once); backup.Verify(b => b.BackupDeploymentConfigAsync(configInfo2), Times.Once); }
static async Task <DeploymentConfigInfo> ReadFromDisk(string path, ISerde <DeploymentConfigInfo> serde) { string json = await DiskFile.ReadAllAsync(path); DeploymentConfigInfo deploymentConfig = serde.Deserialize(json); return(deploymentConfig); }
public void TestEquality(DeploymentConfigInfo configInfo1, DeploymentConfigInfo configInfo2, bool areEqual) { // Act bool result = configInfo1.Equals(configInfo2); // Assert Assert.Equal(areEqual, result); }
public async void ReconcileAsyncReportsFailedWhenEncryptProviderThrows() { var token = default(CancellationToken); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockEnvironmentProvider = new Mock <IEnvironmentProvider>(); var mockPlanner = new Mock <IPlanner>(); var mockPlanRunner = new Mock <IPlanRunner>(); var mockReporter = new Mock <IReporter>(); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var runtimeInfo = Mock.Of <IRuntimeInfo>(); var configStore = Mock.Of <IEntityStore <string, string> >(); var encryptionDecryptionProvider = new Mock <IEncryptionProvider>(); var availabilityMetric = Mock.Of <IAvailabilityMetric>(); var deploymentConfig = new DeploymentConfig( "1.0", runtimeInfo, new SystemModules(null, null), new Dictionary <string, IModule> { { "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, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); var recordKeeper = Option.Some(new TestPlanRecorder()); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); ModuleSet desiredModuleSet = deploymentConfig.GetModuleSet(); ModuleSet currentModuleSet = desiredModuleSet; var commandList = new List <ICommand> { new TestCommand(TestCommandType.TestCreate, desiredModule, recordKeeper) }; var testPlan = new Plan(commandList); mockEnvironmentProvider.Setup(m => m.Create(It.IsAny <DeploymentConfig>())).Returns(mockEnvironment.Object); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(env => env.GetModulesAsync(token)) .ReturnsAsync(currentModuleSet); mockEnvironment.Setup(env => env.GetRuntimeInfoAsync()).ReturnsAsync(runtimeInfo); mockModuleIdentityLifecycleManager.Setup(m => m.GetModuleIdentitiesAsync(It.Is <ModuleSet>(ms => ms.Equals(desiredModuleSet)), currentModuleSet)) .ReturnsAsync(ImmutableDictionary <string, IModuleIdentity> .Empty); mockPlanner.Setup(pl => pl.PlanAsync(It.Is <ModuleSet>(ms => ms.Equals(desiredModuleSet)), currentModuleSet, runtimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty)) .ReturnsAsync(testPlan); encryptionDecryptionProvider.Setup(ep => ep.EncryptAsync(It.IsAny <string>())) .ThrowsAsync(new WorkloadCommunicationException("failed", 404)); var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider.Object, mockPlanner.Object, mockPlanRunner.Object, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider.Object, availabilityMetric); await agent.ReconcileAsync(token); // Assert mockPlanner.Verify(p => p.PlanAsync(It.IsAny <ModuleSet>(), It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), It.IsAny <ImmutableDictionary <string, IModuleIdentity> >()), Times.Once); mockReporter.Verify(r => r.ReportAsync(It.IsAny <CancellationToken>(), It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), 0, new DeploymentStatus(DeploymentStatusCode.Failed, "failed"))); mockPlanRunner.Verify(r => r.ExecuteAsync(0, It.IsAny <Plan>(), token), Times.Once); encryptionDecryptionProvider.Verify(ep => ep.EncryptAsync(It.IsAny <string>()), Times.Exactly(2)); }
void UpdateCurrent(DeploymentConfigInfo updated) { DeploymentConfigInfo snapshot = this.current.Value; if (!this.current.CompareAndSet(snapshot, updated)) { throw new InvalidOperationException("Invalid update current moduleset operation."); } }
public async void GetDeploymentConfigTest2() { // Arrange var runtimeInfo = Mock.Of <IRuntimeInfo>(); var edgeHubModule = Mock.Of <IEdgeHubModule>(m => m.Name == "$edgeHub"); var edgeAgentModule = Mock.Of <IEdgeAgentModule>(m => m.Name == "$edgeAgent"); var systemModules = new SystemModules(edgeAgentModule, edgeHubModule); string customModule1Name = null; string customModule2Name = null; var customModule1 = Mock.Of <IModule>(); var customModule2 = Mock.Of <IModule>(); Mock.Get(customModule1).SetupSet(n => n.Name = It.IsAny <string>()).Callback <string>(n => customModule1Name = n); Mock.Get(customModule2).SetupSet(n => n.Name = It.IsAny <string>()).Callback <string>(n => customModule2Name = n); IDictionary <string, IModule> modules = new Dictionary <string, IModule> { ["module1"] = customModule1, ["module2"] = customModule2 }; var deploymentConfig = new DeploymentConfig("1.0", runtimeInfo, systemModules, modules); var deploymentConfigInfo = new DeploymentConfigInfo(5, deploymentConfig); var edgeAgentConnection = new Mock <IEdgeAgentConnection>(); edgeAgentConnection.Setup(e => e.GetDeploymentConfigInfoAsync()).ReturnsAsync(Option.Some(deploymentConfigInfo)); var configuration = Mock.Of <IConfiguration>(); var twinConfigSource = new TwinConfigSource(edgeAgentConnection.Object, configuration); // Act DeploymentConfigInfo receivedDeploymentConfigInfo = await twinConfigSource.GetDeploymentConfigInfoAsync(); // Assert Assert.NotNull(receivedDeploymentConfigInfo); Assert.NotNull(receivedDeploymentConfigInfo.DeploymentConfig); Assert.Equal(5, receivedDeploymentConfigInfo.Version); DeploymentConfig returnedDeploymentConfig = receivedDeploymentConfigInfo.DeploymentConfig; Assert.Equal(Option.Some(edgeAgentModule), returnedDeploymentConfig.SystemModules.EdgeAgent); Assert.Equal(Option.Some(edgeHubModule), returnedDeploymentConfig.SystemModules.EdgeHub); ModuleSet moduleSet = returnedDeploymentConfig.GetModuleSet(); Assert.Equal(4, returnedDeploymentConfig.GetModuleSet().Modules.Count); Assert.Equal(customModule1.Name, moduleSet.Modules["module1"].Name); Assert.Equal(customModule2.Name, moduleSet.Modules["module2"].Name); Assert.Equal(edgeHubModule.Name, moduleSet.Modules["$edgeHub"].Name); Assert.Equal(edgeAgentModule.Name, moduleSet.Modules["$edgeAgent"].Name); Assert.Equal("module1", customModule1Name); Assert.Equal("module2", customModule2Name); }
public async Task RestartTest() { // Arrange var cts = new CancellationTokenSource(); var edgeAgent = Mock.Of <IEdgeAgentModule>(m => m.Name == "edgeAgent"); var edgeHub = Mock.Of <IEdgeHubModule>(m => m.Name == "edgeHub"); var mod1 = Mock.Of <IRuntimeModule>(m => m.Name == "mod1" && m.RuntimeStatus == ModuleStatus.Running); var mod2 = Mock.Of <IRuntimeModule>(m => m.Name == "mod2" && m.RuntimeStatus == ModuleStatus.Running); var deploymentConfigInfo = new DeploymentConfigInfo( 1, new DeploymentConfig( "1.0", Mock.Of <IRuntimeInfo>(), new SystemModules(edgeAgent, edgeHub), new Dictionary <string, IModule> { ["mod1"] = mod1, ["mod2"] = mod2 }, null)); var configSource = Mock.Of <IConfigSource>(c => c.GetDeploymentConfigInfoAsync() == Task.FromResult(deploymentConfigInfo)); var moduleSet = ModuleSet.Create(edgeAgent, edgeHub, mod1, mod2); var environment = Mock.Of <IEnvironment>(e => e.GetModulesAsync(cts.Token) == Task.FromResult(moduleSet)); var environmentProvider = Mock.Of <IEnvironmentProvider>(e => e.Create(deploymentConfigInfo.DeploymentConfig) == environment); var restartCommand = new Mock <ICommand>(MockBehavior.Strict); restartCommand.Setup(r => r.ExecuteAsync(cts.Token)) .Returns(Task.CompletedTask); var commandFactory = new Mock <ICommandFactory>(MockBehavior.Strict); commandFactory.Setup(c => c.RestartAsync(mod1)).ReturnsAsync(restartCommand.Object); var restartRequestHandler = new RestartRequestHandler(environmentProvider, configSource, commandFactory.Object); string payload = "{\"schemaVersion\": \"1.0\",\"id\": \"mod1\"}"; // Act Option <string> response = await restartRequestHandler.HandleRequest(Option.Some(payload), cts.Token); // Assert Assert.False(response.HasValue); restartCommand.Verify(r => r.ExecuteAsync(cts.Token), Times.Once); commandFactory.Verify(c => c.RestartAsync(mod1), Times.Once); Mock.Get(configSource).VerifyAll(); Mock.Get(environmentProvider).VerifyAll(); Mock.Get(environment).VerifyAll(); }
public async void ReconcileAsyncOnEmptyPlan() { var token = default(CancellationToken); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockEnvironmentProvider = new Mock <IEnvironmentProvider>(); var mockPlanner = new Mock <IPlanner>(); var mockPlanRunner = new Mock <IPlanRunner>(); var mockReporter = new Mock <IReporter>(); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var runtimeInfo = Mock.Of <IRuntimeInfo>(); var configStore = Mock.Of <IEntityStore <string, string> >(); var encryptionDecryptionProvider = Mock.Of <IEncryptionProvider>(); var availabilityMetric = Mock.Of <IAvailabilityMetric>(); var deploymentConfig = new DeploymentConfig( "1.0", runtimeInfo, new SystemModules(null, null), new Dictionary <string, IModule> { { "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(); ModuleSet currentModuleSet = desiredModuleSet; mockEnvironmentProvider.Setup(m => m.Create(It.IsAny <DeploymentConfig>())).Returns(mockEnvironment.Object); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(env => env.GetModulesAsync(token)) .ReturnsAsync(currentModuleSet); mockEnvironment.Setup(env => env.GetRuntimeInfoAsync()).ReturnsAsync(runtimeInfo); mockModuleIdentityLifecycleManager.Setup(m => m.GetModuleIdentitiesAsync(It.Is <ModuleSet>(ms => ms.Equals(desiredModuleSet)), currentModuleSet)) .ReturnsAsync(ImmutableDictionary <string, IModuleIdentity> .Empty); mockPlanner.Setup(pl => pl.PlanAsync(It.Is <ModuleSet>(ms => ms.Equals(desiredModuleSet)), currentModuleSet, runtimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty)) .Returns(Task.FromResult(Plan.Empty)); var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider.Object, mockPlanner.Object, mockPlanRunner.Object, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider, availabilityMetric); await agent.ReconcileAsync(token); mockEnvironment.Verify(env => env.GetModulesAsync(token), Times.Once); mockPlanner.Verify(pl => pl.PlanAsync(It.Is <ModuleSet>(ms => ms.Equals(desiredModuleSet)), currentModuleSet, runtimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty), Times.Once); mockReporter.Verify(r => r.ReportAsync(token, currentModuleSet, runtimeInfo, DeploymentConfigInfo.Empty.Version, DeploymentStatus.Success), Times.Once); mockPlanRunner.Verify(r => r.ExecuteAsync(1, Plan.Empty, token), Times.Never); }
public async void CreateSuccess() { File.WriteAllText(this.tempFileName, ValidJson1); using (FileConfigSource configSource = await FileConfigSource.Create(this.tempFileName, this.config, this.serde)) { Assert.NotNull(configSource); DeploymentConfigInfo deploymentConfigInfo = await configSource.GetDeploymentConfigInfoAsync(); Assert.NotNull(deploymentConfigInfo); Assert.NotNull(deploymentConfigInfo.DeploymentConfig); ModuleSet moduleSet = deploymentConfigInfo.DeploymentConfig.GetModuleSet(); Diff emptyDiff = ValidSet1.Diff(moduleSet); Assert.True(emptyDiff.IsEmpty); } }
public async void ConfigsWithExceptionsDoNotBackUp() { DeploymentConfigInfo configInfo = SetupExceptionDeployment(); var underlying = new Mock <IConfigSource>(); underlying.Setup(u => u.GetDeploymentConfigInfoAsync()).ReturnsAsync(configInfo); var backup = new Mock <IDeploymentBackupSource>(); backup.SetupGet(b => b.Name).Returns("backup"); var backupSource = new BackupConfigSource(backup.Object, underlying.Object); var result1 = await backupSource.GetDeploymentConfigInfoAsync(); Assert.Equal(configInfo, result1); underlying.VerifyAll(); backup.VerifyAll(); }
public async void GetDeploymentConfigTest1() { // Arrange var edgeAgentConnection = new Mock <IEdgeAgentConnection>(); edgeAgentConnection.Setup(e => e.GetDeploymentConfigInfoAsync()).ReturnsAsync(Option.None <DeploymentConfigInfo>()); var configuration = Mock.Of <IConfiguration>(); var twinConfigSource = new TwinConfigSource(edgeAgentConnection.Object, configuration); // Act DeploymentConfigInfo deploymentConfigInfo = await twinConfigSource.GetDeploymentConfigInfoAsync(); // Assert Assert.NotNull(deploymentConfigInfo); Assert.Equal(-1, deploymentConfigInfo.Version); Assert.Equal(DeploymentConfig.Empty, deploymentConfigInfo.DeploymentConfig); }
public async void ReconcileAsyncWithNoDeploymentChange() { var desiredModule = new TestModule("CustomModule", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); var currentModule = new TestModule("CustomModule", "v1", "test", ModuleStatus.Running, new TestConfig("image"), RestartPolicy.OnUnhealthy, ImagePullPolicy.OnCreate, new ConfigurationInfo("1"), null); var testPlan = new Plan(new List <ICommand>()); var token = default(CancellationToken); var runtimeInfo = Mock.Of <IRuntimeInfo>(); var deploymentConfig = new DeploymentConfig("1.0", runtimeInfo, new SystemModules(null, null), new Dictionary <string, IModule> { ["CustomModule"] = desiredModule }); var deploymentConfigInfo = new DeploymentConfigInfo(0, deploymentConfig); ModuleSet desiredSet = deploymentConfig.GetModuleSet(); ModuleSet currentSet = ModuleSet.Create(currentModule); var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockPlanner = new Mock <IPlanner>(); var planRunner = new OrderedPlanRunner(); var mockReporter = new Mock <IReporter>(); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var configStore = Mock.Of <IEntityStore <string, string> >(); var mockEnvironmentProvider = Mock.Of <IEnvironmentProvider>(m => m.Create(It.IsAny <DeploymentConfig>()) == mockEnvironment.Object); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var encryptionDecryptionProvider = Mock.Of <IEncryptionProvider>(); var availabilityMetric = Mock.Of <IAvailabilityMetric>(); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(env => env.GetModulesAsync(token)) .ReturnsAsync(currentSet); mockModuleIdentityLifecycleManager.Setup(m => m.GetModuleIdentitiesAsync(desiredSet, currentSet)) .ReturnsAsync(ImmutableDictionary <string, IModuleIdentity> .Empty); mockPlanner.Setup(pl => pl.PlanAsync(It.IsAny <ModuleSet>(), currentSet, runtimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty)) .Returns(Task.FromResult(testPlan)); mockReporter.Setup(r => r.ReportAsync(token, It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), It.IsAny <long>(), DeploymentStatus.Success)) .Returns(Task.CompletedTask); var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider, mockPlanner.Object, planRunner, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider, availabilityMetric); await agent.ReconcileAsync(token); mockEnvironment.Verify(env => env.GetModulesAsync(token), Times.Exactly(1)); mockPlanner.Verify(pl => pl.PlanAsync(It.IsAny <ModuleSet>(), currentSet, runtimeInfo, ImmutableDictionary <string, IModuleIdentity> .Empty), Times.Once); mockReporter.Verify(r => r.ReportAsync(token, It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), It.IsAny <long>(), DeploymentStatus.Success), Times.Once); }
public async void ReconcileAsyncAbortsWhenModuleIdentityLifecycleManagerThrows() { // Arrange var mockConfigSource = new Mock <IConfigSource>(); var mockEnvironment = new Mock <IEnvironment>(); var mockPlanner = new Mock <IPlanner>(); var mockPlanRunner = new Mock <IPlanRunner>(); var mockReporter = new Mock <IReporter>(); var token = default(CancellationToken); var mockModuleIdentityLifecycleManager = new Mock <IModuleIdentityLifecycleManager>(); var configStore = Mock.Of <IEntityStore <string, string> >(); var mockEnvironmentProvider = Mock.Of <IEnvironmentProvider>(m => m.Create(It.IsAny <DeploymentConfig>()) == mockEnvironment.Object); var serde = Mock.Of <ISerde <DeploymentConfigInfo> >(); var encryptionDecryptionProvider = Mock.Of <IEncryptionProvider>(); var availabilityMetric = Mock.Of <IAvailabilityMetric>(); var deploymentConfig = new DeploymentConfig( "1.0", Mock.Of <IRuntimeInfo>(), new SystemModules(null, null), new Dictionary <string, IModule> { { "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(); mockConfigSource.Setup(cs => cs.GetDeploymentConfigInfoAsync()) .ReturnsAsync(deploymentConfigInfo); mockEnvironment.Setup(env => env.GetModulesAsync(token)) .ReturnsAsync(ModuleSet.Empty); mockModuleIdentityLifecycleManager.Setup(m => m.GetModuleIdentitiesAsync(It.Is <ModuleSet>(ms => ms.Equals(desiredModuleSet)), ModuleSet.Empty)) .Throws <InvalidOperationException>(); mockReporter.Setup(r => r.ReportAsync(token, It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), It.IsAny <long>(), It.Is <DeploymentStatus>(s => s.Code == DeploymentStatusCode.Failed))) .Returns(Task.CompletedTask); var agent = new Agent(mockConfigSource.Object, mockEnvironmentProvider, mockPlanner.Object, mockPlanRunner.Object, mockReporter.Object, mockModuleIdentityLifecycleManager.Object, configStore, DeploymentConfigInfo.Empty, serde, encryptionDecryptionProvider, availabilityMetric); // Act // Assert await agent.ReconcileAsync(token); mockPlanner.Verify(p => p.PlanAsync(It.IsAny <ModuleSet>(), It.IsAny <ModuleSet>(), It.IsAny <IRuntimeInfo>(), It.IsAny <ImmutableDictionary <string, IModuleIdentity> >()), Times.Never); mockReporter.VerifyAll(); mockPlanRunner.Verify(r => r.ExecuteAsync(1, It.IsAny <Plan>(), token), Times.Never); }
FileConfigSource(FileSystemWatcher watcher, DeploymentConfigInfo initial, IConfiguration configuration, ISerde <DeploymentConfigInfo> serde) { this.watcher = Preconditions.CheckNotNull(watcher, nameof(watcher)); this.Configuration = Preconditions.CheckNotNull(configuration, nameof(configuration)); this.current = new AtomicReference <DeploymentConfigInfo>(Preconditions.CheckNotNull(initial, nameof(initial))); this.serde = Preconditions.CheckNotNull(serde, nameof(serde)); this.configFilePath = Path.Combine(this.watcher.Path, this.watcher.Filter); this.sync = new AsyncLock(); this.watcherSubscription = Observable .FromEventPattern <FileSystemEventArgs>(this.watcher, "Changed") // Rx.NET's "Throttle" is really "Debounce". An unfortunate naming mishap. .Throttle(TimeSpan.FromMilliseconds(FileChangeWatcherDebounceInterval)) .Subscribe(this.WatcherOnChanged); this.watcher.EnableRaisingEvents = true; Events.Created(this.configFilePath); }