async Task <IImmutableDictionary <string, IModuleIdentity> > GetModuleIdentitiesAsync(Diff diff) { // System modules have different module names and identity names. We need to convert module names to module identity names // and vice versa, to make sure the right values are being used. // TODO - This will fail if the user adds modules with the same module name as a system module - for example a module called // edgeHub. We might have to catch such cases and flag them as error (or handle them in some other way). IEnumerable <string> updatedModuleIdentites = diff.AddedOrUpdated.Select(m => ModuleIdentityHelper.GetModuleIdentityName(m.Name)); IEnumerable <string> removedModuleIdentites = diff.Removed.Select(m => ModuleIdentityHelper.GetModuleIdentityName(m)); List <Module> modules = (await this.serviceClient.GetModules()).ToList(); ImmutableDictionary <string, Module> modulesDict = modules.ToImmutableDictionary(p => p.Id); IEnumerable <string> createIdentities = updatedModuleIdentites.Where(m => !modulesDict.ContainsKey(m)); IEnumerable <string> removeIdentities = removedModuleIdentites.Where( m => modulesDict.ContainsKey(m) && string.Equals(modulesDict.GetValueOrDefault(m).ManagedBy, Constants.ModuleIdentityEdgeManagedByValue, StringComparison.OrdinalIgnoreCase)); // Update any identities that don't have SAS auth type or where the keys are null (this will happen for single device deployments, // where the identities of modules are created, but the auth keys are not set). IEnumerable <Module> updateIdentities = modules.Where( m => m.Authentication == null || m.Authentication.Type != AuthenticationType.Sas || m.Authentication.SymmetricKey == null || (m.Authentication.SymmetricKey.PrimaryKey == null && m.Authentication.SymmetricKey.SecondaryKey == null)) .Select( m => { m.Authentication = new AuthenticationMechanism { Type = AuthenticationType.Sas }; return(m); }).ToList(); List <Module> updatedModulesIndentity = (await this.UpdateServiceModulesIdentityAsync(removeIdentities, createIdentities, updateIdentities)).ToList(); ImmutableDictionary <string, Module> updatedDict = updatedModulesIndentity.ToImmutableDictionary(p => p.Id); IEnumerable <IModuleIdentity> moduleIdentities; moduleIdentities = updatedModulesIndentity.Concat(modules.Where(p => !updatedDict.ContainsKey(p.Id))).Select( p => { string connectionString = this.GetModuleConnectionString(p); return(new ModuleIdentity( this.iothubHostName, this.deviceId, p.Id, new ConnectionStringCredentials(connectionString))); }); return(moduleIdentities.ToImmutableDictionary(m => ModuleIdentityHelper.GetModuleName(m.ModuleId))); }
public async Task <IImmutableDictionary <string, IModuleIdentity> > GetModuleIdentitiesAsync(ModuleSet desired, ModuleSet current) { Diff diff = desired.Diff(current); if (diff.IsEmpty) { return(ImmutableDictionary <string, IModuleIdentity> .Empty); } IList <string> updatedModuleNames = diff.Updated.Select(m => ModuleIdentityHelper.GetModuleIdentityName(m.Name)).ToList(); IEnumerable <string> removedModuleNames = diff.Removed.Select(m => ModuleIdentityHelper.GetModuleIdentityName(m)); IImmutableDictionary <string, Identity> identities = (await this.identityManager.GetIdentities()).ToImmutableDictionary(i => i.ModuleId); // Create identities for all modules that are in the deployment but aren't in iotedged. IEnumerable <string> createIdentities = updatedModuleNames.Where(m => !identities.ContainsKey(m)); // Update identities for all modules that are in the deployment and are in iotedged (except for Edge Agent which gets special // treatment in iotedged). // // NOTE: This update can potentiatlly be made more efficient by checking that an update is actually needed, i.e. if auth type // is not SAS and/or if the credentials are not what iotedged expects it to be. IEnumerable <Identity> updateIdentities = updatedModuleNames .Where(m => identities.ContainsKey(m) && m != Constants.EdgeAgentModuleIdentityName) .Select(m => identities[m]); // Remove identities which exist in iotedged but don't exist in the deployment anymore. We exclude however, identities that // aren't managed by Edge since these have been created by some out-of-band process and Edge doesn't "own" the identity. IEnumerable <string> removeIdentities = removedModuleNames.Where(m => identities.ContainsKey(m) && Constants.ModuleIdentityEdgeManagedByValue.Equals(identities[m].ManagedBy, StringComparison.OrdinalIgnoreCase)); // First remove identities (so that we don't go over the IoTHub limit). await Task.WhenAll(removeIdentities.Select(i => this.identityManager.DeleteIdentityAsync(i))); // Create/update identities. IEnumerable <Task <Identity> > createTasks = createIdentities.Select(i => this.identityManager.CreateIdentityAsync(i, Constants.ModuleIdentityEdgeManagedByValue)); IEnumerable <Task <Identity> > updateTasks = updateIdentities.Select(i => this.identityManager.UpdateIdentityAsync(i.ModuleId, i.GenerationId, i.ManagedBy)); Identity[] upsertedIdentities = await Task.WhenAll(createTasks.Concat(updateTasks)); List <IModuleIdentity> moduleIdentities = upsertedIdentities.Select(m => this.GetModuleIdentity(m)).ToList(); // Add the module identity for Edge Agent in the returned dictionary // because is was excluded from the update call. if (identities.ContainsKey(Constants.EdgeAgentModuleIdentityName)) { moduleIdentities.Add(this.GetModuleIdentity(identities[Constants.EdgeAgentModuleIdentityName])); } return(moduleIdentities.ToImmutableDictionary(m => ModuleIdentityHelper.GetModuleName(m.ModuleId))); }