|
| 1 | +// Licensed to Elasticsearch B.V under one or more agreements. |
| 2 | +// Elasticsearch B.V licenses this file to you under the Apache 2.0 License. |
| 3 | +// See the LICENSE file in the project root for more information |
| 4 | + |
| 5 | +using System.IO.Abstractions; |
| 6 | +using System.Security.Cryptography.X509Certificates; |
| 7 | +using Actions.Core.Services; |
| 8 | +using Elastic.Documentation.Assembler.Building; |
| 9 | +using Elastic.Documentation.Configuration; |
| 10 | +using Elastic.Documentation.Configuration.Assembler; |
| 11 | +using Elastic.Documentation.Diagnostics; |
| 12 | +using Microsoft.Extensions.Logging; |
| 13 | +using static Elastic.Documentation.Exporter; |
| 14 | + |
| 15 | +namespace Elastic.Documentation.Assembler.Indexing; |
| 16 | + |
| 17 | +public class AssemblerIndexService( |
| 18 | + ILoggerFactory logFactory, |
| 19 | + AssemblyConfiguration assemblyConfiguration, |
| 20 | + IConfigurationContext configurationContext, |
| 21 | + ICoreService githubActionsService |
| 22 | +) : AssemblerBuildService(logFactory, assemblyConfiguration, configurationContext, githubActionsService) |
| 23 | +{ |
| 24 | + private readonly IConfigurationContext _configurationContext = configurationContext; |
| 25 | + |
| 26 | + /// <summary> |
| 27 | + /// Index documentation to Elasticsearch, calls `docs-builder assembler build --exporters elasticsearch`. Exposes more options |
| 28 | + /// </summary> |
| 29 | + /// <param name="collector"></param> |
| 30 | + /// <param name="fileSystem"></param> |
| 31 | + /// <param name="endpoint">Elasticsearch endpoint, alternatively set env DOCUMENTATION_ELASTIC_URL</param> |
| 32 | + /// <param name="environment">The --environment used to clone ends up being part of the index name</param> |
| 33 | + /// <param name="apiKey">Elasticsearch API key, alternatively set env DOCUMENTATION_ELASTIC_APIKEY</param> |
| 34 | + /// <param name="username">Elasticsearch username (basic auth), alternatively set env DOCUMENTATION_ELASTIC_USERNAME</param> |
| 35 | + /// <param name="password">Elasticsearch password (basic auth), alternatively set env DOCUMENTATION_ELASTIC_PASSWORD</param> |
| 36 | + /// <param name="noSemantic">Index without semantic fields</param> |
| 37 | + /// <param name="searchNumThreads">The number of search threads the inference endpoint should use. Defaults: 8</param> |
| 38 | + /// <param name="indexNumThreads">The number of index threads the inference endpoint should use. Defaults: 8</param> |
| 39 | + /// <param name="bootstrapTimeout">Timeout in minutes for the inference endpoint creation. Defaults: 4</param> |
| 40 | + /// <param name="indexNamePrefix">The prefix for the computed index/alias names. Defaults: semantic-docs</param> |
| 41 | + /// <param name="bufferSize">The number of documents to send to ES as part of the bulk. Defaults: 100</param> |
| 42 | + /// <param name="maxRetries">The number of times failed bulk items should be retried. Defaults: 3</param> |
| 43 | + /// <param name="debugMode">Buffer ES request/responses for better error messages and pass ?pretty to all requests</param> |
| 44 | + /// <param name="proxyAddress">Route requests through a proxy server</param> |
| 45 | + /// <param name="proxyPassword">Proxy server password</param> |
| 46 | + /// <param name="proxyUsername">Proxy server username</param> |
| 47 | + /// <param name="disableSslVerification">Disable SSL certificate validation (EXPERT OPTION)</param> |
| 48 | + /// <param name="certificateFingerprint">Pass a self-signed certificate fingerprint to validate the SSL connection</param> |
| 49 | + /// <param name="certificatePath">Pass a self-signed certificate to validate the SSL connection</param> |
| 50 | + /// <param name="certificateNotRoot">If the certificate is not root but only part of the validation chain pass this</param> |
| 51 | + /// <param name="ctx"></param> |
| 52 | + /// <returns></returns> |
| 53 | + public async Task<bool> Index(IDiagnosticsCollector collector, |
| 54 | + FileSystem fileSystem, |
| 55 | + string? endpoint = null, |
| 56 | + string? environment = null, |
| 57 | + string? apiKey = null, |
| 58 | + string? username = null, |
| 59 | + string? password = null, |
| 60 | + // inference options |
| 61 | + bool? noSemantic = null, |
| 62 | + int? searchNumThreads = null, |
| 63 | + int? indexNumThreads = null, |
| 64 | + int? bootstrapTimeout = null, |
| 65 | + // index options |
| 66 | + string? indexNamePrefix = null, |
| 67 | + // channel buffer options |
| 68 | + int? bufferSize = null, |
| 69 | + int? maxRetries = null, |
| 70 | + // connection options |
| 71 | + bool? debugMode = null, |
| 72 | + string? proxyAddress = null, |
| 73 | + string? proxyPassword = null, |
| 74 | + string? proxyUsername = null, |
| 75 | + bool? disableSslVerification = null, |
| 76 | + string? certificateFingerprint = null, |
| 77 | + string? certificatePath = null, |
| 78 | + bool? certificateNotRoot = null, |
| 79 | + Cancel ctx = default |
| 80 | + ) |
| 81 | + { |
| 82 | + var cfg = _configurationContext.Endpoints.Elasticsearch; |
| 83 | + if (!string.IsNullOrEmpty(endpoint)) |
| 84 | + { |
| 85 | + if (!Uri.TryCreate(endpoint, UriKind.Absolute, out var uri)) |
| 86 | + collector.EmitGlobalError($"'{endpoint}' is not a valid URI"); |
| 87 | + else |
| 88 | + cfg.Uri = uri; |
| 89 | + } |
| 90 | + |
| 91 | + if (!string.IsNullOrEmpty(apiKey)) |
| 92 | + cfg.ApiKey = apiKey; |
| 93 | + if (!string.IsNullOrEmpty(username)) |
| 94 | + cfg.Username = username; |
| 95 | + if (!string.IsNullOrEmpty(password)) |
| 96 | + cfg.Password = password; |
| 97 | + |
| 98 | + if (searchNumThreads.HasValue) |
| 99 | + cfg.SearchNumThreads = searchNumThreads.Value; |
| 100 | + if (indexNumThreads.HasValue) |
| 101 | + cfg.IndexNumThreads = indexNumThreads.Value; |
| 102 | + if (!string.IsNullOrEmpty(indexNamePrefix)) |
| 103 | + cfg.IndexNamePrefix = indexNamePrefix; |
| 104 | + if (bufferSize.HasValue) |
| 105 | + cfg.BufferSize = bufferSize.Value; |
| 106 | + if (maxRetries.HasValue) |
| 107 | + cfg.MaxRetries = maxRetries.Value; |
| 108 | + if (debugMode.HasValue) |
| 109 | + cfg.DebugMode = debugMode.Value; |
| 110 | + if (!string.IsNullOrEmpty(certificateFingerprint)) |
| 111 | + cfg.CertificateFingerprint = certificateFingerprint; |
| 112 | + if (!string.IsNullOrEmpty(proxyAddress)) |
| 113 | + cfg.ProxyAddress = proxyAddress; |
| 114 | + if (!string.IsNullOrEmpty(proxyPassword)) |
| 115 | + cfg.ProxyPassword = proxyPassword; |
| 116 | + if (!string.IsNullOrEmpty(proxyUsername)) |
| 117 | + cfg.ProxyUsername = proxyUsername; |
| 118 | + if (disableSslVerification.HasValue) |
| 119 | + cfg.DisableSslVerification = disableSslVerification.Value; |
| 120 | + if (!string.IsNullOrEmpty(certificatePath)) |
| 121 | + { |
| 122 | + if (!fileSystem.File.Exists(certificatePath)) |
| 123 | + collector.EmitGlobalError($"'{certificatePath}' does not exist"); |
| 124 | + var bytes = await fileSystem.File.ReadAllBytesAsync(certificatePath, ctx); |
| 125 | + var loader = X509CertificateLoader.LoadCertificate(bytes); |
| 126 | + cfg.Certificate = loader; |
| 127 | + } |
| 128 | + |
| 129 | + if (certificateNotRoot.HasValue) |
| 130 | + cfg.CertificateIsNotRoot = certificateNotRoot.Value; |
| 131 | + if (bootstrapTimeout.HasValue) |
| 132 | + cfg.BootstrapTimeout = bootstrapTimeout.Value; |
| 133 | + |
| 134 | + var exporters = new HashSet<Exporter> { noSemantic.GetValueOrDefault(false) ? ElasticsearchNoSemantic : Elasticsearch }; |
| 135 | + |
| 136 | + return await BuildAll(collector, strict: false, environment, metadataOnly: true, exporters, fileSystem, ctx); |
| 137 | + } |
| 138 | +} |
0 commit comments