From 02e06da5e17be9f3f4d7c04a8ab49d0def40bdf1 Mon Sep 17 00:00:00 2001 From: Pooneh Mortazavi Date: Fri, 10 May 2019 12:02:46 -0700 Subject: [PATCH] Adding an allocator service that acts as a reverse proxy. --- build/Makefile | 22 +- build/build-required-src-dist.sh | 2 +- build/extract-licenses.sh | 2 +- build/helm.tf | 7 + cmd/allocator/Dockerfile | 24 +++ cmd/allocator/main.go | 169 +++++++++++++++ cmd/allocator/main_test.go | 134 ++++++++++++ .../agones/certs/allocator/client-ca/ca.crt | 23 ++ .../helm/agones/certs/allocator/server.crt | 23 ++ .../helm/agones/certs/allocator/server.key | 27 +++ .../agones/templates/service/allocation.yaml | 203 ++++++++++++++++++ install/helm/agones/values.yaml | 18 ++ install/yaml/install.yaml | 187 ++++++++++++++++ pkg/gameserverallocations/controller.go | 4 +- pkg/gameserverallocations/controller_test.go | 12 +- site/content/en/docs/Installation/helm.md | 7 + test/e2e/allocator_test.go | 129 +++++++++++ 17 files changed, 981 insertions(+), 12 deletions(-) create mode 100644 cmd/allocator/Dockerfile create mode 100644 cmd/allocator/main.go create mode 100644 cmd/allocator/main_test.go create mode 100644 install/helm/agones/certs/allocator/client-ca/ca.crt create mode 100644 install/helm/agones/certs/allocator/server.crt create mode 100644 install/helm/agones/certs/allocator/server.key create mode 100644 install/helm/agones/templates/service/allocation.yaml create mode 100644 test/e2e/allocator_test.go diff --git a/build/Makefile b/build/Makefile index 75e9b722ad..9ce78dc071 100644 --- a/build/Makefile +++ b/build/Makefile @@ -86,6 +86,7 @@ build_tag = agones-build:$(build_version) controller_tag = $(REGISTRY)/agones-controller:$(VERSION) sidecar_tag = $(REGISTRY)/agones-sdk:$(VERSION) ping_tag = $(REGISTRY)/agones-ping:$(VERSION) +allocator_tag = $(REGISTRY)/agones-allocator:$(VERSION) gomod_on = GO111MODULE=on @@ -197,7 +198,7 @@ include ./includes/sdk.mk build: build-images build-sdks # build the docker images -build-images: build-controller-image build-agones-sdk-image build-ping-image +build-images: build-controller-image build-agones-sdk-image build-ping-image build-allocator-image # package the current agones helm chart build-chart: RELEASE_VERSION ?= $(base_version) @@ -262,12 +263,13 @@ test-install-yaml: diff /tmp/agones-install/install.yaml.sorted /tmp/agones-install/install.current.yaml.sorted # Push all the images up to $(REGISTRY) -push: push-controller-image push-agones-sdk-image push-ping-image +push: push-controller-image push-agones-sdk-image push-ping-image push-allocator-image # Installs the current development version of Agones into the Kubernetes cluster install: ALWAYS_PULL_SIDECAR := true install: IMAGE_PULL_POLICY := "Always" install: PING_SERVICE_TYPE := "LoadBalancer" +install: ALLOCATOR_SERVICE_TYPE := "LoadBalancer" install: CRD_CLEANUP := true install: $(ensure-build-image) install-custom-pull-secret $(DOCKER_RUN) \ @@ -276,6 +278,7 @@ install: $(ensure-build-image) install-custom-pull-secret --set agones.image.controller.pullPolicy=$(IMAGE_PULL_POLICY),agones.image.sdk.alwaysPull=$(ALWAYS_PULL_SIDECAR) \ --set agones.image.controller.pullSecret=$(IMAGE_PULL_SECRET) \ --set agones.ping.http.serviceType=$(PING_SERVICE_TYPE),agones.ping.udp.serviceType=$(PING_SERVICE_TYPE) \ + --set agones.allocator.http.serviceType=$(ALLOCATOR_SERVICE_TYPE) \ --set agones.crds.cleanupOnDelete=$(CRD_CLEANUP) \ agones $(mount_path)/install/helm/agones/ @@ -351,6 +354,20 @@ push-ping-image: $(ensure-build-image) build-ping-image: $(ensure-build-image) build-ping-binary build-licenses build-required-src-dist docker build $(agones_path)/cmd/ping/ --tag=$(ping_tag) $(DOCKER_BUILD_ARGS) +# Build a static binary for the allocator service +build-allocator-binary: $(ensure-build-image) + $(GO_BUILD_LINUX_AMD64) \ + -tags $(GO_BUILD_TAGS) -o $(go_build_base_path)/cmd/allocator/bin/allocator \ + $(go_rebuild_flags) $(go_version_flags) -installsuffix cgo $(agones_package)/cmd/allocator + +# Pushes up the allocator image +push-allocator-image: $(ensure-build-image) + docker push $(allocator_tag) + +# Build the image for the allocator service +build-allocator-image: $(ensure-build-image) build-allocator-binary build-licenses build-required-src-dist + docker build $(agones_path)/cmd/allocator/ --tag=$(allocator_tag) $(DOCKER_BUILD_ARGS) + # push the gameservers sidecar image push-agones-sdk-image: $(ensure-build-image) docker push $(sidecar_tag) @@ -360,6 +377,7 @@ gen-install: $(ensure-build-image) docker run --rm $(common_mounts) $(DOCKER_RUN_ARGS) $(build_tag) bash -c \ 'helm template --name=agones-manual --namespace agones-system $(mount_path)/install/helm/agones \ --set agones.controller.generateTLS=false \ + --set agones.allocator.generateTLS=false \ --set agones.crds.cleanupOnDelete=false \ > $(mount_path)/install/yaml/install.yaml' diff --git a/build/build-required-src-dist.sh b/build/build-required-src-dist.sh index 30010e680b..19da8ec34c 100755 --- a/build/build-required-src-dist.sh +++ b/build/build-required-src-dist.sh @@ -26,7 +26,7 @@ tar -zcf ${TMP_DEPS_SRC} -C ${SRC_ROOT}/vendor/ \ github.com/hashicorp/golang-lru \ github.com/hashicorp/hcl -for ddir in ${SRC_ROOT}/cmd/controller/bin/ ${SRC_ROOT}/cmd/ping/bin/ ${SRC_ROOT}/cmd/sdk-server/bin/ ; do +for ddir in ${SRC_ROOT}/cmd/controller/bin/ ${SRC_ROOT}/cmd/ping/bin/ ${SRC_ROOT}/cmd/sdk-server/bin/ ${SRC_ROOT}/cmd/allocator/bin/ ; do mkdir -p ${ddir} cp ${TMP_DEPS_SRC} ${ddir} done diff --git a/build/extract-licenses.sh b/build/extract-licenses.sh index b776221c8d..a47a11f0b4 100755 --- a/build/extract-licenses.sh +++ b/build/extract-licenses.sh @@ -47,7 +47,7 @@ while read -r entry; do append_license ${LIBRARY} ${entry} done <<< "$(find vendor/ -regextype posix-extended -iregex '.*LICENSE(\.txt)?')" -for ddir in ${SRC_ROOT}/cmd/controller/bin/ ${SRC_ROOT}/cmd/ping/bin/ ${SRC_ROOT}/cmd/sdk-server/bin/ ; do +for ddir in ${SRC_ROOT}/cmd/controller/bin/ ${SRC_ROOT}/cmd/ping/bin/ ${SRC_ROOT}/cmd/sdk-server/bin/ ${SRC_ROOT}/cmd/allocator/bin/ ; do mkdir -p ${ddir} cp ${TMP_LICENSES} ${ddir} done diff --git a/build/helm.tf b/build/helm.tf index 8285d2a391..5e5891d047 100644 --- a/build/helm.tf +++ b/build/helm.tf @@ -68,6 +68,9 @@ variable "image_pull_secret" { variable "ping_service_type" { default = "LoadBalancer" } +variable "allocator_service_type" { + default = "LoadBalancer" +} variable "values_file" { default = "../install/helm/agones/values.yaml" @@ -177,6 +180,10 @@ resource "helm_release" "agones" { name = "agones.ping.udp.serviceType" value = "${var.ping_service_type}" } + set { + name = " agones.allocator.http.serviceType" + value = "${var.allocator_service_type}" + } version = "${var.agones_version}" namespace = "agones-system" } diff --git a/cmd/allocator/Dockerfile b/cmd/allocator/Dockerfile new file mode 100644 index 0000000000..d85520746b --- /dev/null +++ b/cmd/allocator/Dockerfile @@ -0,0 +1,24 @@ +# Copyright 2019 Google LLC All Rights Reserved. +# +# 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. + +FROM alpine:3.8 + +RUN apk --update add ca-certificates && \ + adduser -D agones + +COPY --chown=agones:root ./bin/allocator /home/agones/allocator +COPY --chown=agones:root ./bin/LICENSES ./bin/dependencies-src.tgz /home/agones/ + +USER agones +ENTRYPOINT ["/home/agones/allocator"] diff --git a/cmd/allocator/main.go b/cmd/allocator/main.go new file mode 100644 index 0000000000..2001407032 --- /dev/null +++ b/cmd/allocator/main.go @@ -0,0 +1,169 @@ +// Copyright 2019 Google LLC All Rights Reserved. +// +// 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 main + +import ( + "crypto/tls" + "crypto/x509" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + "net/http" + "os" + "path/filepath" + "strings" + + allocationv1alpha1 "agones.dev/agones/pkg/apis/allocation/v1alpha1" + "agones.dev/agones/pkg/client/clientset/versioned" + "agones.dev/agones/pkg/util/runtime" + k8serror "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/client-go/rest" +) + +var ( + logger = runtime.NewLoggerWithSource("main") +) + +const ( + certDir = "/home/allocator/client-ca/" + tlsDir = "/home/allocator/tls/" + port = "8443" +) + +// A handler for the web server +type handler func(w http.ResponseWriter, r *http.Request) + +func main() { + agonesClient, err := getAgonesClient() + if err != nil { + logger.WithError(err).Fatal("could not create agones client") + } + + h := httpHandler{ + agonesClient: agonesClient, + namespace: os.Getenv("NAMESPACE"), + } + + // TODO: add liveness probe + http.HandleFunc("/v1alpha1/gameserverallocation", h.postOnly(h.allocateHandler)) + + caCertPool, err := getCACertPool(certDir) + if err != nil { + logger.WithError(err).Fatal("could not get CA certs") + } + + cfg := &tls.Config{ + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caCertPool, + } + srv := &http.Server{ + Addr: ":" + port, + TLSConfig: cfg, + } + + err = srv.ListenAndServeTLS(tlsDir+"tls.crt", tlsDir+"tls.key") + logger.WithError(err).Fatal("allocation service crashed") +} + +// Set up our client which we will use to call the API +func getAgonesClient() (*versioned.Clientset, error) { + // Create the in-cluster config + config, err := rest.InClusterConfig() + if err != nil { + return nil, errors.New("Could not create in cluster config") + } + + // Access to the Agones resources through the Agones Clientset + agonesClient, err := versioned.NewForConfig(config) + if err != nil { + return nil, errors.New("Could not create the agones api clientset") + } + + return agonesClient, nil +} + +func getCACertPool(path string) (*x509.CertPool, error) { + // Add all certificates under client-certs path because there could be multiple clusters + // and all client certs should be added. + caCertPool := x509.NewCertPool() + filesInfo, err := ioutil.ReadDir(path) + if err != nil { + return nil, fmt.Errorf("error reading certs from dir %s: %s", path, err.Error()) + } + + for _, file := range filesInfo { + if strings.HasSuffix(file.Name(), ".crt") || strings.HasSuffix(file.Name(), ".pem") { + certFile := filepath.Join(path, file.Name()) + caCert, err := ioutil.ReadFile(certFile) + if err != nil { + return nil, fmt.Errorf("ca cert is not readable or missing: %s", err.Error()) + } + if !caCertPool.AppendCertsFromPEM(caCert) { + return nil, fmt.Errorf("client cert %s cannot be installed", certFile) + } + logger.Infof("client cert %s is installed", certFile) + } + } + + return caCertPool, nil +} + +// Limit verbs the web server handles +func (h *httpHandler) postOnly(in handler) handler { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method == "POST" { + in(w, r) + return + } + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + } +} + +type httpHandler struct { + agonesClient versioned.Interface + namespace string +} + +func (h *httpHandler) allocateHandler(w http.ResponseWriter, r *http.Request) { + gsa := allocationv1alpha1.GameServerAllocation{} + if err := json.NewDecoder(r.Body).Decode(&gsa); err != nil { + http.Error(w, "invalid request", http.StatusBadRequest) + return + } + + allocation := h.agonesClient.AllocationV1alpha1().GameServerAllocations(h.namespace) + allocatedGsa, err := allocation.Create(&gsa) + if err != nil { + http.Error(w, err.Error(), httpCode(err)) + logger.Debug(err) + return + } + w.Header().Set("Content-Type", "application/json") + err = json.NewEncoder(w).Encode(allocatedGsa) + if err != nil { + http.Error(w, "internal server error", http.StatusInternalServerError) + logger.Error(err) + return + } +} + +func httpCode(err error) int { + code := http.StatusInternalServerError + switch t := err.(type) { + case k8serror.APIStatus: + code = int(t.Status().Code) + } + return code +} diff --git a/cmd/allocator/main_test.go b/cmd/allocator/main_test.go new file mode 100644 index 0000000000..6bd6717550 --- /dev/null +++ b/cmd/allocator/main_test.go @@ -0,0 +1,134 @@ +// Copyright 2019 Google LLC All Rights Reserved. +// +// 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 main + +import ( + "bytes" + "encoding/json" + "io/ioutil" + "net/http" + "net/http/httptest" + "os" + "testing" + + "agones.dev/agones/pkg/apis/allocation/v1alpha1" + agonesfake "agones.dev/agones/pkg/client/clientset/versioned/fake" + "github.com/stretchr/testify/assert" + k8serror "k8s.io/apimachinery/pkg/api/errors" + k8sruntime "k8s.io/apimachinery/pkg/runtime" + k8stesting "k8s.io/client-go/testing" +) + +func TestAllocateHandler(t *testing.T) { + t.Parallel() + + fakeAgones := &agonesfake.Clientset{} + h := httpHandler{ + agonesClient: fakeAgones, + namespace: "default", + } + + fakeAgones.AddReactor("create", "gameserverallocations", func(action k8stesting.Action) (bool, k8sruntime.Object, error) { + return true, &v1alpha1.GameServerAllocation{ + Status: v1alpha1.GameServerAllocationStatus{ + State: v1alpha1.GameServerAllocationContention, + }, + }, nil + }) + + gsa := &v1alpha1.GameServerAllocation{} + body, _ := json.Marshal(gsa) + buf := bytes.NewBuffer(body) + req, err := http.NewRequest(http.MethodPost, "/", buf) + if !assert.Nil(t, err) { + return + } + + rec := httptest.NewRecorder() + h.allocateHandler(rec, req) + + ret := &v1alpha1.GameServerAllocation{} + assert.Equal(t, rec.Code, 200) + assert.Equal(t, "application/json", rec.Header()["Content-Type"][0]) + err = json.Unmarshal(rec.Body.Bytes(), ret) + assert.NoError(t, err) + assert.Equal(t, v1alpha1.GameServerAllocationContention, ret.Status.State) +} + +func TestAllocateHandlerReturnsError(t *testing.T) { + t.Parallel() + + fakeAgones := &agonesfake.Clientset{} + h := httpHandler{ + agonesClient: fakeAgones, + namespace: "default", + } + + fakeAgones.AddReactor("create", "gameserverallocations", func(action k8stesting.Action) (bool, k8sruntime.Object, error) { + return true, nil, k8serror.NewBadRequest("error") + }) + + gsa := &v1alpha1.GameServerAllocation{} + body, _ := json.Marshal(gsa) + buf := bytes.NewBuffer(body) + req, err := http.NewRequest(http.MethodPost, "/", buf) + if !assert.Nil(t, err) { + return + } + + rec := httptest.NewRecorder() + h.allocateHandler(rec, req) + assert.Equal(t, rec.Code, 400) + assert.Contains(t, rec.Body.String(), "error") +} + +func TestGettingCaCert(t *testing.T) { + t.Parallel() + + file, err := ioutil.TempFile(".", "*.crt") + if assert.Nil(t, err) { + defer os.Remove(file.Name()) // nolint: errcheck + _, err = file.WriteString(clientCert) + if assert.Nil(t, err) { + certPool, err := getCACertPool("./") + if assert.Nil(t, err) { + assert.Len(t, certPool.Subjects(), 1) + } + } + } +} + +var clientCert = `-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIUduDWtqpUsp3rZhCEfUrzI05laVIwDQYJKoZIhvcNAQEL +BQAwbTELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9u +ZG9uMRgwFgYDVQQKDA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFy +dG1lbnQxCjAIBgNVBAMMASowHhcNMTkwNTAyMjIzMDQ3WhcNMjkwNDI5MjIzMDQ3 +WjBtMQswCQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25k +b24xGDAWBgNVBAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0 +bWVudDEKMAgGA1UEAwwBKjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKGDasjadVwe0bXUEQfZCkMEAkzn0qTud3RYytympmaS0c01SWFNZwPRO0rpdIOZ +fyXVXVOAhgmgCR6QuXySmyQIoYl/D6tVhc5r9FyWPIBtzQKCJTX0mZOZwMn22qvo +bfnDnVsZ1Ny3RLZIF3um3xovvePXyg1z7D/NvCogNuYpyUUEITPZX6ss5ods/U78 +BxLhKrT8iyu61ZC+ZegbHQqFRngbeb348gE1JwKTslDfe4oH7tZ+bNDZxnGcvh9j +eyagpM0zys4gFfQf/vfD2aEsUJ+GesUQC6uGVoGnTFshFhBsAK6vpIQ4ZQujaJ0r +NKgJ/ccBJFiJXMCR44yWFY0CAwEAAaNTMFEwHQYDVR0OBBYEFEe1gDd8JpzgnvOo +1AEloAXxmxHCMB8GA1UdIwQYMBaAFEe1gDd8JpzgnvOo1AEloAXxmxHCMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAI5GyuakVgunerCGCSN7Ghsr +ys9vJytbyT+BLmxNBPSXWQwcm3g9yCDdgf0Y3q3Eef7IEZu4I428318iLzhfKln1 +ua4fxvmTFKJ65lQKNkc6Y4e3w1t+C2HOl6fOIVT231qsCoM5SAwQQpqAzEUj6kZl +x+3avw9KSlXqR/mCAkePyoKvprxeb6RVDdq92Ug0qzoAHLpvIkuHdlF0dNp6/kO0 +1pVL0BqW+6UTimSSvH8F/cMeYKbkhpE1u2c/NtNwsR2jN4M9kl3KHqkynk67PfZv +pwlCqZx4M8FpdfCbOZeRLzClUBdD5qzev0L3RNUx7UJzEIN+4LCBv37DIojNOyA= +-----END CERTIFICATE----- +` diff --git a/install/helm/agones/certs/allocator/client-ca/ca.crt b/install/helm/agones/certs/allocator/client-ca/ca.crt new file mode 100644 index 0000000000..158b88a4ad --- /dev/null +++ b/install/helm/agones/certs/allocator/client-ca/ca.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIUKbZWR0Ji6BTqkdbB90Om4uJHi38wDQYJKoZIhvcNAQEL +BQAwdTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEuMCwGCSqGSIb3DQEJARYfYWdvbmVz +LWRpc2N1c3NAZ29vZ2xlZ3JvdXBzLmNvbTAeFw0xOTA1MTQxODMxNTlaFw0yOTA1 +MTExODMxNTlaMHUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxLjAsBgkqhkiG9w0BCQEW +H2Fnb25lcy1kaXNjdXNzQGdvb2dsZWdyb3Vwcy5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDetyULwNujFbXZtGFcOCAwTYfU54D4Gwdk1t7RWqa5 +//riKswqkcrw68lNkINm+yMNgFkdt2zglwjCgjJZXcFovP/7/g32CN5W6gyx7cB0 +FTXJVWe3uUG6PW5YPaH12CucHCq5iNzwlEyDUPCJAaPO5fUBlbCRULYPhBnJXZXr +B6zdtc6R1uykXNfVhZYHvIVr5oWIFygCNnjvMgHmkvfLNximSgpsKXyLjW11SWwx +mxppowklwK2QqaxnaSOTYv7ucmL0O8XE89n/So1YnIOgdQyNmNaUJ4D6MhxvKeJA +Tfg6k91QwW9+EIiht+NjCMspx4n6yliRno1GMHsZIjbHAgMBAAGjUzBRMB0GA1Ud +DgQWBBQxjrrtKpNpM6MH9868q65dq4770TAfBgNVHSMEGDAWgBQxjrrtKpNpM6MH +9868q65dq4770TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCo +cFsxscFNj8wTkuhvmEG285zCs98QjGqsOTB4/GkrTmbNQoqObnc6iNC4bs9AC6HO +abNRC6m5UaVQVH3UB6O3+Fm40TNoTZt1GBF3/LtdwgdRkmFThiB/fIttT0PGaEfe +A+yeyhNbVyUgOYI7nK5PK5s7gBSykGLzXIielommrA6K29/ZNlj+hNwKWHIBZ/Cn +cOkVgPBkeBkY+VrVc3n/HBclj+s7R75KrhpNKOMfv3jorhRAQ8eQoIhHbiqcbM7q +lzpl39Uxsj2V1YBayu9inmqJiBf4SMuntzUpPzKal0O+ieKA2bKSSTlGGnr3RRvy +MXdg7ZXZewKqbbS/BrHq +-----END CERTIFICATE----- diff --git a/install/helm/agones/certs/allocator/server.crt b/install/helm/agones/certs/allocator/server.crt new file mode 100644 index 0000000000..158b88a4ad --- /dev/null +++ b/install/helm/agones/certs/allocator/server.crt @@ -0,0 +1,23 @@ +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIUKbZWR0Ji6BTqkdbB90Om4uJHi38wDQYJKoZIhvcNAQEL +BQAwdTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEuMCwGCSqGSIb3DQEJARYfYWdvbmVz +LWRpc2N1c3NAZ29vZ2xlZ3JvdXBzLmNvbTAeFw0xOTA1MTQxODMxNTlaFw0yOTA1 +MTExODMxNTlaMHUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxLjAsBgkqhkiG9w0BCQEW +H2Fnb25lcy1kaXNjdXNzQGdvb2dsZWdyb3Vwcy5jb20wggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDetyULwNujFbXZtGFcOCAwTYfU54D4Gwdk1t7RWqa5 +//riKswqkcrw68lNkINm+yMNgFkdt2zglwjCgjJZXcFovP/7/g32CN5W6gyx7cB0 +FTXJVWe3uUG6PW5YPaH12CucHCq5iNzwlEyDUPCJAaPO5fUBlbCRULYPhBnJXZXr +B6zdtc6R1uykXNfVhZYHvIVr5oWIFygCNnjvMgHmkvfLNximSgpsKXyLjW11SWwx +mxppowklwK2QqaxnaSOTYv7ucmL0O8XE89n/So1YnIOgdQyNmNaUJ4D6MhxvKeJA +Tfg6k91QwW9+EIiht+NjCMspx4n6yliRno1GMHsZIjbHAgMBAAGjUzBRMB0GA1Ud +DgQWBBQxjrrtKpNpM6MH9868q65dq4770TAfBgNVHSMEGDAWgBQxjrrtKpNpM6MH +9868q65dq4770TAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCo +cFsxscFNj8wTkuhvmEG285zCs98QjGqsOTB4/GkrTmbNQoqObnc6iNC4bs9AC6HO +abNRC6m5UaVQVH3UB6O3+Fm40TNoTZt1GBF3/LtdwgdRkmFThiB/fIttT0PGaEfe +A+yeyhNbVyUgOYI7nK5PK5s7gBSykGLzXIielommrA6K29/ZNlj+hNwKWHIBZ/Cn +cOkVgPBkeBkY+VrVc3n/HBclj+s7R75KrhpNKOMfv3jorhRAQ8eQoIhHbiqcbM7q +lzpl39Uxsj2V1YBayu9inmqJiBf4SMuntzUpPzKal0O+ieKA2bKSSTlGGnr3RRvy +MXdg7ZXZewKqbbS/BrHq +-----END CERTIFICATE----- diff --git a/install/helm/agones/certs/allocator/server.key b/install/helm/agones/certs/allocator/server.key new file mode 100644 index 0000000000..074d228fc8 --- /dev/null +++ b/install/helm/agones/certs/allocator/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAwvzpNSlVvochgfFuj96OdIgMyrvQarrhU/JPMrP7Gz71OU7n +wxh+11jluFKeQLPMROmQ7ANzMCuOk4oJiAfXFRlyUxix/bn0JGlekcfBRSizTUUp +wn/hZhUatdzM1nHnbbhezyDtxeAtWQroEWCpSGU6b2FFxn3O+r1nc4QtmuE1C+KD +w5qUyZtxshDS97v3x8zu92BIjCFITy8Nr1t4Xc9fmgzFXRta5gsIppXcNHPERo3/ +3ZSpVx5q0HOgj9Ha33MlD5Y4cRumro2nQP6sm+72/XwL0/N5sUT9idR/eAN7dZln +pfj/9dpzYDRxPOHespl19tPvtOX2Pcwr3DgFZwIDAQABAoIBAEozCd+UAjAFpieX +ozYWP+lyWEPRoqbqxJI4VBD8UmL020Zak3E3YhU6m/g/YD9I7EORCff1/CBpgtD8 +J1JfgWZjD5E1hY4C9Dfi7PzWoeJacZjG5/Q+y5wYDdkE0+IK6EFldpaldjXlb/xB +XTw3p1OISetWfcHh4CCkcLiRpPUZcY3Y6Ji0WDklabkaaFGn2GBY6atUHAqSRX5/ +CvxNa9GLUSJCXwQLNES1jVocjCfbq38fZtr9YzTF6VSbpy0c7Rp4DPmRXOlEDsTq +0xvalvVl5o4uHFLhgJXKvFt5LW1e6crSLzMGCy+EQy0oXvyt82iCLMzLYdg1Urd8 +pk3dFIkCgYEA8dxbYm5Ds3ZczxP8arjhUEOuIhE95BZjpXMVTeXCUs8WhyargDMB +ns5p6RXyZ4YiySez7ay6thwT/JNkt5cstqpW1ccQh/wiQcZgVrBOvgk16TUaDo3r +illSmFo5q61xJqaz6IVkQbWEuC1jyDeRUyMJONKNGAUhRugzlKoxN80CgYEAzmMQ +W+uB4ZZHdun1JVO4pVvD9F2XSXdUIaAOCCRrT+FyWTWkCp5e1fir/kyndNdL0wHA +YLwlQ0P6+wyQ+wzoQIjxkl6Ji0U99t2rditakdleTRDgwevQM4K9ERpR4olasWwT +Oid/RtzxsPW+IV4eQXvG1eAqkOctY58PKg/71gMCgYEAuA+d0Evf4+y49rLcDxAC +EIZhN/XtJu7PCLOLTAwFleWZ3GLWc6rdmdC2kzcrkhNn17QKX19rfHnjz/0P0hQP +aDg7+1cSQprkKzBgUri8RC1YRNEvslHZJiGSFPXdG8TT7rlBAzy4rrUIeu24GUAI +rb9lHkRGMjh9OawuzP20lSUCgYA4eIqlXA8xtnjfZKybBglj1XQMjP80Lt5qRO0R +9UUXmkw7dJ3p+eNhEKWe80JuiepJVhVZYqGfgh5OSuXwi1uRLOdMcWmZHd0Sixy7 +PKmPdraCx7d32BojvgYVg+ob3hFesn+gTeZZcWMAVH0tjB8jM8b4BlofQ+H7fC4e +CDmUGQKBgEFxGn8yV5tx6egR2N9lwhywoC8qUrQa5KeE6cAU1k4cprMqQEriRwIR +Gf80q25aAnhFvE4N+7qNEirC+kiaw3+DCCmsQ+rnlc6Trs560fHsqISBTj/i9X0r +md2bhpbaz8YuMVm0pb9/c4SZivBz64yK2Ob4snFW0fLkLQQ+pjK5 +-----END RSA PRIVATE KEY----- diff --git a/install/helm/agones/templates/service/allocation.yaml b/install/helm/agones/templates/service/allocation.yaml new file mode 100644 index 0000000000..cae5cb96ef --- /dev/null +++ b/install/helm/agones/templates/service/allocation.yaml @@ -0,0 +1,203 @@ +# Copyright 2019 Google LLC All Rights Reserved. +# +# 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. + +{{- if .Values.agones.allocator.install }} +# Define a Service for the gameserver-allocator +apiVersion: v1 +kind: Service +metadata: + name: gameserver-allocator + namespace: {{ .Release.Namespace }} + labels: + component: allocator + app: {{ template "agones.name" . }} + chart: {{ template "agones.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + selector: + multicluster.agones.dev/role: allocator + ports: + - port: {{ .Values.agones.allocator.http.port }} + name: https + targetPort: 8443 + protocol: TCP + type: {{ .Values.agones.allocator.http.serviceType }} + +--- +# Deploy a pod to run the gameserver-allocator code +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gameserver-allocator + namespace: {{ .Release.Namespace }} + labels: + multicluster.agones.dev/role: allocator + app: {{ template "agones.name" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.agones.allocator.replicas }} + selector: + matchLabels: + multicluster.agones.dev/role: allocator + app: {{ template "agones.name" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + template: + metadata: + labels: + multicluster.agones.dev/role: allocator + app: {{ template "agones.name" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + spec: + serviceAccountName: gameserver-allocator + volumes: + - name: tls + secret: + secretName: allocator-tls + - name: client-ca + secret: + secretName: allocator-client-ca + containers: + - name: agones-allocator + image: "{{ .Values.agones.image.registry }}/{{ .Values.agones.image.allocator.name}}:{{ default .Values.agones.image.tag .Values.agones.image.allocator.tag }}" + imagePullPolicy: {{ .Values.agones.image.controller.pullPolicy }} + ports: + - name: https + containerPort: 8443 + volumeMounts: + - mountPath: /home/allocator/tls + name: tls + readOnly: true + - mountPath: /home/allocator/client-ca + name: client-ca + readOnly: true + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + +--- +# Create a Role in the default namespace that grants access to the agones api +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: gameserver-allocator + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "agones.name" $ }} + chart: {{ template "agones.chart" $ }} + release: {{ $.Release.Name }} + heritage: {{ $.Release.Service }} +rules: +- apiGroups: ["allocation.agones.dev"] + resources: ["gameserverallocations"] + verbs: ["create"] + +--- +# Create a ServiceAccount that will be bound to the above role +apiVersion: v1 +kind: ServiceAccount +metadata: + name: gameserver-allocator + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "agones.name" $ }} + chart: {{ template "agones.chart" $ }} + release: {{ $.Release.Name }} + heritage: {{ $.Release.Service }} + +--- +# Bind the gameserver-allocator ServiceAccount to the gameserver-allocator Role +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: gameserver-allocator + namespace: {{ .Release.Namespace }} + labels: + app: {{ template "agones.name" $ }} + chart: {{ template "agones.chart" $ }} + release: {{ $.Release.Name }} + heritage: {{ $.Release.Service }} +subjects: +- kind: ServiceAccount + name: gameserver-allocator + namespace: {{ .Release.Namespace }} +roleRef: + kind: Role + name: gameserver-allocator + +{{- end }} + +--- +# Allocation CA +{{- $ca := genCA "allocation-ca" 3650 }} +apiVersion: v1 +kind: Secret +metadata: + name: allocator-client-ca + labels: + app: {{ template "agones.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +data: +{{- if .Values.agones.allocator.generateTLS }} + client-ca.crt: {{ b64enc $ca.Cert }} +{{- else }} + {{- (.Files.Glob "certs/allocator/client-ca/*").AsSecrets | nindent 2 }} +{{- end }} + +--- +# Allocation TLS certs +{{- $cert := genSignedCert "" nil nil 3650 $ca }} +apiVersion: v1 +kind: Secret +type: kubernetes.io/tls +metadata: + name: allocator-tls + labels: + app: {{ template "agones.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +data: +{{- if .Values.agones.allocator.generateTLS }} + tls.crt: {{ b64enc $cert.Cert }} + tls.key: {{ b64enc $cert.Key }} +{{- else }} + tls.crt: {{ .Files.Get "certs/allocator/server.crt" | b64enc }} + tls.key: {{ .Files.Get "certs/allocator/server.key" | b64enc }} +{{- end }} + +--- +# Allocation TLS CA +apiVersion: v1 +kind: Secret +metadata: + name: allocator-tls-ca + labels: + app: {{ template "agones.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +data: +{{- if .Values.agones.allocator.generateTLS }} + tls-ca.crt: {{ b64enc $ca.Cert }} +{{- else }} + tls-ca.crt: {{ .Files.Get "certs/allocator/server.crt" | b64enc }} +{{- end }} \ No newline at end of file diff --git a/install/helm/agones/values.yaml b/install/helm/agones/values.yaml index a75e390b31..953a216d01 100644 --- a/install/helm/agones/values.yaml +++ b/install/helm/agones/values.yaml @@ -95,6 +95,20 @@ agones: periodSeconds: 3 failureThreshold: 3 timeoutSeconds: 1 + allocator: + install: true + tolerations: + - key: "stable.agones.dev/agones-system" + operator: "Equal" + value: "true" + effect: "NoExecute" + replicas: 3 + http: + expose: true + response: ok + port: 443 + serviceType: LoadBalancer + generateTLS: true image: registry: gcr.io/agones-images tag: 0.10.0 @@ -109,6 +123,10 @@ agones: ping: name: agones-ping pullPolicy: IfNotPresent + allocator: + name: agones-allocator + pullPolicy: IfNotPresent + gameservers: namespaces: diff --git a/install/yaml/install.yaml b/install/yaml/install.yaml index 34aed68f5a..c46aa85d7d 100644 --- a/install/yaml/install.yaml +++ b/install/yaml/install.yaml @@ -991,6 +991,193 @@ spec: - name: web port: 8080 --- +# Source: agones/templates/service/allocation.yaml +# Copyright 2019 Google LLC All Rights Reserved. +# +# 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. +# Define a Service for the gameserver-allocator +apiVersion: v1 +kind: Service +metadata: + name: gameserver-allocator + namespace: agones-system + labels: + component: allocator + app: agones + chart: agones-0.10.0 + release: agones-manual + heritage: Tiller +spec: + selector: + multicluster.agones.dev/role: allocator + ports: + - port: 443 + name: https + targetPort: 8443 + protocol: TCP + type: LoadBalancer + +--- +# Deploy a pod to run the gameserver-allocator code +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gameserver-allocator + namespace: agones-system + labels: + multicluster.agones.dev/role: allocator + app: agones + release: agones-manual + heritage: Tiller +spec: + replicas: 3 + selector: + matchLabels: + multicluster.agones.dev/role: allocator + app: agones + release: agones-manual + heritage: Tiller + template: + metadata: + labels: + multicluster.agones.dev/role: allocator + app: agones + release: agones-manual + heritage: Tiller + spec: + serviceAccountName: gameserver-allocator + volumes: + - name: tls + secret: + secretName: allocator-tls + - name: client-ca + secret: + secretName: allocator-client-ca + containers: + - name: agones-allocator + image: "gcr.io/agones-images/agones-allocator:0.10.0" + imagePullPolicy: IfNotPresent + ports: + - name: https + containerPort: 8443 + volumeMounts: + - mountPath: /home/allocator/tls + name: tls + readOnly: true + - mountPath: /home/allocator/client-ca + name: client-ca + readOnly: true + env: + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + +--- +# Create a Role in the default namespace that grants access to the agones api +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: gameserver-allocator + namespace: agones-system + labels: + app: agones + chart: agones-0.10.0 + release: agones-manual + heritage: Tiller +rules: +- apiGroups: ["allocation.agones.dev"] + resources: ["gameserverallocations"] + verbs: ["create"] + +--- +# Create a ServiceAccount that will be bound to the above role +apiVersion: v1 +kind: ServiceAccount +metadata: + name: gameserver-allocator + namespace: agones-system + labels: + app: agones + chart: agones-0.10.0 + release: agones-manual + heritage: Tiller + +--- +# Bind the gameserver-allocator ServiceAccount to the gameserver-allocator Role +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: gameserver-allocator + namespace: agones-system + labels: + app: agones + chart: agones-0.10.0 + release: agones-manual + heritage: Tiller +subjects: +- kind: ServiceAccount + name: gameserver-allocator + namespace: agones-system +roleRef: + kind: Role + name: gameserver-allocator + +--- +# Allocation CA +apiVersion: v1 +kind: Secret +metadata: + name: allocator-client-ca + labels: + app: agones-manual + chart: "agones-0.10.0" + release: "agones-manual" + heritage: "Tiller" +data: + ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR5ekNDQXJPZ0F3SUJBZ0lVS2JaV1IwSmk2QlRxa2RiQjkwT200dUpIaTM4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeElUQWZCZ05WQkFvTQpHRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERXVNQ3dHQ1NxR1NJYjNEUUVKQVJZZllXZHZibVZ6CkxXUnBjMk4xYzNOQVoyOXZaMnhsWjNKdmRYQnpMbU52YlRBZUZ3MHhPVEExTVRReE9ETXhOVGxhRncweU9UQTEKTVRFeE9ETXhOVGxhTUhVeEN6QUpCZ05WQkFZVEFrRlZNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFdwpId1lEVlFRS0RCaEpiblJsY201bGRDQlhhV1JuYVhSeklGQjBlU0JNZEdReExqQXNCZ2txaGtpRzl3MEJDUUVXCkgyRm5iMjVsY3kxa2FYTmpkWE56UUdkdmIyZHNaV2R5YjNWd2N5NWpiMjB3Z2dFaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURldHlVTHdOdWpGYlhadEdGY09DQXdUWWZVNTRENEd3ZGsxdDdSV3FhNQovL3JpS3N3cWtjcnc2OGxOa0lObSt5TU5nRmtkdDJ6Z2x3akNnakpaWGNGb3ZQLzcvZzMyQ041VzZneXg3Y0IwCkZUWEpWV2UzdVVHNlBXNVlQYUgxMkN1Y0hDcTVpTnp3bEV5RFVQQ0pBYVBPNWZVQmxiQ1JVTFlQaEJuSlhaWHIKQjZ6ZHRjNlIxdXlrWE5mVmhaWUh2SVZyNW9XSUZ5Z0NObmp2TWdIbWt2ZkxOeGltU2dwc0tYeUxqVzExU1d3eApteHBwb3drbHdLMlFxYXhuYVNPVFl2N3VjbUwwTzhYRTg5bi9TbzFZbklPZ2RReU5tTmFVSjRENk1oeHZLZUpBClRmZzZrOTFRd1c5K0VJaWh0K05qQ01zcHg0bjZ5bGlSbm8xR01Ic1pJamJIQWdNQkFBR2pVekJSTUIwR0ExVWQKRGdRV0JCUXhqcnJ0S3BOcE02TUg5ODY4cTY1ZHE0NzcwVEFmQmdOVkhTTUVHREFXZ0JReGpycnRLcE5wTTZNSAo5ODY4cTY1ZHE0NzcwVEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNvCmNGc3hzY0ZOajh3VGt1aHZtRUcyODV6Q3M5OFFqR3FzT1RCNC9Ha3JUbWJOUW9xT2JuYzZpTkM0YnM5QUM2SE8KYWJOUkM2bTVVYVZRVkgzVUI2TzMrRm00MFROb1RadDFHQkYzL0x0ZHdnZFJrbUZUaGlCL2ZJdHRUMFBHYUVmZQpBK3lleWhOYlZ5VWdPWUk3bks1UEs1czdnQlN5a0dMelhJaWVsb21tckE2SzI5L1pObGoraE53S1dISUJaL0NuCmNPa1ZnUEJrZUJrWStWclZjM24vSEJjbGorczdSNzVLcmhwTktPTWZ2M2pvcmhSQVE4ZVFvSWhIYmlxY2JNN3EKbHpwbDM5VXhzajJWMVlCYXl1OWlubXFKaUJmNFNNdW50elVwUHpLYWwwTytpZUtBMmJLU1NUbEdHbnIzUlJ2eQpNWGRnN1pYWmV3S3FiYlMvQnJIcQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + + +--- +# Allocation TLS certs +apiVersion: v1 +kind: Secret +type: kubernetes.io/tls +metadata: + name: allocator-tls + labels: + app: agones-manual + chart: "agones-0.10.0" + release: "agones-manual" + heritage: "Tiller" +data: + tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR5ekNDQXJPZ0F3SUJBZ0lVS2JaV1IwSmk2QlRxa2RiQjkwT200dUpIaTM4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeElUQWZCZ05WQkFvTQpHRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERXVNQ3dHQ1NxR1NJYjNEUUVKQVJZZllXZHZibVZ6CkxXUnBjMk4xYzNOQVoyOXZaMnhsWjNKdmRYQnpMbU52YlRBZUZ3MHhPVEExTVRReE9ETXhOVGxhRncweU9UQTEKTVRFeE9ETXhOVGxhTUhVeEN6QUpCZ05WQkFZVEFrRlZNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFdwpId1lEVlFRS0RCaEpiblJsY201bGRDQlhhV1JuYVhSeklGQjBlU0JNZEdReExqQXNCZ2txaGtpRzl3MEJDUUVXCkgyRm5iMjVsY3kxa2FYTmpkWE56UUdkdmIyZHNaV2R5YjNWd2N5NWpiMjB3Z2dFaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURldHlVTHdOdWpGYlhadEdGY09DQXdUWWZVNTRENEd3ZGsxdDdSV3FhNQovL3JpS3N3cWtjcnc2OGxOa0lObSt5TU5nRmtkdDJ6Z2x3akNnakpaWGNGb3ZQLzcvZzMyQ041VzZneXg3Y0IwCkZUWEpWV2UzdVVHNlBXNVlQYUgxMkN1Y0hDcTVpTnp3bEV5RFVQQ0pBYVBPNWZVQmxiQ1JVTFlQaEJuSlhaWHIKQjZ6ZHRjNlIxdXlrWE5mVmhaWUh2SVZyNW9XSUZ5Z0NObmp2TWdIbWt2ZkxOeGltU2dwc0tYeUxqVzExU1d3eApteHBwb3drbHdLMlFxYXhuYVNPVFl2N3VjbUwwTzhYRTg5bi9TbzFZbklPZ2RReU5tTmFVSjRENk1oeHZLZUpBClRmZzZrOTFRd1c5K0VJaWh0K05qQ01zcHg0bjZ5bGlSbm8xR01Ic1pJamJIQWdNQkFBR2pVekJSTUIwR0ExVWQKRGdRV0JCUXhqcnJ0S3BOcE02TUg5ODY4cTY1ZHE0NzcwVEFmQmdOVkhTTUVHREFXZ0JReGpycnRLcE5wTTZNSAo5ODY4cTY1ZHE0NzcwVEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNvCmNGc3hzY0ZOajh3VGt1aHZtRUcyODV6Q3M5OFFqR3FzT1RCNC9Ha3JUbWJOUW9xT2JuYzZpTkM0YnM5QUM2SE8KYWJOUkM2bTVVYVZRVkgzVUI2TzMrRm00MFROb1RadDFHQkYzL0x0ZHdnZFJrbUZUaGlCL2ZJdHRUMFBHYUVmZQpBK3lleWhOYlZ5VWdPWUk3bks1UEs1czdnQlN5a0dMelhJaWVsb21tckE2SzI5L1pObGoraE53S1dISUJaL0NuCmNPa1ZnUEJrZUJrWStWclZjM24vSEJjbGorczdSNzVLcmhwTktPTWZ2M2pvcmhSQVE4ZVFvSWhIYmlxY2JNN3EKbHpwbDM5VXhzajJWMVlCYXl1OWlubXFKaUJmNFNNdW50elVwUHpLYWwwTytpZUtBMmJLU1NUbEdHbnIzUlJ2eQpNWGRnN1pYWmV3S3FiYlMvQnJIcQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== + tls.key: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBd3Z6cE5TbFZ2b2NoZ2ZGdWo5Nk9kSWdNeXJ2UWFycmhVL0pQTXJQN0d6NzFPVTduCnd4aCsxMWpsdUZLZVFMUE1ST21RN0FOek1DdU9rNG9KaUFmWEZSbHlVeGl4L2JuMEpHbGVrY2ZCUlNpelRVVXAKd24vaFpoVWF0ZHpNMW5IbmJiaGV6eUR0eGVBdFdRcm9FV0NwU0dVNmIyRkZ4bjNPK3IxbmM0UXRtdUUxQytLRAp3NXFVeVp0eHNoRFM5N3YzeDh6dTkyQklqQ0ZJVHk4TnIxdDRYYzlmbWd6RlhSdGE1Z3NJcHBYY05IUEVSbzMvCjNaU3BWeDVxMEhPZ2o5SGEzM01sRDVZNGNSdW1ybzJuUVA2c20rNzIvWHdMMC9ONXNVVDlpZFIvZUFON2RabG4KcGZqLzlkcHpZRFJ4UE9IZXNwbDE5dFB2dE9YMlBjd3IzRGdGWndJREFRQUJBb0lCQUVvekNkK1VBakFGcGllWApvellXUCtseVdFUFJvcWJxeEpJNFZCRDhVbUwwMjBaYWszRTNZaFU2bS9nL1lEOUk3RU9SQ2ZmMS9DQnBndEQ4CkoxSmZnV1pqRDVFMWhZNEM5RGZpN1B6V29lSmFjWmpHNS9RK3k1d1lEZGtFMCtJSzZFRmxkcGFsZGpYbGIveEIKWFR3M3AxT0lTZXRXZmNIaDRDQ2tjTGlScFBVWmNZM1k2SmkwV0RrbGFia2FhRkduMkdCWTZhdFVIQXFTUlg1LwpDdnhOYTlHTFVTSkNYd1FMTkVTMWpWb2NqQ2ZicTM4Zlp0cjlZelRGNlZTYnB5MGM3UnA0RFBtUlhPbEVEc1RxCjB4dmFsdlZsNW80dUhGTGhnSlhLdkZ0NUxXMWU2Y3JTTHpNR0N5K0VReTBvWHZ5dDgyaUNMTXpMWWRnMVVyZDgKcGszZEZJa0NnWUVBOGR4YlltNURzM1pjenhQOGFyamhVRU91SWhFOTVCWmpwWE1WVGVYQ1VzOFdoeWFyZ0RNQgpuczVwNlJYeVo0WWl5U2V6N2F5NnRod1QvSk5rdDVjc3RxcFcxY2NRaC93aVFjWmdWckJPdmdrMTZUVWFEbzNyCmlsbFNtRm81cTYxeEpxYXo2SVZrUWJXRXVDMWp5RGVSVXlNSk9OS05HQVVoUnVnemxLb3hOODBDZ1lFQXptTVEKVyt1QjRaWkhkdW4xSlZPNHBWdkQ5RjJYU1hkVUlhQU9DQ1JyVCtGeVdUV2tDcDVlMWZpci9reW5kTmRMMHdIQQpZTHdsUTBQNit3eVErd3pvUUlqeGtsNkppMFU5OXQycmRpdGFrZGxlVFJEZ3dldlFNNEs5RVJwUjRvbGFzV3dUCk9pZC9SdHp4c1BXK0lWNGVRWHZHMWVBcWtPY3RZNThQS2cvNzFnTUNnWUVBdUErZDBFdmY0K3k0OXJMY0R4QUMKRUlaaE4vWHRKdTdQQ0xPTFRBd0ZsZVdaM0dMV2M2cmRtZEMya3pjcmtoTm4xN1FLWDE5cmZIbmp6LzBQMGhRUAphRGc3KzFjU1FwcmtLekJnVXJpOFJDMVlSTkV2c2xIWkppR1NGUFhkRzhUVDdybEJBenk0cnJVSWV1MjRHVUFJCnJiOWxIa1JHTWpoOU9hd3V6UDIwbFNVQ2dZQTRlSXFsWEE4eHRuamZaS3liQmdsajFYUU1qUDgwTHQ1cVJPMFIKOVVVWG1rdzdkSjNwK2VOaEVLV2U4MEp1aWVwSlZoVlpZcUdmZ2g1T1N1WHdpMXVSTE9kTWNXbVpIZDBTaXh5NwpQS21QZHJhQ3g3ZDMyQm9qdmdZVmcrb2IzaEZlc24rZ1RlWlpjV01BVkgwdGpCOGpNOGI0QmxvZlErSDdmQzRlCkNEbVVHUUtCZ0VGeEduOHlWNXR4NmVnUjJOOWx3aHl3b0M4cVVyUWE1S2VFNmNBVTFrNGNwck1xUUVyaVJ3SVIKR2Y4MHEyNWFBbmhGdkU0Tis3cU5FaXJDK2tpYXczK0RDQ21zUStybmxjNlRyczU2MGZIc3FJU0JUai9pOVgwcgptZDJiaHBiYXo4WXVNVm0wcGI5L2M0U1ppdkJ6NjR5SzJPYjRzbkZXMGZMa0xRUStwaks1Ci0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg== + +--- +# Allocation TLS CA +apiVersion: v1 +kind: Secret +metadata: + name: allocator-tls-ca + labels: + app: agones-manual + chart: "agones-0.10.0" + release: "agones-manual" + heritage: "Tiller" +data: + tls-ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUR5ekNDQXJPZ0F3SUJBZ0lVS2JaV1IwSmk2QlRxa2RiQjkwT200dUpIaTM4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd2RURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeElUQWZCZ05WQkFvTQpHRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERXVNQ3dHQ1NxR1NJYjNEUUVKQVJZZllXZHZibVZ6CkxXUnBjMk4xYzNOQVoyOXZaMnhsWjNKdmRYQnpMbU52YlRBZUZ3MHhPVEExTVRReE9ETXhOVGxhRncweU9UQTEKTVRFeE9ETXhOVGxhTUhVeEN6QUpCZ05WQkFZVEFrRlZNUk13RVFZRFZRUUlEQXBUYjIxbExWTjBZWFJsTVNFdwpId1lEVlFRS0RCaEpiblJsY201bGRDQlhhV1JuYVhSeklGQjBlU0JNZEdReExqQXNCZ2txaGtpRzl3MEJDUUVXCkgyRm5iMjVsY3kxa2FYTmpkWE56UUdkdmIyZHNaV2R5YjNWd2N5NWpiMjB3Z2dFaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURldHlVTHdOdWpGYlhadEdGY09DQXdUWWZVNTRENEd3ZGsxdDdSV3FhNQovL3JpS3N3cWtjcnc2OGxOa0lObSt5TU5nRmtkdDJ6Z2x3akNnakpaWGNGb3ZQLzcvZzMyQ041VzZneXg3Y0IwCkZUWEpWV2UzdVVHNlBXNVlQYUgxMkN1Y0hDcTVpTnp3bEV5RFVQQ0pBYVBPNWZVQmxiQ1JVTFlQaEJuSlhaWHIKQjZ6ZHRjNlIxdXlrWE5mVmhaWUh2SVZyNW9XSUZ5Z0NObmp2TWdIbWt2ZkxOeGltU2dwc0tYeUxqVzExU1d3eApteHBwb3drbHdLMlFxYXhuYVNPVFl2N3VjbUwwTzhYRTg5bi9TbzFZbklPZ2RReU5tTmFVSjRENk1oeHZLZUpBClRmZzZrOTFRd1c5K0VJaWh0K05qQ01zcHg0bjZ5bGlSbm8xR01Ic1pJamJIQWdNQkFBR2pVekJSTUIwR0ExVWQKRGdRV0JCUXhqcnJ0S3BOcE02TUg5ODY4cTY1ZHE0NzcwVEFmQmdOVkhTTUVHREFXZ0JReGpycnRLcE5wTTZNSAo5ODY4cTY1ZHE0NzcwVEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUNvCmNGc3hzY0ZOajh3VGt1aHZtRUcyODV6Q3M5OFFqR3FzT1RCNC9Ha3JUbWJOUW9xT2JuYzZpTkM0YnM5QUM2SE8KYWJOUkM2bTVVYVZRVkgzVUI2TzMrRm00MFROb1RadDFHQkYzL0x0ZHdnZFJrbUZUaGlCL2ZJdHRUMFBHYUVmZQpBK3lleWhOYlZ5VWdPWUk3bks1UEs1czdnQlN5a0dMelhJaWVsb21tckE2SzI5L1pObGoraE53S1dISUJaL0NuCmNPa1ZnUEJrZUJrWStWclZjM24vSEJjbGorczdSNzVLcmhwTktPTWZ2M2pvcmhSQVE4ZVFvSWhIYmlxY2JNN3EKbHpwbDM5VXhzajJWMVlCYXl1OWlubXFKaUJmNFNNdW50elVwUHpLYWwwTytpZUtBMmJLU1NUbEdHbnIzUlJ2eQpNWGRnN1pYWmV3S3FiYlMvQnJIcQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg== +--- # Source: agones/templates/controller.yaml # Copyright 2018 Google LLC All Rights Reserved. # diff --git a/pkg/gameserverallocations/controller.go b/pkg/gameserverallocations/controller.go index e4a547b30f..3a8f085d67 100644 --- a/pkg/gameserverallocations/controller.go +++ b/pkg/gameserverallocations/controller.go @@ -70,8 +70,8 @@ var ( ) const ( - secretClientCertName = "client.crt" - secretClientKeyName = "client.key" + secretClientCertName = "tls.crt" + secretClientKeyName = "tls.key" secretCaCertName = "ca.crt" ) diff --git a/pkg/gameserverallocations/controller_test.go b/pkg/gameserverallocations/controller_test.go index 5773a9b926..617ab4534c 100644 --- a/pkg/gameserverallocations/controller_test.go +++ b/pkg/gameserverallocations/controller_test.go @@ -1014,7 +1014,7 @@ func TestCreateRestClientError(t *testing.T) { return true, &corev1.SecretList{ Items: []corev1.Secret{{ Data: map[string][]byte{ - "client.crt": clientCert, + "tls.crt": clientCert, }, ObjectMeta: metav1.ObjectMeta{ Name: "secret-name", @@ -1038,8 +1038,8 @@ func TestCreateRestClientError(t *testing.T) { return true, &corev1.SecretList{ Items: []corev1.Secret{{ Data: map[string][]byte{ - "client.crt": []byte("XXX"), - "client.key": []byte("XXX"), + "tls.crt": []byte("XXX"), + "tls.key": []byte("XXX"), }, ObjectMeta: metav1.ObjectMeta{ Name: "secret-name", @@ -1159,9 +1159,9 @@ func getTestSecret(secretName string, serverCert []byte) *corev1.SecretList { Items: []corev1.Secret{ { Data: map[string][]byte{ - "ca.crt": serverCert, - "client.key": clientKey, - "client.crt": clientCert, + "ca.crt": serverCert, + "tls.key": clientKey, + "tls.crt": clientCert, }, ObjectMeta: metav1.ObjectMeta{ Name: secretName, diff --git a/site/content/en/docs/Installation/helm.md b/site/content/en/docs/Installation/helm.md index 6750d54d87..04bdba091b 100644 --- a/site/content/en/docs/Installation/helm.md +++ b/site/content/en/docs/Installation/helm.md @@ -158,6 +158,13 @@ The following tables lists the configurable parameters of the Agones chart and t | `agones.ping.nodeSelector` | Ping [node labels][nodeSelector] for pod assignment | `{}` | | `agones.ping.tolerations` | Ping [toleration][toleration] labels for pod assignment | `[]` | | `agones.ping.affinity` | Ping [affinity][affinity] settings for pod assignment | `{}` | +| `agones.allocator.install` | Whether to install the [allocator service][allocator] | `true` | +| `agones.allocator.replicas` | The number of replicas to run in the deployment | `3` | +| `agones.allocator.http.expose` | Expose the http allocator service via a Service | `true` | +| `agones.allocator.http.response` | The string response returned from the http service | `ok` | +| `agones.allocator.http.port` | The port to expose on the service | `443` | +| `agones.allocator.http.serviceType` | The [Service Type][service] of the HTTP Service | `LoadBalancer` | +| `agones.allocator.generateTLS` | Set to true to generate TLS certificates or false to provide certificates in `certs/allocator/*`| `true` | | `gameservers.namespaces` | a list of namespaces you are planning to use to deploy game servers | `["default"]` | | `gameservers.minPort` | Minimum port to use for dynamic port allocation | `7000` | | `gameservers.maxPort` | Maximum port to use for dynamic port allocation | `8000` | diff --git a/test/e2e/allocator_test.go b/test/e2e/allocator_test.go new file mode 100644 index 0000000000..79755d8a27 --- /dev/null +++ b/test/e2e/allocator_test.go @@ -0,0 +1,129 @@ +// Copyright 2019 Google LLC All Rights Reserved. +// +// 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 e2e + +import ( + "bytes" + "crypto/tls" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "testing" + + "agones.dev/agones/pkg/apis/allocation/v1alpha1" + stablev1alpha1 "agones.dev/agones/pkg/apis/stable/v1alpha1" + e2e "agones.dev/agones/test/e2e/framework" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestAllocator(t *testing.T) { + t.Parallel() + + kubeCore := framework.KubeClient.CoreV1() + svc, err := kubeCore.Services("agones-system").Get("gameserver-allocator", metav1.GetOptions{}) + if !assert.Nil(t, err) { + return + } + if !assert.NotNil(t, svc.Status.LoadBalancer) { + return + } + if !assert.Equal(t, 1, len(svc.Status.LoadBalancer.Ingress)) { + return + } + if !assert.NotNil(t, 0, svc.Status.LoadBalancer.Ingress[0].IP) { + return + } + + port := svc.Spec.Ports[0] + requestURL := fmt.Sprintf("https://%s:%d/v1alpha1/gameserverallocation", svc.Status.LoadBalancer.Ingress[0].IP, port.Port) + + flt, err := createFleet() + if !assert.Nil(t, err) { + return + } + framework.WaitForFleetCondition(t, flt, e2e.FleetReadyCount(flt.Spec.Replicas)) + gsa := &v1alpha1.GameServerAllocation{ + Spec: v1alpha1.GameServerAllocationSpec{ + Required: metav1.LabelSelector{MatchLabels: map[string]string{stablev1alpha1.FleetNameLabel: flt.ObjectMeta.Name}}, + }} + + body, err := json.Marshal(gsa) + if !assert.Nil(t, err) { + return + } + + client, err := creatRestClient("agones-system", "allocator-tls") + if !assert.Nil(t, err) { + return + } + response, err := client.Post(requestURL, "application/json", bytes.NewBuffer(body)) + if !assert.Nil(t, err) { + return + } + defer response.Body.Close() // nolint: errcheck + + assert.Equal(t, http.StatusOK, response.StatusCode) + body, err = ioutil.ReadAll(response.Body) + if !assert.Nil(t, err) { + return + } + result := v1alpha1.GameServerAllocation{} + err = json.Unmarshal(body, &result) + if !assert.Nil(t, err) { + return + } + assert.Equal(t, v1alpha1.GameServerAllocationAllocated, result.Status.State) +} + +// creatRestClient creates a rest client with proper certs to make a remote call. +func creatRestClient(namespace, clientSecretName string) (*http.Client, error) { + kubeCore := framework.KubeClient.CoreV1() + clientSecret, err := kubeCore.Secrets(namespace).Get(clientSecretName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + + // Create http client using cert + clientCert := clientSecret.Data["tls.crt"] + clientKey := clientSecret.Data["tls.key"] + if clientCert == nil || clientKey == nil { + return nil, fmt.Errorf("missing certificate") + } + + // Load client cert + cert, err := tls.X509KeyPair(clientCert, clientKey) + if err != nil { + return nil, err + } + // Setup HTTPS client + return &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) { + return &cert, nil + }, + }, + }, + }, nil +} + +func createFleet() (*stablev1alpha1.Fleet, error) { + fleets := framework.AgonesClient.StableV1alpha1().Fleets(defaultNs) + fleet := defaultFleet() + return fleets.Create(fleet) +}