Skip to content

Commit 3d1fd21

Browse files
authored
Merge pull request #1305 from sunnylovestiramisu/automated-cherry-pick-of-#1101-#1227-#1296-upstream-release-1.7
Automated cherry pick of #1101: Add provisionedThroughput for hyperdisk #1227: Adding new metric pdcsi_operation_errors to fetch error #1296: emit metrics even for success scenarios
2 parents cc2fea0 + 2f9f140 commit 3d1fd21

File tree

15 files changed

+54177
-65606
lines changed

15 files changed

+54177
-65606
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ See Github [Issues](https://github.com/kubernetes-sigs/gcp-compute-persistent-di
6565
| disk-encryption-kms-key | Fully qualified resource identifier for the key to use to encrypt new disks. | Empty string. | Encrypt disk using Customer Managed Encryption Key (CMEK). See [GKE Docs](https://cloud.google.com/kubernetes-engine/docs/how-to/using-cmek#create_a_cmek_protected_attached_disk) for details. |
6666
| labels | `key1=value1,key2=value2` | | Labels allow you to assign custom [GCE Disk labels](https://cloud.google.com/compute/docs/labeling-resources). |
6767
| provisioned-iops-on-create | string (int64 format). Values typically between 10,000 and 120,000 | | Indicates how many IOPS to provision for the disk. See the [Extreme persistent disk documentation](https://cloud.google.com/compute/docs/disks/extreme-persistent-disk) for details, including valid ranges for IOPS. |
68-
68+
| provisioned-throughput-on-create | string (int64 format). Values typically between 1 and 7,124 mb per second | | Indicates how much throughput to provision for the disk. See the [hyperdisk documentation](TBD) for details, including valid ranges for throughput. |
6969

7070
### Topology
7171

cmd/gce-pd-csi-driver/main.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,14 @@ func handle() {
9191
}
9292
klog.V(2).Infof("Driver vendor version %v", version)
9393

94-
if *runControllerService && *httpEndpoint != "" && metrics.IsGKEComponentVersionAvailable() {
94+
if *runControllerService && *httpEndpoint != "" {
9595
mm := metrics.NewMetricsManager()
9696
mm.InitializeHttpHandler(*httpEndpoint, *metricsPath)
97-
mm.EmitGKEComponentVersion()
97+
mm.RegisterPDCSIMetric()
98+
99+
if metrics.IsGKEComponentVersionAvailable() {
100+
mm.EmitGKEComponentVersion()
101+
}
98102
}
99103

100104
if len(*extraVolumeLabelsStr) > 0 && !*runControllerService {

pkg/common/parameters.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ import (
2323

2424
const (
2525
// Parameters for StorageClass
26-
ParameterKeyType = "type"
27-
ParameterKeyReplicationType = "replication-type"
28-
ParameterKeyDiskEncryptionKmsKey = "disk-encryption-kms-key"
29-
ParameterKeyLabels = "labels"
30-
ParameterKeyProvisionedIOPSOnCreate = "provisioned-iops-on-create"
26+
ParameterKeyType = "type"
27+
ParameterKeyReplicationType = "replication-type"
28+
ParameterKeyDiskEncryptionKmsKey = "disk-encryption-kms-key"
29+
ParameterKeyLabels = "labels"
30+
ParameterKeyProvisionedIOPSOnCreate = "provisioned-iops-on-create"
31+
ParameterKeyProvisionedThroughputOnCreate = "provisioned-throughput-on-create"
3132

3233
// Parameters for VolumeSnapshotClass
3334
ParameterKeyStorageLocations = "storage-locations"
@@ -79,6 +80,9 @@ type DiskParameters struct {
7980
// Values: {int64}
8081
// Default: none
8182
ProvisionedIOPSOnCreate int64
83+
// Values: {int64}
84+
// Default: none
85+
ProvisionedThroughputOnCreate int64
8286
}
8387

8488
// SnapshotParameters contains normalized and defaulted parameters for snapshots
@@ -144,6 +148,12 @@ func ExtractAndDefaultParameters(parameters map[string]string, driverName string
144148
return p, fmt.Errorf("parameters contain invalid provisionedIOPSOnCreate parameter: %w", err)
145149
}
146150
p.ProvisionedIOPSOnCreate = paramProvisionedIOPSOnCreate
151+
case ParameterKeyProvisionedThroughputOnCreate:
152+
paramProvisionedThroughputOnCreate, err := ConvertMiBStringToInt64(v)
153+
if err != nil {
154+
return p, fmt.Errorf("parameters contain invalid provisionedThroughputOnCreate parameter: %w", err)
155+
}
156+
p.ProvisionedThroughputOnCreate = paramProvisionedThroughputOnCreate
147157
default:
148158
return p, fmt.Errorf("parameters contains invalid option %q", k)
149159
}

pkg/common/parameters_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ func TestExtractAndDefaultParameters(t *testing.T) {
9090
ProvisionedIOPSOnCreate: 10000,
9191
},
9292
},
93+
{
94+
name: "values from parameters, checking hyperdisk-throughput",
95+
parameters: map[string]string{ParameterKeyType: "hyperdisk-throughput", ParameterKeyReplicationType: "none", ParameterKeyDiskEncryptionKmsKey: "foo/key", ParameterKeyLabels: "key1=value1,key2=value2", ParameterKeyProvisionedThroughputOnCreate: "1000Mi"},
96+
labels: map[string]string{},
97+
expectParams: DiskParameters{
98+
DiskType: "hyperdisk-throughput",
99+
ReplicationType: "none",
100+
DiskEncryptionKMSKey: "foo/key",
101+
Tags: map[string]string{},
102+
Labels: map[string]string{
103+
"key1": "value1",
104+
"key2": "value2",
105+
},
106+
ProvisionedThroughputOnCreate: 1000,
107+
},
108+
},
93109
{
94110
name: "values from parameters, checking balanced pd",
95111
parameters: map[string]string{ParameterKeyType: "pd-balanced", ParameterKeyReplicationType: "regional-pd", ParameterKeyDiskEncryptionKmsKey: "foo/key"},

pkg/common/utils.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,21 @@ limitations under the License.
1717
package common
1818

1919
import (
20+
"context"
21+
"errors"
2022
"fmt"
23+
"net/http"
2124
"regexp"
2225
"strings"
2326

2427
"github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud/meta"
28+
"google.golang.org/api/googleapi"
29+
"google.golang.org/grpc/codes"
30+
"google.golang.org/grpc/status"
2531
"k8s.io/apimachinery/pkg/api/resource"
2632
"k8s.io/apimachinery/pkg/util/sets"
2733
volumehelpers "k8s.io/cloud-provider/volume/helpers"
34+
"k8s.io/klog/v2"
2835
)
2936

3037
const (
@@ -279,3 +286,94 @@ func ConvertStringToInt64(str string) (int64, error) {
279286
}
280287
return volumehelpers.RoundUpToB(quantity)
281288
}
289+
290+
// ConvertMiBStringToInt64 converts a GiB string to int64
291+
func ConvertMiBStringToInt64(str string) (int64, error) {
292+
// Verify regex before
293+
match, _ := regexp.MatchString("^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$", str)
294+
if !match {
295+
return 0, fmt.Errorf("invalid string %s", str)
296+
}
297+
quantity := resource.MustParse(str)
298+
return volumehelpers.RoundUpToMiB(quantity)
299+
}
300+
301+
// CodeForError returns a pointer to the grpc error code that maps to the http
302+
// error code for the passed in user googleapi error or context error. Returns
303+
// codes.Internal if the given error is not a googleapi error caused by the user.
304+
// The following http error codes are considered user errors:
305+
// (1) http 400 Bad Request, returns grpc InvalidArgument,
306+
// (2) http 403 Forbidden, returns grpc PermissionDenied,
307+
// (3) http 404 Not Found, returns grpc NotFound
308+
// (4) http 429 Too Many Requests, returns grpc ResourceExhausted
309+
// The following errors are considered context errors:
310+
// (1) "context deadline exceeded", returns grpc DeadlineExceeded,
311+
// (2) "context canceled", returns grpc Canceled
312+
func CodeForError(err error) *codes.Code {
313+
if err == nil {
314+
return nil
315+
}
316+
317+
if errCode := existingErrorCode(err); errCode != nil {
318+
return errCode
319+
}
320+
if code := isContextError(err); code != nil {
321+
return code
322+
}
323+
324+
internalErrorCode := codes.Internal
325+
// Upwrap the error
326+
var apiErr *googleapi.Error
327+
if !errors.As(err, &apiErr) {
328+
return &internalErrorCode
329+
}
330+
331+
userErrors := map[int]codes.Code{
332+
http.StatusForbidden: codes.PermissionDenied,
333+
http.StatusBadRequest: codes.InvalidArgument,
334+
http.StatusTooManyRequests: codes.ResourceExhausted,
335+
http.StatusNotFound: codes.NotFound,
336+
}
337+
if code, ok := userErrors[apiErr.Code]; ok {
338+
return &code
339+
}
340+
341+
return &internalErrorCode
342+
}
343+
344+
// isContextError returns a pointer to the grpc error code DeadlineExceeded
345+
// if the passed in error contains the "context deadline exceeded" string and returns
346+
// the grpc error code Canceled if the error contains the "context canceled" string.
347+
func isContextError(err error) *codes.Code {
348+
if err == nil {
349+
return nil
350+
}
351+
352+
errStr := err.Error()
353+
if strings.Contains(errStr, context.DeadlineExceeded.Error()) {
354+
return errCodePtr(codes.DeadlineExceeded)
355+
}
356+
if strings.Contains(errStr, context.Canceled.Error()) {
357+
return errCodePtr(codes.Canceled)
358+
}
359+
return nil
360+
}
361+
362+
func existingErrorCode(err error) *codes.Code {
363+
if err == nil {
364+
return nil
365+
}
366+
if status, ok := status.FromError(err); ok {
367+
return errCodePtr(status.Code())
368+
}
369+
return nil
370+
}
371+
372+
func errCodePtr(code codes.Code) *codes.Code {
373+
return &code
374+
}
375+
376+
func LoggedError(msg string, err error) error {
377+
klog.Errorf(msg+"%v", err.Error())
378+
return status.Errorf(*CodeForError(err), msg+"%v", err.Error())
379+
}

0 commit comments

Comments
 (0)