mirror of
https://github.com/ceph/ceph-csi.git
synced 2025-06-13 10:33:35 +00:00
Changes to accommodate client-go changes and kube vendor update
to v1.18.0 Signed-off-by: Humble Chirammal <hchiramm@redhat.com>
This commit is contained in:
committed by
mergify[bot]
parent
4c96ad3c85
commit
34fc1d847e
159
vendor/github.com/kubernetes-csi/csi-lib-utils/connection/connection.go
generated
vendored
159
vendor/github.com/kubernetes-csi/csi-lib-utils/connection/connection.go
generated
vendored
@ -19,16 +19,12 @@ package connection
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||
"github.com/kubernetes-csi/csi-lib-utils/metrics"
|
||||
"github.com/kubernetes-csi/csi-lib-utils/protosanitizer"
|
||||
"google.golang.org/grpc"
|
||||
"k8s.io/klog"
|
||||
@ -63,8 +59,8 @@ const terminationLogPath = "/dev/termination-log"
|
||||
//
|
||||
// For other connections, the default behavior from gRPC is used and
|
||||
// loss of connection is not detected reliably.
|
||||
func Connect(address string, options ...Option) (*grpc.ClientConn, error) {
|
||||
return connect(address, []grpc.DialOption{}, options)
|
||||
func Connect(address string, metricsManager metrics.CSIMetricsManager, options ...Option) (*grpc.ClientConn, error) {
|
||||
return connect(address, metricsManager, []grpc.DialOption{}, options)
|
||||
}
|
||||
|
||||
// Option is the type of all optional parameters for Connect.
|
||||
@ -98,7 +94,10 @@ type options struct {
|
||||
}
|
||||
|
||||
// connect is the internal implementation of Connect. It has more options to enable testing.
|
||||
func connect(address string, dialOptions []grpc.DialOption, connectOptions []Option) (*grpc.ClientConn, error) {
|
||||
func connect(
|
||||
address string,
|
||||
metricsManager metrics.CSIMetricsManager,
|
||||
dialOptions []grpc.DialOption, connectOptions []Option) (*grpc.ClientConn, error) {
|
||||
var o options
|
||||
for _, option := range connectOptions {
|
||||
option(&o)
|
||||
@ -108,7 +107,10 @@ func connect(address string, dialOptions []grpc.DialOption, connectOptions []Opt
|
||||
grpc.WithInsecure(), // Don't use TLS, it's usually local Unix domain socket in a container.
|
||||
grpc.WithBackoffMaxDelay(time.Second), // Retry every second after failure.
|
||||
grpc.WithBlock(), // Block until connection succeeds.
|
||||
grpc.WithUnaryInterceptor(LogGRPC), // Log all messages.
|
||||
grpc.WithChainUnaryInterceptor(
|
||||
LogGRPC, // Log all messages.
|
||||
extendedCSIMetricsManager{metricsManager}.recordMetricsInterceptor, // Record metrics for each gRPC call.
|
||||
),
|
||||
)
|
||||
unixPrefix := "unix://"
|
||||
if strings.HasPrefix(address, "/") {
|
||||
@ -185,126 +187,25 @@ func LogGRPC(ctx context.Context, method string, req, reply interface{}, cc *grp
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDriverName returns name of CSI driver.
|
||||
func GetDriverName(ctx context.Context, conn *grpc.ClientConn) (string, error) {
|
||||
client := csi.NewIdentityClient(conn)
|
||||
|
||||
req := csi.GetPluginInfoRequest{}
|
||||
rsp, err := client.GetPluginInfo(ctx, &req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
name := rsp.GetName()
|
||||
if name == "" {
|
||||
return "", fmt.Errorf("driver name is empty")
|
||||
}
|
||||
return name, nil
|
||||
type extendedCSIMetricsManager struct {
|
||||
metrics.CSIMetricsManager
|
||||
}
|
||||
|
||||
// PluginCapabilitySet is set of CSI plugin capabilities. Only supported capabilities are in the map.
|
||||
type PluginCapabilitySet map[csi.PluginCapability_Service_Type]bool
|
||||
|
||||
// GetPluginCapabilities returns set of supported capabilities of CSI driver.
|
||||
func GetPluginCapabilities(ctx context.Context, conn *grpc.ClientConn) (PluginCapabilitySet, error) {
|
||||
client := csi.NewIdentityClient(conn)
|
||||
req := csi.GetPluginCapabilitiesRequest{}
|
||||
rsp, err := client.GetPluginCapabilities(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caps := PluginCapabilitySet{}
|
||||
for _, cap := range rsp.GetCapabilities() {
|
||||
if cap == nil {
|
||||
continue
|
||||
}
|
||||
srv := cap.GetService()
|
||||
if srv == nil {
|
||||
continue
|
||||
}
|
||||
t := srv.GetType()
|
||||
caps[t] = true
|
||||
}
|
||||
return caps, nil
|
||||
}
|
||||
|
||||
// ControllerCapabilitySet is set of CSI controller capabilities. Only supported capabilities are in the map.
|
||||
type ControllerCapabilitySet map[csi.ControllerServiceCapability_RPC_Type]bool
|
||||
|
||||
// GetControllerCapabilities returns set of supported controller capabilities of CSI driver.
|
||||
func GetControllerCapabilities(ctx context.Context, conn *grpc.ClientConn) (ControllerCapabilitySet, error) {
|
||||
client := csi.NewControllerClient(conn)
|
||||
req := csi.ControllerGetCapabilitiesRequest{}
|
||||
rsp, err := client.ControllerGetCapabilities(ctx, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caps := ControllerCapabilitySet{}
|
||||
for _, cap := range rsp.GetCapabilities() {
|
||||
if cap == nil {
|
||||
continue
|
||||
}
|
||||
rpc := cap.GetRpc()
|
||||
if rpc == nil {
|
||||
continue
|
||||
}
|
||||
t := rpc.GetType()
|
||||
caps[t] = true
|
||||
}
|
||||
return caps, nil
|
||||
}
|
||||
|
||||
// ProbeForever calls Probe() of a CSI driver and waits until the driver becomes ready.
|
||||
// Any error other than timeout is returned.
|
||||
func ProbeForever(conn *grpc.ClientConn, singleProbeTimeout time.Duration) error {
|
||||
for {
|
||||
klog.Info("Probing CSI driver for readiness")
|
||||
ready, err := probeOnce(conn, singleProbeTimeout)
|
||||
if err != nil {
|
||||
st, ok := status.FromError(err)
|
||||
if !ok {
|
||||
// This is not gRPC error. The probe must have failed before gRPC
|
||||
// method was called, otherwise we would get gRPC error.
|
||||
return fmt.Errorf("CSI driver probe failed: %s", err)
|
||||
}
|
||||
if st.Code() != codes.DeadlineExceeded {
|
||||
return fmt.Errorf("CSI driver probe failed: %s", err)
|
||||
}
|
||||
// Timeout -> driver is not ready. Fall through to sleep() below.
|
||||
klog.Warning("CSI driver probe timed out")
|
||||
} else {
|
||||
if ready {
|
||||
return nil
|
||||
}
|
||||
klog.Warning("CSI driver is not ready")
|
||||
}
|
||||
// Timeout was returned or driver is not ready.
|
||||
time.Sleep(probeInterval)
|
||||
}
|
||||
}
|
||||
|
||||
// probeOnce is a helper to simplify defer cancel()
|
||||
func probeOnce(conn *grpc.ClientConn, timeout time.Duration) (bool, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
return Probe(ctx, conn)
|
||||
}
|
||||
|
||||
// Probe calls driver Probe() just once and returns its result without any processing.
|
||||
func Probe(ctx context.Context, conn *grpc.ClientConn) (ready bool, err error) {
|
||||
client := csi.NewIdentityClient(conn)
|
||||
|
||||
req := csi.ProbeRequest{}
|
||||
rsp, err := client.Probe(ctx, &req)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
r := rsp.GetReady()
|
||||
if r == nil {
|
||||
// "If not present, the caller SHALL assume that the plugin is in a ready state"
|
||||
return true, nil
|
||||
}
|
||||
return r.GetValue(), nil
|
||||
// recordMetricsInterceptor is a gPRC unary interceptor for recording metrics for CSI operations.
|
||||
func (cmm extendedCSIMetricsManager) recordMetricsInterceptor(
|
||||
ctx context.Context,
|
||||
method string,
|
||||
req, reply interface{},
|
||||
cc *grpc.ClientConn,
|
||||
invoker grpc.UnaryInvoker,
|
||||
opts ...grpc.CallOption) error {
|
||||
start := time.Now()
|
||||
err := invoker(ctx, method, req, reply, cc, opts...)
|
||||
duration := time.Since(start)
|
||||
cmm.RecordMetrics(
|
||||
method, /* operationName */
|
||||
err, /* operationErr */
|
||||
duration, /* operationDuration */
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
199
vendor/github.com/kubernetes-csi/csi-lib-utils/metrics/metrics.go
generated
vendored
Normal file
199
vendor/github.com/kubernetes-csi/csi-lib-utils/metrics/metrics.go
generated
vendored
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/component-base/metrics"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
const (
|
||||
// Common metric strings
|
||||
subsystem = "csi_sidecar"
|
||||
labelCSIDriverName = "driver_name"
|
||||
labelCSIOperationName = "method_name"
|
||||
labelGrpcStatusCode = "grpc_status_code"
|
||||
unknownCSIDriverName = "unknown-driver"
|
||||
|
||||
// CSI Operation Latency with status code total - Histogram Metric
|
||||
operationsLatencyMetricName = "operations_seconds"
|
||||
operationsLatencyHelp = "Container Storage Interface operation duration with gRPC error code status total"
|
||||
)
|
||||
|
||||
var (
|
||||
operationsLatencyBuckets = []float64{.1, .25, .5, 1, 2.5, 5, 10, 15, 25, 50, 120, 300, 600}
|
||||
)
|
||||
|
||||
// CSIMetricsManager exposes functions for recording metrics for CSI operations.
|
||||
type CSIMetricsManager interface {
|
||||
// GetRegistry() returns the metrics.KubeRegistry used by this metrics manager.
|
||||
GetRegistry() metrics.KubeRegistry
|
||||
|
||||
// RecordMetrics must be called upon CSI Operation completion to record
|
||||
// the operation's metric.
|
||||
// operationName - Name of the CSI operation.
|
||||
// operationErr - Error, if any, that resulted from execution of operation.
|
||||
// operationDuration - time it took for the operation to complete
|
||||
RecordMetrics(
|
||||
operationName string,
|
||||
operationErr error,
|
||||
operationDuration time.Duration)
|
||||
|
||||
// SetDriverName is called to update the CSI driver name. This should be done
|
||||
// as soon as possible, otherwise metrics recorded by this manager will be
|
||||
// recorded with an "unknown-driver" driver_name.
|
||||
// driverName - Name of the CSI driver against which this operation was executed.
|
||||
SetDriverName(driverName string)
|
||||
|
||||
// StartMetricsEndpoint starts the metrics endpoint at the specified address/path
|
||||
// for this metrics manager.
|
||||
// If the metricsAddress is an empty string, this will be a no op.
|
||||
StartMetricsEndpoint(metricsAddress, metricsPath string)
|
||||
}
|
||||
|
||||
// NewCSIMetricsManager creates and registers metrics for for CSI Sidecars and
|
||||
// returns an object that can be used to trigger the metrics.
|
||||
// driverName - Name of the CSI driver against which this operation was executed.
|
||||
// If unknown, leave empty, and use SetDriverName method to update later.
|
||||
func NewCSIMetricsManager(driverName string) CSIMetricsManager {
|
||||
cmm := csiMetricsManager{
|
||||
registry: metrics.NewKubeRegistry(),
|
||||
csiOperationsLatencyMetric: metrics.NewHistogramVec(
|
||||
&metrics.HistogramOpts{
|
||||
Subsystem: subsystem,
|
||||
Name: operationsLatencyMetricName,
|
||||
Help: operationsLatencyHelp,
|
||||
Buckets: operationsLatencyBuckets,
|
||||
StabilityLevel: metrics.ALPHA,
|
||||
},
|
||||
[]string{labelCSIDriverName, labelCSIOperationName, labelGrpcStatusCode},
|
||||
),
|
||||
}
|
||||
|
||||
cmm.SetDriverName(driverName)
|
||||
cmm.registerMetrics()
|
||||
return &cmm
|
||||
}
|
||||
|
||||
var _ CSIMetricsManager = &csiMetricsManager{}
|
||||
|
||||
type csiMetricsManager struct {
|
||||
registry metrics.KubeRegistry
|
||||
driverName string
|
||||
csiOperationsMetric *metrics.CounterVec
|
||||
csiOperationsLatencyMetric *metrics.HistogramVec
|
||||
}
|
||||
|
||||
func (cmm *csiMetricsManager) GetRegistry() metrics.KubeRegistry {
|
||||
return cmm.registry
|
||||
}
|
||||
|
||||
// RecordMetrics must be called upon CSI Operation completion to record
|
||||
// the operation's metric.
|
||||
// operationName - Name of the CSI operation.
|
||||
// operationErr - Error, if any, that resulted from execution of operation.
|
||||
// operationDuration - time it took for the operation to complete
|
||||
func (cmm *csiMetricsManager) RecordMetrics(
|
||||
operationName string,
|
||||
operationErr error,
|
||||
operationDuration time.Duration) {
|
||||
cmm.csiOperationsLatencyMetric.WithLabelValues(
|
||||
cmm.driverName, operationName, getErrorCode(operationErr)).Observe(operationDuration.Seconds())
|
||||
}
|
||||
|
||||
// SetDriverName is called to update the CSI driver name. This should be done
|
||||
// as soon as possible, otherwise metrics recorded by this manager will be
|
||||
// recorded with an "unknown-driver" driver_name.
|
||||
func (cmm *csiMetricsManager) SetDriverName(driverName string) {
|
||||
if driverName == "" {
|
||||
cmm.driverName = unknownCSIDriverName
|
||||
} else {
|
||||
cmm.driverName = driverName
|
||||
}
|
||||
}
|
||||
|
||||
// StartMetricsEndpoint starts the metrics endpoint at the specified address/path
|
||||
// for this metrics manager on a new go routine.
|
||||
// If the metricsAddress is an empty string, this will be a no op.
|
||||
func (cmm *csiMetricsManager) StartMetricsEndpoint(metricsAddress, metricsPath string) {
|
||||
if metricsAddress == "" {
|
||||
klog.Warningf("metrics endpoint will not be started because `metrics-address` was not specified.")
|
||||
return
|
||||
}
|
||||
|
||||
http.Handle(metricsPath, metrics.HandlerFor(
|
||||
cmm.GetRegistry(),
|
||||
metrics.HandlerOpts{
|
||||
ErrorHandling: metrics.ContinueOnError}))
|
||||
|
||||
// Spawn a new go routine to listen on specified endpoint
|
||||
go func() {
|
||||
err := http.ListenAndServe(metricsAddress, nil)
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed to start prometheus metrics endpoint on specified address (%q) and path (%q): %s", metricsAddress, metricsPath, err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// VerifyMetricsMatch is a helper function that verifies that the expected and
|
||||
// actual metrics are identical excluding metricToIgnore.
|
||||
// This method is only used by tests. Ideally it should be in the _test file,
|
||||
// but *_test.go files are compiled into the package only when running go test
|
||||
// for that package and this method is used by metrics_test as well as
|
||||
// connection_test. If there are more consumers in the future, we can consider
|
||||
// moving it to a new, standalone package.
|
||||
func VerifyMetricsMatch(expectedMetrics, actualMetrics string, metricToIgnore string) error {
|
||||
gotScanner := bufio.NewScanner(strings.NewReader(strings.TrimSpace(actualMetrics)))
|
||||
wantScanner := bufio.NewScanner(strings.NewReader(strings.TrimSpace(expectedMetrics)))
|
||||
for gotScanner.Scan() {
|
||||
wantScanner.Scan()
|
||||
wantLine := strings.TrimSpace(wantScanner.Text())
|
||||
gotLine := strings.TrimSpace(gotScanner.Text())
|
||||
if wantLine != gotLine && (metricToIgnore == "" || !strings.HasPrefix(gotLine, metricToIgnore)) {
|
||||
return fmt.Errorf("\r\nMetric Want: %q\r\nMetric Got: %q\r\n", wantLine, gotLine)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmm *csiMetricsManager) registerMetrics() {
|
||||
cmm.registry.MustRegister(cmm.csiOperationsLatencyMetric)
|
||||
}
|
||||
|
||||
func getErrorCode(err error) string {
|
||||
if err == nil {
|
||||
return codes.OK.String()
|
||||
}
|
||||
|
||||
st, ok := status.FromError(err)
|
||||
if !ok {
|
||||
// This is not gRPC error. The operation must have failed before gRPC
|
||||
// method was called, otherwise we would get gRPC error.
|
||||
return "unknown-non-grpc"
|
||||
}
|
||||
|
||||
return st.Code().String()
|
||||
}
|
Reference in New Issue
Block a user