From e250074b38d49fca77be4db8c43bb75abe13f21c Mon Sep 17 00:00:00 2001 From: Ashley Gau Date: Tue, 20 Feb 2018 13:07:33 -0800 Subject: [PATCH] Define hooks for inserting Forwarding Rules and Addresses in all versions --- .../providers/gce/cloud/mock/BUILD | 2 + .../providers/gce/cloud/mock/mock.go | 157 ++++++++++++++++-- 2 files changed, 147 insertions(+), 12 deletions(-) diff --git a/pkg/cloudprovider/providers/gce/cloud/mock/BUILD b/pkg/cloudprovider/providers/gce/cloud/mock/BUILD index fa07f1fb289..bceb2e84739 100644 --- a/pkg/cloudprovider/providers/gce/cloud/mock/BUILD +++ b/pkg/cloudprovider/providers/gce/cloud/mock/BUILD @@ -8,6 +8,8 @@ go_library( deps = [ "//pkg/cloudprovider/providers/gce/cloud:go_default_library", "//pkg/cloudprovider/providers/gce/cloud/meta:go_default_library", + "//vendor/google.golang.org/api/compute/v0.alpha:go_default_library", + "//vendor/google.golang.org/api/compute/v0.beta:go_default_library", "//vendor/google.golang.org/api/compute/v1:go_default_library", "//vendor/google.golang.org/api/googleapi:go_default_library", ], diff --git a/pkg/cloudprovider/providers/gce/cloud/mock/mock.go b/pkg/cloudprovider/providers/gce/cloud/mock/mock.go index 21ba74da706..06ff480d47b 100644 --- a/pkg/cloudprovider/providers/gce/cloud/mock/mock.go +++ b/pkg/cloudprovider/providers/gce/cloud/mock/mock.go @@ -25,16 +25,23 @@ package mock import ( "context" + "encoding/json" "fmt" "net/http" alpha "google.golang.org/api/compute/v0.alpha" + beta "google.golang.org/api/compute/v0.beta" ga "google.golang.org/api/compute/v1" "google.golang.org/api/googleapi" - cloud "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud" + "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud" "k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta" ) +// gceObject is an abstraction of all GCE API object in go client +type gceObject interface { + MarshalJSON() ([]byte, error) +} + // AddInstanceHook mocks adding a Instance to MockTargetPools func AddInstanceHook(ctx context.Context, key *meta.Key, req *ga.TargetPoolsAddInstanceRequest, m *cloud.MockTargetPools) error { pool, err := m.Get(ctx, key) @@ -76,20 +83,146 @@ func RemoveInstanceHook(ctx context.Context, key *meta.Key, req *ga.TargetPoolsR return nil } -// GetAlphaFwdRuleHook mocks getting an AlphaForwardingRule. ForwardingRules -// are expected to default to Premium tier if no NetworkTier is specified. -func GetAlphaFwdRuleHook(ctx context.Context, key *meta.Key, m *cloud.MockAlphaForwardingRules) (bool, *alpha.ForwardingRule, error) { - if obj, ok := m.Objects[*key]; ok { - typedObj := obj.ToAlpha() - if typedObj.NetworkTier == "" { - typedObj.NetworkTier = "PREMIUM" +func convertAndInsertAlphaForwardingRule(key *meta.Key, obj gceObject, mRules map[meta.Key]*cloud.MockForwardingRulesObj, version meta.Version, projectID string) (bool, error) { + if !key.Valid() { + return false, fmt.Errorf("invalid GCE key (%+v)", key) + } + + if _, ok := mRules[*key]; ok { + err := &googleapi.Error{ + Code: http.StatusConflict, + Message: fmt.Sprintf("MockForwardingRule %v exists", key), } - return true, typedObj, nil + return false, err } - err := &googleapi.Error{ - Code: http.StatusNotFound, + enc, err := obj.MarshalJSON() + if err != nil { + return false, err + } + var fwdRule alpha.ForwardingRule + if err := json.Unmarshal(enc, &fwdRule); err != nil { + return false, err + } + // Set the default values for the Alpha fields. + if fwdRule.NetworkTier == "" { + fwdRule.NetworkTier = cloud.NetworkTierDefault.ToGCEValue() } - return false, nil, err + fwdRule.Name = key.Name + if fwdRule.SelfLink == "" { + fwdRule.SelfLink = cloud.SelfLink(version, projectID, "forwardingRules", key) + } + + mRules[*key] = &cloud.MockForwardingRulesObj{Obj: fwdRule} + return true, nil +} + +// InsertFwdRuleHook mocks inserting a ForwardingRule. ForwardingRules are +// expected to default to Premium tier if no NetworkTier is specified. +func InsertFwdRuleHook(ctx context.Context, key *meta.Key, obj *ga.ForwardingRule, m *cloud.MockForwardingRules) (bool, error) { + projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionGA, "forwardingRules") + return convertAndInsertAlphaForwardingRule(key, obj, m.Objects, meta.VersionGA, projectID) +} + +// InsertBetaFwdRuleHook mocks inserting a BetaForwardingRule. +func InsertBetaFwdRuleHook(ctx context.Context, key *meta.Key, obj *beta.ForwardingRule, m *cloud.MockForwardingRules) (bool, error) { + projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionBeta, "forwardingRules") + return convertAndInsertAlphaForwardingRule(key, obj, m.Objects, meta.VersionBeta, projectID) +} + +// InsertAlphaFwdRuleHook mocks inserting an AlphaForwardingRule. +func InsertAlphaFwdRuleHook(ctx context.Context, key *meta.Key, obj *alpha.ForwardingRule, m *cloud.MockForwardingRules) (bool, error) { + projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionAlpha, "forwardingRules") + return convertAndInsertAlphaForwardingRule(key, obj, m.Objects, meta.VersionAlpha, projectID) +} + +// Used to assign Addresses with no IP a unique IP address +var ipCounter = 1 + +func convertAndInsertAlphaAddress(key *meta.Key, obj gceObject, mAddrs map[meta.Key]*cloud.MockAddressesObj, version meta.Version, projectID string) (bool, error) { + if !key.Valid() { + return false, fmt.Errorf("invalid GCE key (%+v)", key) + } + + if _, ok := mAddrs[*key]; ok { + err := &googleapi.Error{ + Code: http.StatusConflict, + Message: fmt.Sprintf("MockAddresses %v exists", key), + } + return false, err + } + + enc, err := obj.MarshalJSON() + if err != nil { + return false, err + } + var addr alpha.Address + if err := json.Unmarshal(enc, &addr); err != nil { + return false, err + } + + // Set default address type if not present. + if addr.AddressType == "" { + addr.AddressType = string(cloud.SchemeExternal) + } + + var existingAddresses []*ga.Address + for _, obj := range mAddrs { + existingAddresses = append(existingAddresses, obj.ToGA()) + } + + for _, existingAddr := range existingAddresses { + if addr.Address == existingAddr.Address { + msg := fmt.Sprintf("MockAddresses IP %v in use", addr.Address) + + // When the IP is already in use, this call returns a StatusBadRequest + // if the address is an external address, and StatusConflict if an + // internal address. This is to be consistent with actual GCE API. + errorCode := http.StatusConflict + if addr.AddressType == string(cloud.SchemeExternal) { + errorCode = http.StatusBadRequest + } + + return false, &googleapi.Error{Code: errorCode, Message: msg} + } + } + + // Set default values used in tests + addr.Name = key.Name + if addr.SelfLink == "" { + addr.SelfLink = cloud.SelfLink(version, projectID, "addresses", key) + } + + if addr.Address == "" { + addr.Address = fmt.Sprintf("1.2.3.%d", ipCounter) + ipCounter++ + } + + // Set the default values for the Alpha fields. + if addr.NetworkTier == "" { + addr.NetworkTier = cloud.NetworkTierDefault.ToGCEValue() + } + + mAddrs[*key] = &cloud.MockAddressesObj{Obj: addr} + return true, nil +} + +// InsertAddressHook mocks inserting an Address. +func InsertAddressHook(ctx context.Context, key *meta.Key, obj *ga.Address, m *cloud.MockAddresses) (bool, error) { + projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionGA, "addresses") + return convertAndInsertAlphaAddress(key, obj, m.Objects, meta.VersionGA, projectID) +} + +// InsertBetaAddressHook mocks inserting a BetaAddress. +func InsertBetaAddressHook(ctx context.Context, key *meta.Key, obj *beta.Address, m *cloud.MockAddresses) (bool, error) { + projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionBeta, "addresses") + return convertAndInsertAlphaAddress(key, obj, m.Objects, meta.VersionBeta, projectID) +} + +// InsertAlphaAddressHook mocks inserting an Address. Addresses are expected to +// default to Premium tier if no NetworkTier is specified. +func InsertAlphaAddressHook(ctx context.Context, key *meta.Key, obj *alpha.Address, m *cloud.MockAlphaAddresses) (bool, error) { + projectID := m.ProjectRouter.ProjectID(ctx, meta.VersionBeta, "addresses") + return convertAndInsertAlphaAddress(key, obj, m.Objects, meta.VersionAlpha, projectID) }