Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes, more e2e tests and logging for multi-cluster allocation #1077

Merged
merged 4 commits into from
Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmd/allocator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,14 +186,16 @@ func (h *httpHandler) allocateHandler(w http.ResponseWriter, r *http.Request) {
gsa := allocationv1.GameServerAllocation{}
if err := json.NewDecoder(r.Body).Decode(&gsa); err != nil {
http.Error(w, "invalid request", http.StatusBadRequest)
logger.WithError(err).Info("bad request")
return
}
logger.WithField("gsa", gsa).Infof("allocation request received")

allocation := h.agonesClient.AllocationV1().GameServerAllocations(gsa.ObjectMeta.Namespace)
allocatedGsa, err := allocation.Create(&gsa)
if err != nil {
http.Error(w, err.Error(), httpCode(err))
logger.Debug(err)
logger.WithField("gsa", gsa).WithError(err).Info("calling allocation extension API failed")
return
}
w.Header().Set("Content-Type", "application/json")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ spec:
type: string
required:
- clusterName
- allocationEndpoints
- secretName
- namespace
type: object
Expand Down
1 change: 0 additions & 1 deletion install/yaml/install.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,6 @@ spec:
type: string
required:
- clusterName
- allocationEndpoints
- secretName
- namespace
type: object
Expand Down
6 changes: 3 additions & 3 deletions pkg/apis/multicluster/v1alpha1/gameserverallocationpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ type GameServerAllocationPolicySpec struct {
type ClusterConnectionInfo struct {
// Optional: the name of the targeted cluster
ClusterName string `json:"clusterName"`
// The endpoints for the allocator service in the targeted cluster
// There should be at least one endpoint or the policy is ineffective
// The endpoints for the allocator service in the targeted cluster.
// If the AllocationEndpoints is not set, the allocation happens on local cluster.
// If there are multiple endpoints any of the endpoints that can handle allocation request should suffice
AllocationEndpoints []string `json:"allocationEndpoints"`
AllocationEndpoints []string `json:"allocationEndpoints,omitempty"`
// The name of the secret that contains TLS client certificates to connect the allocator server in the targeted cluster
SecretName string `json:"secretName"`
// The cluster namespace from which to allocate gameservers
Expand Down
30 changes: 24 additions & 6 deletions pkg/gameserverallocations/allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const (
// from the topNGameServerCount of Ready gameservers
// to reduce the contention while allocating gameservers.
topNGameServerDefaultCount = 100
allocatorRequestURLFmt = "https://%s/v1alpha1/gameserverallocation"
)

const (
Expand Down Expand Up @@ -177,6 +178,7 @@ func (c *Allocator) Allocate(gsa *allocationv1.GameServerAllocation, stop <-chan
if err != nil {
return nil, errors.Wrap(err, "could not find objectkinds for status")
}
c.loggerForGameServerAllocation(gsa).Info("GameServerAllocation is invalid")

status.TypeMeta = metav1.TypeMeta{Kind: gvks[0].Kind, APIVersion: gvks[0].Version}
return status, nil
Expand All @@ -192,6 +194,7 @@ func (c *Allocator) Allocate(gsa *allocationv1.GameServerAllocation, stop <-chan
}

if err != nil {
c.loggerForGameServerAllocation(gsa).WithError(err).Error("allocation failed")
return nil, err
}

Expand All @@ -216,6 +219,9 @@ func (c *Allocator) allocateFromLocalCluster(gsa *allocationv1.GameServerAllocat
err := Retry(allocationRetry, func() error {
var err error
gs, err = c.allocate(gsa, stop)
if err != nil {
c.loggerForGameServerAllocation(gsa).WithError(err).Warn("failed to allocate. Retrying... ")
}
return err
})

Expand Down Expand Up @@ -265,12 +271,22 @@ func (c *Allocator) applyMultiClusterAllocation(gsa *allocationv1.GameServerAllo
if connectionInfo == nil {
break
}
if connectionInfo.ClusterName == gsa.ObjectMeta.ClusterName {
result, err = c.allocateFromLocalCluster(gsa, stop)
c.baseLogger.Error(err)
if len(connectionInfo.AllocationEndpoints) == 0 {
// Change the naemspace to the policy namespace and allocate locally
gsaCopy := gsa
if gsa.Namespace != connectionInfo.Namespace {
gsaCopy = gsa.DeepCopy()
gsaCopy.Namespace = connectionInfo.Namespace
}
result, err = c.allocateFromLocalCluster(gsaCopy, stop)
if err != nil {
c.loggerForGameServerAllocation(gsaCopy).WithError(err).Error("self-allocation failed")
}
} else {
result, err = c.allocateFromRemoteCluster(*gsa, connectionInfo, gsa.ObjectMeta.Namespace)
c.baseLogger.Error(err)
if err != nil {
c.loggerForGameServerAllocation(gsa).WithField("allocConnInfo", connectionInfo).WithError(err).Error("remote-allocation failed")
}
}
if result != nil {
return result, nil
Expand Down Expand Up @@ -303,7 +319,9 @@ func (c *Allocator) allocateFromRemoteCluster(gsa allocationv1.GameServerAllocat

// TODO: Retry on transient error --> response.StatusCode >= 500
for i, endpoint := range connectionInfo.AllocationEndpoints {
response, err := client.Post(endpoint, "application/json", bytes.NewBuffer(body))
c.loggerForGameServerAllocation(&gsa).WithField("endpoint", endpoint).Info("forwarding allocation request")
requestURL := fmt.Sprintf(allocatorRequestURLFmt, endpoint)
response, err := client.Post(requestURL, "application/json", bytes.NewBuffer(body))
if err != nil {
return nil, err
}
Expand All @@ -317,7 +335,7 @@ func (c *Allocator) allocateFromRemoteCluster(gsa allocationv1.GameServerAllocat
// failing with 5xx http status, try the next endpoint. Otherwise, return the error response.
if response.StatusCode >= 500 && (i+1) < len(connectionInfo.AllocationEndpoints) {
// If there is a server error try a different endpoint
c.baseLogger.WithError(err).WithField("endpoint", endpoint).Warn("The request sent failed, trying next endpoint")
c.loggerForGameServerAllocation(&gsa).WithError(err).WithField("endpoint", endpoint).Warn("The request failed. Trying next endpoint")
continue
}
if response.StatusCode >= 400 {
Expand Down
34 changes: 23 additions & 11 deletions pkg/gameserverallocations/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"strconv"
"testing"
"time"
Expand Down Expand Up @@ -802,10 +803,9 @@ func TestMultiClusterAllocationFromLocal(t *testing.T) {
Priority: 1,
Weight: 200,
ConnectionInfo: multiclusterv1alpha1.ClusterConnectionInfo{
AllocationEndpoints: []string{"localhost"},
ClusterName: "multicluster",
SecretName: "localhostsecret",
Namespace: "ns1",
ClusterName: "multicluster",
SecretName: "localhostsecret",
Namespace: defaultNs,
},
},
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -831,9 +831,8 @@ func TestMultiClusterAllocationFromLocal(t *testing.T) {

gsa := &allocationv1.GameServerAllocation{
ObjectMeta: metav1.ObjectMeta{
Namespace: defaultNs,
Name: "alloc1",
ClusterName: "multicluster",
Namespace: defaultNs,
Name: "alloc1",
},
Spec: allocationv1.GameServerAllocationSpec{
MultiClusterSetting: allocationv1.MultiClusterSetting{
Expand All @@ -851,6 +850,7 @@ func TestMultiClusterAllocationFromLocal(t *testing.T) {
ret, err := executeAllocation(gsa, c)
assert.NoError(t, err)
assert.Equal(t, gsa.Spec.Required, ret.Spec.Required)
assert.Equal(t, gsa.Namespace, ret.Namespace)
expectedState := allocationv1.GameServerAllocationAllocated
assert.True(t, expectedState == ret.Status.State, "Failed: %s vs %s", expectedState, ret.Status.State)
})
Expand Down Expand Up @@ -920,6 +920,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) {
_, _ = w.Write(response)
}))
defer server.Close()
serverURL := parseURL(t, server.URL)

// Set client CA for server
certpool := x509.NewCertPool()
Expand All @@ -938,7 +939,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) {
Priority: 1,
Weight: 200,
ConnectionInfo: multiclusterv1alpha1.ClusterConnectionInfo{
AllocationEndpoints: []string{server.URL, "non-existing"},
AllocationEndpoints: []string{serverURL.Host, "non-existing"},
ClusterName: clusterName,
SecretName: secretName,
Namespace: targetedNamespace,
Expand Down Expand Up @@ -996,6 +997,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) {
http.Error(w, "test error message", 500)
}))
defer server.Close()
serverURL := parseURL(t, server.URL)

// Set client CA for server
certpool := x509.NewCertPool()
Expand All @@ -1013,7 +1015,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) {
Priority: 1,
Weight: 200,
ConnectionInfo: multiclusterv1alpha1.ClusterConnectionInfo{
AllocationEndpoints: []string{server.URL},
AllocationEndpoints: []string{serverURL.Host},
ClusterName: clusterName,
SecretName: secretName,
},
Expand Down Expand Up @@ -1069,6 +1071,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) {
http.Error(w, "test error message", 500)
}))
defer unhealthyServer.Close()
unhealthyServerURL := parseURL(t, unhealthyServer.URL)

// Set client CA for unhealthy server
certpool := x509.NewCertPool()
Expand All @@ -1088,6 +1091,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) {
_, _ = w.Write(response)
}))
defer healthyServer.Close()
healthyServerURL := parseURL(t, healthyServer.URL)
healthyServer.TLS = unhealthyServer.TLS

// Allocation policy reactor
Expand All @@ -1100,7 +1104,7 @@ func TestMultiClusterAllocationFromRemote(t *testing.T) {
Priority: 1,
Weight: 200,
ConnectionInfo: multiclusterv1alpha1.ClusterConnectionInfo{
AllocationEndpoints: []string{unhealthyServer.URL, healthyServer.URL},
AllocationEndpoints: []string{unhealthyServerURL.Host, healthyServerURL.Host},
ClusterName: clusterName,
SecretName: secretName,
},
Expand Down Expand Up @@ -1230,7 +1234,7 @@ func executeAllocation(gsa *allocationv1.GameServerAllocation, c *Controller) (*
return nil, err
}
rec := httptest.NewRecorder()
if err = c.processAllocationRequest(rec, r, defaultNs, stop); err != nil {
if err = c.processAllocationRequest(rec, r, gsa.Namespace, stop); err != nil {
return nil, err
}

Expand Down Expand Up @@ -1330,6 +1334,14 @@ func getPEMFromDER(der []byte) []byte {
return pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der})
}

func parseURL(t *testing.T, rawURL string) *url.URL {
serverURL, err := url.Parse(rawURL)
if err != nil {
t.Fatalf("failed to parse URL %s: %s", rawURL, err)
}
return serverURL
}

var clientCert = []byte(`-----BEGIN CERTIFICATE-----
MIIDuzCCAqOgAwIBAgIUduDWtqpUsp3rZhCEfUrzI05laVIwDQYJKoZIhvcNAQEL
BQAwbTELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9u
Expand Down
Loading