Exemplo n.º 1
0
        private static YarpIngressOptions HandleAnnotations(YarpIngressContext context, V1ObjectMeta metadata)
        {
            var options     = context.Options;
            var annotations = metadata.Annotations;

            if (annotations == null)
            {
                return(options);
            }

            if (annotations.TryGetValue("yarp.ingress.kubernetes.io/backend-protocol", out var http))
            {
                options.Https = http.Equals("https", StringComparison.OrdinalIgnoreCase);
            }

            // metadata to support:
            // rewrite target
            // auth
            // http or https
            // default backend
            // CORS
            // GRPC
            // HTTP2
            // Conneciton limits
            // rate limits

            // backend health checks.
            return(options);
        }
Exemplo n.º 2
0
    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;
        }
    }
Exemplo n.º 3
0
        private static void HandleIngressRule(YarpIngressContext context, List <Endpoints> endpoints, IList <V1EndpointSubset> defaultSubsets, V1IngressRule rule)
        {
            var http = rule.Http;

            foreach (var path in http.Paths ?? Enumerable.Empty <V1HTTPIngressPath>())
            {
                HandleIngressRulePath(context, endpoints, defaultSubsets, rule, path);
            }
        }
Exemplo n.º 4
0
        public async Task ParsingTests(string name)
        {
            var(ingress, endpoints) = await GetKubernetesInfo(name).ConfigureAwait(false);

            var context = new YarpIngressContext(ingress, endpoints);

            YarpParser.CovertFromKubernetesIngress(context);

            VerifyClusters(JsonSerializer.Serialize(context.Clusters), name);
            VerifyRoutes(JsonSerializer.Serialize(context.Routes), name);
        }
Exemplo n.º 5
0
 private static void CreateClusters(YarpIngressContext context)
 {
     foreach (var cluster in context.ClusterTransfers)
     {
         context.Clusters.Add(new Cluster()
         {
             Destinations = cluster.Value.Destinations,
             Id           = cluster.Value.ClusterId
         });
     }
 }
Exemplo n.º 6
0
    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);
        }
    }
Exemplo n.º 7
0
    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);
    }
Exemplo n.º 8
0
    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);
        }
    }
Exemplo n.º 9
0
    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;
        }
    }
Exemplo n.º 10
0
    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);
    }
Exemplo n.º 11
0
        private static void HandleIngressRulePath(YarpIngressContext context, List <Endpoints> endpoints, IList <V1EndpointSubset> defaultSubsets, V1IngressRule rule, V1HTTPIngressPath path)
        {
            var backend = path.Backend;
            var service = backend.Service;
            var subsets = defaultSubsets;

            var clusters = context.ClusterTransfers;
            var routes   = context.Routes;

            if (!string.IsNullOrEmpty(service?.Name))
            {
                subsets = endpoints.SingleOrDefault(x => x.Name == service?.Name).Subsets;
            }

            // make sure cluster is present
            foreach (var subset in subsets ?? Enumerable.Empty <V1EndpointSubset>())
            {
                foreach (var port in subset.Ports ?? Enumerable.Empty <V1EndpointPort>())
                {
                    var key = $"{service?.Name}:{port.Port}";

                    if (!clusters.ContainsKey(key))
                    {
                        clusters.Add(key, new ClusterTrasfer());
                    }
                    var cluster = clusters[key];
                    cluster.ClusterId = key;

                    foreach (var address in subset.Addresses ?? Enumerable.Empty <V1EndpointAddress>())
                    {
                        var ip = address.Ip;

                        if (!MatchesPort(port, service?.Port))
                        {
                            continue;
                        }

                        var protocol = context.Options.Https ? "https" : "http";
                        var uri      = $"{protocol}://{address.Ip}:{port.Port}";
                        cluster.Destinations[uri] = new Destination()
                        {
                            Address = uri
                        };

                        var pathMatch = FixupPathMatch(path);
                        var host      = rule.Host;

                        routes.Add(new ProxyRoute()
                        {
                            Match = new ProxyMatch()
                            {
                                Hosts = host != null ? new[] { host } : Array.Empty <string>(),
                                Path  = pathMatch
                            },
                            ClusterId = cluster.ClusterId,
                            RouteId   = path.Path
                        });
                    }
                }
            }
        }
Exemplo n.º 12
0
    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
                    };
                }
            }
        }
    }