mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 10:18:13 +00:00 
			
		
		
		
	Merge pull request #43477 from gnufied/cloudprovider-aws-metrics
Automatic merge from submit-queue Start recording cloud provider metrics for AWS **What this PR does / why we need it**: This PR implements support for emitting metrics from AWS about storage operations. **Which issue this PR fixes** Fixes https://github.com/kubernetes/features/issues/182 **Release note**: ``` Add support for emitting metrics from AWS cloudprovider about storage operations. ```
This commit is contained in:
		| @@ -14,6 +14,7 @@ go_library( | |||||||
|         "aws.go", |         "aws.go", | ||||||
|         "aws_instancegroups.go", |         "aws_instancegroups.go", | ||||||
|         "aws_loadbalancer.go", |         "aws_loadbalancer.go", | ||||||
|  |         "aws_metrics.go", | ||||||
|         "aws_routes.go", |         "aws_routes.go", | ||||||
|         "aws_utils.go", |         "aws_utils.go", | ||||||
|         "device_allocator.go", |         "device_allocator.go", | ||||||
| @@ -42,6 +43,7 @@ go_library( | |||||||
|         "//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library", |         "//vendor/github.com/aws/aws-sdk-go/service/ec2:go_default_library", | ||||||
|         "//vendor/github.com/aws/aws-sdk-go/service/elb:go_default_library", |         "//vendor/github.com/aws/aws-sdk-go/service/elb:go_default_library", | ||||||
|         "//vendor/github.com/golang/glog:go_default_library", |         "//vendor/github.com/golang/glog:go_default_library", | ||||||
|  |         "//vendor/github.com/prometheus/client_golang/prometheus:go_default_library", | ||||||
|         "//vendor/gopkg.in/gcfg.v1:go_default_library", |         "//vendor/gopkg.in/gcfg.v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", | ||||||
|         "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", |         "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", | ||||||
|   | |||||||
| @@ -40,6 +40,7 @@ import ( | |||||||
| 	"github.com/aws/aws-sdk-go/service/ec2" | 	"github.com/aws/aws-sdk-go/service/ec2" | ||||||
| 	"github.com/aws/aws-sdk-go/service/elb" | 	"github.com/aws/aws-sdk-go/service/elb" | ||||||
| 	"github.com/golang/glog" | 	"github.com/golang/glog" | ||||||
|  | 	"github.com/prometheus/client_golang/prometheus" | ||||||
|  |  | ||||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||||
| 	"k8s.io/apimachinery/pkg/types" | 	"k8s.io/apimachinery/pkg/types" | ||||||
| @@ -571,10 +572,11 @@ func (s *awsSdkEC2) DescribeInstances(request *ec2.DescribeInstancesInput) ([]*e | |||||||
| 	// Instances are paged | 	// Instances are paged | ||||||
| 	results := []*ec2.Instance{} | 	results := []*ec2.Instance{} | ||||||
| 	var nextToken *string | 	var nextToken *string | ||||||
|  | 	requestTime := time.Now() | ||||||
| 	for { | 	for { | ||||||
| 		response, err := s.ec2.DescribeInstances(request) | 		response, err := s.ec2.DescribeInstances(request) | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | 			recordAwsMetric("describe_instance", 0, err) | ||||||
| 			return nil, fmt.Errorf("error listing AWS instances: %v", err) | 			return nil, fmt.Errorf("error listing AWS instances: %v", err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -588,7 +590,8 @@ func (s *awsSdkEC2) DescribeInstances(request *ec2.DescribeInstancesInput) ([]*e | |||||||
| 		} | 		} | ||||||
| 		request.NextToken = nextToken | 		request.NextToken = nextToken | ||||||
| 	} | 	} | ||||||
|  | 	timeTaken := time.Since(requestTime).Seconds() | ||||||
|  | 	recordAwsMetric("describe_instance", timeTaken, nil) | ||||||
| 	return results, nil | 	return results, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -603,22 +606,31 @@ func (s *awsSdkEC2) DescribeSecurityGroups(request *ec2.DescribeSecurityGroupsIn | |||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) AttachVolume(request *ec2.AttachVolumeInput) (*ec2.VolumeAttachment, error) { | func (s *awsSdkEC2) AttachVolume(request *ec2.AttachVolumeInput) (*ec2.VolumeAttachment, error) { | ||||||
| 	return s.ec2.AttachVolume(request) | 	requestTime := time.Now() | ||||||
|  | 	resp, err := s.ec2.AttachVolume(request) | ||||||
|  | 	timeTaken := time.Since(requestTime).Seconds() | ||||||
|  | 	recordAwsMetric("attach_volume", timeTaken, err) | ||||||
|  | 	return resp, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) DetachVolume(request *ec2.DetachVolumeInput) (*ec2.VolumeAttachment, error) { | func (s *awsSdkEC2) DetachVolume(request *ec2.DetachVolumeInput) (*ec2.VolumeAttachment, error) { | ||||||
| 	return s.ec2.DetachVolume(request) | 	requestTime := time.Now() | ||||||
|  | 	resp, err := s.ec2.DetachVolume(request) | ||||||
|  | 	timeTaken := time.Since(requestTime).Seconds() | ||||||
|  | 	recordAwsMetric("detach_volume", timeTaken, err) | ||||||
|  | 	return resp, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) DescribeVolumes(request *ec2.DescribeVolumesInput) ([]*ec2.Volume, error) { | func (s *awsSdkEC2) DescribeVolumes(request *ec2.DescribeVolumesInput) ([]*ec2.Volume, error) { | ||||||
| 	// Volumes are paged | 	// Volumes are paged | ||||||
| 	results := []*ec2.Volume{} | 	results := []*ec2.Volume{} | ||||||
| 	var nextToken *string | 	var nextToken *string | ||||||
|  | 	requestTime := time.Now() | ||||||
| 	for { | 	for { | ||||||
| 		response, err := s.ec2.DescribeVolumes(request) | 		response, err := s.ec2.DescribeVolumes(request) | ||||||
|  |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
|  | 			recordAwsMetric("describe_volume", 0, err) | ||||||
| 			return nil, fmt.Errorf("error listing AWS volumes: %v", err) | 			return nil, fmt.Errorf("error listing AWS volumes: %v", err) | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| @@ -630,16 +642,25 @@ func (s *awsSdkEC2) DescribeVolumes(request *ec2.DescribeVolumesInput) ([]*ec2.V | |||||||
| 		} | 		} | ||||||
| 		request.NextToken = nextToken | 		request.NextToken = nextToken | ||||||
| 	} | 	} | ||||||
|  | 	timeTaken := time.Since(requestTime).Seconds() | ||||||
|  | 	recordAwsMetric("describe_volume", timeTaken, nil) | ||||||
| 	return results, nil | 	return results, nil | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) CreateVolume(request *ec2.CreateVolumeInput) (resp *ec2.Volume, err error) { | func (s *awsSdkEC2) CreateVolume(request *ec2.CreateVolumeInput) (*ec2.Volume, error) { | ||||||
| 	return s.ec2.CreateVolume(request) | 	requestTime := time.Now() | ||||||
|  | 	resp, err := s.ec2.CreateVolume(request) | ||||||
|  | 	timeTaken := time.Since(requestTime).Seconds() | ||||||
|  | 	recordAwsMetric("create_volume", timeTaken, err) | ||||||
|  | 	return resp, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) DeleteVolume(request *ec2.DeleteVolumeInput) (*ec2.DeleteVolumeOutput, error) { | func (s *awsSdkEC2) DeleteVolume(request *ec2.DeleteVolumeInput) (*ec2.DeleteVolumeOutput, error) { | ||||||
| 	return s.ec2.DeleteVolume(request) | 	requestTime := time.Now() | ||||||
|  | 	resp, err := s.ec2.DeleteVolume(request) | ||||||
|  | 	timeTaken := time.Since(requestTime).Seconds() | ||||||
|  | 	recordAwsMetric("delete_volume", timeTaken, err) | ||||||
|  | 	return resp, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) DescribeSubnets(request *ec2.DescribeSubnetsInput) ([]*ec2.Subnet, error) { | func (s *awsSdkEC2) DescribeSubnets(request *ec2.DescribeSubnetsInput) ([]*ec2.Subnet, error) { | ||||||
| @@ -668,7 +689,11 @@ func (s *awsSdkEC2) RevokeSecurityGroupIngress(request *ec2.RevokeSecurityGroupI | |||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) CreateTags(request *ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { | func (s *awsSdkEC2) CreateTags(request *ec2.CreateTagsInput) (*ec2.CreateTagsOutput, error) { | ||||||
| 	return s.ec2.CreateTags(request) | 	requestTime := time.Now() | ||||||
|  | 	resp, err := s.ec2.CreateTags(request) | ||||||
|  | 	timeTaken := time.Since(requestTime).Seconds() | ||||||
|  | 	recordAwsMetric("create_tags", timeTaken, err) | ||||||
|  | 	return resp, err | ||||||
| } | } | ||||||
|  |  | ||||||
| func (s *awsSdkEC2) DescribeRouteTables(request *ec2.DescribeRouteTablesInput) ([]*ec2.RouteTable, error) { | func (s *awsSdkEC2) DescribeRouteTables(request *ec2.DescribeRouteTablesInput) ([]*ec2.RouteTable, error) { | ||||||
| @@ -693,6 +718,7 @@ func (s *awsSdkEC2) ModifyInstanceAttribute(request *ec2.ModifyInstanceAttribute | |||||||
| } | } | ||||||
|  |  | ||||||
| func init() { | func init() { | ||||||
|  | 	registerMetrics() | ||||||
| 	cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) { | 	cloudprovider.RegisterCloudProvider(ProviderName, func(config io.Reader) (cloudprovider.Interface, error) { | ||||||
| 		creds := credentials.NewChainCredentials( | 		creds := credentials.NewChainCredentials( | ||||||
| 			[]credentials.Provider{ | 			[]credentials.Provider{ | ||||||
| @@ -3337,3 +3363,12 @@ func setNodeDisk( | |||||||
| 	} | 	} | ||||||
| 	volumeMap[volumeID] = check | 	volumeMap[volumeID] = check | ||||||
| } | } | ||||||
|  |  | ||||||
|  | func recordAwsMetric(actionName string, timeTaken float64, err error) { | ||||||
|  | 	if err != nil { | ||||||
|  | 		awsApiErrorMetric.With(prometheus.Labels{"request": actionName}).Inc() | ||||||
|  | 	} else { | ||||||
|  | 		awsApiMetric.With(prometheus.Labels{"request": actionName}).Observe(timeTaken) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|   | |||||||
							
								
								
									
										40
									
								
								pkg/cloudprovider/providers/aws/aws_metrics.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								pkg/cloudprovider/providers/aws/aws_metrics.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | /* | ||||||
|  | Copyright 2017 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 aws | ||||||
|  |  | ||||||
|  | import "github.com/prometheus/client_golang/prometheus" | ||||||
|  |  | ||||||
|  | var awsApiMetric = prometheus.NewHistogramVec( | ||||||
|  | 	prometheus.HistogramOpts{ | ||||||
|  | 		Name: "cloudprovider_aws_api_request_duration_seconds", | ||||||
|  | 		Help: "Latency of aws api call", | ||||||
|  | 	}, | ||||||
|  | 	[]string{"request"}, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | var awsApiErrorMetric = prometheus.NewCounterVec( | ||||||
|  | 	prometheus.CounterOpts{ | ||||||
|  | 		Name: "cloudprovider_aws_api_request_errors", | ||||||
|  | 		Help: "AWS Api errors", | ||||||
|  | 	}, | ||||||
|  | 	[]string{"request"}, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | func registerMetrics() { | ||||||
|  | 	prometheus.MustRegister(awsApiMetric) | ||||||
|  | 	prometheus.MustRegister(awsApiErrorMetric) | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Kubernetes Submit Queue
					Kubernetes Submit Queue