github.com/cilium/cilium@v1.16.2/pkg/envoy/envoyadminclient.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package envoy
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"net"
    12  	"net/http"
    13  	"strings"
    14  
    15  	"github.com/sirupsen/logrus"
    16  
    17  	"github.com/cilium/cilium/pkg/safeio"
    18  )
    19  
    20  type EnvoyAdminClient struct {
    21  	adminURL string
    22  	unixPath string
    23  	level    string
    24  }
    25  
    26  func NewEnvoyAdminClientForSocket(envoySocketDir string) *EnvoyAdminClient {
    27  	return &EnvoyAdminClient{
    28  		// Needs to be provided to envoy (received as ':authority') - even though we Dial to a Unix domain socket.
    29  		adminURL: fmt.Sprintf("http://%s/", "envoy-admin"),
    30  		unixPath: getAdminSocketPath(envoySocketDir),
    31  	}
    32  }
    33  
    34  func (a *EnvoyAdminClient) transact(query string) error {
    35  	// Use a custom dialer to use a Unix domain socket for an HTTP connection.
    36  	var conn net.Conn
    37  	var err error
    38  	client := &http.Client{
    39  		Transport: &http.Transport{
    40  			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
    41  				conn, err = net.Dial("unix", a.unixPath)
    42  				return conn, err
    43  			},
    44  		},
    45  	}
    46  
    47  	resp, err := client.Post(a.adminURL+query, "", nil)
    48  	if err != nil {
    49  		return err
    50  	}
    51  	defer conn.Close()
    52  	defer resp.Body.Close()
    53  	body, err := safeio.ReadAllLimit(resp.Body, safeio.MB)
    54  	if err != nil {
    55  		return err
    56  	}
    57  	ret := strings.Replace(string(body), "\r", "", -1)
    58  	log.Debugf("Envoy: Admin response to %s: %s", query, ret)
    59  	return nil
    60  }
    61  
    62  // ChangeLogLevel changes Envoy log level to correspond to the logrus log level 'level'.
    63  func (a *EnvoyAdminClient) ChangeLogLevel(level logrus.Level) error {
    64  	envoyLevel := mapLogLevel(level)
    65  
    66  	if envoyLevel == a.level {
    67  		log.Debugf("Envoy: Log level is already set as: %v", envoyLevel)
    68  		return nil
    69  	}
    70  
    71  	err := a.transact("logging?level=" + envoyLevel)
    72  	if err != nil {
    73  		log.WithError(err).Warnf("Envoy: Failed to set log level to: %v", envoyLevel)
    74  	} else {
    75  		a.level = envoyLevel
    76  	}
    77  	return err
    78  }
    79  
    80  func (a *EnvoyAdminClient) quit() error {
    81  	return a.transact("quitquitquit")
    82  }
    83  
    84  // GetEnvoyVersion returns the envoy binary version string
    85  func (a *EnvoyAdminClient) GetEnvoyVersion() (string, error) {
    86  	// Use a custom dialer to use a Unix domain socket for a HTTP connection.
    87  	var conn net.Conn
    88  	var err error
    89  	client := &http.Client{
    90  		Transport: &http.Transport{
    91  			DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
    92  				conn, err = net.Dial("unix", a.unixPath)
    93  				return conn, err
    94  			},
    95  		},
    96  	}
    97  
    98  	resp, err := client.Get(fmt.Sprintf("%s%s", a.adminURL, "server_info"))
    99  	if err != nil {
   100  		return "", fmt.Errorf("failed to call ServerInfo endpoint: %w", err)
   101  	}
   102  	defer conn.Close()
   103  	defer resp.Body.Close()
   104  
   105  	body, err := safeio.ReadAllLimit(resp.Body, safeio.MB)
   106  	if err != nil {
   107  		return "", fmt.Errorf("failed to read ServerInfo response: %w", err)
   108  	}
   109  
   110  	serverInfo := map[string]interface{}{}
   111  	if err := json.Unmarshal(body, &serverInfo); err != nil {
   112  		return "", fmt.Errorf("failed to parse ServerInfo: %w", err)
   113  	}
   114  
   115  	version, ok := serverInfo["version"]
   116  
   117  	if !ok {
   118  		return "", errors.New("failed to read version from ServerInfo")
   119  	}
   120  
   121  	return fmt.Sprintf("%s", version), nil
   122  }