public Agent( IConfigSource configSource, IEnvironmentProvider environmentProvider, IPlanner planner, IPlanRunner planRunner, IReporter reporter, IModuleIdentityLifecycleManager moduleIdentityLifecycleManager, IEntityStore <string, string> configStore, DeploymentConfigInfo initialDeployedConfigInfo, ISerde <DeploymentConfigInfo> deploymentConfigInfoSerde, IEncryptionProvider encryptionProvider, IAvailabilityMetric availabilityMetric) { this.configSource = Preconditions.CheckNotNull(configSource, nameof(configSource)); this.planner = Preconditions.CheckNotNull(planner, nameof(planner)); this.planRunner = Preconditions.CheckNotNull(planRunner, nameof(planRunner)); this.reporter = Preconditions.CheckNotNull(reporter, nameof(reporter)); this.moduleIdentityLifecycleManager = Preconditions.CheckNotNull(moduleIdentityLifecycleManager, nameof(moduleIdentityLifecycleManager)); this.configStore = Preconditions.CheckNotNull(configStore, nameof(configStore)); this.environmentProvider = Preconditions.CheckNotNull(environmentProvider, nameof(environmentProvider)); this.currentConfig = Preconditions.CheckNotNull(initialDeployedConfigInfo); this.deploymentConfigInfoSerde = Preconditions.CheckNotNull(deploymentConfigInfoSerde, nameof(deploymentConfigInfoSerde)); this.environment = this.environmentProvider.Create(this.currentConfig.DeploymentConfig); this.encryptionProvider = Preconditions.CheckNotNull(encryptionProvider, nameof(encryptionProvider)); this.availabilityMetric = Preconditions.CheckNotNull(availabilityMetric, nameof(availabilityMetric)); this.status = DeploymentStatus.Unknown; Events.AgentCreated(); }
internal async Task ReportShutdownAsync(CancellationToken token) { try { var status = new DeploymentStatus(DeploymentStatusCode.Unknown, "Agent is not running"); await this.reporter.ReportShutdown(status, token); Events.ReportShutdown(); } catch (Exception ex) when (!ex.IsFatal()) { Events.ReportShutdownFailed(ex); } }
public async Task HandleShutdown(CancellationToken token) { try { Events.InitiateShutdown(); Task shutdownModulesTask = this.ShutdownModules(token); var status = new DeploymentStatus(DeploymentStatusCode.Unknown, "Agent is not running"); Task reportShutdownTask = this.reporter.ReportShutdown(status, token); await Task.WhenAll(shutdownModulesTask, reportShutdownTask); Events.CompletedShutdown(); } catch (Exception ex) when (!ex.IsFatal()) { Events.HandleShutdownFailed(ex); } }
public async Task ReconcileAsync(CancellationToken token) { ModuleSet moduleSetToReport = null; using (await this.reconcileLock.LockAsync(token)) { try { Events.StartingReconcile(); (ModuleSet current, DeploymentConfigInfo deploymentConfigInfo, Exception exception) = await this.GetReconcileData(token); moduleSetToReport = current; if (exception != null) { ExceptionDispatchInfo.Capture(exception).Throw(); } DeploymentConfig deploymentConfig = deploymentConfigInfo.DeploymentConfig; if (deploymentConfig.Equals(DeploymentConfig.Empty)) { this.status = DeploymentStatus.Success; } else { ModuleSet desiredModuleSet = deploymentConfig.GetModuleSet(); _ = Task.Run(() => this.availabilityMetric.ComputeAvailability(desiredModuleSet, current)) .ContinueWith(t => Events.UnknownFailure(t.Exception), TaskContinuationOptions.OnlyOnFaulted) .ConfigureAwait(false); // TODO - Update this logic to create identities only when needed, in the Command factory, instead of creating all the identities // up front here. That will allow handling the case when only the state of the system has changed (say one module crashes), and // no new identities need to be created. This will simplify the logic to allow EdgeAgent to work when offline. // But that required ModuleSet.Diff to be updated to include modules updated by deployment, and modules updated by state change. IImmutableDictionary <string, IModuleIdentity> identities = await this.moduleIdentityLifecycleManager.GetModuleIdentitiesAsync(desiredModuleSet, current); Plan plan = await this.planner.PlanAsync(desiredModuleSet, current, deploymentConfig.Runtime, identities); if (plan.IsEmpty) { this.status = DeploymentStatus.Success; } else { try { bool result = await this.planRunner.ExecuteAsync(deploymentConfigInfo.Version, plan, token); await this.UpdateCurrentConfig(deploymentConfigInfo); if (result) { this.status = DeploymentStatus.Success; } } catch (Exception ex) when(!ex.IsFatal()) { Events.PlanExecutionFailed(ex); await this.UpdateCurrentConfig(deploymentConfigInfo); throw; } } } } catch (Exception ex) when(!ex.IsFatal()) { switch (ex) { case ConfigEmptyException _: this.status = new DeploymentStatus(DeploymentStatusCode.ConfigEmptyError, ex.Message); Events.EmptyConfig(ex); break; case InvalidSchemaVersionException _: this.status = new DeploymentStatus(DeploymentStatusCode.InvalidSchemaVersion, ex.Message); Events.InvalidSchemaVersion(ex); break; case ConfigFormatException _: this.status = new DeploymentStatus(DeploymentStatusCode.ConfigFormatError, ex.Message); Events.InvalidConfigFormat(ex); break; default: this.status = new DeploymentStatus(DeploymentStatusCode.Failed, ex.Message); Events.UnknownFailure(ex); break; } } await this.reporter.ReportAsync(token, moduleSetToReport, await this.environment.GetRuntimeInfoAsync(), this.currentConfig.Version, this.status); Events.FinishedReconcile(); } }