mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
Merge pull request #44510 from bowei/gce-metrics
Automatic merge from submit-queue (batch tested with PRs 44124, 44510) Add metrics to all major gce operations (latency, errors) ```release-note Add metrics to all major gce operations {latency, errors} The new metrics are: cloudprovider_gce_api_request_duration_seconds{request, region, zone} cloudprovider_gce_api_request_errors{request, region, zone} `request` is the specific function that is used. `region` is the target region (Will be "<n/a>" if not applicable) `zone` is the target zone (Will be "<n/a>" if not applicable) Note: this fixes some issues with the previous implementation of metrics for disks: - Time duration tracked was of the initial API call, not the entire operation. - Metrics label tuple would have resulted in many independent histograms stored, one for each disk. (Did not aggregate well). ```
This commit is contained in:
commit
09747e6bee
@ -23,7 +23,6 @@ go_library(
|
|||||||
"gce_instancegroup.go",
|
"gce_instancegroup.go",
|
||||||
"gce_instances.go",
|
"gce_instances.go",
|
||||||
"gce_loadbalancer.go",
|
"gce_loadbalancer.go",
|
||||||
"gce_metrics.go",
|
|
||||||
"gce_op.go",
|
"gce_op.go",
|
||||||
"gce_routes.go",
|
"gce_routes.go",
|
||||||
"gce_staticip.go",
|
"gce_staticip.go",
|
||||||
@ -31,6 +30,7 @@ go_library(
|
|||||||
"gce_urlmap.go",
|
"gce_urlmap.go",
|
||||||
"gce_util.go",
|
"gce_util.go",
|
||||||
"gce_zones.go",
|
"gce_zones.go",
|
||||||
|
"metrics.go",
|
||||||
"token_source.go",
|
"token_source.go",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
@ -43,13 +43,11 @@ go_library(
|
|||||||
"//vendor/cloud.google.com/go/compute/metadata:go_default_library",
|
"//vendor/cloud.google.com/go/compute/metadata: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/github.com/prometheus/client_golang/prometheus:go_default_library",
|
||||||
"//vendor/golang.org/x/net/context:go_default_library",
|
|
||||||
"//vendor/golang.org/x/oauth2:go_default_library",
|
"//vendor/golang.org/x/oauth2:go_default_library",
|
||||||
"//vendor/golang.org/x/oauth2/google:go_default_library",
|
"//vendor/golang.org/x/oauth2/google:go_default_library",
|
||||||
"//vendor/google.golang.org/api/compute/v0.alpha:go_default_library",
|
"//vendor/google.golang.org/api/compute/v0.alpha:go_default_library",
|
||||||
"//vendor/google.golang.org/api/compute/v1:go_default_library",
|
"//vendor/google.golang.org/api/compute/v1:go_default_library",
|
||||||
"//vendor/google.golang.org/api/container/v1:go_default_library",
|
"//vendor/google.golang.org/api/container/v1:go_default_library",
|
||||||
"//vendor/google.golang.org/api/gensupport:go_default_library",
|
|
||||||
"//vendor/google.golang.org/api/googleapi:go_default_library",
|
"//vendor/google.golang.org/api/googleapi: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",
|
||||||
|
@ -25,7 +25,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"cloud.google.com/go/compute/metadata"
|
"cloud.google.com/go/compute/metadata"
|
||||||
"golang.org/x/net/context"
|
|
||||||
|
|
||||||
"gopkg.in/gcfg.v1"
|
"gopkg.in/gcfg.v1"
|
||||||
|
|
||||||
@ -39,7 +38,6 @@ import (
|
|||||||
computealpha "google.golang.org/api/compute/v0.alpha"
|
computealpha "google.golang.org/api/compute/v0.alpha"
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
container "google.golang.org/api/container/v1"
|
container "google.golang.org/api/container/v1"
|
||||||
"google.golang.org/api/gensupport"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -103,47 +101,12 @@ type Config struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApiWithNamespace stores api and namespace in context
|
|
||||||
type apiWithNamespace struct {
|
|
||||||
namespace string
|
|
||||||
apiCall string
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
registerMetrics()
|
|
||||||
cloudprovider.RegisterCloudProvider(
|
cloudprovider.RegisterCloudProvider(
|
||||||
ProviderName,
|
ProviderName,
|
||||||
func(config io.Reader) (cloudprovider.Interface, error) {
|
func(config io.Reader) (cloudprovider.Interface, error) {
|
||||||
return newGCECloud(config)
|
return newGCECloud(config)
|
||||||
})
|
})
|
||||||
gensupport.RegisterHook(trackAPILatency)
|
|
||||||
}
|
|
||||||
|
|
||||||
func trackAPILatency(ctx context.Context, req *http.Request) func(resp *http.Response) {
|
|
||||||
requestTime := time.Now()
|
|
||||||
t := ctx.Value("kube-api-namespace")
|
|
||||||
apiNamespace, ok := t.(apiWithNamespace)
|
|
||||||
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
apiResponseReceived := func(resp *http.Response) {
|
|
||||||
timeTaken := time.Since(requestTime).Seconds()
|
|
||||||
if mi, ok := gceMetricMap[apiNamespace.apiCall]; ok {
|
|
||||||
mi.WithLabelValues(apiNamespace.namespace).Observe(timeTaken)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return apiResponseReceived
|
|
||||||
}
|
|
||||||
|
|
||||||
func contextWithNamespace(namespace string, apiCall string) context.Context {
|
|
||||||
rootContext := context.Background()
|
|
||||||
apiNamespace := apiWithNamespace{
|
|
||||||
namespace: namespace,
|
|
||||||
apiCall: apiCall,
|
|
||||||
}
|
|
||||||
return context.WithValue(rootContext, "kube-api-namespace", apiNamespace)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw access to the underlying GCE service, probably should only be used for e2e tests
|
// Raw access to the underlying GCE service, probably should only be used for e2e tests
|
||||||
@ -340,7 +303,7 @@ func getNetworkNameViaAPICall(svc *compute.Service, projectID string) (string, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
if networkList == nil || len(networkList.Items) <= 0 {
|
if networkList == nil || len(networkList.Items) <= 0 {
|
||||||
return "", fmt.Errorf("GCE Network List call returned no networks for project %q.", projectID)
|
return "", fmt.Errorf("GCE Network List call returned no networks for project %q", projectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return networkList.Items[0].Name, nil
|
return networkList.Items[0].Name, nil
|
||||||
|
@ -18,11 +18,17 @@ package gce
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BackendService Management
|
func newBackendServiceMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"backendservice_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetBackendService retrieves a backend by name.
|
// GetBackendService retrieves a backend by name.
|
||||||
func (gce *GCECloud) GetBackendService(name string) (*compute.BackendService, error) {
|
func (gce *GCECloud) GetBackendService(name string) (*compute.BackendService, error) {
|
||||||
@ -31,32 +37,38 @@ func (gce *GCECloud) GetBackendService(name string) (*compute.BackendService, er
|
|||||||
|
|
||||||
// UpdateBackendService applies the given BackendService as an update to an existing service.
|
// UpdateBackendService applies the given BackendService as an update to an existing service.
|
||||||
func (gce *GCECloud) UpdateBackendService(bg *compute.BackendService) error {
|
func (gce *GCECloud) UpdateBackendService(bg *compute.BackendService) error {
|
||||||
|
mc := newBackendServiceMetricContext("update")
|
||||||
op, err := gce.service.BackendServices.Update(gce.projectID, bg.Name, bg).Do()
|
op, err := gce.service.BackendServices.Update(gce.projectID, bg.Name, bg).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteBackendService deletes the given BackendService by name.
|
// DeleteBackendService deletes the given BackendService by name.
|
||||||
func (gce *GCECloud) DeleteBackendService(name string) error {
|
func (gce *GCECloud) DeleteBackendService(name string) error {
|
||||||
|
mc := newBackendServiceMetricContext("delete")
|
||||||
op, err := gce.service.BackendServices.Delete(gce.projectID, name).Do()
|
op, err := gce.service.BackendServices.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateBackendService creates the given BackendService.
|
// CreateBackendService creates the given BackendService.
|
||||||
func (gce *GCECloud) CreateBackendService(bg *compute.BackendService) error {
|
func (gce *GCECloud) CreateBackendService(bg *compute.BackendService) error {
|
||||||
|
mc := newBackendServiceMetricContext("create")
|
||||||
op, err := gce.service.BackendServices.Insert(gce.projectID, bg).Do()
|
op, err := gce.service.BackendServices.Insert(gce.projectID, bg).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListBackendServices lists all backend services in the project.
|
// ListBackendServices lists all backend services in the project.
|
||||||
|
@ -18,11 +18,17 @@ package gce
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SSL Certificate management
|
func newCertMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"cert_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetSslCertificate returns the SslCertificate by name.
|
// GetSslCertificate returns the SslCertificate by name.
|
||||||
func (gce *GCECloud) GetSslCertificate(name string) (*compute.SslCertificate, error) {
|
func (gce *GCECloud) GetSslCertificate(name string) (*compute.SslCertificate, error) {
|
||||||
@ -31,26 +37,34 @@ func (gce *GCECloud) GetSslCertificate(name string) (*compute.SslCertificate, er
|
|||||||
|
|
||||||
// CreateSslCertificate creates and returns a SslCertificate.
|
// CreateSslCertificate creates and returns a SslCertificate.
|
||||||
func (gce *GCECloud) CreateSslCertificate(sslCerts *compute.SslCertificate) (*compute.SslCertificate, error) {
|
func (gce *GCECloud) CreateSslCertificate(sslCerts *compute.SslCertificate) (*compute.SslCertificate, error) {
|
||||||
|
mc := newCertMetricContext("create")
|
||||||
op, err := gce.service.SslCertificates.Insert(gce.projectID, sslCerts).Do()
|
op, err := gce.service.SslCertificates.Insert(gce.projectID, sslCerts).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, mc.Observe(err)
|
||||||
}
|
}
|
||||||
if err = gce.waitForGlobalOp(op); err != nil {
|
|
||||||
return nil, err
|
if err = gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
|
return nil, mc.Observe(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gce.GetSslCertificate(sslCerts.Name)
|
return gce.GetSslCertificate(sslCerts.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteSslCertificate deletes the SslCertificate by name.
|
// DeleteSslCertificate deletes the SslCertificate by name.
|
||||||
func (gce *GCECloud) DeleteSslCertificate(name string) error {
|
func (gce *GCECloud) DeleteSslCertificate(name string) error {
|
||||||
|
mc := newCertMetricContext("delete")
|
||||||
op, err := gce.service.SslCertificates.Delete(gce.projectID, name).Do()
|
op, err := gce.service.SslCertificates.Delete(gce.projectID, name).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
|
||||||
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListSslCertificates lists all SslCertificates in the project.
|
// ListSslCertificates lists all SslCertificates in the project.
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
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"
|
||||||
@ -84,6 +85,13 @@ type GCEDisk struct {
|
|||||||
Type string
|
Type string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newDiskMetricContext(request, zone string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"disk_" + request, unusedMetricLabel, zone},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOnly bool) error {
|
func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOnly bool) error {
|
||||||
instanceName := mapNodeNameToInstanceName(nodeName)
|
instanceName := mapNodeNameToInstanceName(nodeName)
|
||||||
instance, err := gce.getInstanceByName(instanceName)
|
instance, err := gce.getInstanceByName(instanceName)
|
||||||
@ -99,13 +107,16 @@ func (gce *GCECloud) AttachDisk(diskName string, nodeName types.NodeName, readOn
|
|||||||
readWrite = "READ_ONLY"
|
readWrite = "READ_ONLY"
|
||||||
}
|
}
|
||||||
attachedDisk := gce.convertDiskToAttachedDisk(disk, readWrite)
|
attachedDisk := gce.convertDiskToAttachedDisk(disk, readWrite)
|
||||||
dc := contextWithNamespace(diskName, "gce_attach_disk")
|
|
||||||
attachOp, err := gce.service.Instances.AttachDisk(gce.projectID, disk.Zone, instance.Name, attachedDisk).Context(dc).Do()
|
mc := newDiskMetricContext("attach", instance.Zone)
|
||||||
|
attachOp, err := gce.service.Instances.AttachDisk(
|
||||||
|
gce.projectID, disk.Zone, instance.Name, attachedDisk).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gce.waitForZoneOp(attachOp, disk.Zone)
|
return gce.waitForZoneOp(attachOp, disk.Zone, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) DetachDisk(devicePath string, nodeName types.NodeName) error {
|
func (gce *GCECloud) DetachDisk(devicePath string, nodeName types.NodeName) error {
|
||||||
@ -123,13 +134,14 @@ func (gce *GCECloud) DetachDisk(devicePath string, nodeName types.NodeName) erro
|
|||||||
|
|
||||||
return fmt.Errorf("error getting instance %q", instanceName)
|
return fmt.Errorf("error getting instance %q", instanceName)
|
||||||
}
|
}
|
||||||
dc := contextWithNamespace(devicePath, "gce_detach_disk")
|
|
||||||
detachOp, err := gce.service.Instances.DetachDisk(gce.projectID, inst.Zone, inst.Name, devicePath).Context(dc).Do()
|
mc := newDiskMetricContext("detach", inst.Zone)
|
||||||
|
detachOp, err := gce.service.Instances.DetachDisk(gce.projectID, inst.Zone, inst.Name, devicePath).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gce.waitForZoneOp(detachOp, inst.Zone)
|
return gce.waitForZoneOp(detachOp, inst.Zone, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) DiskIsAttached(diskName string, nodeName types.NodeName) (bool, error) {
|
func (gce *GCECloud) DiskIsAttached(diskName string, nodeName types.NodeName) (bool, error) {
|
||||||
@ -193,7 +205,9 @@ func (gce *GCECloud) DisksAreAttached(diskNames []string, nodeName types.NodeNam
|
|||||||
// CreateDisk creates a new Persistent Disk, with the specified name &
|
// CreateDisk creates a new Persistent Disk, with the specified name &
|
||||||
// size, in the specified zone. It stores specified tags encoded in
|
// size, in the specified zone. It stores specified tags encoded in
|
||||||
// JSON in Description field.
|
// JSON in Description field.
|
||||||
func (gce *GCECloud) CreateDisk(name string, diskType string, zone string, sizeGb int64, tags map[string]string) error {
|
func (gce *GCECloud) CreateDisk(
|
||||||
|
name string, diskType string, zone string, sizeGb int64, tags map[string]string) error {
|
||||||
|
|
||||||
// Do not allow creation of PDs in zones that are not managed. Such PDs
|
// Do not allow creation of PDs in zones that are not managed. Such PDs
|
||||||
// then cannot be deleted by DeleteDisk.
|
// then cannot be deleted by DeleteDisk.
|
||||||
isManaged := false
|
isManaged := false
|
||||||
@ -228,13 +242,14 @@ func (gce *GCECloud) CreateDisk(name string, diskType string, zone string, sizeG
|
|||||||
Description: tagsStr,
|
Description: tagsStr,
|
||||||
Type: diskTypeUri,
|
Type: diskTypeUri,
|
||||||
}
|
}
|
||||||
dc := contextWithNamespace(name, "gce_disk_insert")
|
|
||||||
createOp, err := gce.service.Disks.Insert(gce.projectID, zone, diskToCreate).Context(dc).Do()
|
mc := newDiskMetricContext("create", zone)
|
||||||
|
createOp, err := gce.service.Disks.Insert(gce.projectID, zone, diskToCreate).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = gce.waitForZoneOp(createOp, zone)
|
err = gce.waitForZoneOp(createOp, zone, mc)
|
||||||
if isGCEError(err, "alreadyExists") {
|
if isGCEError(err, "alreadyExists") {
|
||||||
glog.Warningf("GCE PD %q already exists, reusing", name)
|
glog.Warningf("GCE PD %q already exists, reusing", name)
|
||||||
return nil
|
return nil
|
||||||
@ -304,8 +319,7 @@ func (gce *GCECloud) GetAutoLabelsForPD(name string, zone string) (map[string]st
|
|||||||
// Returns a GCEDisk for the disk, if it is found in the specified zone.
|
// Returns a GCEDisk for the disk, if it is found in the specified zone.
|
||||||
// If not found, returns (nil, nil)
|
// If not found, returns (nil, nil)
|
||||||
func (gce *GCECloud) findDiskByName(diskName string, zone string) (*GCEDisk, error) {
|
func (gce *GCECloud) findDiskByName(diskName string, zone string) (*GCEDisk, error) {
|
||||||
dc := contextWithNamespace(diskName, "gce_list_disk")
|
disk, err := gce.service.Disks.Get(gce.projectID, zone, diskName).Do()
|
||||||
disk, err := gce.service.Disks.Get(gce.projectID, zone, diskName).Context(dc).Do()
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
d := &GCEDisk{
|
d := &GCEDisk{
|
||||||
Zone: lastComponent(disk.Zone),
|
Zone: lastComponent(disk.Zone),
|
||||||
@ -390,13 +404,14 @@ func (gce *GCECloud) doDeleteDisk(diskToDelete string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dc := contextWithNamespace(diskToDelete, "gce_disk_delete")
|
mc := newDiskMetricContext("delete", disk.Zone)
|
||||||
deleteOp, err := gce.service.Disks.Delete(gce.projectID, disk.Zone, disk.Name).Context(dc).Do()
|
|
||||||
|
deleteOp, err := gce.service.Disks.Delete(gce.projectID, disk.Zone, disk.Name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return gce.waitForZoneOp(deleteOp, disk.Zone)
|
return gce.waitForZoneOp(deleteOp, disk.Zone, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts a Disk resource to an AttachedDisk resource.
|
// Converts a Disk resource to an AttachedDisk resource.
|
||||||
|
@ -17,14 +17,20 @@ limitations under the License.
|
|||||||
package gce
|
package gce
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/kubernetes/pkg/api/v1"
|
"k8s.io/kubernetes/pkg/api/v1"
|
||||||
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
netsets "k8s.io/kubernetes/pkg/util/net/sets"
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Firewall management: These methods are just passthrough to the existing
|
func newFirewallMetricContext(request string, region string) *metricContext {
|
||||||
// internal firewall creation methods used to manage TCPLoadBalancer.
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"firewall_" + request, region, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetFirewall returns the Firewall by name.
|
// GetFirewall returns the Firewall by name.
|
||||||
func (gce *GCECloud) GetFirewall(name string) (*compute.Firewall, error) {
|
func (gce *GCECloud) GetFirewall(name string) (*compute.Firewall, error) {
|
||||||
@ -37,22 +43,29 @@ func (gce *GCECloud) CreateFirewall(name, desc string, sourceRanges netsets.IPNe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// TODO: This completely breaks modularity in the cloudprovider but the methods
|
|
||||||
// shared with the TCPLoadBalancer take v1.ServicePorts.
|
mc := newFirewallMetricContext("create", region)
|
||||||
|
|
||||||
|
// TODO: This completely breaks modularity in the cloudprovider but
|
||||||
|
// the methods shared with the TCPLoadBalancer take v1.ServicePorts.
|
||||||
svcPorts := []v1.ServicePort{}
|
svcPorts := []v1.ServicePort{}
|
||||||
// TODO: Currently the only consumer of this method is the GCE L7
|
// TODO: Currently the only consumer of this method is the GCE L7
|
||||||
// loadbalancer controller, which never needs a protocol other than TCP.
|
// loadbalancer controller, which never needs a protocol other than
|
||||||
// We should pipe through a mapping of port:protocol and default to TCP
|
// TCP. We should pipe through a mapping of port:protocol and
|
||||||
// if UDP ports are required. This means the method signature will change
|
// default to TCP if UDP ports are required. This means the method
|
||||||
// forcing downstream clients to refactor interfaces.
|
// signature will change forcing downstream clients to refactor
|
||||||
|
// interfaces.
|
||||||
for _, p := range ports {
|
for _, p := range ports {
|
||||||
svcPorts = append(svcPorts, v1.ServicePort{Port: int32(p), Protocol: v1.ProtocolTCP})
|
svcPorts = append(svcPorts, v1.ServicePort{Port: int32(p), Protocol: v1.ProtocolTCP})
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, err := gce.getInstancesByNames(hostNames)
|
hosts, err := gce.getInstancesByNames(hostNames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.createFirewall(name, region, desc, sourceRanges, svcPorts, hosts)
|
|
||||||
|
return mc.Observe(gce.createFirewall(name, region, desc, sourceRanges, svcPorts, hosts))
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteFirewall deletes the given firewall rule.
|
// DeleteFirewall deletes the given firewall rule.
|
||||||
@ -61,30 +74,41 @@ func (gce *GCECloud) DeleteFirewall(name string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.deleteFirewall(name, region)
|
|
||||||
|
mc := newFirewallMetricContext("delete", region)
|
||||||
|
|
||||||
|
return mc.Observe(gce.deleteFirewall(name, region))
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateFirewall applies the given firewall rule as an update to an existing
|
// UpdateFirewall applies the given firewall rule as an update to an
|
||||||
// firewall rule with the same name.
|
// existing firewall rule with the same name.
|
||||||
func (gce *GCECloud) UpdateFirewall(name, desc string, sourceRanges netsets.IPNet, ports []int64, hostNames []string) error {
|
func (gce *GCECloud) UpdateFirewall(name, desc string, sourceRanges netsets.IPNet, ports []int64, hostNames []string) error {
|
||||||
|
|
||||||
region, err := GetGCERegion(gce.localZone)
|
region, err := GetGCERegion(gce.localZone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// TODO: This completely breaks modularity in the cloudprovider but the methods
|
|
||||||
// shared with the TCPLoadBalancer take v1.ServicePorts.
|
mc := newFirewallMetricContext("update", region)
|
||||||
|
|
||||||
|
// TODO: This completely breaks modularity in the cloudprovider but
|
||||||
|
// the methods shared with the TCPLoadBalancer take v1.ServicePorts.
|
||||||
svcPorts := []v1.ServicePort{}
|
svcPorts := []v1.ServicePort{}
|
||||||
// TODO: Currently the only consumer of this method is the GCE L7
|
// TODO: Currently the only consumer of this method is the GCE L7
|
||||||
// loadbalancer controller, which never needs a protocol other than TCP.
|
// loadbalancer controller, which never needs a protocol other than
|
||||||
// We should pipe through a mapping of port:protocol and default to TCP
|
// TCP. We should pipe through a mapping of port:protocol and
|
||||||
// if UDP ports are required. This means the method signature will change,
|
// default to TCP if UDP ports are required. This means the method
|
||||||
// forcing downstream clients to refactor interfaces.
|
// signature will change, forcing downstream clients to refactor
|
||||||
|
// interfaces.
|
||||||
for _, p := range ports {
|
for _, p := range ports {
|
||||||
svcPorts = append(svcPorts, v1.ServicePort{Port: int32(p), Protocol: v1.ProtocolTCP})
|
svcPorts = append(svcPorts, v1.ServicePort{Port: int32(p), Protocol: v1.ProtocolTCP})
|
||||||
}
|
}
|
||||||
|
|
||||||
hosts, err := gce.getInstancesByNames(hostNames)
|
hosts, err := gce.getInstancesByNames(hostNames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.updateFirewall(name, region, desc, sourceRanges, svcPorts, hosts)
|
|
||||||
|
return mc.Observe(gce.updateFirewall(name, region, desc, sourceRanges, svcPorts, hosts))
|
||||||
}
|
}
|
||||||
|
@ -18,16 +18,24 @@ package gce
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GlobalForwardingRule management
|
func newForwardingRuleMetricContext(request, region string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"forwardingrule_" + request, region, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CreateGlobalForwardingRule creates and returns a
|
// CreateGlobalForwardingRule creates and returns a
|
||||||
// GlobalForwardingRule that points to the given TargetHttp(s)Proxy.
|
// GlobalForwardingRule that points to the given TargetHttp(s)Proxy.
|
||||||
// targetProxyLink is the SelfLink of a TargetHttp(s)Proxy.
|
// targetProxyLink is the SelfLink of a TargetHttp(s)Proxy.
|
||||||
func (gce *GCECloud) CreateGlobalForwardingRule(targetProxyLink, ip, name, portRange string) (*compute.ForwardingRule, error) {
|
func (gce *GCECloud) CreateGlobalForwardingRule(targetProxyLink, ip, name, portRange string) (*compute.ForwardingRule, error) {
|
||||||
|
mc := newForwardingRuleMetricContext("create", "")
|
||||||
|
|
||||||
rule := &compute.ForwardingRule{
|
rule := &compute.ForwardingRule{
|
||||||
Name: name,
|
Name: name,
|
||||||
IPAddress: ip,
|
IPAddress: ip,
|
||||||
@ -37,34 +45,47 @@ func (gce *GCECloud) CreateGlobalForwardingRule(targetProxyLink, ip, name, portR
|
|||||||
}
|
}
|
||||||
op, err := gce.service.GlobalForwardingRules.Insert(gce.projectID, rule).Do()
|
op, err := gce.service.GlobalForwardingRules.Insert(gce.projectID, rule).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err = gce.waitForGlobalOp(op); err != nil {
|
if err = gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return gce.GetGlobalForwardingRule(name)
|
return gce.GetGlobalForwardingRule(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetProxyForGlobalForwardingRule links the given TargetHttp(s)Proxy with the given GlobalForwardingRule.
|
// SetProxyForGlobalForwardingRule links the given TargetHttp(s)Proxy with the given GlobalForwardingRule.
|
||||||
// targetProxyLink is the SelfLink of a TargetHttp(s)Proxy.
|
// targetProxyLink is the SelfLink of a TargetHttp(s)Proxy.
|
||||||
func (gce *GCECloud) SetProxyForGlobalForwardingRule(fw *compute.ForwardingRule, targetProxyLink string) error {
|
func (gce *GCECloud) SetProxyForGlobalForwardingRule(fw *compute.ForwardingRule, targetProxyLink string) error {
|
||||||
op, err := gce.service.GlobalForwardingRules.SetTarget(gce.projectID, fw.Name, &compute.TargetReference{Target: targetProxyLink}).Do()
|
mc := newForwardingRuleMetricContext("set_proxy", "")
|
||||||
|
|
||||||
|
op, err := gce.service.GlobalForwardingRules.SetTarget(
|
||||||
|
gce.projectID, fw.Name, &compute.TargetReference{Target: targetProxyLink}).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteGlobalForwardingRule deletes the GlobalForwardingRule by name.
|
// DeleteGlobalForwardingRule deletes the GlobalForwardingRule by name.
|
||||||
func (gce *GCECloud) DeleteGlobalForwardingRule(name string) error {
|
func (gce *GCECloud) DeleteGlobalForwardingRule(name string) error {
|
||||||
|
mc := newForwardingRuleMetricContext("delete", "")
|
||||||
|
|
||||||
op, err := gce.service.GlobalForwardingRules.Delete(gce.projectID, name).Do()
|
op, err := gce.service.GlobalForwardingRules.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
|
mc.Observe(nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGlobalForwardingRule returns the GlobalForwardingRule by name.
|
// GetGlobalForwardingRule returns the GlobalForwardingRule by name.
|
||||||
|
@ -16,9 +16,18 @@ limitations under the License.
|
|||||||
|
|
||||||
package gce
|
package gce
|
||||||
|
|
||||||
import compute "google.golang.org/api/compute/v1"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
// Legacy HTTP Health Checks
|
compute "google.golang.org/api/compute/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newHealthcheckMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"healthcheck_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetHttpHealthCheck returns the given HttpHealthCheck by name.
|
// GetHttpHealthCheck returns the given HttpHealthCheck by name.
|
||||||
func (gce *GCECloud) GetHttpHealthCheck(name string) (*compute.HttpHealthCheck, error) {
|
func (gce *GCECloud) GetHttpHealthCheck(name string) (*compute.HttpHealthCheck, error) {
|
||||||
@ -27,29 +36,41 @@ func (gce *GCECloud) GetHttpHealthCheck(name string) (*compute.HttpHealthCheck,
|
|||||||
|
|
||||||
// UpdateHttpHealthCheck applies the given HttpHealthCheck as an update.
|
// UpdateHttpHealthCheck applies the given HttpHealthCheck as an update.
|
||||||
func (gce *GCECloud) UpdateHttpHealthCheck(hc *compute.HttpHealthCheck) error {
|
func (gce *GCECloud) UpdateHttpHealthCheck(hc *compute.HttpHealthCheck) error {
|
||||||
|
mc := newHealthcheckMetricContext("update_legacy")
|
||||||
|
|
||||||
op, err := gce.service.HttpHealthChecks.Update(gce.projectID, hc.Name, hc).Do()
|
op, err := gce.service.HttpHealthChecks.Update(gce.projectID, hc.Name, hc).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteHttpHealthCheck deletes the given HttpHealthCheck by name.
|
// DeleteHttpHealthCheck deletes the given HttpHealthCheck by name.
|
||||||
func (gce *GCECloud) DeleteHttpHealthCheck(name string) error {
|
func (gce *GCECloud) DeleteHttpHealthCheck(name string) error {
|
||||||
|
mc := newHealthcheckMetricContext("delete_legacy")
|
||||||
|
|
||||||
op, err := gce.service.HttpHealthChecks.Delete(gce.projectID, name).Do()
|
op, err := gce.service.HttpHealthChecks.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHttpHealthCheck creates the given HttpHealthCheck.
|
// CreateHttpHealthCheck creates the given HttpHealthCheck.
|
||||||
func (gce *GCECloud) CreateHttpHealthCheck(hc *compute.HttpHealthCheck) error {
|
func (gce *GCECloud) CreateHttpHealthCheck(hc *compute.HttpHealthCheck) error {
|
||||||
|
mc := newHealthcheckMetricContext("create_legacy")
|
||||||
|
|
||||||
op, err := gce.service.HttpHealthChecks.Insert(gce.projectID, hc).Do()
|
op, err := gce.service.HttpHealthChecks.Insert(gce.projectID, hc).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListHttpHealthChecks lists all HttpHealthChecks in the project.
|
// ListHttpHealthChecks lists all HttpHealthChecks in the project.
|
||||||
@ -67,29 +88,38 @@ func (gce *GCECloud) GetHttpsHealthCheck(name string) (*compute.HttpsHealthCheck
|
|||||||
|
|
||||||
// UpdateHttpsHealthCheck applies the given HttpsHealthCheck as an update.
|
// UpdateHttpsHealthCheck applies the given HttpsHealthCheck as an update.
|
||||||
func (gce *GCECloud) UpdateHttpsHealthCheck(hc *compute.HttpsHealthCheck) error {
|
func (gce *GCECloud) UpdateHttpsHealthCheck(hc *compute.HttpsHealthCheck) error {
|
||||||
|
mc := newHealthcheckMetricContext("update_legacy")
|
||||||
op, err := gce.service.HttpsHealthChecks.Update(gce.projectID, hc.Name, hc).Do()
|
op, err := gce.service.HttpsHealthChecks.Update(gce.projectID, hc.Name, hc).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteHttpsHealthCheck deletes the given HttpsHealthCheck by name.
|
// DeleteHttpsHealthCheck deletes the given HttpsHealthCheck by name.
|
||||||
func (gce *GCECloud) DeleteHttpsHealthCheck(name string) error {
|
func (gce *GCECloud) DeleteHttpsHealthCheck(name string) error {
|
||||||
|
mc := newHealthcheckMetricContext("delete_legacy")
|
||||||
op, err := gce.service.HttpsHealthChecks.Delete(gce.projectID, name).Do()
|
op, err := gce.service.HttpsHealthChecks.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHttpsHealthCheck creates the given HttpsHealthCheck.
|
// CreateHttpsHealthCheck creates the given HttpsHealthCheck.
|
||||||
func (gce *GCECloud) CreateHttpsHealthCheck(hc *compute.HttpsHealthCheck) error {
|
func (gce *GCECloud) CreateHttpsHealthCheck(hc *compute.HttpsHealthCheck) error {
|
||||||
|
mc := newHealthcheckMetricContext("create_legacy")
|
||||||
op, err := gce.service.HttpsHealthChecks.Insert(gce.projectID, hc).Do()
|
op, err := gce.service.HttpsHealthChecks.Insert(gce.projectID, hc).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListHttpsHealthChecks lists all HttpsHealthChecks in the project.
|
// ListHttpsHealthChecks lists all HttpsHealthChecks in the project.
|
||||||
@ -107,29 +137,43 @@ func (gce *GCECloud) GetHealthCheck(name string) (*compute.HealthCheck, error) {
|
|||||||
|
|
||||||
// UpdateHealthCheck applies the given HealthCheck as an update.
|
// UpdateHealthCheck applies the given HealthCheck as an update.
|
||||||
func (gce *GCECloud) UpdateHealthCheck(hc *compute.HealthCheck) error {
|
func (gce *GCECloud) UpdateHealthCheck(hc *compute.HealthCheck) error {
|
||||||
|
mc := newHealthcheckMetricContext("update")
|
||||||
|
|
||||||
op, err := gce.service.HealthChecks.Update(gce.projectID, hc.Name, hc).Do()
|
op, err := gce.service.HealthChecks.Update(gce.projectID, hc.Name, hc).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteHealthCheck deletes the given HealthCheck by name.
|
// DeleteHealthCheck deletes the given HealthCheck by name.
|
||||||
func (gce *GCECloud) DeleteHealthCheck(name string) error {
|
func (gce *GCECloud) DeleteHealthCheck(name string) error {
|
||||||
|
mc := newHealthcheckMetricContext("delete")
|
||||||
|
|
||||||
op, err := gce.service.HealthChecks.Delete(gce.projectID, name).Do()
|
op, err := gce.service.HealthChecks.Delete(gce.projectID, name).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHealthCheck creates the given HealthCheck.
|
// CreateHealthCheck creates the given HealthCheck.
|
||||||
func (gce *GCECloud) CreateHealthCheck(hc *compute.HealthCheck) error {
|
func (gce *GCECloud) CreateHealthCheck(hc *compute.HealthCheck) error {
|
||||||
|
mc := newHealthcheckMetricContext("create")
|
||||||
|
|
||||||
op, err := gce.service.HealthChecks.Insert(gce.projectID, hc).Do()
|
op, err := gce.service.HealthChecks.Insert(gce.projectID, hc).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
|
||||||
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListHealthChecks lists all HealthCheck in the project.
|
// ListHealthChecks lists all HealthCheck in the project.
|
||||||
|
@ -20,43 +20,63 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InstanceGroup Management
|
func newInstanceGroupMetricContext(request string, zone string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"instancegroup_" + request, unusedMetricLabel, zone},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CreateInstanceGroup creates an instance group with the given instances. It is the callers responsibility to add named ports.
|
// CreateInstanceGroup creates an instance group with the given
|
||||||
|
// instances. It is the callers responsibility to add named ports.
|
||||||
func (gce *GCECloud) CreateInstanceGroup(name string, zone string) (*compute.InstanceGroup, error) {
|
func (gce *GCECloud) CreateInstanceGroup(name string, zone string) (*compute.InstanceGroup, error) {
|
||||||
|
mc := newInstanceGroupMetricContext("create", zone)
|
||||||
|
|
||||||
op, err := gce.service.InstanceGroups.Insert(
|
op, err := gce.service.InstanceGroups.Insert(
|
||||||
gce.projectID, zone, &compute.InstanceGroup{Name: name}).Do()
|
gce.projectID, zone, &compute.InstanceGroup{Name: name}).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err = gce.waitForZoneOp(op, zone); err != nil {
|
|
||||||
|
if err = gce.waitForZoneOp(op, zone, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return gce.GetInstanceGroup(name, zone)
|
return gce.GetInstanceGroup(name, zone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteInstanceGroup deletes an instance group.
|
// DeleteInstanceGroup deletes an instance group.
|
||||||
func (gce *GCECloud) DeleteInstanceGroup(name string, zone string) error {
|
func (gce *GCECloud) DeleteInstanceGroup(name string, zone string) error {
|
||||||
|
mc := newInstanceGroupMetricContext("delete", zone)
|
||||||
|
|
||||||
op, err := gce.service.InstanceGroups.Delete(
|
op, err := gce.service.InstanceGroups.Delete(
|
||||||
gce.projectID, zone, name).Do()
|
gce.projectID, zone, name).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForZoneOp(op, zone)
|
|
||||||
|
return gce.waitForZoneOp(op, zone, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListInstanceGroups lists all InstanceGroups in the project and zone.
|
// ListInstanceGroups lists all InstanceGroups in the project and
|
||||||
|
// zone.
|
||||||
func (gce *GCECloud) ListInstanceGroups(zone string) (*compute.InstanceGroupList, error) {
|
func (gce *GCECloud) ListInstanceGroups(zone string) (*compute.InstanceGroupList, error) {
|
||||||
// TODO: use PageToken to list all not just the first 500
|
// TODO: use PageToken to list all not just the first 500
|
||||||
return gce.service.InstanceGroups.List(gce.projectID, zone).Do()
|
return gce.service.InstanceGroups.List(gce.projectID, zone).Do()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListInstancesInInstanceGroup lists all the instances in a given instance group and state.
|
// ListInstancesInInstanceGroup lists all the instances in a given
|
||||||
|
// instance group and state.
|
||||||
func (gce *GCECloud) ListInstancesInInstanceGroup(name string, zone string, state string) (*compute.InstanceGroupsListInstances, error) {
|
func (gce *GCECloud) ListInstancesInInstanceGroup(name string, zone string, state string) (*compute.InstanceGroupsListInstances, error) {
|
||||||
// TODO: use PageToken to list all not just the first 500
|
// TODO: use PageToken to list all not just the first 500
|
||||||
return gce.service.InstanceGroups.ListInstances(
|
return gce.service.InstanceGroups.ListInstances(
|
||||||
@ -64,8 +84,11 @@ func (gce *GCECloud) ListInstancesInInstanceGroup(name string, zone string, stat
|
|||||||
&compute.InstanceGroupsListInstancesRequest{InstanceState: state}).Do()
|
&compute.InstanceGroupsListInstancesRequest{InstanceState: state}).Do()
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddInstancesToInstanceGroup adds the given instances to the given instance group.
|
// AddInstancesToInstanceGroup adds the given instances to the given
|
||||||
|
// instance group.
|
||||||
func (gce *GCECloud) AddInstancesToInstanceGroup(name string, zone string, instanceNames []string) error {
|
func (gce *GCECloud) AddInstancesToInstanceGroup(name string, zone string, instanceNames []string) error {
|
||||||
|
mc := newInstanceGroupMetricContext("add_instances", zone)
|
||||||
|
|
||||||
if len(instanceNames) == 0 {
|
if len(instanceNames) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -81,13 +104,18 @@ func (gce *GCECloud) AddInstancesToInstanceGroup(name string, zone string, insta
|
|||||||
}).Do()
|
}).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForZoneOp(op, zone)
|
|
||||||
|
return gce.waitForZoneOp(op, zone, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveInstancesFromInstanceGroup removes the given instances from the instance group.
|
// RemoveInstancesFromInstanceGroup removes the given instances from
|
||||||
|
// the instance group.
|
||||||
func (gce *GCECloud) RemoveInstancesFromInstanceGroup(name string, zone string, instanceNames []string) error {
|
func (gce *GCECloud) RemoveInstancesFromInstanceGroup(name string, zone string, instanceNames []string) error {
|
||||||
|
mc := newInstanceGroupMetricContext("remove_instances", zone)
|
||||||
|
|
||||||
if len(instanceNames) == 0 {
|
if len(instanceNames) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -104,21 +132,28 @@ func (gce *GCECloud) RemoveInstancesFromInstanceGroup(name string, zone string,
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
|
mc.Observe(nil)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mc.Observe(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return gce.waitForZoneOp(op, zone)
|
|
||||||
|
return gce.waitForZoneOp(op, zone, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddPortToInstanceGroup adds a port to the given instance group.
|
// AddPortToInstanceGroup adds a port to the given instance group.
|
||||||
func (gce *GCECloud) AddPortToInstanceGroup(ig *compute.InstanceGroup, port int64) (*compute.NamedPort, error) {
|
func (gce *GCECloud) AddPortToInstanceGroup(ig *compute.InstanceGroup, port int64) (*compute.NamedPort, error) {
|
||||||
|
mc := newInstanceGroupMetricContext("add_port", ig.Zone)
|
||||||
|
|
||||||
for _, np := range ig.NamedPorts {
|
for _, np := range ig.NamedPorts {
|
||||||
if np.Port == port {
|
if np.Port == port {
|
||||||
glog.V(3).Infof("Instance group %v already has named port %+v", ig.Name, np)
|
glog.V(3).Infof("Instance group %v already has named port %+v", ig.Name, np)
|
||||||
return np, nil
|
return np, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Infof("Adding port %v to instance group %v with %d ports", port, ig.Name, len(ig.NamedPorts))
|
glog.Infof("Adding port %v to instance group %v with %d ports", port, ig.Name, len(ig.NamedPorts))
|
||||||
namedPort := compute.NamedPort{Name: fmt.Sprintf("port%v", port), Port: port}
|
namedPort := compute.NamedPort{Name: fmt.Sprintf("port%v", port), Port: port}
|
||||||
ig.NamedPorts = append(ig.NamedPorts, &namedPort)
|
ig.NamedPorts = append(ig.NamedPorts, &namedPort)
|
||||||
@ -133,12 +168,16 @@ func (gce *GCECloud) AddPortToInstanceGroup(ig *compute.InstanceGroup, port int6
|
|||||||
gce.projectID, zone, ig.Name,
|
gce.projectID, zone, ig.Name,
|
||||||
&compute.InstanceGroupsSetNamedPortsRequest{
|
&compute.InstanceGroupsSetNamedPortsRequest{
|
||||||
NamedPorts: ig.NamedPorts}).Do()
|
NamedPorts: ig.NamedPorts}).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
mc.Observe(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err = gce.waitForZoneOp(op, zone); err != nil {
|
|
||||||
|
if err = gce.waitForZoneOp(op, zone, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &namedPort, nil
|
return &namedPort, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,13 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func newInstancesMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"instances_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NodeAddresses is an implementation of Instances.NodeAddresses.
|
// NodeAddresses is an implementation of Instances.NodeAddresses.
|
||||||
func (gce *GCECloud) NodeAddresses(_ types.NodeName) ([]v1.NodeAddress, error) {
|
func (gce *GCECloud) NodeAddresses(_ types.NodeName) ([]v1.NodeAddress, error) {
|
||||||
internalIP, err := metadata.Get("instance/network-interfaces/0/ip")
|
internalIP, err := metadata.Get("instance/network-interfaces/0/ip")
|
||||||
@ -156,15 +163,22 @@ func (gce *GCECloud) AddSSHKeyToAllInstances(user string, keyData []byte) error
|
|||||||
Value: &keyString,
|
Value: &keyString,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
op, err := gce.service.Projects.SetCommonInstanceMetadata(gce.projectID, project.CommonInstanceMetadata).Do()
|
|
||||||
|
mc := newInstancesMetricContext("add_ssh_key")
|
||||||
|
op, err := gce.service.Projects.SetCommonInstanceMetadata(
|
||||||
|
gce.projectID, project.CommonInstanceMetadata).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("Could not Set Metadata: %v", err)
|
glog.Errorf("Could not Set Metadata: %v", err)
|
||||||
|
mc.Observe(err)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
if err := gce.waitForGlobalOp(op); err != nil {
|
|
||||||
|
if err := gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
glog.Errorf("Could not Set Metadata: %v", err)
|
glog.Errorf("Could not Set Metadata: %v", err)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
glog.Infof("Successfully added sshKey to project metadata")
|
glog.Infof("Successfully added sshKey to project metadata")
|
||||||
return true, nil
|
return true, nil
|
||||||
})
|
})
|
||||||
@ -324,8 +338,7 @@ func (gce *GCECloud) getInstanceByName(name string) (*gceInstance, error) {
|
|||||||
// Avoid changing behaviour when not managing multiple zones
|
// Avoid changing behaviour when not managing multiple zones
|
||||||
for _, zone := range gce.managedZones {
|
for _, zone := range gce.managedZones {
|
||||||
name = canonicalizeInstanceName(name)
|
name = canonicalizeInstanceName(name)
|
||||||
dc := contextWithNamespace(name, "gce_instance_list")
|
res, err := gce.service.Instances.Get(gce.projectID, zone, name).Do()
|
||||||
res, err := gce.service.Instances.Get(gce.projectID, zone, name).Context(dc).Do()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Errorf("getInstanceByName: failed to get instance %s; err: %v", name, err)
|
glog.Errorf("getInstanceByName: failed to get instance %s; err: %v", name, err)
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
@ -42,7 +43,30 @@ type cidrs struct {
|
|||||||
isSet bool
|
isSet bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var lbSrcRngsFlag cidrs
|
var (
|
||||||
|
lbSrcRngsFlag cidrs
|
||||||
|
)
|
||||||
|
|
||||||
|
func newLoadBalancerMetricContext(request, region string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"loadbalancer_" + request, region, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTargetPoolMetricContext(request, region string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"targetpool_" + request, region, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newAddressMetricContext(request, region string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"address_" + request, region, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
var err error
|
var err error
|
||||||
@ -106,6 +130,7 @@ func (gce *GCECloud) GetLoadBalancer(clusterName string, service *v1.Service) (*
|
|||||||
// Our load balancers in GCE consist of four separate GCE resources - a static
|
// Our load balancers in GCE consist of four separate GCE resources - a static
|
||||||
// IP address, a firewall rule, a target pool, and a forwarding rule. This
|
// IP address, a firewall rule, a target pool, and a forwarding rule. This
|
||||||
// function has to manage all of them.
|
// function has to manage all of them.
|
||||||
|
//
|
||||||
// Due to an interesting series of design decisions, this handles both creating
|
// Due to an interesting series of design decisions, this handles both creating
|
||||||
// new load balancers and updating existing load balancers, recognizing when
|
// new load balancers and updating existing load balancers, recognizing when
|
||||||
// each is needed.
|
// each is needed.
|
||||||
@ -131,7 +156,8 @@ func (gce *GCECloud) EnsureLoadBalancer(clusterName string, apiService *v1.Servi
|
|||||||
affinityType := apiService.Spec.SessionAffinity
|
affinityType := apiService.Spec.SessionAffinity
|
||||||
|
|
||||||
serviceName := types.NamespacedName{Namespace: apiService.Namespace, Name: apiService.Name}
|
serviceName := types.NamespacedName{Namespace: apiService.Namespace, Name: apiService.Name}
|
||||||
glog.V(2).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)", loadBalancerName, gce.region, loadBalancerIP, portStr, hostNames, serviceName, apiService.Annotations)
|
glog.V(2).Infof("EnsureLoadBalancer(%v, %v, %v, %v, %v, %v, %v)",
|
||||||
|
loadBalancerName, gce.region, loadBalancerIP, portStr, hostNames, serviceName, apiService.Annotations)
|
||||||
|
|
||||||
// Check if the forwarding rule exists, and if so, what its IP is.
|
// Check if the forwarding rule exists, and if so, what its IP is.
|
||||||
fwdRuleExists, fwdRuleNeedsUpdate, fwdRuleIP, err := gce.forwardingRuleNeedsUpdate(loadBalancerName, gce.region, loadBalancerIP, ports)
|
fwdRuleExists, fwdRuleNeedsUpdate, fwdRuleIP, err := gce.forwardingRuleNeedsUpdate(loadBalancerName, gce.region, loadBalancerIP, ports)
|
||||||
@ -139,7 +165,8 @@ func (gce *GCECloud) EnsureLoadBalancer(clusterName string, apiService *v1.Servi
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if !fwdRuleExists {
|
if !fwdRuleExists {
|
||||||
glog.Infof("Forwarding rule %v for Service %v/%v doesn't exist", loadBalancerName, apiService.Namespace, apiService.Name)
|
glog.V(2).Infof("Forwarding rule %v for Service %v/%v doesn't exist",
|
||||||
|
loadBalancerName, apiService.Namespace, apiService.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we know which IP address will be used and have properly reserved
|
// Make sure we know which IP address will be used and have properly reserved
|
||||||
@ -454,8 +481,6 @@ func (gce *GCECloud) EnsureLoadBalancerDeleted(clusterName string, service *v1.S
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX ----------
|
|
||||||
|
|
||||||
func (gce *GCECloud) DeleteForwardingRule(name string) error {
|
func (gce *GCECloud) DeleteForwardingRule(name string) error {
|
||||||
region, err := GetGCERegion(gce.localZone)
|
region, err := GetGCERegion(gce.localZone)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -465,15 +490,18 @@ func (gce *GCECloud) DeleteForwardingRule(name string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) deleteForwardingRule(name, region string) error {
|
func (gce *GCECloud) deleteForwardingRule(name, region string) error {
|
||||||
|
mc := newForwardingRuleMetricContext("delete", region)
|
||||||
op, err := gce.service.ForwardingRules.Delete(gce.projectID, region, name).Do()
|
op, err := gce.service.ForwardingRules.Delete(gce.projectID, region, name).Do()
|
||||||
|
|
||||||
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
glog.Infof("Forwarding rule %s already deleted. Continuing to delete other resources.", name)
|
glog.Infof("Forwarding rule %s already deleted. Continuing to delete other resources.", name)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
glog.Warningf("Failed to delete forwarding rule %s: got error %s.", name, err.Error())
|
glog.Warningf("Failed to delete forwarding rule %s: got error %s.", name, err.Error())
|
||||||
return err
|
return mc.Observe(err)
|
||||||
} else {
|
} else {
|
||||||
if err := gce.waitForRegionOp(op, region); err != nil {
|
if err := gce.waitForRegionOp(op, region, mc); err != nil {
|
||||||
glog.Warningf("Failed waiting for forwarding rule %s to be deleted: got error %s.", name, err.Error())
|
glog.Warningf("Failed waiting for forwarding rule %s to be deleted: got error %s.",
|
||||||
|
name, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -490,18 +518,22 @@ func (gce *GCECloud) DeleteTargetPool(name string, hc *compute.HttpHealthCheck)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) deleteTargetPool(name, region string, hc *compute.HttpHealthCheck) error {
|
func (gce *GCECloud) deleteTargetPool(name, region string, hc *compute.HttpHealthCheck) error {
|
||||||
|
mc := newTargetPoolMetricContext("delete", region)
|
||||||
op, err := gce.service.TargetPools.Delete(gce.projectID, region, name).Do()
|
op, err := gce.service.TargetPools.Delete(gce.projectID, region, name).Do()
|
||||||
|
|
||||||
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
glog.Infof("Target pool %s already deleted. Continuing to delete other resources.", name)
|
glog.Infof("Target pool %s already deleted. Continuing to delete other resources.", name)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
glog.Warningf("Failed to delete target pool %s, got error %s.", name, err.Error())
|
glog.Warningf("Failed to delete target pool %s, got error %s.", name, err.Error())
|
||||||
return err
|
return mc.Observe(err)
|
||||||
} else {
|
} else {
|
||||||
if err := gce.waitForRegionOp(op, region); err != nil {
|
if err := gce.waitForRegionOp(op, region, mc); err != nil {
|
||||||
glog.Warningf("Failed waiting for target pool %s to be deleted: got error %s.", name, err.Error())
|
glog.Warningf("Failed waiting for target pool %s to be deleted: got error %s.",
|
||||||
|
name, err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deletion of health checks is allowed only after the TargetPool reference is deleted
|
// Deletion of health checks is allowed only after the TargetPool reference is deleted
|
||||||
if hc != nil {
|
if hc != nil {
|
||||||
glog.Infof("Deleting health check %v", hc.Name)
|
glog.Infof("Deleting health check %v", hc.Name)
|
||||||
@ -546,12 +578,14 @@ func (gce *GCECloud) createTargetPool(name, serviceName, region string, hosts []
|
|||||||
SessionAffinity: translateAffinityType(affinityType),
|
SessionAffinity: translateAffinityType(affinityType),
|
||||||
HealthChecks: hcLinks,
|
HealthChecks: hcLinks,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mc := newTargetPoolMetricContext("insert", region)
|
||||||
op, err := gce.service.TargetPools.Insert(gce.projectID, region, pool).Do()
|
op, err := gce.service.TargetPools.Insert(gce.projectID, region, pool).Do()
|
||||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
if op != nil {
|
if op != nil {
|
||||||
err = gce.waitForRegionOp(op, region)
|
err = gce.waitForRegionOp(op, region, mc)
|
||||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -575,22 +609,25 @@ func (gce *GCECloud) updateTargetPool(loadBalancerName string, existing sets.Str
|
|||||||
|
|
||||||
if len(toAdd) > 0 {
|
if len(toAdd) > 0 {
|
||||||
add := &compute.TargetPoolsAddInstanceRequest{Instances: toAdd}
|
add := &compute.TargetPoolsAddInstanceRequest{Instances: toAdd}
|
||||||
|
|
||||||
|
mc := newTargetPoolMetricContext("update", gce.region)
|
||||||
op, err := gce.service.TargetPools.AddInstance(gce.projectID, gce.region, loadBalancerName, add).Do()
|
op, err := gce.service.TargetPools.AddInstance(gce.projectID, gce.region, loadBalancerName, add).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
if err := gce.waitForRegionOp(op, gce.region); err != nil {
|
if err := gce.waitForRegionOp(op, gce.region, mc); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(toRemove) > 0 {
|
if len(toRemove) > 0 {
|
||||||
|
mc := newTargetPoolMetricContext("delete", gce.region)
|
||||||
rm := &compute.TargetPoolsRemoveInstanceRequest{Instances: toRemove}
|
rm := &compute.TargetPoolsRemoveInstanceRequest{Instances: toRemove}
|
||||||
op, err := gce.service.TargetPools.RemoveInstance(gce.projectID, gce.region, loadBalancerName, rm).Do()
|
op, err := gce.service.TargetPools.RemoveInstance(gce.projectID, gce.region, loadBalancerName, rm).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
if err := gce.waitForRegionOp(op, gce.region); err != nil {
|
if err := gce.waitForRegionOp(op, gce.region, mc); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -866,12 +903,13 @@ func (gce *GCECloud) createForwardingRule(name, serviceName, region, ipAddress s
|
|||||||
Target: gce.targetPoolURL(name, region),
|
Target: gce.targetPoolURL(name, region),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mc := newForwardingRuleMetricContext("create", region)
|
||||||
op, err := gce.service.ForwardingRules.Insert(gce.projectID, region, req).Do()
|
op, err := gce.service.ForwardingRules.Insert(gce.projectID, region, req).Do()
|
||||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
if op != nil {
|
if op != nil {
|
||||||
err = gce.waitForRegionOp(op, region)
|
err = gce.waitForRegionOp(op, region, mc)
|
||||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -880,16 +918,17 @@ func (gce *GCECloud) createForwardingRule(name, serviceName, region, ipAddress s
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) createFirewall(name, region, desc string, sourceRanges netsets.IPNet, ports []v1.ServicePort, hosts []*gceInstance) error {
|
func (gce *GCECloud) createFirewall(name, region, desc string, sourceRanges netsets.IPNet, ports []v1.ServicePort, hosts []*gceInstance) error {
|
||||||
|
mc := newFirewallMetricContext("create", region)
|
||||||
firewall, err := gce.firewallObject(name, region, desc, sourceRanges, ports, hosts)
|
firewall, err := gce.firewallObject(name, region, desc, sourceRanges, ports, hosts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
op, err := gce.service.Firewalls.Insert(gce.projectID, firewall).Do()
|
op, err := gce.service.Firewalls.Insert(gce.projectID, firewall).Do()
|
||||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
if op != nil {
|
if op != nil {
|
||||||
err = gce.waitForGlobalOp(op)
|
err = gce.waitForGlobalOp(op, mc)
|
||||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -898,16 +937,17 @@ func (gce *GCECloud) createFirewall(name, region, desc string, sourceRanges nets
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) updateFirewall(name, region, desc string, sourceRanges netsets.IPNet, ports []v1.ServicePort, hosts []*gceInstance) error {
|
func (gce *GCECloud) updateFirewall(name, region, desc string, sourceRanges netsets.IPNet, ports []v1.ServicePort, hosts []*gceInstance) error {
|
||||||
|
mc := newFirewallMetricContext("update", region)
|
||||||
firewall, err := gce.firewallObject(name, region, desc, sourceRanges, ports, hosts)
|
firewall, err := gce.firewallObject(name, region, desc, sourceRanges, ports, hosts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
op, err := gce.service.Firewalls.Update(gce.projectID, makeFirewallName(name), firewall).Do()
|
op, err := gce.service.Firewalls.Update(gce.projectID, makeFirewallName(name), firewall).Do()
|
||||||
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
if err != nil && !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
if op != nil {
|
if op != nil {
|
||||||
err = gce.waitForGlobalOp(op)
|
err = gce.waitForGlobalOp(op, mc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1065,19 +1105,23 @@ func (gce *GCECloud) ensureStaticIP(name, serviceName, region, existingIP string
|
|||||||
Name: name,
|
Name: name,
|
||||||
Description: fmt.Sprintf(`{"kubernetes.io/service-name":"%s"}`, serviceName),
|
Description: fmt.Sprintf(`{"kubernetes.io/service-name":"%s"}`, serviceName),
|
||||||
}
|
}
|
||||||
|
|
||||||
if existingIP != "" {
|
if existingIP != "" {
|
||||||
addressObj.Address = existingIP
|
addressObj.Address = existingIP
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mc := newAddressMetricContext("create", region)
|
||||||
op, err := gce.service.Addresses.Insert(gce.projectID, region, addressObj).Do()
|
op, err := gce.service.Addresses.Insert(gce.projectID, region, addressObj).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !isHTTPErrorCode(err, http.StatusConflict) {
|
if !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return "", false, fmt.Errorf("error creating gce static IP address: %v", err)
|
return "", false, fmt.Errorf("error creating gce static IP address: %v",
|
||||||
|
mc.Observe(err))
|
||||||
}
|
}
|
||||||
// StatusConflict == the IP exists already.
|
// StatusConflict == the IP exists already.
|
||||||
existed = true
|
existed = true
|
||||||
}
|
}
|
||||||
if op != nil {
|
if op != nil {
|
||||||
err := gce.waitForRegionOp(op, region)
|
err := gce.waitForRegionOp(op, region, mc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !isHTTPErrorCode(err, http.StatusConflict) {
|
if !isHTTPErrorCode(err, http.StatusConflict) {
|
||||||
return "", false, fmt.Errorf("error waiting for gce static IP address to be created: %v", err)
|
return "", false, fmt.Errorf("error waiting for gce static IP address to be created: %v", err)
|
||||||
@ -1096,15 +1140,17 @@ func (gce *GCECloud) ensureStaticIP(name, serviceName, region, existingIP string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) deleteFirewall(name, region string) error {
|
func (gce *GCECloud) deleteFirewall(name, region string) error {
|
||||||
|
mc := newFirewallMetricContext("delete", region)
|
||||||
fwName := makeFirewallName(name)
|
fwName := makeFirewallName(name)
|
||||||
op, err := gce.service.Firewalls.Delete(gce.projectID, fwName).Do()
|
op, err := gce.service.Firewalls.Delete(gce.projectID, fwName).Do()
|
||||||
|
|
||||||
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
glog.Infof("Firewall %s already deleted. Continuing to delete other resources.", name)
|
glog.V(2).Infof("Firewall %s already deleted. Continuing to delete other resources.", name)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
glog.Warningf("Failed to delete firewall %s, got error %v", fwName, err)
|
glog.Warningf("Failed to delete firewall %s, got error %v", fwName, err)
|
||||||
return err
|
return mc.Observe(err)
|
||||||
} else {
|
} else {
|
||||||
if err := gce.waitForGlobalOp(op); err != nil {
|
if err := gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
glog.Warningf("Failed waiting for Firewall %s to be deleted. Got error: %v", fwName, err)
|
glog.Warningf("Failed waiting for Firewall %s to be deleted. Got error: %v", fwName, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1113,14 +1159,15 @@ func (gce *GCECloud) deleteFirewall(name, region string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) deleteStaticIP(name, region string) error {
|
func (gce *GCECloud) deleteStaticIP(name, region string) error {
|
||||||
|
mc := newAddressMetricContext("delete", region)
|
||||||
op, err := gce.service.Addresses.Delete(gce.projectID, region, name).Do()
|
op, err := gce.service.Addresses.Delete(gce.projectID, region, name).Do()
|
||||||
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
if err != nil && isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
glog.Infof("Static IP address %s is not reserved", name)
|
glog.Infof("Static IP address %s is not reserved", name)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
glog.Warningf("Failed to delete static IP address %s, got error %v", name, err)
|
glog.Warningf("Failed to delete static IP address %s, got error %v", name, err)
|
||||||
return err
|
return mc.Observe(err)
|
||||||
} else {
|
} else {
|
||||||
if err := gce.waitForRegionOp(op, region); err != nil {
|
if err := gce.waitForRegionOp(op, region, mc); err != nil {
|
||||||
glog.Warningf("Failed waiting for address %s to be deleted, got error: %v", name, err)
|
glog.Warningf("Failed waiting for address %s to be deleted, got error: %v", name, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
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 gce
|
|
||||||
|
|
||||||
import "github.com/prometheus/client_golang/prometheus"
|
|
||||||
|
|
||||||
var gceMetricMap = map[string]*prometheus.HistogramVec{
|
|
||||||
"gce_instance_list": prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "gce_instance_list_duration_seconds",
|
|
||||||
Help: "Latency of instance listing calls",
|
|
||||||
},
|
|
||||||
[]string{"namespace"},
|
|
||||||
),
|
|
||||||
"gce_disk_insert": prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "gce_disk_insert_duration_seconds",
|
|
||||||
Help: "Latency of disk insert calls",
|
|
||||||
},
|
|
||||||
[]string{"namespace"},
|
|
||||||
),
|
|
||||||
"gce_disk_delete": prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "gce_disk_delete_duration_seconds",
|
|
||||||
Help: "Latency of disk delete calls",
|
|
||||||
},
|
|
||||||
[]string{"namespace"},
|
|
||||||
),
|
|
||||||
"gce_attach_disk": prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "gce_attach_disk_duration_seconds",
|
|
||||||
Help: "Latency of attach disk calls",
|
|
||||||
},
|
|
||||||
[]string{"namespace"},
|
|
||||||
),
|
|
||||||
"gce_detach_disk": prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "gce_detach_disk_duration_seconds",
|
|
||||||
Help: "Latency of detach disk calls",
|
|
||||||
},
|
|
||||||
[]string{"namespace"},
|
|
||||||
),
|
|
||||||
"gce_list_disk": prometheus.NewHistogramVec(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Name: "gce_list_disk_duration_seconds",
|
|
||||||
Help: "Latency of list disk calls",
|
|
||||||
},
|
|
||||||
[]string{"namespace"},
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerMetrics() {
|
|
||||||
for _, metric := range gceMetricMap {
|
|
||||||
prometheus.MustRegister(metric)
|
|
||||||
}
|
|
||||||
}
|
|
@ -27,9 +27,9 @@ import (
|
|||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (gce *GCECloud) waitForOp(op *compute.Operation, getOperation func(operationName string) (*compute.Operation, error)) error {
|
func (gce *GCECloud) waitForOp(op *compute.Operation, getOperation func(operationName string) (*compute.Operation, error), mc *metricContext) error {
|
||||||
if op == nil {
|
if op == nil {
|
||||||
return fmt.Errorf("operation must not be nil")
|
return mc.Observe(fmt.Errorf("operation must not be nil"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if opIsDone(op) {
|
if opIsDone(op) {
|
||||||
@ -38,18 +38,20 @@ func (gce *GCECloud) waitForOp(op *compute.Operation, getOperation func(operatio
|
|||||||
|
|
||||||
opStart := time.Now()
|
opStart := time.Now()
|
||||||
opName := op.Name
|
opName := op.Name
|
||||||
|
|
||||||
return wait.Poll(operationPollInterval, operationPollTimeoutDuration, func() (bool, error) {
|
return wait.Poll(operationPollInterval, operationPollTimeoutDuration, func() (bool, error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
gce.operationPollRateLimiter.Accept()
|
gce.operationPollRateLimiter.Accept()
|
||||||
duration := time.Now().Sub(start)
|
duration := time.Now().Sub(start)
|
||||||
if duration > 5*time.Second {
|
if duration > 5*time.Second {
|
||||||
glog.Infof("pollOperation: throttled %v for %v", duration, opName)
|
glog.V(2).Infof("pollOperation: throttled %v for %v", duration, opName)
|
||||||
}
|
}
|
||||||
pollOp, err := getOperation(opName)
|
pollOp, err := getOperation(opName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.Warningf("GCE poll operation %s failed: pollOp: [%v] err: [%v] getErrorFromOp: [%v]",
|
glog.Warningf("GCE poll operation %s failed: pollOp: [%v] err: [%v] getErrorFromOp: [%v]",
|
||||||
opName, pollOp, err, getErrorFromOp(pollOp))
|
opName, pollOp, err, getErrorFromOp(pollOp))
|
||||||
}
|
}
|
||||||
|
|
||||||
done := opIsDone(pollOp)
|
done := opIsDone(pollOp)
|
||||||
if done {
|
if done {
|
||||||
duration := time.Now().Sub(opStart)
|
duration := time.Now().Sub(opStart)
|
||||||
@ -60,12 +62,13 @@ func (gce *GCECloud) waitForOp(op *compute.Operation, getOperation func(operatio
|
|||||||
glog.Warningf("waitForOperation: long operation (%v): %v (failed to encode to JSON: %v)",
|
glog.Warningf("waitForOperation: long operation (%v): %v (failed to encode to JSON: %v)",
|
||||||
duration, pollOp, err)
|
duration, pollOp, err)
|
||||||
} else {
|
} else {
|
||||||
glog.Infof("waitForOperation: long operation (%v): %v",
|
glog.V(2).Infof("waitForOperation: long operation (%v): %v",
|
||||||
duration, string(enc))
|
duration, string(enc))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return done, getErrorFromOp(pollOp)
|
|
||||||
|
return done, mc.Observe(getErrorFromOp(pollOp))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,20 +89,20 @@ func getErrorFromOp(op *compute.Operation) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) waitForGlobalOp(op *compute.Operation) error {
|
func (gce *GCECloud) waitForGlobalOp(op *compute.Operation, mc *metricContext) error {
|
||||||
return gce.waitForOp(op, func(operationName string) (*compute.Operation, error) {
|
return gce.waitForOp(op, func(operationName string) (*compute.Operation, error) {
|
||||||
return gce.service.GlobalOperations.Get(gce.projectID, operationName).Do()
|
return gce.service.GlobalOperations.Get(gce.projectID, operationName).Do()
|
||||||
})
|
}, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) waitForRegionOp(op *compute.Operation, region string) error {
|
func (gce *GCECloud) waitForRegionOp(op *compute.Operation, region string, mc *metricContext) error {
|
||||||
return gce.waitForOp(op, func(operationName string) (*compute.Operation, error) {
|
return gce.waitForOp(op, func(operationName string) (*compute.Operation, error) {
|
||||||
return gce.service.RegionOperations.Get(gce.projectID, region, operationName).Do()
|
return gce.service.RegionOperations.Get(gce.projectID, region, operationName).Do()
|
||||||
})
|
}, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) waitForZoneOp(op *compute.Operation, zone string) error {
|
func (gce *GCECloud) waitForZoneOp(op *compute.Operation, zone string, mc *metricContext) error {
|
||||||
return gce.waitForOp(op, func(operationName string) (*compute.Operation, error) {
|
return gce.waitForOp(op, func(operationName string) (*compute.Operation, error) {
|
||||||
return gce.service.ZoneOperations.Get(gce.projectID, zone, operationName).Do()
|
return gce.service.ZoneOperations.Get(gce.projectID, zone, operationName).Do()
|
||||||
})
|
}, mc)
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/cloudprovider"
|
"k8s.io/kubernetes/pkg/cloudprovider"
|
||||||
@ -29,6 +30,13 @@ import (
|
|||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func newRoutesMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"routes_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, error) {
|
func (gce *GCECloud) ListRoutes(clusterName string) ([]*cloudprovider.Route, error) {
|
||||||
var routes []*cloudprovider.Route
|
var routes []*cloudprovider.Route
|
||||||
pageToken := ""
|
pageToken := ""
|
||||||
@ -80,6 +88,8 @@ func (gce *GCECloud) CreateRoute(clusterName string, nameHint string, route *clo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mc := newRoutesMetricContext("create")
|
||||||
insertOp, err := gce.service.Routes.Insert(gce.projectID, &compute.Route{
|
insertOp, err := gce.service.Routes.Insert(gce.projectID, &compute.Route{
|
||||||
Name: routeName,
|
Name: routeName,
|
||||||
DestRange: route.DestinationCIDR,
|
DestRange: route.DestinationCIDR,
|
||||||
@ -93,18 +103,19 @@ func (gce *GCECloud) CreateRoute(clusterName string, nameHint string, route *clo
|
|||||||
glog.Info("Route %v already exists.")
|
glog.Info("Route %v already exists.")
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(insertOp)
|
return gce.waitForGlobalOp(insertOp, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gce *GCECloud) DeleteRoute(clusterName string, route *cloudprovider.Route) error {
|
func (gce *GCECloud) DeleteRoute(clusterName string, route *cloudprovider.Route) error {
|
||||||
|
mc := newRoutesMetricContext("create")
|
||||||
deleteOp, err := gce.service.Routes.Delete(gce.projectID, route.Name).Do()
|
deleteOp, err := gce.service.Routes.Delete(gce.projectID, route.Name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(deleteOp)
|
return gce.waitForGlobalOp(deleteOp, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
func truncateClusterName(clusterName string) string {
|
func truncateClusterName(clusterName string) string {
|
||||||
|
@ -16,33 +16,46 @@ limitations under the License.
|
|||||||
|
|
||||||
package gce
|
package gce
|
||||||
|
|
||||||
import compute "google.golang.org/api/compute/v1"
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
// Global static IP management
|
compute "google.golang.org/api/compute/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func newStaticIPMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"staticip_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ReserveGlobalStaticIP creates a global static IP.
|
// ReserveGlobalStaticIP creates a global static IP.
|
||||||
// Caller is allocated a random IP if they do not specify an ipAddress. If an
|
// Caller is allocated a random IP if they do not specify an ipAddress. If an
|
||||||
// ipAddress is specified, it must belong to the current project, eg: an
|
// ipAddress is specified, it must belong to the current project, eg: an
|
||||||
// ephemeral IP associated with a global forwarding rule.
|
// ephemeral IP associated with a global forwarding rule.
|
||||||
func (gce *GCECloud) ReserveGlobalStaticIP(name, ipAddress string) (address *compute.Address, err error) {
|
func (gce *GCECloud) ReserveGlobalStaticIP(name, ipAddress string) (address *compute.Address, err error) {
|
||||||
|
mc := newStaticIPMetricContext("reserve")
|
||||||
op, err := gce.service.GlobalAddresses.Insert(gce.projectID, &compute.Address{Name: name, Address: ipAddress}).Do()
|
op, err := gce.service.GlobalAddresses.Insert(gce.projectID, &compute.Address{Name: name, Address: ipAddress}).Do()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
return nil, mc.Observe(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := gce.waitForGlobalOp(op); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// We have to get the address to know which IP was allocated for us.
|
|
||||||
return gce.service.GlobalAddresses.Get(gce.projectID, name).Do()
|
return gce.service.GlobalAddresses.Get(gce.projectID, name).Do()
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteGlobalStaticIP deletes a global static IP by name.
|
// DeleteGlobalStaticIP deletes a global static IP by name.
|
||||||
func (gce *GCECloud) DeleteGlobalStaticIP(name string) error {
|
func (gce *GCECloud) DeleteGlobalStaticIP(name string) error {
|
||||||
|
mc := newStaticIPMetricContext("delete")
|
||||||
op, err := gce.service.GlobalAddresses.Delete(gce.projectID, name).Do()
|
op, err := gce.service.GlobalAddresses.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGlobalStaticIP returns the global static IP by name.
|
// GetGlobalStaticIP returns the global static IP by name.
|
||||||
|
@ -18,11 +18,17 @@ package gce
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TargetHttpProxy management
|
func newTargetProxyMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"targetproxy_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetTargetHttpProxy returns the UrlMap by name.
|
// GetTargetHttpProxy returns the UrlMap by name.
|
||||||
func (gce *GCECloud) GetTargetHttpProxy(name string) (*compute.TargetHttpProxy, error) {
|
func (gce *GCECloud) GetTargetHttpProxy(name string) (*compute.TargetHttpProxy, error) {
|
||||||
@ -35,11 +41,13 @@ func (gce *GCECloud) CreateTargetHttpProxy(urlMap *compute.UrlMap, name string)
|
|||||||
Name: name,
|
Name: name,
|
||||||
UrlMap: urlMap.SelfLink,
|
UrlMap: urlMap.SelfLink,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mc := newTargetProxyMetricContext("create")
|
||||||
op, err := gce.service.TargetHttpProxies.Insert(gce.projectID, proxy).Do()
|
op, err := gce.service.TargetHttpProxies.Insert(gce.projectID, proxy).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, mc.Observe(err)
|
||||||
}
|
}
|
||||||
if err = gce.waitForGlobalOp(op); err != nil {
|
if err = gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return gce.GetTargetHttpProxy(name)
|
return gce.GetTargetHttpProxy(name)
|
||||||
@ -47,23 +55,26 @@ func (gce *GCECloud) CreateTargetHttpProxy(urlMap *compute.UrlMap, name string)
|
|||||||
|
|
||||||
// SetUrlMapForTargetHttpProxy sets the given UrlMap for the given TargetHttpProxy.
|
// SetUrlMapForTargetHttpProxy sets the given UrlMap for the given TargetHttpProxy.
|
||||||
func (gce *GCECloud) SetUrlMapForTargetHttpProxy(proxy *compute.TargetHttpProxy, urlMap *compute.UrlMap) error {
|
func (gce *GCECloud) SetUrlMapForTargetHttpProxy(proxy *compute.TargetHttpProxy, urlMap *compute.UrlMap) error {
|
||||||
op, err := gce.service.TargetHttpProxies.SetUrlMap(gce.projectID, proxy.Name, &compute.UrlMapReference{UrlMap: urlMap.SelfLink}).Do()
|
mc := newTargetProxyMetricContext("set_url_map")
|
||||||
|
op, err := gce.service.TargetHttpProxies.SetUrlMap(
|
||||||
|
gce.projectID, proxy.Name, &compute.UrlMapReference{UrlMap: urlMap.SelfLink}).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTargetHttpProxy deletes the TargetHttpProxy by name.
|
// DeleteTargetHttpProxy deletes the TargetHttpProxy by name.
|
||||||
func (gce *GCECloud) DeleteTargetHttpProxy(name string) error {
|
func (gce *GCECloud) DeleteTargetHttpProxy(name string) error {
|
||||||
|
mc := newTargetProxyMetricContext("delete")
|
||||||
op, err := gce.service.TargetHttpProxies.Delete(gce.projectID, name).Do()
|
op, err := gce.service.TargetHttpProxies.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListTargetHttpProxies lists all TargetHttpProxies in the project.
|
// ListTargetHttpProxies lists all TargetHttpProxies in the project.
|
||||||
@ -81,6 +92,7 @@ func (gce *GCECloud) GetTargetHttpsProxy(name string) (*compute.TargetHttpsProxy
|
|||||||
|
|
||||||
// CreateTargetHttpsProxy creates and returns a TargetHttpsProxy with the given UrlMap and SslCertificate.
|
// CreateTargetHttpsProxy creates and returns a TargetHttpsProxy with the given UrlMap and SslCertificate.
|
||||||
func (gce *GCECloud) CreateTargetHttpsProxy(urlMap *compute.UrlMap, sslCert *compute.SslCertificate, name string) (*compute.TargetHttpsProxy, error) {
|
func (gce *GCECloud) CreateTargetHttpsProxy(urlMap *compute.UrlMap, sslCert *compute.SslCertificate, name string) (*compute.TargetHttpsProxy, error) {
|
||||||
|
mc := newTargetProxyMetricContext("delete")
|
||||||
proxy := &compute.TargetHttpsProxy{
|
proxy := &compute.TargetHttpsProxy{
|
||||||
Name: name,
|
Name: name,
|
||||||
UrlMap: urlMap.SelfLink,
|
UrlMap: urlMap.SelfLink,
|
||||||
@ -88,9 +100,9 @@ func (gce *GCECloud) CreateTargetHttpsProxy(urlMap *compute.UrlMap, sslCert *com
|
|||||||
}
|
}
|
||||||
op, err := gce.service.TargetHttpsProxies.Insert(gce.projectID, proxy).Do()
|
op, err := gce.service.TargetHttpsProxies.Insert(gce.projectID, proxy).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, mc.Observe(err)
|
||||||
}
|
}
|
||||||
if err = gce.waitForGlobalOp(op); err != nil {
|
if err = gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return gce.GetTargetHttpsProxy(name)
|
return gce.GetTargetHttpsProxy(name)
|
||||||
@ -98,32 +110,38 @@ func (gce *GCECloud) CreateTargetHttpsProxy(urlMap *compute.UrlMap, sslCert *com
|
|||||||
|
|
||||||
// SetUrlMapForTargetHttpsProxy sets the given UrlMap for the given TargetHttpsProxy.
|
// SetUrlMapForTargetHttpsProxy sets the given UrlMap for the given TargetHttpsProxy.
|
||||||
func (gce *GCECloud) SetUrlMapForTargetHttpsProxy(proxy *compute.TargetHttpsProxy, urlMap *compute.UrlMap) error {
|
func (gce *GCECloud) SetUrlMapForTargetHttpsProxy(proxy *compute.TargetHttpsProxy, urlMap *compute.UrlMap) error {
|
||||||
op, err := gce.service.TargetHttpsProxies.SetUrlMap(gce.projectID, proxy.Name, &compute.UrlMapReference{UrlMap: urlMap.SelfLink}).Do()
|
mc := newTargetProxyMetricContext("set_url_map")
|
||||||
|
op, err := gce.service.TargetHttpsProxies.SetUrlMap(
|
||||||
|
gce.projectID, proxy.Name, &compute.UrlMapReference{UrlMap: urlMap.SelfLink}).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSslCertificateForTargetHttpsProxy sets the given SslCertificate for the given TargetHttpsProxy.
|
// SetSslCertificateForTargetHttpsProxy sets the given SslCertificate for the given TargetHttpsProxy.
|
||||||
func (gce *GCECloud) SetSslCertificateForTargetHttpsProxy(proxy *compute.TargetHttpsProxy, sslCert *compute.SslCertificate) error {
|
func (gce *GCECloud) SetSslCertificateForTargetHttpsProxy(proxy *compute.TargetHttpsProxy, sslCert *compute.SslCertificate) error {
|
||||||
op, err := gce.service.TargetHttpsProxies.SetSslCertificates(gce.projectID, proxy.Name, &compute.TargetHttpsProxiesSetSslCertificatesRequest{SslCertificates: []string{sslCert.SelfLink}}).Do()
|
mc := newTargetProxyMetricContext("set_ssl_cert")
|
||||||
|
op, err := gce.service.TargetHttpsProxies.SetSslCertificates(
|
||||||
|
gce.projectID, proxy.Name, &compute.TargetHttpsProxiesSetSslCertificatesRequest{SslCertificates: []string{sslCert.SelfLink}}).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTargetHttpsProxy deletes the TargetHttpsProxy by name.
|
// DeleteTargetHttpsProxy deletes the TargetHttpsProxy by name.
|
||||||
func (gce *GCECloud) DeleteTargetHttpsProxy(name string) error {
|
func (gce *GCECloud) DeleteTargetHttpsProxy(name string) error {
|
||||||
|
mc := newTargetProxyMetricContext("delete")
|
||||||
|
|
||||||
op, err := gce.service.TargetHttpsProxies.Delete(gce.projectID, name).Do()
|
op, err := gce.service.TargetHttpsProxies.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListTargetHttpsProxies lists all TargetHttpsProxies in the project.
|
// ListTargetHttpsProxies lists all TargetHttpsProxies in the project.
|
||||||
|
@ -18,11 +18,17 @@ package gce
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
compute "google.golang.org/api/compute/v1"
|
compute "google.golang.org/api/compute/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
// UrlMap management
|
func newUrlMapMetricContext(request string) *metricContext {
|
||||||
|
return &metricContext{
|
||||||
|
start: time.Now(),
|
||||||
|
attributes: []string{"urlmap_" + request, unusedMetricLabel, unusedMetricLabel},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetUrlMap returns the UrlMap by name.
|
// GetUrlMap returns the UrlMap by name.
|
||||||
func (gce *GCECloud) GetUrlMap(name string) (*compute.UrlMap, error) {
|
func (gce *GCECloud) GetUrlMap(name string) (*compute.UrlMap, error) {
|
||||||
@ -35,11 +41,12 @@ func (gce *GCECloud) CreateUrlMap(backend *compute.BackendService, name string)
|
|||||||
Name: name,
|
Name: name,
|
||||||
DefaultService: backend.SelfLink,
|
DefaultService: backend.SelfLink,
|
||||||
}
|
}
|
||||||
|
mc := newUrlMapMetricContext("create")
|
||||||
op, err := gce.service.UrlMaps.Insert(gce.projectID, urlMap).Do()
|
op, err := gce.service.UrlMaps.Insert(gce.projectID, urlMap).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, mc.Observe(err)
|
||||||
}
|
}
|
||||||
if err = gce.waitForGlobalOp(op); err != nil {
|
if err = gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return gce.GetUrlMap(name)
|
return gce.GetUrlMap(name)
|
||||||
@ -47,11 +54,12 @@ func (gce *GCECloud) CreateUrlMap(backend *compute.BackendService, name string)
|
|||||||
|
|
||||||
// UpdateUrlMap applies the given UrlMap as an update, and returns the new UrlMap.
|
// UpdateUrlMap applies the given UrlMap as an update, and returns the new UrlMap.
|
||||||
func (gce *GCECloud) UpdateUrlMap(urlMap *compute.UrlMap) (*compute.UrlMap, error) {
|
func (gce *GCECloud) UpdateUrlMap(urlMap *compute.UrlMap) (*compute.UrlMap, error) {
|
||||||
|
mc := newUrlMapMetricContext("update")
|
||||||
op, err := gce.service.UrlMaps.Update(gce.projectID, urlMap.Name, urlMap).Do()
|
op, err := gce.service.UrlMaps.Update(gce.projectID, urlMap.Name, urlMap).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, mc.Observe(err)
|
||||||
}
|
}
|
||||||
if err = gce.waitForGlobalOp(op); err != nil {
|
if err = gce.waitForGlobalOp(op, mc); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return gce.service.UrlMaps.Get(gce.projectID, urlMap.Name).Do()
|
return gce.service.UrlMaps.Get(gce.projectID, urlMap.Name).Do()
|
||||||
@ -59,14 +67,15 @@ func (gce *GCECloud) UpdateUrlMap(urlMap *compute.UrlMap) (*compute.UrlMap, erro
|
|||||||
|
|
||||||
// DeleteUrlMap deletes a url map by name.
|
// DeleteUrlMap deletes a url map by name.
|
||||||
func (gce *GCECloud) DeleteUrlMap(name string) error {
|
func (gce *GCECloud) DeleteUrlMap(name string) error {
|
||||||
|
mc := newUrlMapMetricContext("delete")
|
||||||
op, err := gce.service.UrlMaps.Delete(gce.projectID, name).Do()
|
op, err := gce.service.UrlMaps.Delete(gce.projectID, name).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isHTTPErrorCode(err, http.StatusNotFound) {
|
if isHTTPErrorCode(err, http.StatusNotFound) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return mc.Observe(err)
|
||||||
}
|
}
|
||||||
return gce.waitForGlobalOp(op)
|
return gce.waitForGlobalOp(op, mc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListUrlMaps lists all UrlMaps in the project.
|
// ListUrlMaps lists all UrlMaps in the project.
|
||||||
|
80
pkg/cloudprovider/providers/gce/metrics.go
Normal file
80
pkg/cloudprovider/providers/gce/metrics.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2014 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 gce
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
|
)
|
||||||
|
|
||||||
|
type apiCallMetrics struct {
|
||||||
|
latency *prometheus.HistogramVec
|
||||||
|
errors *prometheus.CounterVec
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
apiMetrics = registerAPIMetrics(
|
||||||
|
"request", // API function that is begin invoked.
|
||||||
|
"region", // region (optional).
|
||||||
|
"zone", // zone (optional).
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
type metricContext struct {
|
||||||
|
start time.Time
|
||||||
|
attributes []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Value for an unused label in the metric dimension.
|
||||||
|
const unusedMetricLabel = "<n/a>"
|
||||||
|
|
||||||
|
// Observe the result of a API call.
|
||||||
|
func (mc *metricContext) Observe(err error) error {
|
||||||
|
apiMetrics.latency.WithLabelValues(mc.attributes...).Observe(
|
||||||
|
time.Since(mc.start).Seconds())
|
||||||
|
if err != nil {
|
||||||
|
apiMetrics.errors.WithLabelValues(mc.attributes...).Inc()
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerApiMetrics adds metrics definitions for a category of API calls.
|
||||||
|
func registerAPIMetrics(attributes ...string) *apiCallMetrics {
|
||||||
|
metrics := &apiCallMetrics{
|
||||||
|
latency: prometheus.NewHistogramVec(
|
||||||
|
prometheus.HistogramOpts{
|
||||||
|
Name: "cloudprovider_gce_api_request_duration_seconds",
|
||||||
|
Help: "Latency of a GCE API call",
|
||||||
|
},
|
||||||
|
attributes,
|
||||||
|
),
|
||||||
|
errors: prometheus.NewCounterVec(
|
||||||
|
prometheus.CounterOpts{
|
||||||
|
Name: "cloudprovider_gce_api_request_errors",
|
||||||
|
Help: "Number of errors for an API call",
|
||||||
|
},
|
||||||
|
attributes,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
prometheus.MustRegister(metrics.latency)
|
||||||
|
prometheus.MustRegister(metrics.errors)
|
||||||
|
|
||||||
|
return metrics
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user