public async Task ProcessAsync(CancellationToken cancellationToken) { try { var ingresses = _cache.GetIngresses().ToArray(); var configContext = new YarpConfigContext(); foreach (var ingress in ingresses) { if (_cache.TryGetReconcileData(new NamespacedName(ingress.Metadata.NamespaceProperty, ingress.Metadata.Name), out var data)) { var ingressContext = new YarpIngressContext(ingress, data.ServiceList, data.EndpointsList); YarpParser.ConvertFromKubernetesIngress(ingressContext, configContext); } } var clusters = configContext.BuildClusterConfig(); _logger.LogInformation(JsonSerializer.Serialize(configContext.Routes)); _logger.LogInformation(JsonSerializer.Serialize(clusters)); await _updateConfig.UpdateAsync(configContext.Routes, clusters, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.LogWarning(ex, "Uncaught exception occured while reconciling"); throw; } }
public async Task ParsingTests(string name) { var cache = await GetKubernetesInfo(name).ConfigureAwait(false); var configContext = new YarpConfigContext(); var ingresses = cache.GetIngresses().ToArray(); foreach (var ingress in ingresses) { if (cache.TryGetReconcileData(new NamespacedName(ingress.Metadata.NamespaceProperty, ingress.Metadata.Name), out var data)) { var ingressContext = new YarpIngressContext(ingress, data.ServiceList, data.EndpointsList); YarpParser.ConvertFromKubernetesIngress(ingressContext, configContext); } } VerifyClusters(JsonSerializer.Serialize(configContext.BuildClusterConfig()), name); VerifyRoutes(JsonSerializer.Serialize(configContext.Routes), name); }
public async Task ProcessAsync(CancellationToken cancellationToken) { try { var ingresses = _cache.GetIngresses().ToArray(); var message = new Message { MessageType = MessageType.Update, Key = string.Empty, }; var configContext = new YarpConfigContext(); foreach (var ingress in ingresses) { if (_cache.TryGetReconcileData(new NamespacedName(ingress.Metadata.NamespaceProperty, ingress.Metadata.Name), out var data)) { var ingressContext = new YarpIngressContext(ingress, data.ServiceList, data.EndpointsList); YarpParser.ConvertFromKubernetesIngress(ingressContext, configContext); } } message.Cluster = configContext.BuildClusterConfig(); message.Routes = configContext.Routes; var bytes = JsonSerializer.SerializeToUtf8Bytes(message); _logger.LogInformation(JsonSerializer.Serialize(message)); await _dispatcher.SendAsync(null, bytes, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.LogWarning(ex.Message); throw; } }
public async Task ParsingTests(string name) { var ingressClass = KubeResourceGenerator.CreateIngressClass("yarp", "microsoft.com/ingress-yarp", true); var cache = await GetKubernetesInfo(name, ingressClass).ConfigureAwait(false); var configContext = new YarpConfigContext(); var ingresses = cache.GetIngresses().ToArray(); foreach (var ingress in ingresses) { if (cache.TryGetReconcileData(new NamespacedName(ingress.Metadata.NamespaceProperty, ingress.Metadata.Name), out var data)) { var ingressContext = new YarpIngressContext(ingress, data.ServiceList, data.EndpointsList); YarpParser.ConvertFromKubernetesIngress(ingressContext, configContext); } } var options = new JsonSerializerOptions { Converters = { new JsonStringEnumConverter() } }; VerifyClusters(JsonSerializer.Serialize(configContext.BuildClusterConfig(), options), name); VerifyRoutes(JsonSerializer.Serialize(configContext.Routes, options), name); }
private static void HandleIngressRulePath(YarpIngressContext ingressContext, V1ServicePort servicePort, List <Endpoints> endpoints, IList <V1EndpointSubset> defaultSubsets, V1IngressRule rule, V1HTTPIngressPath path, YarpConfigContext configContext) { var backend = path.Backend; var ingressServiceBackend = backend.Service; var subsets = defaultSubsets; var clusters = configContext.ClusterTransfers; var routes = configContext.Routes; if (!string.IsNullOrEmpty(ingressServiceBackend?.Name)) { subsets = endpoints.SingleOrDefault(x => x.Name == ingressServiceBackend?.Name).Subsets; } // Each ingress rule path can only be for one service var key = ingressServiceBackend.Port.Number.HasValue ? $"{ingressServiceBackend?.Name}:{ingressServiceBackend?.Port.Number}" : $"{ingressServiceBackend?.Name}:{ingressServiceBackend?.Port.Name}"; if (!clusters.ContainsKey(key)) { clusters.Add(key, new ClusterTransfer()); } var cluster = clusters[key]; cluster.ClusterId = key; // make sure cluster is present foreach (var subset in subsets ?? Enumerable.Empty <V1EndpointSubset>()) { foreach (var port in subset.Ports ?? Enumerable.Empty <V1EndpointPort>()) { if (!MatchesPort(port, servicePort.TargetPort)) { continue; } var pathMatch = FixupPathMatch(path); var host = rule.Host; routes.Add(new RouteConfig() { Match = new RouteMatch() { Hosts = host != null ? new[] { host } : Array.Empty <string>(), Path = pathMatch }, ClusterId = cluster.ClusterId, RouteId = $"{ingressContext.Ingress.Metadata.Name}:{path.Path}" }); // Add destination for every endpoint address foreach (var address in subset.Addresses ?? Enumerable.Empty <V1EndpointAddress>()) { var protocol = ingressContext.Options.Https ? "https" : "http"; var uri = $"{protocol}://{address.Ip}:{port.Port}"; cluster.Destinations[uri] = new DestinationConfig() { Address = uri }; } } } }
private static void HandleIngressRule(YarpIngressContext ingressContext, List <Endpoints> endpoints, IList <V1EndpointSubset> defaultSubsets, V1IngressRule rule, YarpConfigContext configContext) { var http = rule.Http; foreach (var path in http.Paths ?? Enumerable.Empty <V1HTTPIngressPath>()) { var service = ingressContext.Services.SingleOrDefault(s => s.Metadata.Name == path.Backend.Service.Name); var servicePort = service.Spec.Ports.SingleOrDefault(p => MatchesPort(p, path.Backend.Service.Port)); HandleIngressRulePath(ingressContext, servicePort, endpoints, defaultSubsets, rule, path, configContext); } }
internal static void ConvertFromKubernetesIngress(YarpIngressContext ingressContext, YarpConfigContext configContext) { var spec = ingressContext.Ingress.Spec; var defaultBackend = spec?.DefaultBackend; var defaultService = defaultBackend?.Service; IList <V1EndpointSubset> defaultSubsets = default; if (!string.IsNullOrEmpty(defaultService?.Name)) { defaultSubsets = ingressContext.Endpoints.SingleOrDefault(x => x.Name == defaultService?.Name).Subsets; } // cluster can contain multiple replicas for each destination, need to know the lookup base don endpoints var options = HandleAnnotations(ingressContext, ingressContext.Ingress.Metadata); foreach (var rule in spec.Rules ?? Enumerable.Empty <V1IngressRule>()) { HandleIngressRule(ingressContext, ingressContext.Endpoints, defaultSubsets, rule, configContext); } }