예제 #1
0
        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);
            }
        }