istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/test/framework/components/opentelemetry/kube.go (about)

     1  // Copyright Istio Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package opentelemetry
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  	"os"
    21  	"strings"
    22  
    23  	"istio.io/istio/pkg/test/env"
    24  	"istio.io/istio/pkg/test/framework/components/cluster"
    25  	"istio.io/istio/pkg/test/framework/components/istio"
    26  	"istio.io/istio/pkg/test/framework/resource"
    27  	testKube "istio.io/istio/pkg/test/kube"
    28  )
    29  
    30  type otel struct {
    31  	id      resource.ID
    32  	cluster cluster.Cluster
    33  }
    34  
    35  const (
    36  	appName         = "opentelemetry-collector"
    37  	remoteOtelEntry = `
    38  apiVersion: networking.istio.io/v1alpha3
    39  kind: Gateway
    40  metadata:
    41    name: otel-gateway
    42    namespace: istio-system
    43  spec:
    44    selector:
    45      istio: ingressgateway
    46    servers:
    47    - port:
    48        number: 55678
    49        name: http-tracing-span
    50        protocol: HTTP
    51      hosts:
    52      - "opentelemetry-collector.{INGRESS_DOMAIN}"
    53  ---
    54  apiVersion: networking.istio.io/v1alpha3
    55  kind: VirtualService
    56  metadata:
    57    name: opentelemetry-collector
    58    namespace: istio-system
    59  spec:
    60    hosts:
    61    - "opentelemetry-collector.{INGRESS_DOMAIN}"
    62    gateways:
    63    - otel-gateway
    64    http:
    65    - match:
    66      - port: 55678
    67      route:
    68      - destination:
    69          host: opentelemetry-collector
    70          port:
    71            number: 55678
    72  ---
    73  apiVersion: networking.istio.io/v1alpha3
    74  kind: DestinationRule
    75  metadata:
    76    name: opentelemetry-collector
    77    namespace: istio-system
    78  spec:
    79    host: opentelemetry-collector
    80    trafficPolicy:
    81      tls:
    82        mode: DISABLE
    83  ---`
    84  
    85  	extServiceEntry = `
    86  apiVersion: networking.istio.io/v1alpha3
    87  kind: ServiceEntry
    88  metadata:
    89    name: opentelemetry-collector
    90  spec:
    91    hosts:
    92    # must be of form name.namespace.global
    93    - opentelemetry-collector.istio-system.global
    94    # Treat remote cluster services as part of the service mesh
    95    # as all clusters in the service mesh share the same root of trust.
    96    location: MESH_INTERNAL
    97    ports:
    98    - name: http-tracing-span
    99      number: 55678
   100      protocol: http
   101    resolution: DNS
   102    addresses:
   103    # the IP address to which opentelemetry-collector.istio-system.global will resolve to
   104    # must be unique for each remote service, within a given cluster.
   105    # This address need not be routable. Traffic for this IP will be captured
   106    # by the sidecar and routed appropriately.
   107    - 240.0.0.2
   108    endpoints:
   109    # This is the routable address of the ingress gateway in cluster1 that
   110    # sits in front of otel service. Traffic from the sidecar will be
   111    # routed to this address.
   112    - address: {INGRESS_DOMAIN}
   113      ports:
   114        http-tracing-span: 15443 # Do not change this port value
   115  `
   116  )
   117  
   118  func getYaml() (string, error) {
   119  	b, err := os.ReadFile(env.OtelCollectorInstallFilePath)
   120  	if err != nil {
   121  		return "", err
   122  	}
   123  	return string(b), nil
   124  }
   125  
   126  func install(ctx resource.Context, ns string) error {
   127  	y, err := getYaml()
   128  	if err != nil {
   129  		return err
   130  	}
   131  	return ctx.ConfigKube().YAML(ns, y).Apply()
   132  }
   133  
   134  func installServiceEntry(ctx resource.Context, ns, ingressAddr string) error {
   135  	// Setup remote access to zipkin in cluster
   136  	yaml := strings.ReplaceAll(remoteOtelEntry, "{INGRESS_DOMAIN}", ingressAddr)
   137  	if err := ctx.ConfigIstio().YAML(ns, yaml).Apply(); err != nil {
   138  		return err
   139  	}
   140  	// For all other clusters, add a service entry so that can access
   141  	// zipkin in cluster installed.
   142  	yaml = strings.ReplaceAll(extServiceEntry, "{INGRESS_DOMAIN}", ingressAddr)
   143  	if err := ctx.ConfigIstio().YAML(ns, yaml).Apply(); err != nil {
   144  		return err
   145  	}
   146  	return nil
   147  }
   148  
   149  func newCollector(ctx resource.Context, c Config) (*otel, error) {
   150  	o := &otel{
   151  		cluster: ctx.Clusters().GetOrDefault(c.Cluster),
   152  	}
   153  	ctx.TrackResource(o)
   154  
   155  	istioCfg, err := istio.DefaultConfig(ctx)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	ns := istioCfg.TelemetryNamespace
   161  	if err := install(ctx, ns); err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	f := testKube.NewSinglePodFetch(o.cluster, ns, fmt.Sprintf("app=%s", appName))
   166  	_, err = testKube.WaitUntilPodsAreReady(f)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	isIP := net.ParseIP(c.IngressAddr).String() != "<nil>"
   172  	ingressDomain := c.IngressAddr
   173  	if isIP {
   174  		ingressDomain = fmt.Sprintf("%s.sslip.io", strings.ReplaceAll(c.IngressAddr, ":", "-"))
   175  	}
   176  
   177  	err = installServiceEntry(ctx, istioCfg.TelemetryNamespace, ingressDomain)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	return o, nil
   182  }
   183  
   184  func (o *otel) ID() resource.ID {
   185  	return o.id
   186  }