Skip to content

Commit

Permalink
Merge pull request #366 from freehan/neg-beta-healthcheck
Browse files Browse the repository at this point in the history
Swtich to use beta HealthCheck for NEG
  • Loading branch information
bowei authored Jun 27, 2018
2 parents f64895e + 94e3c1c commit 4fe4d22
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 48 deletions.
14 changes: 6 additions & 8 deletions pkg/backends/backends_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,7 @@ func TestBackendPoolAdd(t *testing.T) {
t.Fatalf("Port %v not added to instance group", sp)
}

// Check the created healthcheck is the correct protocol
isAlpha := sp.Protocol == annotations.ProtocolHTTP2
hc, err := pool.healthChecker.Get(beName, isAlpha)
hc, err := pool.healthChecker.Get(beName, sp.Version())
if err != nil {
t.Fatalf("Unexpected err when querying fake healthchecker: %v", err)
}
Expand Down Expand Up @@ -203,7 +201,7 @@ func TestHealthCheckMigration(t *testing.T) {
pool.Ensure([]utils.ServicePort{p}, nil)

// Assert the proper health check was created
hc, _ := pool.healthChecker.Get(beName, p.IsAlpha())
hc, _ := pool.healthChecker.Get(beName, p.Version())
if hc == nil || hc.Protocol() != p.Protocol {
t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
}
Expand Down Expand Up @@ -237,7 +235,7 @@ func TestBackendPoolUpdateHTTPS(t *testing.T) {
}

// Assert the proper health check was created
hc, _ := pool.healthChecker.Get(beName, p.IsAlpha())
hc, _ := pool.healthChecker.Get(beName, p.Version())
if hc == nil || hc.Protocol() != p.Protocol {
t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
}
Expand All @@ -257,7 +255,7 @@ func TestBackendPoolUpdateHTTPS(t *testing.T) {
}

// Assert the proper health check was created
hc, _ = pool.healthChecker.Get(beName, p.IsAlpha())
hc, _ = pool.healthChecker.Get(beName, p.Version())
if hc == nil || hc.Protocol() != p.Protocol {
t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
}
Expand All @@ -282,7 +280,7 @@ func TestBackendPoolUpdateHTTP2(t *testing.T) {
}

// Assert the proper health check was created
hc, _ := pool.healthChecker.Get(beName, p.IsAlpha())
hc, _ := pool.healthChecker.Get(beName, p.Version())
if hc == nil || hc.Protocol() != p.Protocol {
t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
}
Expand All @@ -302,7 +300,7 @@ func TestBackendPoolUpdateHTTP2(t *testing.T) {
}

// Assert the proper health check was created
hc, _ = pool.healthChecker.Get(beName, true)
hc, _ = pool.healthChecker.Get(beName, meta.VersionAlpha)
if hc == nil || hc.Protocol() != p.Protocol {
t.Fatalf("Expected %s health check, received %v: ", p.Protocol, hc)
}
Expand Down
33 changes: 30 additions & 3 deletions pkg/healthchecks/fakes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package healthchecks

import (
computealpha "google.golang.org/api/compute/v0.alpha"
computebeta "google.golang.org/api/compute/v0.beta"
compute "google.golang.org/api/compute/v1"

"k8s.io/ingress-gce/pkg/utils"
Expand Down Expand Up @@ -80,7 +81,7 @@ func (f *FakeHealthCheckProvider) UpdateHttpHealthCheck(hc *compute.HttpHealthCh
func (f *FakeHealthCheckProvider) CreateHealthCheck(hc *compute.HealthCheck) error {
v := *hc
v.SelfLink = cloud.NewHealthChecksResourceID("mock-project", hc.Name).SelfLink(meta.VersionGA)
alphaHC, _ := toAlphaHealthCheck(&v)
alphaHC, _ := v1ToAlphaHealthCheck(&v)
f.generic[hc.Name] = *alphaHC
return nil
}
Expand All @@ -93,6 +94,15 @@ func (f *FakeHealthCheckProvider) CreateAlphaHealthCheck(hc *computealpha.Health
return nil
}

// CreateHealthCheck fakes out http health check creation.
func (f *FakeHealthCheckProvider) CreateBetaHealthCheck(hc *computebeta.HealthCheck) error {
v := *hc
v.SelfLink = cloud.NewHealthChecksResourceID("mock-project", hc.Name).SelfLink(meta.VersionBeta)
alphaHC, _ := betaToAlphaHealthCheck(&v)
f.generic[hc.Name] = *alphaHC
return nil
}

// GetHealthCheck fakes out getting a http health check from the cloud.
func (f *FakeHealthCheckProvider) GetHealthCheck(name string) (*compute.HealthCheck, error) {
if hc, found := f.generic[name]; found {
Expand All @@ -103,14 +113,22 @@ func (f *FakeHealthCheckProvider) GetHealthCheck(name string) (*compute.HealthCh
return nil, utils.FakeGoogleAPINotFoundErr()
}

// GetHealthCheck fakes out getting a http health check from the cloud.
func (f *FakeHealthCheckProvider) GetAlphaHealthCheck(name string) (*computealpha.HealthCheck, error) {
if hc, found := f.generic[name]; found {
return &hc, nil
}
return nil, utils.FakeGoogleAPINotFoundErr()
}

func (f *FakeHealthCheckProvider) GetBetaHealthCheck(name string) (*computebeta.HealthCheck, error) {
if hc, found := f.generic[name]; found {
ret := &computebeta.HealthCheck{}
err := copyViaJSON(ret, &hc)
return ret, err
}
return nil, utils.FakeGoogleAPINotFoundErr()
}

// DeleteHealthCheck fakes out deleting a http health check.
func (f *FakeHealthCheckProvider) DeleteHealthCheck(name string) error {
if _, exists := f.generic[name]; !exists {
Expand All @@ -126,7 +144,7 @@ func (f *FakeHealthCheckProvider) UpdateHealthCheck(hc *compute.HealthCheck) err
if _, exists := f.generic[hc.Name]; !exists {
return utils.FakeGoogleAPINotFoundErr()
}
alphaHC, _ := toAlphaHealthCheck(hc)
alphaHC, _ := v1ToAlphaHealthCheck(hc)
f.generic[hc.Name] = *alphaHC
return nil
}
Expand All @@ -139,3 +157,12 @@ func (f *FakeHealthCheckProvider) UpdateAlphaHealthCheck(hc *computealpha.Health
f.generic[hc.Name] = *hc
return nil
}

func (f *FakeHealthCheckProvider) UpdateBetaHealthCheck(hc *computebeta.HealthCheck) error {
if _, exists := f.generic[hc.Name]; !exists {
return utils.FakeGoogleAPINotFoundErr()
}
alphaHC, _ := betaToAlphaHealthCheck(hc)
f.generic[hc.Name] = *alphaHC
return nil
}
119 changes: 94 additions & 25 deletions pkg/healthchecks/healthchecks.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ limitations under the License.
package healthchecks

import (
"encoding/json"
"fmt"
"net/http"
"time"

computealpha "google.golang.org/api/compute/v0.alpha"
computebeta "google.golang.org/api/compute/v0.beta"
compute "google.golang.org/api/compute/v1"
"k8s.io/apimachinery/pkg/types"

"github.com/golang/glog"

"encoding/json"

"k8s.io/apimachinery/pkg/types"
"k8s.io/ingress-gce/pkg/annotations"
"k8s.io/ingress-gce/pkg/utils"
"k8s.io/kubernetes/pkg/cloudprovider/providers/gce/cloud/meta"
)

const (
Expand Down Expand Up @@ -102,9 +103,7 @@ func (h *HealthChecks) New(sp utils.ServicePort) *HealthCheck {
// Sync retrieves a health check based on port, checks type and settings and updates/creates if necessary.
// Sync is only called by the backends.Add func - it's not a pool like other resources.
func (h *HealthChecks) Sync(hc *HealthCheck) (string, error) {
// Use alpha API when PORT_SPECIFICATION field is specified or when Type
// is HTTP2
existingHC, err := h.Get(hc.Name, hc.isHttp2() || hc.ForNEG)
existingHC, err := h.Get(hc.Name, hc.Version())
if err != nil {
if !utils.IsHTTPErrorCode(err, http.StatusNotFound) {
return "", err
Expand All @@ -114,7 +113,7 @@ func (h *HealthChecks) Sync(hc *HealthCheck) (string, error) {
return "", err
}

return h.getHealthCheckLink(hc.Name, hc.isHttp2())
return h.getHealthCheckLink(hc.Name, hc.Version())
}

if needToUpdate(existingHC, hc) {
Expand All @@ -135,30 +134,51 @@ func (h *HealthChecks) Sync(hc *HealthCheck) (string, error) {
}

func (h *HealthChecks) create(hc *HealthCheck) error {
if hc.isHttp2() || hc.ForNEG {
glog.V(2).Infof("Creating health check with protocol %v", hc.Type)
switch hc.Version() {
case meta.VersionAlpha:
glog.V(2).Infof("Creating alpha health check with protocol %v", hc.Type)
return h.cloud.CreateAlphaHealthCheck(hc.ToAlphaComputeHealthCheck())
} else {
case meta.VersionBeta:
glog.V(2).Infof("Creating beta health check with protocol %v", hc.Type)
betaHC, err := hc.ToBetaComputeHealthCheck()
if err != nil {
return err
}
return h.cloud.CreateBetaHealthCheck(betaHC)
case meta.VersionGA:
glog.V(2).Infof("Creating health check for port %v with protocol %v", hc.Port, hc.Type)
v1hc, err := hc.ToComputeHealthCheck()
if err != nil {
return err
}
return h.cloud.CreateHealthCheck(v1hc)
default:
return fmt.Errorf("Unknown Version: %q", hc.Version())
}
}

func (h *HealthChecks) update(oldHC, newHC *HealthCheck) error {
if newHC.isHttp2() || newHC.ForNEG {
glog.V(2).Infof("Updating health check with protocol %v, ForNEG: %v", newHC.Type, newHC.ForNEG)
switch newHC.Version() {
case meta.VersionAlpha:
glog.V(2).Infof("Updating alpha health check with protocol %v", newHC.Type)
return h.cloud.UpdateAlphaHealthCheck(mergeHealthcheck(oldHC, newHC).ToAlphaComputeHealthCheck())
} else {
case meta.VersionBeta:
glog.V(2).Infof("Updating beta health check with protocol %v", newHC.Type)
betaHC, err := mergeHealthcheck(oldHC, newHC).ToBetaComputeHealthCheck()
if err != nil {
return err
}
return h.cloud.UpdateBetaHealthCheck(betaHC)
case meta.VersionGA:
glog.V(2).Infof("Updating health check for port %v with protocol %v", newHC.Port, newHC.Type)
v1hc, err := newHC.ToComputeHealthCheck()
if err != nil {
return err
}
return h.cloud.UpdateHealthCheck(v1hc)
default:
return fmt.Errorf("Unknown Version: %q", newHC.Version())

}
}

Expand All @@ -182,8 +202,8 @@ func mergeHealthcheck(oldHC, newHC *HealthCheck) *HealthCheck {
return newHC
}

func (h *HealthChecks) getHealthCheckLink(name string, alpha bool) (string, error) {
hc, err := h.Get(name, alpha)
func (h *HealthChecks) getHealthCheckLink(name string, version meta.Version) (string, error) {
hc, err := h.Get(name, version)
if err != nil {
return "", err
}
Expand All @@ -197,18 +217,29 @@ func (h *HealthChecks) Delete(name string) error {
}

// Get returns the health check by port
func (h *HealthChecks) Get(name string, alpha bool) (*HealthCheck, error) {
func (h *HealthChecks) Get(name string, version meta.Version) (*HealthCheck, error) {
var hc *computealpha.HealthCheck
var err error
if alpha {
switch version {
case meta.VersionAlpha:
hc, err = h.cloud.GetAlphaHealthCheck(name)
} else {
var v1hc *compute.HealthCheck
v1hc, err = h.cloud.GetHealthCheck(name)
if err != nil {
return nil, err
}
hc, err = toAlphaHealthCheck(v1hc)
case meta.VersionBeta:
betaHC, err := h.cloud.GetBetaHealthCheck(name)
if err != nil {
return nil, err
}
hc, err = betaToAlphaHealthCheck(betaHC)
case meta.VersionGA:
v1hc, err := h.cloud.GetHealthCheck(name)
if err != nil {
return nil, err
}
hc, err = v1ToAlphaHealthCheck(v1hc)
default:
return nil, fmt.Errorf("Unknown version %v", version)
}
return NewHealthCheck(hc), err
}
Expand Down Expand Up @@ -321,7 +352,17 @@ func (hc *HealthCheck) ToComputeHealthCheck() (*compute.HealthCheck, error) {
return toV1HealthCheck(&hc.HealthCheck)
}

// ToComputeHealthCheck returns a valid compute.HealthCheck object
// ToBetaComputeHealthCheck returns a valid computebeta.HealthCheck object
func (hc *HealthCheck) ToBetaComputeHealthCheck() (*computebeta.HealthCheck, error) {
// Cannot specify both portSpecification and port field.
if len(hc.PortSpecification) > 0 {
hc.Port = 0
}
hc.merge()
return toBetaHealthCheck(&hc.HealthCheck)
}

// ToAlphaComputeHealthCheck returns a valid computealpha.HealthCheck object
func (hc *HealthCheck) ToAlphaComputeHealthCheck() *computealpha.HealthCheck {
// Cannot specify both portSpecification and port field.
if len(hc.PortSpecification) > 0 {
Expand Down Expand Up @@ -354,6 +395,19 @@ func (hc *HealthCheck) isHttp2() bool {
return hc.Protocol() == annotations.ProtocolHTTP2
}

// Version returns the appropriate API version to handle the health check
// Use Alpha API for HTTP2
// Use Beta API for NEG as PORT_SPECIFICATION is required
func (hc *HealthCheck) Version() meta.Version {
if hc.isHttp2() {
return meta.VersionAlpha
}
if hc.ForNEG {
return meta.VersionBeta
}
return meta.VersionGA
}

func needToUpdate(old, new *HealthCheck) bool {
if old.Protocol() != new.Protocol() {
glog.V(2).Infof("Updating health check %v because it has protocol %v but need %v", old.Name, old.Type, new.Type)
Expand All @@ -376,9 +430,24 @@ func toV1HealthCheck(hc *computealpha.HealthCheck) (*compute.HealthCheck, error)
return ret, err
}

// toV1HealthCheck converts v1 health check to alpha health check.
// toBetaHealthCheck converts alpha health check to beta health check.
func toBetaHealthCheck(hc *computealpha.HealthCheck) (*computebeta.HealthCheck, error) {
ret := &computebeta.HealthCheck{}
err := copyViaJSON(ret, hc)
return ret, err
}

// v1ToAlphaHealthCheck converts v1 health check to alpha health check.
// There should be no information lost after conversion.
func v1ToAlphaHealthCheck(hc *compute.HealthCheck) (*computealpha.HealthCheck, error) {
ret := &computealpha.HealthCheck{}
err := copyViaJSON(ret, hc)
return ret, err
}

// betaToAlphaHealthCheck converts beta health check to alpha health check.
// There should be no information lost after conversion.
func toAlphaHealthCheck(hc *compute.HealthCheck) (*computealpha.HealthCheck, error) {
func betaToAlphaHealthCheck(hc *computebeta.HealthCheck) (*computealpha.HealthCheck, error) {
ret := &computealpha.HealthCheck{}
err := copyViaJSON(ret, hc)
return ret, err
Expand Down
Loading

0 comments on commit 4fe4d22

Please sign in to comment.