tools/code/publisher/ApiDiagnostic.cs (225 lines of code) (raw):

using Azure.Core.Pipeline; using common; using LanguageExt; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace publisher; public delegate ValueTask PutApiDiagnostics(CancellationToken cancellationToken); public delegate ValueTask DeleteApiDiagnostics(CancellationToken cancellationToken); public delegate Option<(ApiDiagnosticName Name, ApiName ApiName)> TryParseApiDiagnosticName(FileInfo file); public delegate bool IsApiDiagnosticNameInSourceControl(ApiDiagnosticName name, ApiName apiName); public delegate ValueTask PutApiDiagnostic(ApiDiagnosticName name, ApiName apiName, CancellationToken cancellationToken); public delegate ValueTask<Option<ApiDiagnosticDto>> FindApiDiagnosticDto(ApiDiagnosticName name, ApiName apiName, CancellationToken cancellationToken); public delegate ValueTask PutApiDiagnosticInApim(ApiDiagnosticName name, ApiDiagnosticDto dto, ApiName apiName, CancellationToken cancellationToken); public delegate ValueTask DeleteApiDiagnostic(ApiDiagnosticName name, ApiName apiName, CancellationToken cancellationToken); public delegate ValueTask DeleteApiDiagnosticFromApim(ApiDiagnosticName name, ApiName apiName, CancellationToken cancellationToken); internal static class ApiDiagnosticModule { public static void ConfigurePutApiDiagnostics(IHostApplicationBuilder builder) { CommonModule.ConfigureGetPublisherFiles(builder); ConfigureTryParseApiDiagnosticName(builder); ConfigureIsApiDiagnosticNameInSourceControl(builder); ConfigurePutApiDiagnostic(builder); builder.Services.TryAddSingleton(GetPutApiDiagnostics); } private static PutApiDiagnostics GetPutApiDiagnostics(IServiceProvider provider) { var getPublisherFiles = provider.GetRequiredService<GetPublisherFiles>(); var tryParseName = provider.GetRequiredService<TryParseApiDiagnosticName>(); var isNameInSourceControl = provider.GetRequiredService<IsApiDiagnosticNameInSourceControl>(); var put = provider.GetRequiredService<PutApiDiagnostic>(); var activitySource = provider.GetRequiredService<ActivitySource>(); var logger = provider.GetRequiredService<ILogger>(); return async cancellationToken => { using var _ = activitySource.StartActivity(nameof(PutApiDiagnostics)); logger.LogInformation("Putting diagnostics..."); await getPublisherFiles() .Choose(tryParseName.Invoke) .Where(resource => isNameInSourceControl(resource.Name, resource.ApiName)) .Distinct() .IterParallel(put.Invoke, cancellationToken); }; } private static void ConfigureTryParseApiDiagnosticName(IHostApplicationBuilder builder) { AzureModule.ConfigureManagementServiceDirectory(builder); builder.Services.TryAddSingleton(GetTryParseApiDiagnosticName); } private static TryParseApiDiagnosticName GetTryParseApiDiagnosticName(IServiceProvider provider) { var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>(); return file => from informationFile in ApiDiagnosticInformationFile.TryParse(file, serviceDirectory) select (informationFile.Parent.Name, informationFile.Parent.Parent.Parent.Name); } private static void ConfigureIsApiDiagnosticNameInSourceControl(IHostApplicationBuilder builder) { CommonModule.ConfigureGetArtifactFiles(builder); AzureModule.ConfigureManagementServiceDirectory(builder); builder.Services.TryAddSingleton(GetIsApiDiagnosticNameInSourceControl); } private static IsApiDiagnosticNameInSourceControl GetIsApiDiagnosticNameInSourceControl(IServiceProvider provider) { var getArtifactFiles = provider.GetRequiredService<GetArtifactFiles>(); var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>(); return doesInformationFileExist; bool doesInformationFileExist(ApiDiagnosticName name, ApiName apiName) { var artifactFiles = getArtifactFiles(); var informationFile = ApiDiagnosticInformationFile.From(name, apiName, serviceDirectory); return artifactFiles.Contains(informationFile.ToFileInfo()); } } private static void ConfigurePutApiDiagnostic(IHostApplicationBuilder builder) { ConfigureFindApiDiagnosticDto(builder); ConfigurePutApiDiagnosticInApim(builder); builder.Services.TryAddSingleton(GetPutApiDiagnostic); } private static PutApiDiagnostic GetPutApiDiagnostic(IServiceProvider provider) { var findDto = provider.GetRequiredService<FindApiDiagnosticDto>(); var putInApim = provider.GetRequiredService<PutApiDiagnosticInApim>(); var activitySource = provider.GetRequiredService<ActivitySource>(); return async (name, apiName, cancellationToken) => { using var _ = activitySource.StartActivity(nameof(PutApiDiagnostic)) ?.AddTag("api.name", apiName) ?.AddTag("api_diagnostic.name", name); var dtoOption = await findDto(name, apiName, cancellationToken); await dtoOption.IterTask(async dto => await putInApim(name, dto, apiName, cancellationToken)); }; } private static void ConfigureFindApiDiagnosticDto(IHostApplicationBuilder builder) { AzureModule.ConfigureManagementServiceDirectory(builder); CommonModule.ConfigureTryGetFileContents(builder); ConfigurationModule.ConfigureConfigurationJson(builder); builder.Services.TryAddSingleton(GetFindApiDiagnosticDto); } public static FindApiDiagnosticDto GetFindApiDiagnosticDto(IServiceProvider provider) { var serviceDirectory = provider.GetRequiredService<ManagementServiceDirectory>(); var tryGetFileContents = provider.GetRequiredService<TryGetFileContents>(); var configurationJson = provider.GetRequiredService<ConfigurationJson>(); return async (name, apiName, cancellationToken) => { var informationFile = ApiDiagnosticInformationFile.From(name, apiName, serviceDirectory); var contentsOption = await tryGetFileContents(informationFile.ToFileInfo(), cancellationToken); return from contents in contentsOption let dto = contents.ToObjectFromJson<ApiDiagnosticDto>() select overrideDto(dto, name, apiName); }; ApiDiagnosticDto overrideDto(ApiDiagnosticDto dto, ApiDiagnosticName name, ApiName apiName) { var diagnosticSectionOption = // Get the apis section from the configuration json from apis in configurationJson.Value .TryGetJsonArrayProperty("apis") .ToOption() // Get the API with the specified name from api in apis.PickJsonObjects() .Where(api => api.TryGetStringProperty("name") .Where(name => name.Equals(apiName.ToString(), StringComparison.OrdinalIgnoreCase)) .Any()) .HeadOrNone() // Get the diagnostics section from the API from diagnostics in api.TryGetJsonArrayProperty("diagnostics") .ToOption() // Get the diagnostic with the specified name from diagnostic in diagnostics.PickJsonObjects() .Where(diagnostic => diagnostic.TryGetStringProperty("name") .Where(name => name.Equals(name.ToString(), StringComparison.OrdinalIgnoreCase)) .Any()) .HeadOrNone() select diagnostic; return diagnosticSectionOption.Map(json => OverrideDtoFactory.Override(dto, json)) .IfNone(dto); } } private static void ConfigurePutApiDiagnosticInApim(IHostApplicationBuilder builder) { AzureModule.ConfigureManagementServiceUri(builder); AzureModule.ConfigureHttpPipeline(builder); builder.Services.TryAddSingleton(GetPutApiDiagnosticInApim); } private static PutApiDiagnosticInApim GetPutApiDiagnosticInApim(IServiceProvider provider) { var serviceUri = provider.GetRequiredService<ManagementServiceUri>(); var pipeline = provider.GetRequiredService<HttpPipeline>(); var logger = provider.GetRequiredService<ILogger>(); return async (name, dto, apiName, cancellationToken) => { logger.LogInformation("Adding diagnostic {ApiDiagnosticName} to API {ApiName}...", name, apiName); var resourceUri = ApiDiagnosticUri.From(name, apiName, serviceUri); await resourceUri.PutDto(dto, pipeline, cancellationToken); }; } public static void ConfigureDeleteApiDiagnostics(IHostApplicationBuilder builder) { CommonModule.ConfigureGetPublisherFiles(builder); ConfigureTryParseApiDiagnosticName(builder); ConfigureIsApiDiagnosticNameInSourceControl(builder); ConfigureDeleteApiDiagnostic(builder); builder.Services.TryAddSingleton(GetDeleteApiDiagnostics); } private static DeleteApiDiagnostics GetDeleteApiDiagnostics(IServiceProvider provider) { var getPublisherFiles = provider.GetRequiredService<GetPublisherFiles>(); var tryParseName = provider.GetRequiredService<TryParseApiDiagnosticName>(); var isNameInSourceControl = provider.GetRequiredService<IsApiDiagnosticNameInSourceControl>(); var delete = provider.GetRequiredService<DeleteApiDiagnostic>(); var activitySource = provider.GetRequiredService<ActivitySource>(); var logger = provider.GetRequiredService<ILogger>(); return async cancellationToken => { using var _ = activitySource.StartActivity(nameof(DeleteApiDiagnostics)); logger.LogInformation("Deleting diagnostics..."); await getPublisherFiles() .Choose(tryParseName.Invoke) .Where(resource => isNameInSourceControl(resource.Name, resource.ApiName) is false) .Distinct() .IterParallel(delete.Invoke, cancellationToken); }; } private static void ConfigureDeleteApiDiagnostic(IHostApplicationBuilder builder) { ConfigureDeleteApiDiagnosticFromApim(builder); builder.Services.TryAddSingleton(GetDeleteApiDiagnostic); } private static DeleteApiDiagnostic GetDeleteApiDiagnostic(IServiceProvider provider) { var deleteFromApim = provider.GetRequiredService<DeleteApiDiagnosticFromApim>(); var activitySource = provider.GetRequiredService<ActivitySource>(); return async (name, apiName, cancellationToken) => { using var _ = activitySource.StartActivity(nameof(DeleteApiDiagnostic)) ?.AddTag("api.name", apiName) ?.AddTag("api_diagnostic.name", name); await deleteFromApim(name, apiName, cancellationToken); }; } private static void ConfigureDeleteApiDiagnosticFromApim(IHostApplicationBuilder builder) { AzureModule.ConfigureManagementServiceUri(builder); AzureModule.ConfigureHttpPipeline(builder); builder.Services.TryAddSingleton(GetDeleteApiDiagnosticFromApim); } private static DeleteApiDiagnosticFromApim GetDeleteApiDiagnosticFromApim(IServiceProvider provider) { var serviceUri = provider.GetRequiredService<ManagementServiceUri>(); var pipeline = provider.GetRequiredService<HttpPipeline>(); var logger = provider.GetRequiredService<ILogger>(); return async (name, apiName, cancellationToken) => { logger.LogInformation("Removing diagnostic {ApiDiagnosticName} from API {ApiName}...", name, apiName); var resourceUri = ApiDiagnosticUri.From(name, apiName, serviceUri); await resourceUri.Delete(pipeline, cancellationToken); }; } }