public async Task <UserTenantListModel> GetAllTenantsAsync(string userId) { try { IdentityGatewayApiListModel identityGatewayUserTenants = await this.identityGatewayClient.GetAllTenantsForUserAsync(userId); UserTenantListModel userTenants = new UserTenantListModel(identityGatewayUserTenants); foreach (var userTenant in userTenants.Models) { userTenant.TenantName = await this.GetTenantNameAsync(userTenant.TenantId); } return(userTenants); } catch (Exception e) { throw new Exception("Unable to retrieve the tenants", e); } }
public async Task <UserTenantListModel> GetAllTenantsAsync(string userId) { try { IdentityGatewayApiListModel identityGatewayUserTenants = await this.identityGatewayClient.GetAllTenantsForUserAsync(userId); UserTenantListModel userTenants = new UserTenantListModel(identityGatewayUserTenants); foreach (var userTenant in userTenants.Models) { var tenantResponse = await this.GetTenantNameAsync(userTenant.TenantId); userTenant.TenantName = tenantResponse != null && !string.IsNullOrWhiteSpace(tenantResponse.TenantName) ? tenantResponse.TenantName : $"tenant#{tenantResponse.TenantId.Substring(0, 5)}"; userTenant.IotHubName = tenantResponse != null && !string.IsNullOrWhiteSpace(tenantResponse.IotHubName) ? tenantResponse.IotHubName : string.Empty; } return(userTenants); } catch (Exception e) { throw new Exception("Unable to retrieve the tenants", e); } }
public async Task <CreateTenantModel> CreateTenantAsync(string tenantId, string userId, string createdBy) { /* Creates a new tenant */ string iotHubName = this.FormatResourceName(this.iotHubNameFormat, tenantId); string dpsName = this.FormatResourceName(this.dpsNameFormat, tenantId); // Create a new tenant and save it to table storage var tenant = new TenantModel(tenantId); tenant.IotHubName = iotHubName; tenant.DpsName = dpsName; await this.tableStorageClient.InsertAsync <TenantModel>(TenantTableId, tenant); // Give the requesting user an admin role to the new tenant try { await this.identityGatewayClient.AddTenantForUserAsync(userId, tenantId, CreatedRole, null, createdBy); } catch (Exception e) { throw new Exception("Unable to add user to tenant.", e); } // Update the userSettings table with the lastUsedTenant if there isn't already a lastUsedTenant IdentityGatewayApiSettingModel userSettings = null; try { userSettings = await this.identityGatewayClient.GetSettingsForUserAsync(userId, LastUsedSettingKey); } catch (Exception e) { throw new Exception("Could not access user settings for LastUsedTenant.", e); } if (userSettings == null) { // Set the last used tenant to be this new tenant try { await this.identityGatewayClient.AddSettingsForUserAsync(userId, LastUsedSettingKey, tenantId); } catch (Exception e) { throw new Exception("Could not set user settings for LastUsedTenant.", e); } } // Add all the system admins as admin users to this system try { IdentityGatewayApiListModel systemAdmins = await this.identityGatewayClient.GetAllSystemAdminsAsync(); foreach (var systemAdmin in systemAdmins.Models) { if (systemAdmin.UserId != userId) { await this.identityGatewayClient.AddTenantForUserAsync(systemAdmin.UserId, tenantId, CreatedRole, systemAdmin.Name, createdBy); } } } catch (Exception e) { throw new Exception("Could not insert system admins as users.", e); } // Write tenant info cosmos db collection name to app config try { foreach (string collection in this.tenantCollections.Keys) { string collectionKey = string.Format(this.appConfigCollectionKeyFormat, tenantId, collection); string collectionId = $"{collection}-{tenantId}"; await this.appConfigClient.SetValueAsync(collectionKey, collectionId); } } catch (Exception e) { // In order for a complete tenant creation, all app config keys must be created. throw an error if not throw new Exception($"Unable to add required collection ids to App Config for tenant {tenantId}", e); } try { await this.deviceGroupClient.CreateDefaultDeviceGroupAsync(tenantId); } catch (Exception e) { throw new Exception("Unable to create the default device group for the new tenant.", e); } string grafanaTaskName = this.FormatResourceName(this.grafanaNameFormat, tenantId); if (string.Equals(this.config.DeviceTelemetryService.Messages.TelemetryStorageType, TelemetryStorageTypeConstants.Ade, StringComparison.OrdinalIgnoreCase)) { // trigger grafana dashboard try { await this.tableStorageClient.InsertAsync(TenantOperationTable, new TenantOperationModel(tenantId, TenantOperation.GrafanaDashboardCreation, grafanaTaskName)); } catch (Exception e) { this.logger.LogInformation(e, "Unable to create grafana dashboard for tenant {tenantId}", tenantId); } } return(new CreateTenantModel(tenantId)); }
protected async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { Console.WriteLine("Getting Tenant Operations..."); TableQuery <TenantOperationModel> query = new TableQuery <TenantOperationModel>(); var items = await this.tableStorageClient.QueryAsync(TableName, query, stoppingToken); foreach (var item in items) { try { switch (item.Type) { case TenantOperation.IoTHubDeletion: Console.WriteLine($"Processing {item.TenantId}"); try { Console.WriteLine($"Deleting {item.Name}..."); await this.azureManagementClient.IotHubManagementClient.DeleteAsync( item.Name, stoppingToken); Console.WriteLine($"Deleting Table Operation Record..."); await this.tableStorageClient.DeleteAsync(TableName, item); } catch (Microsoft.Azure.Management.IotHub.Models.ErrorDetailsException e) { if (e.Message == "Operation returned an invalid status code 'NotFound'") { // Handle edge case } } break; case TenantOperation.SaJobDeletion: try { var job = await this.azureManagementClient.AsaManagementClient.RetrieveAsync( item.Name, null, stoppingToken); Console.WriteLine($"SA job {item.Name} found"); if (new List <string> { "Starting", "Running" }.Contains(job.JobState)) { Console.WriteLine($"Stopping job"); await this.azureManagementClient.AsaManagementClient.StopAsync( item.Name, null, stoppingToken); } else if (job.JobState != "Stopping") { Console.WriteLine($"Deleting job"); await this.azureManagementClient.AsaManagementClient.DeleteAsync( item.Name, null, stoppingToken); } } catch (ResourceNotFoundException) { // Item does not exist... delete the record Console.WriteLine($"SA job {item.Name} does not exist...deleting tenant operation"); await this.tableStorageClient.DeleteAsync(TableName, item); } break; case TenantOperation.SaJobCreation: { await this.blobStorageClient.CreateBlobContainerIfNotExistsAsync(item.TenantId); Console.WriteLine("File Upload Container Made"); var tenant = await this.tableStorageClient.RetrieveAsync <TenantModel>( "tenant", item.TenantId.Substring(0, 1), item.TenantId); this.azureManagementClient.IotHubManagementClient.AddConsumerGroup( tenant.IotHubName, "events", "sajobconsumergroup"); Console.WriteLine("Event Consumer Group created"); try { var job = await this.azureManagementClient.AsaManagementClient.RetrieveAsync( item.Name, null, stoppingToken); Console.WriteLine($"SA job {item.Name} found"); Console.WriteLine($"Updating tenant table..."); tenant.SAJobName = item.Name; await this.tableStorageClient.InsertOrMergeAsync("tenant", tenant); Console.WriteLine($"Deleting tenant operations table..."); await this.tableStorageClient.DeleteAsync(TableName, item); } catch (ResourceNotFoundException) { // Item does not exist... delete the record Console.WriteLine($"SA job {item.Name} does not exist...creating it"); Assembly assembly = Assembly.GetExecutingAssembly(); string template = string.Empty; if (string.Equals(this.config.DeviceTelemetryService.Messages.TelemetryStorageType, TelemetryStorageTypeConstants.Ade, StringComparison.OrdinalIgnoreCase)) { string eventHubNameSpace = string.Format(EventHubNamespaceFormat, item.TenantId.Substring(0, 8)); string primaryKey = this.appConfigurationClient.GetValue($"tenant:{item.TenantId}:eventHubPrimaryKey"); StreamReader reader = new StreamReader(assembly.GetManifestResourceStream("sajob_ADX.json")); template = await reader.ReadToEndAsync(); template = string.Format( template, item.Name, this.config.Global.Location, this.config.Global.StorageAccount.Name, this.config.Global.StorageAccountConnectionString.Split(";")[2].Replace("AccountKey=", string.Empty), tenant.IotHubName, this.azureManagementClient.IotHubManagementClient.GetAccessKey( tenant.IotHubName, "iothubowner"), item.TenantId, this.config.Global.EventHub.Name, this.config.Global.EventHub.RootKey, this.config.Global.CosmosDb.AccountName, this.config.Global.CosmosDb.DocumentDbAuthKey, this.config.Global.LogAnalytics.WorkspaceId, this.config.Global.DiagnosticSetting.Name, $"{item.TenantId}-alerts", eventHubNameSpace, primaryKey); } else { StreamReader reader = new StreamReader(assembly.GetManifestResourceStream("sajob.json")); template = await reader.ReadToEndAsync(); template = string.Format( template, item.Name, this.config.Global.Location, this.config.Global.StorageAccount.Name, this.config.Global.StorageAccountConnectionString.Split(";")[2].Replace("AccountKey=", string.Empty), tenant.IotHubName, this.azureManagementClient.IotHubManagementClient.GetAccessKey( tenant.IotHubName, "iothubowner"), item.TenantId, this.config.Global.EventHub.Name, this.config.Global.EventHub.RootKey, this.config.Global.CosmosDb.AccountName, this.config.Global.CosmosDb.DocumentDbAuthKey, this.config.Global.LogAnalytics.WorkspaceId, this.config.Global.DiagnosticSetting.Name); } await this.azureManagementClient.DeployTemplateAsync(template); } } break; case TenantOperation.DpsDeletion: try { Console.WriteLine($"Deleting {item.Name}..."); await this.azureManagementClient.DpsManagmentClient.DeleteAsync(item.Name); } catch (ResourceNotFoundException) { Console.WriteLine($"Deleting Table Operation Record..."); await this.tableStorageClient.DeleteAsync(TableName, item); } break; case TenantOperation.GrafanaDashboardCreation: { Console.WriteLine($"Creating Grafana Organization."); string orgId = await this.grafanaClient.CreateOrganization(item.TenantId); await this.appConfigurationClient.SetValueAsync(string.Format(GrafanaOrgIdNameFormat, item.TenantId), orgId); Console.WriteLine($"Creating APIKey for Organization:{orgId}"); string apiKey = await this.grafanaClient.CreateAPIKey(orgId); await this.keyVaultClient.SetValueAsync(string.Format(GrafanaAPIKeyNameFormat, item.TenantId), apiKey); Console.WriteLine($"Adding admin user to Organization:{orgId}"); await this.grafanaClient.AddUserToOrg("admin", GrafanaRoleType.Admin, apiKey); Console.WriteLine($"Adding Tenant:{item.TenantId} users to Grafana Organization:{orgId}"); IdentityGatewayApiListModel users = await this.identityGatewayClient.GetAllUsersForTenant(item.TenantId); foreach (var userDetals in users.Models) { GrafanaGlobalUserRequestModel user = new GrafanaGlobalUserRequestModel(userDetals.Name, userDetals.Name, userDetals.UserId, GrafanaPassword); await this.grafanaClient.AddGlobalUser(user); await this.grafanaClient.AddUserToOrg(userDetals.UserId, GrafanaRoleType.Admin, apiKey); } string tenantIdSubstring = item.TenantId.Substring(0, 8); string mainDashboardName = $"{tenantIdSubstring}-Dashboard"; string mainDashboardUid = tenantIdSubstring; string adminDashboardName = $"{tenantIdSubstring}-AdminDashboard"; string adminDashboardUid = $"{tenantIdSubstring}-adm"; var tenant = await this.tableStorageClient.RetrieveAsync <TenantModel>( "tenant", item.TenantId.Substring(0, 1), item.TenantId); Assembly assembly = Assembly.GetExecutingAssembly(); Console.WriteLine($"Adding Azure Monitor data source to Grafana Organization:{orgId}."); StreamReader reader = new StreamReader(assembly.GetManifestResourceStream("sample-azuremonitor-datasource-template.json")); string template = await reader.ReadToEndAsync(); template = string.Format( template, this.config.Global.AzureActiveDirectory.AppId, this.config.Global.AzureActiveDirectory.TenantId, this.config.Global.AzureActiveDirectory.AppSecret); await this.grafanaClient.AddDataSource(template, apiKey); Console.WriteLine($"Adding Data Explorer data source to Grafana Organization:{orgId}."); reader = new StreamReader(assembly.GetManifestResourceStream("sample-dataexplorer-datasource-template.json")); template = await reader.ReadToEndAsync(); template = string.Format( template, this.config.Global.AzureActiveDirectory.AppId, this.config.Global.AzureActiveDirectory.TenantId, this.config.Global.AzureActiveDirectory.AppSecret, $"https://{this.config.Global.DataExplorer.Name}.{this.config.Global.Location}.kusto.windows.net/"); await this.grafanaClient.AddDataSource(template, apiKey); Console.WriteLine($"Adding Main dashboard to Grafana Organization:{orgId}."); reader = new StreamReader(assembly.GetManifestResourceStream("grafana-main-dashboard.json")); template = await reader.ReadToEndAsync(); template = string.Format( template, this.config.ExternalDependencies.GrafanaUrl, $"{adminDashboardUid}/{adminDashboardName}", this.config.Global.SubscriptionId, this.config.Global.ResourceGroup, this.config.Global.LogAnalytics.Name, $"IoT-{item.TenantId}", mainDashboardUid, mainDashboardName, orgId); await this.grafanaClient.CreateAndUpdateDashboard(template, apiKey); Console.WriteLine($"Adding Admin dashboard to Grafana Organization:{orgId}."); reader = new StreamReader(assembly.GetManifestResourceStream("grafana-admin-dashboard.json")); template = await reader.ReadToEndAsync(); template = string.Format( template, this.config.ExternalDependencies.GrafanaUrl, $"{mainDashboardUid}/{mainDashboardName}", this.config.Global.SubscriptionId, this.config.Global.ResourceGroup, this.config.Global.LogAnalytics.Name, tenant.IotHubName, this.config.Global.EventHub.Name, this.config.Global.CosmosDb.AccountName, adminDashboardUid, adminDashboardName, orgId); await this.grafanaClient.CreateAndUpdateDashboard(template, apiKey); await this.appConfigurationClient.SetValueAsync(string.Format(GrafanaUrlNameFormat, item.TenantId), $"{mainDashboardUid}/{mainDashboardName}"); await this.tableStorageClient.DeleteAsync(TableName, item); } break; case TenantOperation.GrafanaDashboardDeletion: { var orgId = this.appConfigurationClient.GetValue(string.Format(GrafanaOrgIdNameFormat, item.TenantId)); bool result = await this.grafanaClient.DeleteOrganizationByUid(orgId); if (result) { await this.appConfigurationClient.DeleteKeyAsync(string.Format(GrafanaUrlNameFormat, item.TenantId)); await this.appConfigurationClient.DeleteKeyAsync(string.Format(GrafanaOrgIdNameFormat, item.TenantId)); await this.tableStorageClient.DeleteAsync(TableName, item); } } break; case TenantOperation.ADXDatabaseDeletion: try { Console.WriteLine($"Deleting {item.Name}..."); await this.azureManagementClient.KustoClusterManagementClient.DeleteDatabaseAsync(item.Name); await this.tableStorageClient.DeleteAsync(TableName, item); } catch (ResourceNotFoundException) { Console.WriteLine($"Deleting Table Operation Record..."); } break; case TenantOperation.EventHubDeletion: try { Console.WriteLine($"Deleting {item.Name}..."); await this.azureManagementClient.EventHubsManagementClient.DeleteEventHubNameSpace(item.Name); await this.tableStorageClient.DeleteAsync(TableName, item); } catch (ResourceNotFoundException) { Console.WriteLine($"Deleting Table Operation Record..."); } break; default: break; } } catch (Exception e) { Console.WriteLine(e.Message); } } await Task.Delay(15000, stoppingToken); } }