Merge pull request #135 from jeremyje/master

Merge 040wip into master.
This commit is contained in:
Jeremy Edwards
2019-03-29 14:29:22 -07:00
committed by GitHub
8364 changed files with 341346 additions and 3220 deletions

View File

@ -12,3 +12,4 @@
# below:
.git
.gitignore
#!include:.gitignore

25
.gitignore vendored
View File

@ -25,7 +25,7 @@
populations
# local config files
*.json
#*.json
# Discarded code snippets
build.sh
@ -67,3 +67,26 @@ msbuild.wrn
# Visual Studio 2015
.vs/
# Goland
.idea/
# Nodejs files placed when building Hugo, ok to allow if we actually start using Nodejs.
package.json
package-lock.json
site/resources/_gen/
# Node Modules
node_modules/
# Compiled Binaries
cmd/backendapi/backendapi
cmd/frontendapi/frontendapi
cmd/mmforc/mmforc
cmd/mmlogicapi/mmlogicapi
examples/backendclient/backendclient
examples/evaluators/golang/simple/simple
examples/functions/golang/manual-simple/manual-simple
test/cmd/clientloadgen/clientloadgen
test/cmd/frontendclient/frontendclient

View File

@ -1,5 +1,12 @@
# Release history
## v0.4.0 (alpha)
### Release notes
- Thanks to completion of Issues [#42](issues/42) and [#45](issues/45), there is no longer a need to use the `openmatch-base` image when building components of Open Match. Each stand alone appliation now is self-contained in its `Dockerfile` and `cloudbuild.yaml` files, and builds have been substantially simplified. **Note**: The default `Dockerfile` and `cloudbuild.yaml` now tag their images with the version number, not `dev`, and the YAML files in the `install` directory now reflect this.
- This paves the way for CI/CD in an upcoming version.
- This paves the way for public images in an upcoming version!
## v0.3.0 (alpha)
This update is focused on the Frontend API and Player Records, including more robust code for indexing, deindexing, reading, writing, and expiring player requests from Open Match state storage. All Frontend API function argument have changed, although many only slightly. Please join the [Slack channel](https://open-match.slack.com/) if you need help ([Signup link](https://join.slack.com/t/open-match/shared_invite/enQtNDM1NjcxNTY4MTgzLWQzMzE1MGY5YmYyYWY3ZjE2MjNjZTdmYmQ1ZTQzMmNiNGViYmQyN2M4ZmVkMDY2YzZlOTUwMTYwMzI1Y2I2MjU))!

View File

@ -2,6 +2,8 @@
FROM golang:1.10.3 as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match
COPY config config
RUN rm -f config/matchmaker_config.json
RUN rm -f config/matchmaker_config.yaml
COPY internal internal
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/internal
RUN go get -d -v ...

7
Dockerfile.base-build Normal file
View File

@ -0,0 +1,7 @@
FROM golang:1.12
ENV GO111MODULE=on
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match
COPY . .
RUN go mod download

524
Makefile Normal file
View File

@ -0,0 +1,524 @@
################################################################################
## Open Match Makefile ##
################################################################################
# Notice: There's 2 variables you need to make sure are set.
# GCP_PROJECT_ID if you're working against GCP.
# Or $REGISTRY if you want to use your own custom docker registry.
# Basic Deployment
# make create-gke-cluster OR make create-mini-cluster
# make push-helm
# make REGISTRY=gcr.io/$PROJECT_ID push-images -j$(nproc)
# make install-chart
#
# Generate Files
# make all-protos
#
# Building
# make all -j$(nproc)
#
# Access monitoring
# make proxy-prometheus
# make proxy-grafana
#
# Run those tools
# make run-backendclient
# make run-frontendclient
# make run-clientloadgen
#
# Teardown
# make delete-mini-cluster
# make delete-gke-cluster
#
## http://makefiletutorial.com/
BASE_VERSION = 0.4.0
VERSION_SUFFIX = $(shell git rev-parse --short=7 HEAD)
VERSION ?= $(BASE_VERSION)-$(VERSION_SUFFIX)
PROTOC_VERSION = 3.7.0
GOLANG_VERSION = 1.12
HELM_VERSION = 2.13.0
HUGO_VERSION = 0.54.0
KUBECTL_VERSION = 1.13.0
PROTOC_RELEASE_BASE = https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/protoc-$(PROTOC_VERSION)
GO = go
GO_BIN := $(GOPATH)/bin
GO_BUILD_COMMAND = CGO_ENABLED=0 GOOS=linux $(GO) build -a -installsuffix cgo .
BUILD_DIR = $(CURDIR)/build
TOOLCHAIN_DIR = $(BUILD_DIR)/toolchain
TOOLCHAIN_BIN = $(TOOLCHAIN_DIR)/bin
PROTOC := $(TOOLCHAIN_BIN)/protoc
PROTOC_INCLUDES := $(TOOLCHAIN_DIR)/include/
GCP_PROJECT_ID =
GCP_PROJECT_FLAG = --project=$(GCP_PROJECT_ID)
OM_SITE_GCP_PROJECT_ID = open-match-site
OM_SITE_GCP_PROJECT_FLAG = --project=$(OM_SITE_GCP_PROJECT_ID)
REGISTRY = gcr.io/$(GCP_PROJECT_ID)
TAG := $(VERSION)
ALTERNATE_TAG := dev
GKE_CLUSTER_NAME = om-cluster
GCP_REGION = us-west1
GCP_ZONE = us-west1-a
EXE_EXTENSION =
LOCAL_CLOUD_BUILD_PUSH = # --push
GOPATH_PRIMARY = $(HOME)
KUBECTL_RUN_ENV = --env='REDIS_SERVICE_HOST=$$(OPEN_MATCH_REDIS_MASTER_SERVICE_HOST)' --env='REDIS_SERVICE_PORT=$$(OPEN_MATCH_REDIS_MASTER_SERVICE_PORT)'
GCP_LOCATION_FLAG = --zone $(GCP_ZONE)
GO111MODULE = on
PROMETHEUS_PORT = 9090
GRAFANA_PORT = 3000
SITE_PORT = 8080
HELM = $(TOOLCHAIN_BIN)/helm
TILLER = $(TOOLCHAIN_BIN)/tiller
MINIKUBE = $(TOOLCHAIN_BIN)/minikube
KUBECTL = $(TOOLCHAIN_BIN)/kubectl
SERVICE = default
## Make port forwards accessible outside of the proxy machine.
PORT_FORWARD_ADDRESS_FLAG = --address 0.0.0.0
DASHBOARD_PORT = 9092
export PATH := $(CURDIR)/node_modules/.bin/:$(TOOLCHAIN_BIN):$(TOOLCHAIN_DIR)/nodejs/bin:$(PATH)
ifneq (,$(wildcard $(TOOLCHAIN_GOLANG_DIR)/bin/go))
export GO = $(CURDIR)/$(TOOLCHAIN_GOLANG_DIR)/bin/go
export GOROOT = $(CURDIR)/$(TOOLCHAIN_GOLANG_DIR)
export PATH := $(TOOLCHAIN_GOLANG_DIR):$(PATH)
endif
# Get the project from gcloud if it's not set.
ifeq ($(GCP_PROJECT_ID),)
export GCP_PROJECT_ID = $(shell gcloud config list --format 'value(core.project)')
endif
ifeq ($(OS),Windows_NT)
# TODO: Windows packages are here but things are broken since many paths are Linux based and zip vs tar.gz.
HELM_PACKAGE = https://storage.googleapis.com/kubernetes-helm/helm-v$(HELM_VERSION)-windows-amd64.zip
MINIKUBE_PACKAGE = https://storage.googleapis.com/minikube/releases/latest/minikube-windows-amd64.exe
SKAFFOLD_PACKAGE = https://storage.googleapis.com/skaffold/releases/latest/skaffold-windows-amd64.exe
EXE_EXTENSION = .exe
PROTOC_PACKAGE = $(PROTOC_RELEASE_BASE)-win64.zip
GO_PACKAGE = https://storage.googleapis.com/golang/go$(GOLANG_VERSION).windows-amd64.zip
KUBECTL_PACKAGE = https://storage.googleapis.com/kubernetes-release/release/v$(KUBECTL_VERSION)/bin/windows/amd64/kubectl.exe
HUGO_PACKAGE = https://github.com/gohugoio/hugo/releases/download/v$(HUGO_VERSION)/hugo_extended_$(HUGO_VERSION)_Windows-64bit.zip
NODEJS_PACKAGE = https://nodejs.org/dist/v10.15.3/node-v10.15.3-win-x64.zip
NODEJS_PACKAGE_NAME = nodejs.zip
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Linux)
HELM_PACKAGE = https://storage.googleapis.com/kubernetes-helm/helm-v$(HELM_VERSION)-linux-amd64.tar.gz
MINIKUBE_PACKAGE = https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
SKAFFOLD_PACKAGE = https://storage.googleapis.com/skaffold/releases/latest/skaffold-linux-amd64
PROTOC_PACKAGE = $(PROTOC_RELEASE_BASE)-linux-x86_64.zip
GO_PACKAGE = https://storage.googleapis.com/golang/go$(GOLANG_VERSION).linux-amd64.tar.gz
KUBECTL_PACKAGE = https://storage.googleapis.com/kubernetes-release/release/v$(KUBECTL_VERSION)/bin/linux/amd64/kubectl
HUGO_PACKAGE = https://github.com/gohugoio/hugo/releases/download/v$(HUGO_VERSION)/hugo_extended_$(HUGO_VERSION)_Linux-64bit.tar.gz
NODEJS_PACKAGE = https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.xz
NODEJS_PACKAGE_NAME = nodejs.tar.xz
endif
ifeq ($(UNAME_S),Darwin)
HELM_PACKAGE = https://storage.googleapis.com/kubernetes-helm/helm-v$(HELM_VERSION)-darwin-amd64.tar.gz
MINIKUBE_PACKAGE = https://storage.googleapis.com/minikube/releases/latest/minikube-darwin-amd64
SKAFFOLD_PACKAGE = https://storage.googleapis.com/skaffold/releases/latest/skaffold-darwin-amd64
PROTOC_PACKAGE = $(PROTOC_RELEASE_BASE)-osx-x86_64.zip
GO_PACKAGE = https://storage.googleapis.com/golang/go$(GOLANG_VERSION).darwin-amd64.tar.gz
KUBECTL_PACKAGE = https://storage.googleapis.com/kubernetes-release/release/v$(KUBECTL_VERSION)/bin/darwin/amd64/kubectl
HUGO_PACKAGE = https://github.com/gohugoio/hugo/releases/download/v$(HUGO_VERSION)/hugo_extended_$(HUGO_VERSION)_macOS-64bit.tar.gz
NODEJS_PACKAGE = https://nodejs.org/dist/v10.15.3/node-v10.15.3-darwin-x64.tar.gz
NODEJS_PACKAGE_NAME = nodejs.tar.gz
endif
endif
help:
@cat Makefile | grep ^\# | grep -v ^\#\# | cut -c 3-
local-cloud-build:
cloud-build-local --config=cloudbuild.yaml --dryrun=false $(LOCAL_CLOUD_BUILD_PUSH) -substitutions SHORT_SHA=$(VERSION_SUFFIX) .
push-images: push-service-images push-client-images push-mmf-example-images push-evaluator-example-images
push-service-images: push-frontendapi-image push-backendapi-image push-mmforc-image push-mmlogicapi-image
push-mmf-example-images: push-mmf-cs-mmlogic-simple-image push-mmf-go-mmlogic-simple-image push-mmf-php-mmlogic-simple-image push-mmf-py3-mmlogic-simple-image
push-client-images: push-backendclient-image push-clientloadgen-image push-frontendclient-image
push-evaluator-example-images: push-evaluator-simple-image
push-frontendapi-image: build-frontendapi-image
docker push $(REGISTRY)/openmatch-frontendapi:$(TAG)
docker push $(REGISTRY)/openmatch-frontendapi:$(ALTERNATE_TAG)
push-backendapi-image: build-backendapi-image
docker push $(REGISTRY)/openmatch-backendapi:$(TAG)
docker push $(REGISTRY)/openmatch-backendapi:$(ALTERNATE_TAG)
push-mmforc-image: build-mmforc-image
docker push $(REGISTRY)/openmatch-mmforc:$(TAG)
docker push $(REGISTRY)/openmatch-mmforc:$(ALTERNATE_TAG)
push-mmlogicapi-image: build-mmlogicapi-image
docker push $(REGISTRY)/openmatch-mmlogicapi:$(TAG)
docker push $(REGISTRY)/openmatch-mmlogicapi:$(ALTERNATE_TAG)
push-mmf-cs-mmlogic-simple-image: build-mmf-cs-mmlogic-simple-image
docker push $(REGISTRY)/openmatch-mmf-cs-mmlogic-simple:$(TAG)
docker push $(REGISTRY)/openmatch-mmf-cs-mmlogic-simple:$(ALTERNATE_TAG)
push-mmf-go-mmlogic-simple-image: build-mmf-go-mmlogic-simple-image
docker push $(REGISTRY)/openmatch-mmf-go-mmlogic-simple:$(TAG)
docker push $(REGISTRY)/openmatch-mmf-go-mmlogic-simple:$(ALTERNATE_TAG)
push-mmf-php-mmlogic-simple-image: build-mmf-php-mmlogic-simple-image
docker push $(REGISTRY)/openmatch-mmf-php-mmlogic-simple:$(TAG)
docker push $(REGISTRY)/openmatch-mmf-php-mmlogic-simple:$(ALTERNATE_TAG)
push-mmf-py3-mmlogic-simple-image: build-mmf-py3-mmlogic-simple-image
docker push $(REGISTRY)/openmatch-mmf-py3-mmlogic-simple:$(TAG)
docker push $(REGISTRY)/openmatch-mmf-py3-mmlogic-simple:$(ALTERNATE_TAG)
push-backendclient-image: build-backendclient-image
docker push $(REGISTRY)/openmatch-backendclient:$(TAG)
docker push $(REGISTRY)/openmatch-backendclient:$(ALTERNATE_TAG)
push-clientloadgen-image: build-clientloadgen-image
docker push $(REGISTRY)/openmatch-clientloadgen:$(TAG)
docker push $(REGISTRY)/openmatch-clientloadgen:$(ALTERNATE_TAG)
push-frontendclient-image: build-frontendclient-image
docker push $(REGISTRY)/openmatch-frontendclient:$(TAG)
docker push $(REGISTRY)/openmatch-frontendclient:$(ALTERNATE_TAG)
push-evaluator-simple-image: build-evaluator-simple-image
docker push $(REGISTRY)/openmatch-evaluator-simple:$(TAG)
docker push $(REGISTRY)/openmatch-evaluator-simple:$(ALTERNATE_TAG)
build-images: build-service-images build-client-images build-mmf-example-images build-evaluator-example-images
build-service-images: build-frontendapi-image build-backendapi-image build-mmforc-image build-mmlogicapi-image
build-client-images: build-backendclient-image build-clientloadgen-image build-frontendclient-image
build-mmf-example-images: build-mmf-cs-mmlogic-simple-image build-mmf-go-mmlogic-simple-image build-mmf-php-mmlogic-simple-image build-mmf-py3-mmlogic-simple-image
build-evaluator-example-images: build-evaluator-simple-image
build-frontendapi-image: cmd/frontendapi/frontendapi
docker build -f cmd/frontendapi/Dockerfile -t $(REGISTRY)/openmatch-frontendapi:$(TAG) -t $(REGISTRY)/openmatch-frontendapi:$(ALTERNATE_TAG) .
build-backendapi-image: cmd/backendapi/backendapi
docker build -f cmd/backendapi/Dockerfile -t $(REGISTRY)/openmatch-backendapi:$(TAG) -t $(REGISTRY)/openmatch-backendapi:$(ALTERNATE_TAG) .
build-mmforc-image: cmd/mmforc/mmforc
docker build -f cmd/mmforc/Dockerfile -t $(REGISTRY)/openmatch-mmforc:$(TAG) -t $(REGISTRY)/openmatch-mmforc:$(ALTERNATE_TAG) .
build-mmlogicapi-image: cmd/mmlogicapi/mmlogicapi
docker build -f cmd/mmlogicapi/Dockerfile -t $(REGISTRY)/openmatch-mmlogicapi:$(TAG) -t $(REGISTRY)/openmatch-mmlogicapi:$(ALTERNATE_TAG) .
build-mmf-cs-mmlogic-simple-image:
cd examples/functions/csharp/simple/ && docker build -f Dockerfile -t $(REGISTRY)/openmatch-mmf-cs-mmlogic-simple:$(TAG) -t $(REGISTRY)/openmatch-mmf-cs-mmlogic-simple:$(ALTERNATE_TAG) .
build-mmf-go-mmlogic-simple-image:
docker build -f examples/functions/golang/manual-simple/Dockerfile -t $(REGISTRY)/openmatch-mmf-go-mmlogic-simple:$(TAG) -t $(REGISTRY)/openmatch-mmf-go-mmlogic-simple:$(ALTERNATE_TAG) .
build-mmf-php-mmlogic-simple-image:
docker build -f examples/functions/php/mmlogic-simple/Dockerfile -t $(REGISTRY)/openmatch-mmf-php-mmlogic-simple:$(TAG) -t $(REGISTRY)/openmatch-mmf-php-mmlogic-simple:$(ALTERNATE_TAG) .
build-mmf-py3-mmlogic-simple-image:
docker build -f examples/functions/python3/mmlogic-simple/Dockerfile -t $(REGISTRY)/openmatch-mmf-py3-mmlogic-simple:$(TAG) -t $(REGISTRY)/openmatch-mmf-py3-mmlogic-simple:$(ALTERNATE_TAG) .
build-backendclient-image: examples/backendclient/backendclient
docker build -f examples/backendclient/Dockerfile -t $(REGISTRY)/openmatch-backendclient:$(TAG) -t $(REGISTRY)/openmatch-backendclient:$(ALTERNATE_TAG) .
build-clientloadgen-image: test/cmd/clientloadgen/clientloadgen
docker build -f test/cmd/clientloadgen/Dockerfile -t $(REGISTRY)/openmatch-clientloadgen:$(TAG) -t $(REGISTRY)/openmatch-clientloadgen:$(ALTERNATE_TAG) .
build-frontendclient-image: test/cmd/frontendclient/frontendclient
docker build -f test/cmd/frontendclient/Dockerfile -t $(REGISTRY)/openmatch-frontendclient:$(TAG) -t $(REGISTRY)/openmatch-frontendclient:$(ALTERNATE_TAG) .
build-evaluator-simple-image: examples/evaluators/golang/simple/simple
docker build -f examples/evaluators/golang/simple/Dockerfile -t $(REGISTRY)/openmatch-evaluator-simple:$(TAG) -t $(REGISTRY)/openmatch-evaluator-simple:$(ALTERNATE_TAG) .
clean-images:
-docker rmi -f $(REGISTRY)/openmatch-frontendapi:$(TAG) $(REGISTRY)/openmatch-frontendapi:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-backendapi:$(TAG) $(REGISTRY)/openmatch-backendapi:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-mmforc:$(TAG) $(REGISTRY)/openmatch-mmforc:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-mmlogicapi:$(TAG) $(REGISTRY)/openmatch-mmlogicapi:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-mmf-cs-mmlogic-simple:$(TAG) $(REGISTRY)/openmatch-mmf-cs-mmlogic-simple:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-mmf-go-mmlogic-simple:$(TAG) $(REGISTRY)/openmatch-mmf-go-mmlogic-simple:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-mmf-php-mmlogic-simple:$(TAG) $(REGISTRY)/openmatch-mmf-php-mmlogic-simple:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-mmf-py3-mmlogic-simple:$(TAG) $(REGISTRY)/openmatch-mmf-py3-mmlogic-simple:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-backendclient:$(TAG) $(REGISTRY)/openmatch-backendclient:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-clientloadgen:$(TAG) $(REGISTRY)/openmatch-clientloadgen:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-frontendclient:$(TAG) $(REGISTRY)/openmatch-frontendclient:$(ALTERNATE_TAG)
-docker rmi -f $(REGISTRY)/openmatch-evaluator-simple:$(TAG) $(REGISTRY)/openmatch-evaluator-simple:$(ALTERNATE_TAG)
install-redis: build/toolchain/bin/helm$(EXE_EXTENSION)
$(HELM) upgrade --install --wait --debug redis stable/redis --namespace redis
chart-deps: build/toolchain/bin/helm$(EXE_EXTENSION)
(cd install/helm/open-match; $(HELM) dependency update)
print-chart: build/toolchain/bin/helm$(EXE_EXTENSION)
(cd install/helm; $(HELM) lint open-match; $(HELM) install --dry-run --debug open-match)
install-chart: build/toolchain/bin/helm$(EXE_EXTENSION)
$(HELM) upgrade --install --wait --debug open-match install/helm/open-match \
--namespace=open-match \
--set openmatch.image.registry=$(REGISTRY) \
--set openmatch.image.tag=$(TAG)
install-example-chart: build/toolchain/bin/helm$(EXE_EXTENSION)
$(HELM) upgrade --install --wait --debug open-match-example install/helm/open-match-example \
--namespace=open-match \
--set openmatch.image.registry=$(REGISTRY) \
--set openmatch.image.tag=$(TAG)
delete-example-chart: build/toolchain/bin/helm$(EXE_EXTENSION)
-$(HELM) delete --purge open-match-example
dry-chart: build/toolchain/bin/helm$(EXE_EXTENSION)
$(HELM) upgrade --install --wait --debug --dry-run open-match install/helm/open-match \
--namespace=open-match \
--set openmatch.image.registry=$(REGISTRY) \
--set openmatch.image.tag=$(TAG)
delete-chart: build/toolchain/bin/helm$(EXE_EXTENSION) build/toolchain/bin/kubectl$(EXE_EXTENSION)
-$(HELM) delete --purge open-match
-$(KUBECTL) delete crd prometheuses.monitoring.coreos.com
-$(KUBECTL) delete crd servicemonitors.monitoring.coreos.com
-$(KUBECTL) delete crd prometheusrules.monitoring.coreos.com
update-helm-deps:
(cd install/helm/open-match; helm dependencies update)
install-toolchain: build/toolchain/bin/protoc$(EXE_EXTENSION) build/toolchain/bin/protoc-gen-go$(EXE_EXTENSION) build/toolchain/bin/kubectl$(EXE_EXTENSION) build/toolchain/bin/helm$(EXE_EXTENSION) build/toolchain/bin/minikube$(EXE_EXTENSION) build/toolchain/bin/skaffold$(EXE_EXTENSION) build/toolchain/bin/hugo$(EXE_EXTENSION) build/toolchain/python/
build/toolchain/bin/helm$(EXE_EXTENSION):
mkdir -p $(TOOLCHAIN_BIN)
mkdir -p $(TOOLCHAIN_DIR)/temp-helm
cd $(TOOLCHAIN_DIR)/temp-helm && curl -Lo helm.tar.gz $(HELM_PACKAGE) && tar xvzf helm.tar.gz --strip-components 1
mv $(TOOLCHAIN_DIR)/temp-helm/helm$(EXE_EXTENSION) $(TOOLCHAIN_BIN)/helm$(EXE_EXTENSION)
mv $(TOOLCHAIN_DIR)/temp-helm/tiller$(EXE_EXTENSION) $(TOOLCHAIN_BIN)/tiller$(EXE_EXTENSION)
rm -rf $(TOOLCHAIN_DIR)/temp-helm/
build/toolchain/bin/hugo$(EXE_EXTENSION):
mkdir -p $(TOOLCHAIN_BIN)
mkdir -p $(TOOLCHAIN_DIR)/temp-hugo
cd $(TOOLCHAIN_DIR)/temp-hugo && curl -Lo hugo.tar.gz $(HUGO_PACKAGE) && tar xvzf hugo.tar.gz
mv $(TOOLCHAIN_DIR)/temp-hugo/hugo$(EXE_EXTENSION) $(TOOLCHAIN_BIN)/hugo$(EXE_EXTENSION)
rm -rf $(TOOLCHAIN_DIR)/temp-hugo/
build/toolchain/bin/minikube$(EXE_EXTENSION):
mkdir -p $(TOOLCHAIN_BIN)
curl -Lo minikube$(EXE_EXTENSION) $(MINIKUBE_PACKAGE)
chmod +x minikube$(EXE_EXTENSION)
mv minikube$(EXE_EXTENSION) $(TOOLCHAIN_BIN)/minikube$(EXE_EXTENSION)
build/toolchain/bin/kubectl$(EXE_EXTENSION):
mkdir -p $(TOOLCHAIN_BIN)
curl -Lo kubectl$(EXE_EXTENSION) $(KUBECTL_PACKAGE)
chmod +x kubectl$(EXE_EXTENSION)
mv kubectl$(EXE_EXTENSION) $(TOOLCHAIN_BIN)/kubectl$(EXE_EXTENSION)
build/toolchain/bin/skaffold$(EXE_EXTENSION):
mkdir -p $(TOOLCHAIN_BIN)
curl -Lo skaffold$(EXE_EXTENSION) $(SKAFFOLD_PACKAGE)
chmod +x skaffold$(EXE_EXTENSION)
mv skaffold$(EXE_EXTENSION) $(TOOLCHAIN_BIN)/skaffold$(EXE_EXTENSION)
push-helm: build/toolchain/bin/helm$(EXE_EXTENSION) build/toolchain/bin/kubectl$(EXE_EXTENSION)
$(KUBECTL) create serviceaccount --namespace kube-system tiller
$(HELM) init --service-account tiller --force-upgrade
$(KUBECTL) create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
ifneq ($(strip $($(KUBECTL) get clusterroles | grep -i rbac)),)
$(KUBECTL) patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
endif
echo "Waiting for Tiller to become ready..."
$(KUBECTL) wait deployment --timeout=60s --for condition=available -l app=helm,name=tiller --namespace kube-system
delete-helm: build/toolchain/bin/helm$(EXE_EXTENSION) build/toolchain/bin/kubectl$(EXE_EXTENSION)
-$(HELM) reset
-$(KUBECTL) delete serviceaccount --namespace kube-system tiller
-$(KUBECTL) delete clusterrolebinding tiller-cluster-rule
ifneq ($(strip $($(KUBECTL) get clusterroles | grep -i rbac)),)
-$(KUBECTL) delete deployment --namespace kube-system tiller-deploy
endif
echo "Waiting for Tiller to go away..."
-$(KUBECTL) wait deployment --timeout=60s --for delete -l app=helm,name=tiller --namespace kube-system
auth-docker:
gcloud $(GCP_PROJECT_FLAG) auth configure-docker
auth-gke-cluster:
gcloud $(GCP_PROJECT_FLAG) container clusters get-credentials $(GKE_CLUSTER_NAME) $(GCP_LOCATION_FLAG)
create-gke-cluster:
gcloud $(GCP_PROJECT_FLAG) container clusters create $(GKE_CLUSTER_NAME) $(GCP_LOCATION_FLAG) --machine-type n1-standard-4 --tags open-match
delete-gke-cluster:
gcloud $(GCP_PROJECT_FLAG) container clusters delete $(GKE_CLUSTER_NAME) $(GCP_LOCATION_FLAG)
create-mini-cluster: build/toolchain/bin/minikube$(EXE_EXTENSION)
$(MINIKUBE) start --memory 6144 --cpus 4 --disk-size 50g
delete-mini-cluster: build/toolchain/bin/minikube$(EXE_EXTENSION)
$(MINIKUBE) delete
build/toolchain/python/:
mkdir -p build/toolchain/python/
virtualenv --python=python3 build/toolchain/python/
# Hack to workaround some crazy bug in pip that's chopping off python executable's name.
cd build/toolchain/python/bin && ln -s python3 pytho
cd build/toolchain/python/ && source bin/activate && pip install grpcio-tools && deactivate
build/toolchain/bin/protoc$(EXE_EXTENSION):
mkdir -p $(TOOLCHAIN_BIN)
curl -o $(TOOLCHAIN_DIR)/protoc-temp.zip -L $(PROTOC_PACKAGE)
(cd $(TOOLCHAIN_DIR); unzip -o protoc-temp.zip)
rm $(TOOLCHAIN_DIR)/protoc-temp.zip $(TOOLCHAIN_DIR)/readme.txt
build/toolchain/bin/protoc-gen-go$(EXE_EXTENSION):
$(GO) get github.com/golang/protobuf/protoc-gen-go
$(GO) install github.com/golang/protobuf/protoc-gen-go
mv $(GOPATH)/bin/protoc-gen-go$(EXE_EXTENSION) build/toolchain/bin/protoc-gen-go$(EXE_EXTENSION)
all-protos: internal/pb/backend.pb.go internal/pb/frontend.pb.go internal/pb/function.pb.go internal/pb/messages.pb.go internal/pb/mmlogic.pb.go mmlogic-simple-protos
internal/pb/%.pb.go: api/protobuf-spec/%.proto build/toolchain/bin/protoc$(EXE_EXTENSION) build/toolchain/bin/protoc-gen-go$(EXE_EXTENSION)
$(PROTOC) $< \
-I $(CURDIR) -I $(PROTOC_INCLUDES) \
--go_out=plugins=grpc:$(GOPATH)/src
## Include structure of the protos needs to be called out do the dependency chain is run through properly.
internal/pb/backend.pb.go: internal/pb/messages.pb.go
internal/pb/frontend.pb.go: internal/pb/messages.pb.go
internal/pb/mmlogic.pb.go: internal/pb/messages.pb.go
internal/pb/function.pb.go: internal/pb/messages.pb.go
mmlogic-simple-protos: examples/functions/python3/mmlogic-simple/api/protobuf_spec/messages_pb2.py examples/functions/python3/mmlogic-simple/api/protobuf_spec/mmlogic_pb2.py
examples/functions/python3/mmlogic-simple/api/protobuf_spec/%_pb2.py: api/protobuf-spec/%.proto build/toolchain/python/
source build/toolchain/python/bin/activate && python3 -m grpc_tools.protoc -I $(CURDIR) -I $(PROTOC_INCLUDES) --python_out=examples/functions/python3/mmlogic-simple/ --grpc_python_out=examples/functions/python3/mmlogic-simple/ $< && deactivate
internal/pb/%_pb2.py: api/protobuf-spec/%.proto build/toolchain/python/
source build/toolchain/python/bin/activate && python3 -m grpc_tools.protoc -I $(CURDIR) -I $(PROTOC_INCLUDES) --python_out=$(CURDIR) --grpc_python_out=$(CURDIR) $< && deactivate
build:
$(GO) build ./...
test:
$(GO) test ./... -race
fmt:
$(GO) fmt ./...
vet:
$(GO) vet ./...
cmd/backendapi/backendapi: internal/pb/backend.pb.go
cd cmd/backendapi; $(GO_BUILD_COMMAND)
cmd/frontendapi/frontendapi: internal/pb/frontend.pb.go
cd cmd/frontendapi; $(GO_BUILD_COMMAND)
cmd/mmforc/mmforc:
cd cmd/mmforc; $(GO_BUILD_COMMAND)
cmd/mmlogicapi/mmlogicapi: internal/pb/mmlogic.pb.go
cd cmd/mmlogicapi; $(GO_BUILD_COMMAND)
examples/backendclient/backendclient: internal/pb/backend.pb.go
cd examples/backendclient; $(GO_BUILD_COMMAND)
examples/evaluators/golang/simple/simple: internal/pb/messages.pb.go
cd examples/evaluators/golang/simple; $(GO_BUILD_COMMAND)
examples/functions/golang/manual-simple/manual-simple: internal/pb/messages.pb.go
cd examples/functions/golang/manual-simple; $(GO_BUILD_COMMAND)
test/cmd/clientloadgen/clientloadgen:
cd test/cmd/clientloadgen; $(GO_BUILD_COMMAND)
test/cmd/frontendclient/frontendclient: internal/pb/frontend.pb.go internal/pb/messages.pb.go
cd test/cmd/frontendclient; $(GO_BUILD_COMMAND)
build/archives/${NODEJS_PACKAGE_NAME}:
mkdir -p build/archives/
cd build/archives/ && curl -L -o ${NODEJS_PACKAGE_NAME} ${NODEJS_PACKAGE}
build/toolchain/nodejs/: build/archives/${NODEJS_PACKAGE_NAME}
mkdir -p build/toolchain/nodejs/
cd build/toolchain/nodejs/ && tar xjf ../../archives/${NODEJS_PACKAGE_NAME} --strip-components 1
install-npm: build/toolchain/nodejs/
echo "{}" > package.json
$(TOOLCHAIN_DIR)/nodejs/bin/npm install postcss-cli autoprefixer
build/site/: build/archives/govanityurls.zip build/toolchain/bin/hugo$(EXE_EXTENSION)
rm -rf build/site/
mkdir -p build/site/
cd site/ && ../build/toolchain/bin/hugo$(EXE_EXTENSION) --enableGitInfo --config=config.toml --source . --destination $(BUILD_DIR)/site/public/
-cp -f site/* $(BUILD_DIR)/site
#cd $(BUILD_DIR)/site && "SERVICE=$(SERVICE) envsubst < app.yaml > .app.yaml"
cp $(BUILD_DIR)/site/app.yaml $(BUILD_DIR)/site/.app.yaml
browse-site: build/site/
cd $(BUILD_DIR)/site && dev_appserver.py .app.yaml
deploy-dev-site: build/site/
cd $(BUILD_DIR)/site && gcloud $(OM_SITE_GCP_PROJECT_FLAG) app deploy .app.yaml --promote --version=$(VERSION_SUFFIX) --quiet
run-site: build/toolchain/bin/hugo$(EXE_EXTENSION)
cd site/ && ../build/toolchain/bin/hugo$(EXE_EXTENSION) server --debug --watch --enableGitInfo . --bind 0.0.0.0 --port $(SITE_PORT) --disableFastRender
all: service-binaries client-binaries example-binaries
service-binaries: cmd/backendapi/backendapi cmd/frontendapi/frontendapi cmd/mmforc/mmforc cmd/mmlogicapi/mmlogicapi
client-binaries: examples/backendclient/backendclient test/cmd/clientloadgen/clientloadgen test/cmd/frontendclient/frontendclient
example-binaries: examples/evaluators/golang/simple/simple examples/functions/golang/manual-simple
presubmit: fmt vet build test
clean-site:
rm -rf build/site/
clean-protos:
rm -rf internal/pb/
rm -rf api/protobuf_spec/
clean-binaries:
rm -rf cmd/backendapi/backendapi
rm -rf cmd/frontendapi/frontendapi
rm -rf cmd/mmforc/mmforc
rm -rf cmd/mmlogicapi/mmlogicapi
rm -rf examples/backendclient/backendclient
rm -rf examples/evaluators/golang/simple/simple
rm -rf examples/functions/golang/manual-simple/manual-simple
rm -rf test/cmd/clientloadgen/clientloadgen
rm -rf test/cmd/frontendclient/frontendclient
clean-toolchain:
rm -rf build/toolchain/
clean-nodejs:
rm -rf build/toolchain/nodejs/
rm -rf node_modules/
rm -rf package.json
clean: clean-images clean-binaries clean-site clean-toolchain clean-protos clean-nodejs
run-backendclient: build/toolchain/bin/kubectl$(EXE_EXTENSION)
$(KUBECTL) run om-backendclient --rm --restart=Never --image-pull-policy=Always -i --tty --image=$(REGISTRY)/openmatch-backendclient:$(TAG) --namespace=open-match $(KUBECTL_RUN_ENV)
run-frontendclient: build/toolchain/bin/kubectl$(EXE_EXTENSION)
$(KUBECTL) run om-frontendclient --rm --restart=Never --image-pull-policy=Always -i --tty --image=$(REGISTRY)/openmatch-frontendclient:$(TAG) --namespace=open-match $(KUBECTL_RUN_ENV)
run-clientloadgen: build/toolchain/bin/kubectl$(EXE_EXTENSION)
$(KUBECTL) run om-clientloadgen --rm --restart=Never --image-pull-policy=Always -i --tty --image=$(REGISTRY)/openmatch-clientloadgen:$(TAG) --namespace=open-match $(KUBECTL_RUN_ENV)
proxy-grafana: build/toolchain/bin/kubectl$(EXE_EXTENSION)
echo "User: admin"
echo "Password: openmatch"
$(KUBECTL) port-forward --namespace open-match $(shell $(KUBECTL) get pod --namespace open-match --selector="app=grafana,release=open-match" --output jsonpath='{.items[0].metadata.name}') $(GRAFANA_PORT):3000 $(PORT_FORWARD_ADDRESS_FLAG)
proxy-prometheus: build/toolchain/bin/kubectl$(EXE_EXTENSION)
$(KUBECTL) port-forward --namespace open-match $(shell $(KUBECTL) get pod --namespace open-match --selector="app=prometheus,component=server,release=open-match" --output jsonpath='{.items[0].metadata.name}') $(PROMETHEUS_PORT):9090 $(PORT_FORWARD_ADDRESS_FLAG)
proxy-dashboard: build/toolchain/bin/kubectl$(EXE_EXTENSION)
$(KUBECTL) port-forward --namespace kube-system $(shell $(KUBECTL) get pod --namespace kube-system --selector="app=kubernetes-dashboard" --output jsonpath='{.items[0].metadata.name}') $(DASHBOARD_PORT):9090 $(PORT_FORWARD_ADDRESS_FLAG)
.PHONY: proxy-dashboard proxy-prometheus proxy-grafana clean clean-toolchain clean-binaries clean-protos presubmit test vet

View File

@ -47,9 +47,9 @@ Open Match is designed to support massively concurrent matchmaking, and to be sc
* **Ignore List** &mdash; Removing players from matchmaking consideration is accomplished using _ignore lists_. They contain lists of player IDs that your MMF should not include when making matches.
## Requirements
* [Kubernetes](https://kubernetes.io/) cluster &mdash; tested with version 1.9.
* [Kubernetes](https://kubernetes.io/) cluster &mdash; tested with version 1.11.7.
* [Redis 4+](https://redis.io/) &mdash; tested with 4.0.11.
* Open Match is compiled against the latest release of [Golang](https://golang.org/) &mdash; tested with 1.10.9.
* Open Match is compiled against the latest release of [Golang](https://golang.org/) &mdash; tested with 1.11.5.
## Components
@ -179,7 +179,65 @@ Once we reach a 1.0 release, we plan to produce publicly available (Linux) Docke
### Compiling from source
All components of Open Match produce (Linux) Docker container images as artifacts, and there are included `Dockerfile`s for each. [Google Cloud Platform Cloud Build](https://cloud.google.com/cloud-build/docs/) users will also find `cloudbuild.yaml` files for each component in the corresponding `cmd/<COMPONENT>` directories.
The easiest way to build Open Match is to use the Makefile. Before you can use the Makefile make sure you have the following dependencies:
```bash
# Install Open Match Toolchain Dependencies (Debian other OSes including Mac OS X have similar dependencies)
sudo apt-get update; sudo apt-get install -y python3 python3-virtualenv virtualenv make gcloud
```
Go 1.11+ is also required. If your distro is new enough you can probably run `sudo apt-get install -y golang` or download the newest version from https://golang.org/.
To build all the artifacts of Open Match you can simply run the following commands.
```bash
# Downloads all the tools needed to build Open Match
make install-toolchain
# Generates protocol buffer code files
make all-protos
# Builds all the binaries
make all
# Builds all the images.
make build-images
```
Once build you can use a command like `docker images` to see all the images that were build.
Before creating a pull request you can run `make local-cloud-build` to simulate a Cloud Build run to check for regressions.
The directory structure is a typical Go structure so if you do the following you should be able to work on this project within your IDE.
```bash
cd $GOPATH
mkdir -p src/github.com/GoogleCloudPlatform/
cd src/github.com/GoogleCloudPlatform/
# If you're going to contribute you'll want to fork open-match, see CONTRIBUTING.md for details.
git clone https://github.com/GoogleCloudPlatform/open-match.git
cd open-match
# Open IDE in this directory.
```
Lastly, this project uses go modules so you'll want to set `export GO111MODULE=on` before building.
## Zero to Open Match
To deploy Open Match quickly to a Kubernetes cluster run these commands.
```bash
# Downloads all the tools.
make install-toolchain
# Create a GKE Cluster
make create-gke-cluster
# OR Create a Minikube Cluster
make create-mini-cluster
# Install Helm
make push-helm
# Build and push images
make push-images -j4
# Deploy Open Match with example functions
make install-chart install-example-chart
```
## Docker Image Builds
All the core components for Open Match are written in Golang and use the [Dockerfile multistage builder pattern](https://docs.docker.com/develop/develop-images/multistage-build/). This pattern uses intermediate Docker containers as a Golang build environment while producing lightweight, minimized container images as final build artifacts. When the project is ready for production, we will modify the `Dockerfile`s to uncomment the last build stage. Although this pattern is great for production container images, it removes most of the utilities required to troubleshoot issues during development.

View File

@ -4,12 +4,9 @@ This directory contains the API specification files for Open Match. API documena
* [Protobuf .proto files for all APIs](./protobuf-spec/)
These proto files are copied to the container image during `docker build` for the Open Match core components. The `Dockerfiles` handle the compilation for you transparently, and copy the resulting `SPEC.pb.go` files to the appropriate place in your final container image.
References:
* [gRPC](https://grpc.io/)
* [Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3)
Manual gRPC compilation commmand, from the directory containing the proto:
```protoc -I . ./<filename>.proto --go_out=plugins=grpc:.```
If you want to regenerate the golang gRPC modules (for local Open Match core component development, for example), the `protoc_go.sh` file in this directory may be of use to you!

View File

@ -0,0 +1,18 @@
syntax = 'proto3';
package api;
option go_package = "github.com/GoogleCloudPlatform/open-match/internal/pb";
// The protobuf messages sent in the gRPC calls are defined 'messages.proto'.
import 'api/protobuf-spec/messages.proto';
// The MMF proto defines the API for running MMFs as long-lived, 'serving'
// functions inside of the kubernetes cluster.
service Function {
// The assumption is that there will be one service for each MMF that is
// being served. Build your MMF in the appropriate serving harness, deploy it
// to the K8s cluster with a unique service name, then connect to that service
// and call 'Run()' to execute the fuction.
rpc Run(messages.Arguments) returns (messages.Result) {}
}

View File

@ -19,6 +19,7 @@ message MatchObject{
string error = 3; // Last error encountered.
repeated Roster rosters = 4; // Rosters of players.
repeated PlayerPool pools = 5; // 'Hard' filters, and the players who match them.
string status = 6; // Resulting status of the match function
}
// Data structure to hold a list of players in a match.
@ -92,3 +93,23 @@ message Assignments{
repeated Roster rosters = 1;
string assignment = 10;
}
// Messages for gRPC-served matchmaking functions.
// The message for passing in the per-request identifiers
// to a matchmaking function; used so it knows which records to
// write/update in state storage.
message Request {
string profile_id = 1;
string proposal_id = 2;
string request_id = 3;
string error_id = 4;
string timestamp = 5;
}
// The message for passing all the necessary arguments to a
// matchmaking function.
message Arguments{
Request request = 1;
MatchObject matchobject = 2;
}

View File

@ -1,3 +1,5 @@
#!/bin/bash
python3 -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. mmlogic.proto
python3 -m grpc_tools.protoc -I . --python_out=. --grpc_python_out=. messages.proto
cp *pb2* $OM/examples/functions/python3/simple/.

View File

@ -19,6 +19,7 @@ cd $GOPATH/src
protoc \
${GOPATH}/src/github.com/GoogleCloudPlatform/open-match/api/protobuf-spec/backend.proto \
${GOPATH}/src/github.com/GoogleCloudPlatform/open-match/api/protobuf-spec/frontend.proto \
${GOPATH}/src/github.com/GoogleCloudPlatform/open-match/api/protobuf-spec/function.proto \
${GOPATH}/src/github.com/GoogleCloudPlatform/open-match/api/protobuf-spec/mmlogic.proto \
${GOPATH}/src/github.com/GoogleCloudPlatform/open-match/api/protobuf-spec/messages.proto \
-I ${GOPATH}/src/github.com/GoogleCloudPlatform/open-match/ \

295
cloudbuild.yaml Normal file
View File

@ -0,0 +1,295 @@
# Copyright 2019 Google Inc. 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.
################################################################################
# Open Match Script for Google Cloud Build #
################################################################################
# To run this locally:
# cloud-build-local --config=cloudbuild.yaml --dryrun=false --substitutions=_OM_VERSION=DEV .
# To run this remotely:
# gcloud builds submit --config=cloudbuild.yaml --substitutions=_OM_VERSION=DEV .
# Requires gcloud to be installed to work. (https://cloud.google.com/sdk/)
# gcloud auth login
# gcloud components install cloud-build-local
# This YAML contains all the build steps for building Open Match.
# All PRs are verified against this script to prevent build breakages and regressions.
# Conventions
# Each build step is ID'ed with "Prefix: Description".
# The prefix portion determines what kind of step it is and it's impact.
# Docker Image: Read-Only, outputs a docker image.
# Lint: Read-Only, verifies correctness and formatting of a file.
# Build: Read-Write, outputs a build artifact. Ok to run in parallel if the artifact will not collide with another one.
# Generate: Read-Write, outputs files within /workspace that are used in other build step. Do not run these in parallel.
# Setup: Read-Write, similar to generate but steps that run before any other step.
# Some useful things to know about Cloud Build.
# The root of this repository is always stored in /workspace.
# Any modifications that occur within /workspace are persisted between builds anything else is forgotten.
# If a build step has intermediate files that need to be persisted for a future step then use volumes.
# An example of this is the go-vol which is where the pkg/ data for go mod is stored.
# More information here: https://cloud.google.com/cloud-build/docs/build-config#build_steps
# A build step is basically a docker image that is tuned for Cloud Build,
# https://github.com/GoogleCloudPlatform/cloud-builders/tree/master/go
steps:
- id: 'Docker Image: open-match-base-build'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'open-match-base-build', '-f', 'Dockerfile.base-build', '.']
waitFor: ['-']
- id: 'Docker Image: backendapi'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-backendapi:${_OM_VERSION}-${SHORT_SHA}', 'cmd/backendapi']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: frontendapi'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-frontendapi:${_OM_VERSION}-${SHORT_SHA}', 'cmd/frontendapi']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: mmforc'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-mmforc:${_OM_VERSION}-${SHORT_SHA}', 'cmd/mmforc']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: mmlogicapi'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-mmlogicapi:${_OM_VERSION}-${SHORT_SHA}', 'cmd/mmlogicapi']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: Evaluator Simple'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-evaluator-simple:${_OM_VERSION}-${SHORT_SHA}', 'examples/evaluators/golang/simple']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: openmatch-mmf-cs-mmlogic-simple'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-mmf-cs-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}', '.']
dir: 'examples/functions/csharp/simple'
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: openmatch-mmf-go-mmlogic-simple'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-mmf-go-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}', '-f', 'examples/functions/golang/manual-simple/Dockerfile', '.']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: openmatch-mmf-php-mmlogic-simple'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-mmf-php-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}', '-f', 'examples/functions/php/mmlogic-simple/Dockerfile', '.']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: openmatch-mmf-py3-mmlogic-simple'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-mmf-py3-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}', '-f', 'examples/functions/python3/mmlogic-simple/Dockerfile', '.']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: backendclient'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-backendclient:${_OM_VERSION}-${SHORT_SHA}', 'examples/backendclient']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: clientloadgen'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-clientloadgen:${_OM_VERSION}-${SHORT_SHA}', 'test/cmd/clientloadgen']
waitFor: ['Docker Image: open-match-base-build']
- id: 'Docker Image: frontendclient'
name: gcr.io/cloud-builders/docker
args: ['build', '-t', 'gcr.io/$PROJECT_ID/openmatch-frontendclient:${_OM_VERSION}-${SHORT_SHA}', 'test/cmd/frontendclient']
waitFor: ['Docker Image: open-match-base-build']
# Cannot enable, produces lots of errors but can be useful.
#- id: 'Lint: YAML Files'
# name: wpengine/yamllint
# args: ['/workspace']
# waitFor: ['-']
- id: 'Lint: Kubernetes Configs'
name: garethr/kubeval
args: ['install/yaml/01-redis.yaml', 'install/yaml/02-open-match.yaml']
waitFor: ['-']
- id: 'Setup: Pull Dependencies'
name: golang
env: ['GO111MODULE=on', 'CGO_ENABLED=0']
args: ['go', 'mod', 'download']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['-']
- id: 'Lint: Formatting'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'fmt', './...']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Lint: Vetting'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'vet', './...']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Test: 10x with Race Detection and Coverage'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off']
args: ['go', 'test', './...', '-race', '-test.count', '10', '-cover']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: All Binaries'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', './...']
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: cmd/backendapi/backendapi'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'cmd/backendapi/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: cmd/frontendapi/frontendapi'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'cmd/frontendapi/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: cmd/mmforc/mmforc'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'cmd/mmforc/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: cmd/mmlogicapi/mmlogicapi'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'cmd/mmlogicapi/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: examples/functions/golang/manual-simple'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'examples/functions/golang/manual-simple/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: examples/backendclient'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'examples/backendclient/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: test/cmd/clientloadgen'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'test/cmd/clientloadgen/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
- id: 'Build: test/cmd/frontendclient'
name: golang
env: ['GO111MODULE=on', 'GOPROXY=off', 'CGO_ENABLED=0']
args: ['go', 'build', '-a', '-installsuffix', 'cgo', '.']
dir: 'test/cmd/frontendclient/'
volumes:
- name: 'go-vol'
path: '/go'
waitFor: ['Setup: Pull Dependencies']
artifacts:
objects:
location: gs://open-match-build-artifacts/output/
paths:
- cmd/backendapi/backendapi
- cmd/frontendapi/frontendapi
- cmd/mmforc/mmforc
- cmd/mmlogicapi/mmlogicapi
- examples/functions/golang/manual-simple/manual-simple
- examples/backendclient/backendclient
- test/cmd/clientloadgen/clientloadgen
- test/cmd/frontendclient/frontendclient
images:
- 'gcr.io/$PROJECT_ID/openmatch-backendapi:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-frontendapi:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmforc:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmlogicapi:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-evaluator-simple:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmf-cs-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmf-go-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmf-php-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-mmf-py3-mmlogic-simple:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-backendclient:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-clientloadgen:${_OM_VERSION}-${SHORT_SHA}'
- 'gcr.io/$PROJECT_ID/openmatch-frontendclient:${_OM_VERSION}-${SHORT_SHA}'
substitutions:
_OM_VERSION: 0.4.0
logsBucket: 'gs://open-match-build-logs/'
options:
sourceProvenanceHash: ['SHA256']
machineType: 'N1_HIGHCPU_8'
# TODO: The build is slow because we don't vendor. go get takes a very long time.
# Also we are rebuilding a lot of code unnecessarily. This should improve once
# we have new hermetic and reproducible Dockerfiles.
timeout: 1200s
# TODO Build Steps
# api/protobuf-spec/*: Build Protocol Buffers (golang, python, php)
# config/matchmaker_config.yaml: Lint this file so it's verified as a valid YAML file.
# deployments/k8s: Verify with kubelint.
# examples/profiles/*.json: Verify valid JSON files.
#
# Consolidate many of these build steps via Makefile.
# Caching of dependencies is a serious problem. Cloud Build does not complete within 20 minutes!

View File

@ -1,9 +0,0 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--tag=gcr.io/$PROJECT_ID/openmatch-base:dev',
'-f', 'Dockerfile.base',
'.'
]
images: ['gcr.io/$PROJECT_ID/openmatch-base:dev']

View File

@ -1,9 +0,0 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--tag=gcr.io/$PROJECT_ID/openmatch-mmf-php-mmlogic-simple',
'-f', 'Dockerfile.mmf_php',
'.'
]
images: ['gcr.io/$PROJECT_ID/openmatch-mmf-php-mmlogic-simple']

View File

@ -1,9 +0,0 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--tag=gcr.io/$PROJECT_ID/openmatch-mmf-py3-mmlogic-simple:dev',
'-f', 'Dockerfile.mmf_py3',
'.'
]
images: ['gcr.io/$PROJECT_ID/openmatch-mmf-py3-mmlogic-simple:dev']

View File

@ -1,10 +1,9 @@
# Golang application builder steps
FROM gcr.io/open-match-public-images/openmatch-base:dev as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/cmd/backendapi
COPY . .
RUN go get -d -v
FROM open-match-base-build as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/cmd/backendapi/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
#FROM scratch
#COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/backendapi/backendapi .
ENTRYPOINT ["./backendapi"]
FROM gcr.io/distroless/static
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/backendapi/backendapi .
ENTRYPOINT ["/backendapi"]

View File

@ -1,10 +1,8 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'pull', 'gcr.io/$PROJECT_ID/openmatch-base:dev' ]
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--tag=gcr.io/$PROJECT_ID/openmatch-backendapi:dev',
'--tag=gcr.io/$PROJECT_ID/openmatch-backendapi:0.4',
'.'
]
images: ['gcr.io/$PROJECT_ID/openmatch-backendapi:dev']
images: ['gcr.io/$PROJECT_ID/openmatch-backendapi:0.4']

View File

@ -23,81 +23,9 @@ limitations under the License.
package main
import (
"errors"
"os"
"os/signal"
"github.com/GoogleCloudPlatform/open-match/cmd/backendapi/apisrv"
"github.com/GoogleCloudPlatform/open-match/config"
"github.com/GoogleCloudPlatform/open-match/internal/logging"
"github.com/GoogleCloudPlatform/open-match/internal/metrics"
redishelpers "github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
"go.opencensus.io/plugin/ocgrpc"
"github.com/GoogleCloudPlatform/open-match/internal/app/backendapi"
)
var (
// Logrus structured logging setup
beLogFields = log.Fields{
"app": "openmatch",
"component": "backend",
}
beLog = log.WithFields(beLogFields)
// Viper config management setup
cfg = viper.New()
err = errors.New("")
)
func init() {
// Add a hook to the logger to auto-count log lines for metrics output thru OpenCensus
log.AddHook(metrics.NewHook(apisrv.BeLogLines, apisrv.KeySeverity))
// Viper config management initialization
cfg, err = config.Read()
if err != nil {
beLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Unable to load config file")
}
// Configure open match logging defaults
logging.ConfigureLogging(cfg)
// Configure OpenCensus exporter to Prometheus
// metrics.ConfigureOpenCensusPrometheusExporter expects that every OpenCensus view you
// want to register is in an array, so append any views you want from other
// packages to a single array here.
ocServerViews := apisrv.DefaultBackendAPIViews // BackendAPI OpenCensus views.
ocServerViews = append(ocServerViews, ocgrpc.DefaultServerViews...) // gRPC OpenCensus views.
ocServerViews = append(ocServerViews, config.CfgVarCountView) // config loader view.
// Waiting on https://github.com/opencensus-integrations/redigo/pull/1
// ocServerViews = append(ocServerViews, redis.ObservabilityMetricViews...) // redis OpenCensus views.
beLog.WithFields(log.Fields{"viewscount": len(ocServerViews)}).Info("Loaded OpenCensus views")
metrics.ConfigureOpenCensusPrometheusExporter(cfg, ocServerViews)
}
func main() {
// Connect to redis
pool := redishelpers.ConnectionPool(cfg)
defer pool.Close()
// Instantiate the gRPC server with the connections we've made
beLog.Info("Attempting to start gRPC server")
srv := apisrv.New(cfg, pool)
// Run the gRPC server
err := srv.Open()
if err != nil {
beLog.WithFields(log.Fields{"error": err.Error()}).Fatal("Failed to start gRPC server")
}
// Exit when we see a signal
terminate := make(chan os.Signal, 1)
signal.Notify(terminate, os.Interrupt)
<-terminate
beLog.Info("Shutting down gRPC server")
backendapi.RunApplication()
}

View File

@ -1 +0,0 @@
../../config/matchmaker_config.json

View File

@ -0,0 +1 @@
../../config/matchmaker_config.yaml

View File

@ -1,10 +1,9 @@
# Golang application builder steps
FROM gcr.io/open-match-public-images/openmatch-base:dev as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/cmd/frontendapi
COPY . .
RUN go get -d -v
FROM open-match-base-build as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/cmd/frontendapi/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
#FROM scratch
#COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/frontendapi/frontendapi .
ENTRYPOINT ["./frontendapi"]
FROM gcr.io/distroless/static
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/frontendapi/frontendapi .
ENTRYPOINT ["/frontendapi"]

View File

@ -1,10 +1,8 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'pull', 'gcr.io/$PROJECT_ID/openmatch-base:dev' ]
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--tag=gcr.io/$PROJECT_ID/openmatch-frontendapi:dev',
'--tag=gcr.io/$PROJECT_ID/openmatch-frontendapi:0.4',
'.'
]
images: ['gcr.io/$PROJECT_ID/openmatch-frontendapi:dev']
images: ['gcr.io/$PROJECT_ID/openmatch-frontendapi:0.4']

View File

@ -19,87 +19,13 @@ 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 (
"errors"
"os"
"os/signal"
"github.com/GoogleCloudPlatform/open-match/cmd/frontendapi/apisrv"
"github.com/GoogleCloudPlatform/open-match/config"
"github.com/GoogleCloudPlatform/open-match/internal/logging"
"github.com/GoogleCloudPlatform/open-match/internal/metrics"
redishelpers "github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
"go.opencensus.io/plugin/ocgrpc"
"github.com/GoogleCloudPlatform/open-match/internal/app/frontendapi"
)
var (
// Logrus structured logging setup
feLogFields = log.Fields{
"app": "openmatch",
"component": "frontend",
}
feLog = log.WithFields(feLogFields)
// Viper config management setup
cfg = viper.New()
err = errors.New("")
)
func init() {
// Add a hook to the logger to auto-count log lines for metrics output thru OpenCensus
log.AddHook(metrics.NewHook(apisrv.FeLogLines, apisrv.KeySeverity))
// Add a hook to the logger to log the filename & line number.
log.SetReportCaller(true)
// Viper config management initialization
cfg, err = config.Read()
if err != nil {
feLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Unable to load config file")
}
// Configure open match logging defaults
logging.ConfigureLogging(cfg)
// Configure OpenCensus exporter to Prometheus
// metrics.ConfigureOpenCensusPrometheusExporter expects that every OpenCensus view you
// want to register is in an array, so append any views you want from other
// packages to a single array here.
ocServerViews := apisrv.DefaultFrontendAPIViews // FrontendAPI OpenCensus views.
ocServerViews = append(ocServerViews, ocgrpc.DefaultServerViews...) // gRPC OpenCensus views.
ocServerViews = append(ocServerViews, config.CfgVarCountView) // config loader view.
// Waiting on https://github.com/opencensus-integrations/redigo/pull/1
// ocServerViews = append(ocServerViews, redis.ObservabilityMetricViews...) // redis OpenCensus views.
feLog.WithFields(log.Fields{"viewscount": len(ocServerViews)}).Info("Loaded OpenCensus views")
metrics.ConfigureOpenCensusPrometheusExporter(cfg, ocServerViews)
}
func main() {
// Connect to redis
pool := redishelpers.ConnectionPool(cfg)
defer pool.Close()
// Instantiate the gRPC server with the connections we've made
feLog.Info("Attempting to start gRPC server")
srv := apisrv.New(cfg, pool)
// Run the gRPC server
err := srv.Open()
if err != nil {
feLog.WithFields(log.Fields{"error": err.Error()}).Fatal("Failed to start gRPC server")
}
// Exit when we see a signal
terminate := make(chan os.Signal, 1)
signal.Notify(terminate, os.Interrupt)
<-terminate
feLog.Info("Shutting down gRPC server")
frontendapi.RunApplication()
}

View File

@ -1 +0,0 @@
../../config/matchmaker_config.json

View File

@ -0,0 +1 @@
../../config/matchmaker_config.yaml

View File

@ -1,21 +1,9 @@
# Golang application builder steps
FROM gcr.io/open-match-public-images/openmatch-base:dev as builder
# Necessary to get a specific version of the golang k8s client
RUN go get github.com/tools/godep
RUN go get k8s.io/client-go/...
WORKDIR /go/src/k8s.io/client-go
RUN git checkout v7.0.0
RUN godep restore ./...
RUN rm -rf vendor/
RUN rm -rf /go/src/github.com/golang/protobuf/
FROM open-match-base-build as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/cmd/mmforc/
COPY . .
RUN go get -d -v
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
# Uncomment to build production images (removes all troubleshooting tools)
#FROM scratch
#COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/mmforc/mmforc .
CMD ["./mmforc"]
FROM gcr.io/distroless/static
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/mmforc/mmforc .
ENTRYPOINT ["/mmforc"]

View File

@ -1,10 +1,8 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'pull', 'gcr.io/$PROJECT_ID/openmatch-base:dev' ]
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--tag=gcr.io/$PROJECT_ID/openmatch-mmforc:dev',
'--tag=gcr.io/$PROJECT_ID/openmatch-mmforc:0.4',
'.'
]
images: ['gcr.io/$PROJECT_ID/openmatch-mmforc:dev']
images: ['gcr.io/$PROJECT_ID/openmatch-mmforc:0.4']

View File

@ -17,388 +17,13 @@ limitations under the License.
// Note: the example only works with the code within the same release/branch.
// This is based on the example from the official k8s golang client repository:
// k8s.io/client-go/examples/create-update-delete-deployment/
package main
import (
"context"
"errors"
"os"
"strconv"
"strings"
"time"
"github.com/GoogleCloudPlatform/open-match/config"
"github.com/GoogleCloudPlatform/open-match/internal/logging"
"github.com/GoogleCloudPlatform/open-match/internal/metrics"
redisHelpers "github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis"
"github.com/tidwall/gjson"
"go.opencensus.io/stats"
"go.opencensus.io/tag"
"github.com/gomodule/redigo/redis"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
batchv1 "k8s.io/api/batch/v1"
apiv1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
//"k8s.io/kubernetes/pkg/api"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
// Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters).
_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
"github.com/GoogleCloudPlatform/open-match/internal/app/mmforc"
)
var (
// Logrus structured logging setup
mmforcLogFields = log.Fields{
"app": "openmatch",
"component": "mmforc",
}
mmforcLog = log.WithFields(mmforcLogFields)
// Viper config management setup
cfg = viper.New()
err = errors.New("")
)
func init() {
// Add a hook to the logger to auto-count log lines for metrics output thru OpenCensus
log.AddHook(metrics.NewHook(MmforcLogLines, KeySeverity))
// Viper config management initialization
cfg, err = config.Read()
if err != nil {
mmforcLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Unable to load config file")
}
// Configure open match logging defaults
logging.ConfigureLogging(cfg)
// Configure OpenCensus exporter to Prometheus
// metrics.ConfigureOpenCensusPrometheusExporter expects that every OpenCensus view you
// want to register is in an array, so append any views you want from other
// packages to a single array here.
ocMmforcViews := DefaultMmforcViews // mmforc OpenCensus views.
// Waiting on https://github.com/opencensus-integrations/redigo/pull/1
// ocMmforcViews = append(ocMmforcViews, redis.ObservabilityMetricViews...) // redis OpenCensus views.
mmforcLog.WithFields(log.Fields{"viewscount": len(ocMmforcViews)}).Info("Loaded OpenCensus views")
metrics.ConfigureOpenCensusPrometheusExporter(cfg, ocMmforcViews)
}
func main() {
pool := redisHelpers.ConnectionPool(cfg)
redisConn := pool.Get()
defer redisConn.Close()
// Get k8s credentials so we can starts k8s Jobs
mmforcLog.Info("Attempting to acquire k8s credentials")
config, err := rest.InClusterConfig()
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
mmforcLog.Info("K8s credentials acquired")
start := time.Now()
checkProposals := true
// main loop; kick off matchmaker functions for profiles in the profile
// queue and an evaluator when proposals are in the proposals queue
for {
ctx, cancel := context.WithCancel(context.Background())
_ = cancel
// Get profiles and kick off a job for each
mmforcLog.WithFields(log.Fields{
"profileQueueName": cfg.GetString("queues.profiles.name"),
"pullCount": cfg.GetInt("queues.profiles.pullCount"),
"query": "SPOP",
"component": "statestorage",
}).Debug("Retreiving match profiles")
results, err := redis.Strings(redisConn.Do("SPOP",
cfg.GetString("queues.profiles.name"), cfg.GetInt("queues.profiles.pullCount")))
if err != nil {
panic(err)
}
if len(results) > 0 {
mmforcLog.WithFields(log.Fields{
"numProfiles": len(results),
}).Info("Starting MMF jobs...")
for _, profile := range results {
// Kick off the job asynchrnously
go mmfunc(ctx, profile, cfg, clientset, pool)
// Count the number of jobs running
redisHelpers.Increment(context.Background(), pool, "concurrentMMFs")
}
} else {
mmforcLog.WithFields(log.Fields{
"profileQueueName": cfg.GetString("queues.profiles.name"),
}).Info("Unable to retreive match profiles from statestorage - have you entered any?")
}
// Check to see if we should run the evaluator.
// Get number of running MMFs
r, err := redisHelpers.Retrieve(context.Background(), pool, "concurrentMMFs")
if err != nil {
if err.Error() == "redigo: nil returned" {
// No MMFs have run since we last evaluated; reset timer and loop
mmforcLog.Debug("Number of concurrentMMFs is nil")
start = time.Now()
time.Sleep(1000 * time.Millisecond)
}
continue
}
numRunning, err := strconv.Atoi(r)
if err != nil {
mmforcLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Issue retrieving number of currently running MMFs")
}
// We are ready to evaluate either when all MMFs are complete, or the
// timeout is reached.
//
// Tuning how frequently the evaluator runs is a complex topic and
// probably only of interest to users running large-scale production
// workloads with many concurrently running matchmaking functions,
// which have some overlap in the matchmaking player pools. Suffice to
// say that under load, this switch should almost always trigger the
// timeout interval code path. The concurrentMMFs check to see how
// many are still running is meant as a deadman's switch to prevent
// waiting to run the evaluator when all your MMFs are already
// finished.
switch {
case time.Since(start).Seconds() >= float64(cfg.GetInt("evaluator.interval")):
mmforcLog.WithFields(log.Fields{
"interval": cfg.GetInt("evaluator.interval"),
}).Info("Maximum evaluator interval exceeded")
checkProposals = true
// Opencensus tagging
ctx, _ = tag.New(ctx, tag.Insert(KeyEvalReason, "interval_exceeded"))
case numRunning <= 0:
mmforcLog.Info("All MMFs complete")
checkProposals = true
numRunning = 0
ctx, _ = tag.New(ctx, tag.Insert(KeyEvalReason, "mmfs_completed"))
}
if checkProposals {
// Make sure there are proposals in the queue. No need to run the
// evaluator if there are none.
checkProposals = false
mmforcLog.Info("Checking statestorage for match object proposals")
results, err := redisHelpers.Count(context.Background(), pool, cfg.GetString("queues.proposals.name"))
switch {
case err != nil:
mmforcLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Couldn't retrieve the length of the proposal queue from statestorage!")
case results == 0:
mmforcLog.WithFields(log.Fields{}).Warn("No proposals in the queue!")
default:
mmforcLog.WithFields(log.Fields{
"numProposals": results,
}).Info("Proposals available, evaluating!")
go evaluator(ctx, cfg, clientset)
}
err = redisHelpers.Delete(context.Background(), pool, "concurrentMMFs")
if err != nil {
mmforcLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Error deleting concurrent MMF counter!")
}
start = time.Now()
}
// TODO: Make this tunable via config.
// A sleep here is not critical but just a useful safety valve in case
// things are broken, to keep the main loop from going all-out and spamming the log.
mainSleep := 1000
mmforcLog.WithFields(log.Fields{
"ms": mainSleep,
}).Info("Sleeping...")
time.Sleep(time.Duration(mainSleep) * time.Millisecond)
} // End main for loop
mmforc.RunApplication()
}
// mmfunc generates a k8s job that runs the specified mmf container image.
// resultsID is the redis key that the Backend API is monitoring for results; we can 'short circuit' and write errors directly to this key if we can't run the MMF for some reason.
func mmfunc(ctx context.Context, resultsID string, cfg *viper.Viper, clientset *kubernetes.Clientset, pool *redis.Pool) {
// Generate the various keys/names, some of which must be populated to the k8s job.
imageName := cfg.GetString("defaultImages.mmf.name") + ":" + cfg.GetString("defaultImages.mmf.tag")
jobType := "mmf"
ids := strings.Split(resultsID, ".") // comes in as dot-concatinated moID and profID.
moID := ids[0]
profID := ids[1]
timestamp := strconv.Itoa(int(time.Now().Unix()))
jobName := timestamp + "." + moID + "." + profID + "." + jobType
propID := "proposal." + timestamp + "." + moID + "." + profID
// Extra fields for structured logging
lf := log.Fields{"jobName": jobName}
if cfg.GetBool("debug") { // Log a lot more info.
lf = log.Fields{
"jobType": jobType,
"backendMatchObject": moID,
"profile": profID,
"jobTimestamp": timestamp,
"containerImage": imageName,
"jobName": jobName,
"profileImageJSONKey": cfg.GetString("jsonkeys.mmfImage"),
}
}
mmfuncLog := mmforcLog.WithFields(lf)
// Read the full profile from redis and access any keys that are important to deciding how MMFs are run.
// TODO: convert this to using redispb and directly access the protobuf message instead of retrieving as a map?
profile, err := redisHelpers.RetrieveAll(ctx, pool, profID)
if err != nil {
// Log failure to read this profile and return - won't run an MMF for an unreadable profile.
mmfuncLog.WithFields(log.Fields{"error": err.Error()}).Error("Failure retreiving profile from statestorage")
return
}
// Got profile from state storage, make sure it is valid
if gjson.Valid(profile["properties"]) {
profileImage := gjson.Get(profile["properties"], cfg.GetString("jsonkeys.mmfImage"))
if profileImage.Exists() {
imageName = profileImage.String()
mmfuncLog = mmfuncLog.WithFields(log.Fields{"containerImage": imageName})
} else {
mmfuncLog.Warn("Failed to read image name from profile at configured json key, using default image instead")
}
}
mmfuncLog.Info("Attempting to create mmf k8s job")
// Kick off k8s job
envvars := []apiv1.EnvVar{
{Name: "MMF_PROFILE_ID", Value: profID},
{Name: "MMF_PROPOSAL_ID", Value: propID},
{Name: "MMF_REQUEST_ID", Value: moID},
{Name: "MMF_ERROR_ID", Value: resultsID},
{Name: "MMF_TIMESTAMP", Value: timestamp},
}
err = submitJob(clientset, jobType, jobName, imageName, envvars)
if err != nil {
// Record failure & log
stats.Record(ctx, mmforcMmfFailures.M(1))
mmfuncLog.WithFields(log.Fields{"error": err.Error()}).Error("MMF job submission failure!")
} else {
// Record Success
stats.Record(ctx, mmforcMmfs.M(1))
}
}
// evaluator generates a k8s job that runs the specified evaluator container image.
func evaluator(ctx context.Context, cfg *viper.Viper, clientset *kubernetes.Clientset) {
imageName := cfg.GetString("defaultImages.evaluator.name") + ":" + cfg.GetString("defaultImages.evaluator.tag")
// Generate the job name
timestamp := strconv.Itoa(int(time.Now().Unix()))
jobType := "evaluator"
jobName := timestamp + "." + jobType
mmforcLog.WithFields(log.Fields{
"jobName": jobName,
"containerImage": imageName,
}).Info("Attempting to create evaluator k8s job")
// Kick off k8s job
envvars := []apiv1.EnvVar{{Name: "MMF_TIMESTAMP", Value: timestamp}}
err = submitJob(clientset, jobType, jobName, imageName, envvars)
if err != nil {
// Record failure & log
stats.Record(ctx, mmforcEvalFailures.M(1))
mmforcLog.WithFields(log.Fields{
"error": err.Error(),
"jobName": jobName,
"containerImage": imageName,
}).Error("Evaluator job submission failure!")
} else {
// Record success
stats.Record(ctx, mmforcEvals.M(1))
}
}
// submitJob submits a job to kubernetes
func submitJob(clientset *kubernetes.Clientset, jobType string, jobName string, imageName string, envvars []apiv1.EnvVar) error {
// DEPRECATED: will be removed in a future vrsion. Please switch to using the 'MMF_*' environment variables.
v := strings.Split(jobName, ".")
envvars = append(envvars, apiv1.EnvVar{Name: "PROFILE", Value: strings.Join(v[:len(v)-1], ".")})
job := &batchv1.Job{
ObjectMeta: metav1.ObjectMeta{
Name: jobName,
},
Spec: batchv1.JobSpec{
Completions: int32Ptr(1),
Template: apiv1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": jobType,
},
Annotations: map[string]string{
// Unused; here as an example.
// Later we can put things more complicated than
// env vars here and read them using k8s downward API
// volumes
"profile": jobName,
},
},
Spec: apiv1.PodSpec{
RestartPolicy: "Never",
Containers: []apiv1.Container{
{
Name: jobType,
Image: imageName,
ImagePullPolicy: "Always",
Env: envvars,
},
},
},
},
},
}
// Get the namespace for the job from the current namespace, otherwise, use default
namespace := os.Getenv("METADATA_NAMESPACE")
if len(namespace) == 0 {
namespace = apiv1.NamespaceDefault
}
// Submit kubernetes job
jobsClient := clientset.BatchV1().Jobs(namespace)
result, err := jobsClient.Create(job)
if err != nil {
// TODO: replace queued profiles if things go south
mmforcLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Couldn't create k8s job!")
}
mmforcLog.WithFields(log.Fields{
"jobName": result.GetObjectMeta().GetName(),
}).Info("Created job.")
return err
}
// readability functions used by generateJobSpec
func int32Ptr(i int32) *int32 { return &i }
func strPtr(i string) *string { return &i }

View File

@ -1 +0,0 @@
../../config/matchmaker_config.json

View File

@ -0,0 +1 @@
../../config/matchmaker_config.yaml

View File

@ -1,10 +1,9 @@
# Golang application builder steps
FROM gcr.io/open-match-public-images/openmatch-base:dev as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/cmd/mmlogicapi
COPY . .
RUN go get -d -v
FROM open-match-base-build as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/cmd/mmlogicapi/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
#FROM scratch
#COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/frontendapi/frontendapi .
ENTRYPOINT ["./mmlogicapi"]
FROM gcr.io/distroless/static
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/cmd/mmlogicapi/mmlogicapi .
ENTRYPOINT ["/mmlogicapi"]

View File

@ -1,10 +1,8 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args: [ 'pull', 'gcr.io/$PROJECT_ID/openmatch-base:dev' ]
- name: 'gcr.io/cloud-builders/docker'
args: [
'build',
'--tag=gcr.io/$PROJECT_ID/openmatch-mmlogicapi:dev',
'--tag=gcr.io/$PROJECT_ID/openmatch-mmlogicapi:0.4',
'.'
]
images: ['gcr.io/$PROJECT_ID/openmatch-mmlogicapi:dev']
images: ['gcr.io/$PROJECT_ID/openmatch-mmlogicapi:0.4']

View File

@ -22,83 +22,9 @@ limitations under the License.
package main
import (
"errors"
"os"
"os/signal"
"github.com/GoogleCloudPlatform/open-match/cmd/mmlogicapi/apisrv"
"github.com/GoogleCloudPlatform/open-match/config"
"github.com/GoogleCloudPlatform/open-match/internal/metrics"
redisHelpers "github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis"
log "github.com/sirupsen/logrus"
"github.com/spf13/viper"
"go.opencensus.io/plugin/ocgrpc"
"github.com/GoogleCloudPlatform/open-match/internal/app/mmlogicapi"
)
var (
// Logrus structured logging setup
mlLogFields = log.Fields{
"app": "openmatch",
"component": "mmlogic",
}
mlLog = log.WithFields(mlLogFields)
// Viper config management setup
cfg = viper.New()
err = errors.New("")
)
func init() {
// Logrus structured logging initialization
// Add a hook to the logger to auto-count log lines for metrics output thru OpenCensus
log.AddHook(metrics.NewHook(apisrv.MlLogLines, apisrv.KeySeverity))
// Viper config management initialization
cfg, err = config.Read()
if err != nil {
mlLog.WithFields(log.Fields{
"error": err.Error(),
}).Error("Unable to load config file")
}
if cfg.GetBool("debug") == true {
log.SetLevel(log.DebugLevel) // debug only, verbose - turn off in production!
mlLog.Warn("Debug logging configured. Not recommended for production!")
}
// Configure OpenCensus exporter to Prometheus
// metrics.ConfigureOpenCensusPrometheusExporter expects that every OpenCensus view you
// want to register is in an array, so append any views you want from other
// packages to a single array here.
ocServerViews := apisrv.DefaultMmlogicAPIViews // Matchmaking logic API OpenCensus views.
ocServerViews = append(ocServerViews, ocgrpc.DefaultServerViews...) // gRPC OpenCensus views.
ocServerViews = append(ocServerViews, config.CfgVarCountView) // config loader view.
// Waiting on https://github.com/opencensus-integrations/redigo/pull/1
// ocServerViews = append(ocServerViews, redis.ObservabilityMetricViews...) // redis OpenCensus views.
mlLog.WithFields(log.Fields{"viewscount": len(ocServerViews)}).Info("Loaded OpenCensus views")
metrics.ConfigureOpenCensusPrometheusExporter(cfg, ocServerViews)
}
func main() {
// Connect to redis
pool := redisHelpers.ConnectionPool(cfg)
defer pool.Close()
// Instantiate the gRPC server with the connections we've made
mlLog.Info("Attempting to start gRPC server")
srv := apisrv.New(cfg, pool)
// Run the gRPC server
err := srv.Open()
if err != nil {
mlLog.WithFields(log.Fields{"error": err.Error()}).Fatal("Failed to start gRPC server")
}
// Exit when we see a signal
terminate := make(chan os.Signal, 1)
signal.Notify(terminate, os.Interrupt)
<-terminate
mlLog.Info("Shutting down gRPC server")
mmlogicapi.RunApplication()
}

View File

@ -1 +0,0 @@
../../config/matchmaker_config.json

View File

@ -0,0 +1 @@
../../config/matchmaker_config.yaml

View File

@ -41,12 +41,20 @@ var (
// REDIS_SENTINEL_PORT_6379_TCP_PORT=6379
// REDIS_SENTINEL_PORT_6379_TCP_PROTO=tcp
// REDIS_SENTINEL_SERVICE_HOST=10.55.253.195
//
// MMFs are expected to get their configuation from env vars instead
// of reading the config file. So, config parameters that are required
// by MMFs should be populated to env vars.
envMappings = map[string]string{
"redis.user": "REDIS_USER",
"redis.password": "REDIS_PASSWORD",
"redis.hostname": "REDIS_SERVICE_HOST",
"redis.port": "REDIS_SERVICE_PORT",
"redis.pool.maxIdle": "REDIS_POOL_MAXIDLE",
"redis.pool.maxActive": "REDIS_POOL_MAXACTIVE",
"redis.pool.idleTimeout": "REDIS_POOL_IDLETIMEOUT",
"api.mmlogic.hostname": "OM_MMLOGICAPI_SERVICE_HOST",
"api.mmlogic.port": "OM_MMLOGICAPI_SERVICE_PORT",
}
// Viper config management setup
@ -74,6 +82,7 @@ func Read() (*viper.Viper, error) {
cfg.SetConfigType("yaml")
cfg.SetConfigName("matchmaker_config")
cfg.AddConfigPath(".")
cfg.AddConfigPath("config")
// Read in config file using Viper
err := cfg.ReadInConfig()

View File

@ -1,110 +0,0 @@
{
"debug": true,
"logging":{
"level": "debug",
"format": "text",
"source": true
},
"api": {
"backend": {
"hostname": "om-backendapi",
"port": 50505,
"timeout": 90
},
"frontend": {
"hostname": "om-frontendapi",
"port": 50504,
"timeout": 300
},
"mmlogic": {
"hostname": "om-mmlogicapi",
"port": 50503
}
},
"evalutor": {
"interval": 10
},
"metrics": {
"port": 9555,
"endpoint": "/metrics",
"reportingPeriod": 5
},
"queues": {
"profiles": {
"name": "profileq",
"pullCount": 100
},
"proposals": {
"name": "proposalq"
}
},
"ignoreLists": {
"proposed": {
"name": "proposed",
"offset": 0,
"duration": 800
},
"deindexed": {
"name": "deindexed",
"offset": 0,
"duration": 800
},
"expired": {
"name": "OM_METADATA.accessed",
"offset": 800,
"duration": 0
}
},
"defaultImages": {
"evaluator": {
"name": "gcr.io/open-match-public-images/openmatch-evaluator",
"tag": "dev"
},
"mmf": {
"name": "gcr.io/open-match-public-images/openmatch-mmf-py3-mmlogic-simple",
"tag": "dev"
}
},
"redis": {
"user": "",
"password": "",
"pool" : {
"maxIdle" : 3,
"maxActive" : 0,
"idleTimeout" : 60
},
"queryArgs":{
"count": 10000
},
"results": {
"pageSize": 10000
},
"expirations": {
"player": 43200,
"matchobject":43200
}
},
"jsonkeys": {
"mmfImage": "imagename",
"rosters": "properties.rosters",
"pools": "properties.pools"
},
"playerIndices": [
"char.cleric",
"char.knight",
"char.paladin",
"map.aleroth",
"map.oasis",
"mmr.rating",
"mode.battleroyale",
"mode.ctf",
"region.europe-east1",
"region.europe-west1",
"region.europe-west2",
"region.europe-west3",
"region.europe-west4",
"role.dps",
"role.support",
"role.tank"
]
}

View File

@ -0,0 +1,97 @@
# kubectl create configmap om-configmap --from-file=config/matchmaker_config.yaml
debug: true
logging:
level: debug
format: text
source: true
api:
backend:
hostname: om-backendapi
port: 50505
backoff: "[2 32] *2 ~0.33 <30"
frontend:
hostname: om-frontendapi
port: 50504
backoff: "[2 32] *2 ~0.33 <300"
mmlogic:
hostname: om-mmlogicapi
port: 50503
functions:
port: 50502
evalutor:
interval: 10
metrics:
port: 9555
endpoint: /metrics
reportingPeriod: 5
queues:
profiles:
name: profileq
pullCount: 100
proposals:
name: proposalq
ignoreLists:
proposed:
name: proposed
offset: 0
duration: 800
deindexed:
name: deindexed
offset: 0
duration: 800
expired:
name: OM_METADATA.accessed
offset: 800
duration: 0
defaultImages:
evaluator:
name: gcr.io/matchmaker-dev-201405/openmatch-evaluator
tag: dev
mmf:
name: gcr.io/matchmaker-dev-201405/openmatch-mmf-py3-mmlogic-simple
tag: dev
redis:
pool:
maxIdle: 3
maxActive: 0
idleTimeout: 60
queryArgs:
count: 10000
results:
pageSize: 10000
expirations:
player: 43200
matchobject: 43200
jsonkeys:
mmfImage: imagename
mmfService: hostname
rosters: properties.rosters
pools: properties.pools
playerIndices:
- char.cleric
- char.knight
- char.paladin
- map.aleroth
- map.oasis
- mmr.rating
- mode.battleroyale
- mode.ctf
- mode.demo
- region.europe-east1
- region.europe-west1
- region.europe-west2
- region.europe-west3
- region.europe-west4
- role.dps
- role.support
- role.tank

View File

@ -1,53 +0,0 @@
{
"apiVersion":"extensions/v1beta1",
"kind":"Deployment",
"metadata":{
"name":"om-backendapi",
"labels":{
"app":"openmatch",
"component": "backend"
}
},
"spec":{
"replicas":1,
"selector":{
"matchLabels":{
"app":"openmatch",
"component": "backend"
}
},
"template":{
"metadata":{
"labels":{
"app":"openmatch",
"component": "backend"
}
},
"spec":{
"containers":[
{
"name":"om-backend",
"image":"gcr.io/open-match-public-images/openmatch-backendapi:dev",
"imagePullPolicy":"Always",
"ports": [
{
"name": "grpc",
"containerPort": 50505
},
{
"name": "metrics",
"containerPort": 9555
}
],
"resources":{
"requests":{
"memory":"100Mi",
"cpu":"100m"
}
}
}
]
}
}
}
}

View File

@ -0,0 +1,32 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: om-backendapi
labels:
app: openmatch
component: backend
spec:
replicas: 1
selector:
matchLabels:
app: openmatch
component: backend
template:
metadata:
labels:
app: openmatch
component: backend
spec:
containers:
- name: om-backend
image: gcr.io/open-match-public-images/openmatch-backendapi:dev
imagePullPolicy: Always
ports:
- name: grpc
containerPort: 50505
- name: metrics
containerPort: 9555
resources:
requests:
memory: 100Mi
cpu: 100m

View File

@ -1,20 +0,0 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "om-backendapi"
},
"spec": {
"selector": {
"app": "openmatch",
"component": "backend"
},
"ports": [
{
"protocol": "TCP",
"port": 50505,
"targetPort": "grpc"
}
]
}
}

View File

@ -0,0 +1,12 @@
kind: Service
apiVersion: v1
metadata:
name: om-backendapi
spec:
selector:
app: openmatch
component: backend
ports:
- protocol: TCP
port: 50505
targetPort: grpc

View File

@ -1,53 +0,0 @@
{
"apiVersion":"extensions/v1beta1",
"kind":"Deployment",
"metadata":{
"name":"om-frontendapi",
"labels":{
"app":"openmatch",
"component": "frontend"
}
},
"spec":{
"replicas":1,
"selector":{
"matchLabels":{
"app":"openmatch",
"component": "frontend"
}
},
"template":{
"metadata":{
"labels":{
"app":"openmatch",
"component": "frontend"
}
},
"spec":{
"containers":[
{
"name":"om-frontendapi",
"image":"gcr.io/open-match-public-images/openmatch-frontendapi:dev",
"imagePullPolicy":"Always",
"ports": [
{
"name": "grpc",
"containerPort": 50504
},
{
"name": "metrics",
"containerPort": 9555
}
],
"resources":{
"requests":{
"memory":"100Mi",
"cpu":"100m"
}
}
}
]
}
}
}
}

View File

@ -0,0 +1,32 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: om-frontendapi
labels:
app: openmatch
component: frontend
spec:
replicas: 1
selector:
matchLabels:
app: openmatch
component: frontend
template:
metadata:
labels:
app: openmatch
component: frontend
spec:
containers:
- name: om-frontendapi
image: gcr.io/open-match-public-images/openmatch-frontendapi:dev
imagePullPolicy: Always
ports:
- name: grpc
containerPort: 50504
- name: metrics
containerPort: 9555
resources:
requests:
memory: 100Mi
cpu: 100m

View File

@ -1,20 +0,0 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "om-frontendapi"
},
"spec": {
"selector": {
"app": "openmatch",
"component": "frontend"
},
"ports": [
{
"protocol": "TCP",
"port": 50504,
"targetPort": "grpc"
}
]
}
}

View File

@ -0,0 +1,12 @@
kind: Service
apiVersion: v1
metadata:
name: om-frontendapi
spec:
selector:
app: openmatch
component: frontend
ports:
- protocol: TCP
port: 50504
targetPort: grpc

View File

@ -1,27 +0,0 @@
{
"apiVersion": "monitoring.coreos.com/v1",
"kind": "ServiceMonitor",
"metadata": {
"name": "openmatch-metrics",
"labels": {
"app": "openmatch",
"agent": "opencensus",
"destination": "prometheus"
}
},
"spec": {
"selector": {
"matchLabels": {
"app": "openmatch",
"agent": "opencensus",
"destination": "prometheus"
}
},
"endpoints": [
{
"port": "metrics",
"interval": "10s"
}
]
}
}

View File

@ -0,0 +1,17 @@
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: openmatch-metrics
labels:
app: openmatch
agent: opencensus
destination: prometheus
spec:
selector:
matchLabels:
app: openmatch
agent: opencensus
destination: prometheus
endpoints:
- port: metrics
interval: 10s

View File

@ -1,78 +0,0 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "om-frontend-metrics",
"labels": {
"app": "openmatch",
"component": "frontend",
"agent": "opencensus",
"destination": "prometheus"
}
},
"spec": {
"selector": {
"app": "openmatch",
"component": "frontend"
},
"ports": [
{
"name": "metrics",
"targetPort": 9555,
"port": 19555
}
]
}
}
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "om-backend-metrics",
"labels": {
"app": "openmatch",
"component": "backend",
"agent": "opencensus",
"destination": "prometheus"
}
},
"spec": {
"selector": {
"app": "openmatch",
"component": "backend"
},
"ports": [
{
"name": "metrics",
"targetPort": 9555,
"port": 29555
}
]
}
}
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "om-mmforc-metrics",
"labels": {
"app": "openmatch",
"component": "mmforc",
"agent": "opencensus",
"destination": "prometheus"
}
},
"spec": {
"selector": {
"app": "openmatch",
"component": "mmforc"
},
"ports": [
{
"name": "metrics",
"targetPort": 9555,
"port": 39555
}
]
}
}

View File

@ -0,0 +1,54 @@
---
kind: Service
apiVersion: v1
metadata:
name: om-frontend-metrics
labels:
app: openmatch
component: frontend
agent: opencensus
destination: prometheus
spec:
selector:
app: openmatch
component: frontend
ports:
- name: metrics
targetPort: 9555
port: 19555
---
kind: Service
apiVersion: v1
metadata:
name: om-backend-metrics
labels:
app: openmatch
component: backend
agent: opencensus
destination: prometheus
spec:
selector:
app: openmatch
component: backend
ports:
- name: metrics
targetPort: 9555
port: 29555
---
kind: Service
apiVersion: v1
metadata:
name: om-mmforc-metrics
labels:
app: openmatch
component: mmforc
agent: opencensus
destination: prometheus
spec:
selector:
app: openmatch
component: mmforc
ports:
- name: metrics
targetPort: 9555
port: 39555

View File

@ -1,59 +0,0 @@
{
"apiVersion":"extensions/v1beta1",
"kind":"Deployment",
"metadata":{
"name":"om-mmforc",
"labels":{
"app":"openmatch",
"component": "mmforc"
}
},
"spec":{
"replicas":1,
"selector":{
"matchLabels":{
"app":"openmatch",
"component": "mmforc"
}
},
"template":{
"metadata":{
"labels":{
"app":"openmatch",
"component": "mmforc"
}
},
"spec":{
"containers":[
{
"name":"om-mmforc",
"image":"gcr.io/open-match-public-images/openmatch-mmforc:dev",
"imagePullPolicy":"Always",
"ports": [
{
"name": "metrics",
"containerPort":9555
}
],
"resources":{
"requests":{
"memory":"100Mi",
"cpu":"100m"
}
},
"env":[
{
"name":"METADATA_NAMESPACE",
"valueFrom": {
"fieldRef": {
"fieldPath": "metadata.namespace"
}
}
}
]
}
]
}
}
}
}

View File

@ -0,0 +1,35 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: om-mmforc
labels:
app: openmatch
component: mmforc
spec:
replicas: 1
selector:
matchLabels:
app: openmatch
component: mmforc
template:
metadata:
labels:
app: openmatch
component: mmforc
spec:
containers:
- name: om-mmforc
image: gcr.io/open-match-public-images/openmatch-mmforc:dev
imagePullPolicy: Always
ports:
- name: metrics
containerPort: 9555
resources:
requests:
memory: 100Mi
cpu: 100m
env:
- name: METADATA_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace

View File

@ -1,19 +0,0 @@
{
"apiVersion": "rbac.authorization.k8s.io/v1beta1",
"kind": "ClusterRoleBinding",
"metadata": {
"name": "mmf-sa"
},
"subjects": [
{
"kind": "ServiceAccount",
"name": "default",
"namespace": "default"
}
],
"roleRef": {
"kind": "ClusterRole",
"name": "cluster-admin",
"apiGroup": "rbac.authorization.k8s.io"
}
}

View File

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: mmf-sa
subjects:
- kind: ServiceAccount
name: default
namespace: default
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io

View File

@ -1,53 +0,0 @@
{
"apiVersion":"extensions/v1beta1",
"kind":"Deployment",
"metadata":{
"name":"om-mmlogicapi",
"labels":{
"app":"openmatch",
"component": "mmlogic"
}
},
"spec":{
"replicas":1,
"selector":{
"matchLabels":{
"app":"openmatch",
"component": "mmlogic"
}
},
"template":{
"metadata":{
"labels":{
"app":"openmatch",
"component": "mmlogic"
}
},
"spec":{
"containers":[
{
"name":"om-mmlogic",
"image":"gcr.io/open-match-public-images/openmatch-mmlogicapi:dev",
"imagePullPolicy":"Always",
"ports": [
{
"name": "grpc",
"containerPort": 50503
},
{
"name": "metrics",
"containerPort": 9555
}
],
"resources":{
"requests":{
"memory":"100Mi",
"cpu":"100m"
}
}
}
]
}
}
}
}

View File

@ -0,0 +1,32 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: om-mmlogicapi
labels:
app: openmatch
component: mmlogic
spec:
replicas: 1
selector:
matchLabels:
app: openmatch
component: mmlogic
template:
metadata:
labels:
app: openmatch
component: mmlogic
spec:
containers:
- name: om-mmlogic
image: gcr.io/open-match-public-images/openmatch-mmlogicapi:dev
imagePullPolicy: Always
ports:
- name: grpc
containerPort: 50503
- name: metrics
containerPort: 9555
resources:
requests:
memory: 100Mi
cpu: 100m

View File

@ -1,20 +0,0 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "om-mmlogicapi"
},
"spec": {
"selector": {
"app": "openmatch",
"component": "mmlogic"
},
"ports": [
{
"protocol": "TCP",
"port": 50503,
"targetPort": "grpc"
}
]
}
}

View File

@ -0,0 +1,12 @@
kind: Service
apiVersion: v1
metadata:
name: om-mmlogicapi
spec:
selector:
app: openmatch
component: mmlogic
ports:
- protocol: TCP
port: 50503
targetPort: grpc

View File

@ -1,20 +0,0 @@
{
"apiVersion": "monitoring.coreos.com/v1",
"kind": "Prometheus",
"metadata": {
"name": "prometheus"
},
"spec": {
"serviceMonitorSelector": {
"matchLabels": {
"app": "openmatch"
}
},
"serviceAccountName": "prometheus",
"resources": {
"requests": {
"memory": "400Mi"
}
}
}
}

View File

@ -0,0 +1,12 @@
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
spec:
serviceMonitorSelector:
matchLabels:
app: openmatch
serviceAccountName: prometheus
resources:
requests:
memory: 400Mi

View File

@ -1,266 +0,0 @@
{
"apiVersion": "rbac.authorization.k8s.io/v1beta1",
"kind": "ClusterRoleBinding",
"metadata": {
"name": "prometheus-operator"
},
"roleRef": {
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": "prometheus-operator"
},
"subjects": [
{
"kind": "ServiceAccount",
"name": "prometheus-operator",
"namespace": "default"
}
]
}
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "prometheus"
}
}
{
"apiVersion": "rbac.authorization.k8s.io/v1beta1",
"kind": "ClusterRole",
"metadata": {
"name": "prometheus"
},
"rules": [
{
"apiGroups": [
""
],
"resources": [
"nodes",
"services",
"endpoints",
"pods"
],
"verbs": [
"get",
"list",
"watch"
]
},
{
"apiGroups": [
""
],
"resources": [
"configmaps"
],
"verbs": [
"get"
]
},
{
"nonResourceURLs": [
"/metrics"
],
"verbs": [
"get"
]
}
]
}
{
"apiVersion": "rbac.authorization.k8s.io/v1beta1",
"kind": "ClusterRoleBinding",
"metadata": {
"name": "prometheus"
},
"roleRef": {
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": "prometheus"
},
"subjects": [
{
"kind": "ServiceAccount",
"name": "prometheus",
"namespace": "default"
}
]
}
{
"apiVersion": "rbac.authorization.k8s.io/v1beta1",
"kind": "ClusterRole",
"metadata": {
"name": "prometheus-operator"
},
"rules": [
{
"apiGroups": [
"extensions"
],
"resources": [
"thirdpartyresources"
],
"verbs": [
"*"
]
},
{
"apiGroups": [
"apiextensions.k8s.io"
],
"resources": [
"customresourcedefinitions"
],
"verbs": [
"*"
]
},
{
"apiGroups": [
"monitoring.coreos.com"
],
"resources": [
"alertmanagers",
"prometheuses",
"prometheuses/finalizers",
"servicemonitors"
],
"verbs": [
"*"
]
},
{
"apiGroups": [
"apps"
],
"resources": [
"statefulsets"
],
"verbs": [
"*"
]
},
{
"apiGroups": [
""
],
"resources": [
"configmaps",
"secrets"
],
"verbs": [
"*"
]
},
{
"apiGroups": [
""
],
"resources": [
"pods"
],
"verbs": [
"list",
"delete"
]
},
{
"apiGroups": [
""
],
"resources": [
"services",
"endpoints"
],
"verbs": [
"get",
"create",
"update"
]
},
{
"apiGroups": [
""
],
"resources": [
"nodes"
],
"verbs": [
"list",
"watch"
]
},
{
"apiGroups": [
""
],
"resources": [
"namespaces"
],
"verbs": [
"list"
]
}
]
}
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"name": "prometheus-operator"
}
}
{
"apiVersion": "extensions/v1beta1",
"kind": "Deployment",
"metadata": {
"labels": {
"k8s-app": "prometheus-operator"
},
"name": "prometheus-operator"
},
"spec": {
"replicas": 1,
"template": {
"metadata": {
"labels": {
"k8s-app": "prometheus-operator"
}
},
"spec": {
"containers": [
{
"args": [
"--kubelet-service=kube-system/kubelet",
"--config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1"
],
"image": "quay.io/coreos/prometheus-operator:v0.17.0",
"name": "prometheus-operator",
"ports": [
{
"containerPort": 8080,
"name": "http"
}
],
"resources": {
"limits": {
"cpu": "200m",
"memory": "100Mi"
},
"requests": {
"cpu": "100m",
"memory": "50Mi"
}
}
}
],
"securityContext": {
"runAsNonRoot": true,
"runAsUser": 65534
},
"serviceAccountName": "prometheus-operator"
}
}
}
}

View File

@ -0,0 +1,166 @@
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: prometheus-operator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus-operator
subjects:
- kind: ServiceAccount
name: prometheus-operator
namespace: default
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: prometheus
rules:
- apiGroups:
- ''
resources:
- nodes
- services
- endpoints
- pods
verbs:
- get
- list
- watch
- apiGroups:
- ''
resources:
- configmaps
verbs:
- get
- nonResourceURLs:
- "/metrics"
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: prometheus
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus
subjects:
- kind: ServiceAccount
name: prometheus
namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
name: prometheus-operator
rules:
- apiGroups:
- extensions
resources:
- thirdpartyresources
verbs:
- "*"
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- "*"
- apiGroups:
- monitoring.coreos.com
resources:
- alertmanagers
- prometheuses
- prometheuses/finalizers
- servicemonitors
verbs:
- "*"
- apiGroups:
- apps
resources:
- statefulsets
verbs:
- "*"
- apiGroups:
- ''
resources:
- configmaps
- secrets
verbs:
- "*"
- apiGroups:
- ''
resources:
- pods
verbs:
- list
- delete
- apiGroups:
- ''
resources:
- services
- endpoints
verbs:
- get
- create
- update
- apiGroups:
- ''
resources:
- nodes
verbs:
- list
- watch
- apiGroups:
- ''
resources:
- namespaces
verbs:
- list
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus-operator
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
k8s-app: prometheus-operator
name: prometheus-operator
spec:
replicas: 1
template:
metadata:
labels:
k8s-app: prometheus-operator
spec:
containers:
- args:
- "--kubelet-service=kube-system/kubelet"
- "--config-reloader-image=quay.io/coreos/configmap-reload:v0.0.1"
image: quay.io/coreos/prometheus-operator:v0.17.0
name: prometheus-operator
ports:
- containerPort: 8080
name: http
resources:
limits:
cpu: 200m
memory: 100Mi
requests:
cpu: 100m
memory: 50Mi
securityContext:
runAsNonRoot: true
runAsUser: 65534
serviceAccountName: prometheus-operator

View File

@ -1,22 +0,0 @@
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"name": "prometheus"
},
"spec": {
"type": "NodePort",
"ports": [
{
"name": "web",
"nodePort": 30900,
"port": 9090,
"protocol": "TCP",
"targetPort": "web"
}
],
"selector": {
"prometheus": "prometheus"
}
}
}

View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: prometheus
spec:
type: NodePort
ports:
- name: web
nodePort: 30900
port: 9090
protocol: TCP
targetPort: web
selector:
prometheus: prometheus

View File

@ -1,38 +0,0 @@
{
"apiVersion": "extensions/v1beta1",
"kind": "Deployment",
"metadata": {
"name": "redis-master"
},
"spec": {
"selector": {
"matchLabels": {
"app": "mm",
"tier": "storage"
}
},
"replicas": 1,
"template": {
"metadata": {
"labels": {
"app": "mm",
"tier": "storage"
}
},
"spec": {
"containers": [
{
"name": "redis-master",
"image": "redis:4.0.11",
"ports": [
{
"name": "redis",
"containerPort": 6379
}
]
}
]
}
}
}
}

View File

@ -0,0 +1,22 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: redis-master
spec:
selector:
matchLabels:
app: mm
tier: storage
replicas: 1
template:
metadata:
labels:
app: mm
tier: storage
spec:
containers:
- name: redis-master
image: redis:4.0.11
ports:
- name: redis
containerPort: 6379

View File

@ -1,20 +0,0 @@
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "redis"
},
"spec": {
"selector": {
"app": "mm",
"tier": "storage"
},
"ports": [
{
"protocol": "TCP",
"port": 6379,
"targetPort": "redis"
}
]
}
}

View File

@ -0,0 +1,12 @@
kind: Service
apiVersion: v1
metadata:
name: redis
spec:
selector:
app: mm
tier: storage
ports:
- protocol: TCP
port: 6379
targetPort: redis

View File

@ -1,3 +1,7 @@
# Development Guide
This doc explains how to setup a development environment so you can get started contributing to Open Match. If you instead want to write a matchmaker that _uses_ Open Match, you probably want to read the [User Guide](user_guide.md).
# Compiling from source
All components of Open Match produce (Linux) Docker container images as artifacts, and there are included `Dockerfile`s for each. [Google Cloud Platform Cloud Build](https://cloud.google.com/cloud-build/docs/) users will also find `cloudbuild.yaml` files for each component in their respective directories. Note that most of them build from an 'base' image called `openmatch-devbase`. You can find a `Dockerfile` and `cloudbuild_base.yaml` file for this in the repository root. Build it first!
@ -11,11 +15,11 @@ Note: Although Google Cloud Platform includes some free usage, you may incur cha
**NOTE**: Before starting with this guide, you'll need to update all the URIs from the tutorial's gcr.io container image registry with the URI for your own image registry. If you are using the gcr.io registry on GCP, the default URI is `gcr.io/<PROJECT_NAME>`. Here's an example command in Linux to do the replacement for you this (replace YOUR_REGISTRY_URI with your URI, this should be run from the repository root directory):
```
# Linux
egrep -lR 'open-match-public-images' . | xargs sed -i -e 's|open-match-public-images|<PROJECT_NAME>|g'
egrep -lR 'matchmaker-dev-201405' . | xargs sed -i -e 's|matchmaker-dev-201405|<PROJECT_NAME>|g'
```
```
# Mac OS, you can delete the .backup files after if all looks good
egrep -lR 'open-match-public-images' . | xargs sed -i'.backup' -e 's|open-match-public-images|<PROJECT_NAME>|g'
egrep -lR 'matchmaker-dev-201405' . | xargs sed -i'.backup' -e 's|matchmaker-dev-201405|<PROJECT_NAME>|g'
```
## Example of building using Google Cloud Builder
@ -42,15 +46,15 @@ The [Quickstart for Docker](https://cloud.google.com/cloud-build/docs/quickstart
(your registry name will be different)
```
NAME
gcr.io/open-match-public-images/openmatch-backendapi
gcr.io/open-match-public-images/openmatch-devbase
gcr.io/open-match-public-images/openmatch-evaluator
gcr.io/open-match-public-images/openmatch-frontendapi
gcr.io/open-match-public-images/openmatch-mmf-golang-manual-simple
gcr.io/open-match-public-images/openmatch-mmf-php-mmlogic-simple
gcr.io/open-match-public-images/openmatch-mmf-py3-mmlogic-simple
gcr.io/open-match-public-images/openmatch-mmforc
gcr.io/open-match-public-images/openmatch-mmlogicapi
gcr.io/matchmaker-dev-201405/openmatch-backendapi
gcr.io/matchmaker-dev-201405/openmatch-devbase
gcr.io/matchmaker-dev-201405/openmatch-evaluator
gcr.io/matchmaker-dev-201405/openmatch-frontendapi
gcr.io/matchmaker-dev-201405/openmatch-mmf-golang-manual-simple
gcr.io/matchmaker-dev-201405/openmatch-mmf-php-mmlogic-simple
gcr.io/matchmaker-dev-201405/openmatch-mmf-py3-mmlogic-simple
gcr.io/matchmaker-dev-201405/openmatch-mmforc
gcr.io/matchmaker-dev-201405/openmatch-mmlogicapi
```
## Example of starting a GKE cluster
@ -76,24 +80,24 @@ The rest of this guide assumes you have a cluster (example is using GKE, but wor
* Start a copy of redis and a service in front of it:
```
kubectl apply -f redis_deployment.json
kubectl apply -f redis_service.json
kubectl apply -f redis_deployment.yaml
kubectl apply -f redis_service.yaml
```
* Run the **core components**: the frontend API, the backend API, the matchmaker function orchestrator (MMFOrc), and the matchmaking logic API.
**NOTE** In order to kick off jobs, the matchmaker function orchestrator needs a service account with permission to administer the cluster. This should be updated to have min required perms before launch, this is pretty permissive but acceptable for closed testing:
```
kubectl apply -f backendapi_deployment.json
kubectl apply -f backendapi_service.json
kubectl apply -f frontendapi_deployment.json
kubectl apply -f frontendapi_service.json
kubectl apply -f mmforc_deployment.json
kubectl apply -f mmforc_serviceaccount.json
kubectl apply -f mmlogicapi_deployment.json
kubectl apply -f mmlogicapi_service.json
kubectl apply -f backendapi_deployment.yaml
kubectl apply -f backendapi_service.yaml
kubectl apply -f frontendapi_deployment.yaml
kubectl apply -f frontendapi_service.yaml
kubectl apply -f mmforc_deployment.yaml
kubectl apply -f mmforc_serviceaccount.yaml
kubectl apply -f mmlogicapi_deployment.yaml
kubectl apply -f mmlogicapi_service.yaml
```
* [optional, but recommended] Configure the OpenCensus metrics services:
```
kubectl apply -f metrics_services.json
kubectl apply -f metrics_services.yaml
```
* [optional] Trying to apply the Kubernetes Prometheus Operator resource definition files without a cluster-admin rolebinding on GKE doesn't work without running the following command first. See https://github.com/coreos/prometheus-operator/issues/357
```
@ -102,10 +106,10 @@ The rest of this guide assumes you have a cluster (example is using GKE, but wor
* [optional, uses beta software] If using Prometheus as your metrics gathering backend, configure the [Prometheus Kubernetes Operator](https://github.com/coreos/prometheus-operator):
```
kubectl apply -f prometheus_operator.json
kubectl apply -f prometheus.json
kubectl apply -f prometheus_service.json
kubectl apply -f metrics_servicemonitor.json
kubectl apply -f prometheus_operator.yaml
kubectl apply -f prometheus.yaml
kubectl apply -f prometheus_service.yaml
kubectl apply -f metrics_servicemonitor.yaml
```
You should now be able to see the core component pods running using a `kubectl get pods`, and the core component metrics in the Prometheus Web UI by running `kubectl proxy <PROMETHEUS_POD_NAME> 9090:9090` in your local shell, then opening http://localhost:9090/targets in your browser to see which services Prometheus is collecting from.

View File

@ -11,7 +11,12 @@ All the usual guidance around hardening and securing Kubernetes are applicable t
* Note that the default MMForc process has cluster management permissions by default. Before moving to production, you should create a role with only access to create kubernetes jobs and configure the MMForc to use it.
### Kubernetes Jobs (MMFOrc)
The 0.3.0 MMFOrc component runs your MMFs as Kubernetes Jobs. You should periodically delete these jobs to keep the cluster running smoothly. How often you need to delete them is dependant on how many you are running. There are a number of open source solutions to do this for you. ***Note that once you delete the job, you won't have access to that job's logs anymore unless you're sending your logs from kubernetes to a log aggregator like Google Stackdriver. This can make it a challenge to troubleshoot issues***
### CPU and Memory limits
For any production Kubernetes deployment, it is good practice to profile your processes and select [resource limits and requests](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/) according to your results. For example, you'll likely want to set adequate resource requests based on your expected player base and some load testing for the Redis state storage pods. This will help Kubernetes avoid scheduling other intensive processes on the same underlying node and keep you from running into resource contention issues. Another example might be an MMF with a particularly large memory or CPU footprint - maybe you have one that searches a lot of players for a potential match. This would be a good candidate for resource limits and requests in Kubernetes to both ensure it gets the CPU and RAM it needs to complete quickly, and to make sure it's not scheduled alongside another intensive Kubernetes pod.
### State storage
The default state storage for Open Match is a _single instance_ of Redis. Although it _is_ possible to go to production with this as the solution if you're willing to accept the potential downsides, for most deployments, a HA Redis configuration would better fit your needs. An example YAML file for creating a [self-healing HA Redis deployment on Kubernetes](../install/yaml/01-redis-failover.yaml) is available. Regardless of which configuation you use, it is probably a good idea to put some [resource requests](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/) in your Kubernetes resource definition as mentioned above.
You can find more discussion in the [state storage readme doc](../internal/statestorage/redis/README.md).
## Open Match config
Debug logging and the extra debug code paths should be disabled in the `config/matchmaker_config.json` file (as of the time of this writing, 0.3.0).

16
examples/backendclient/Dockerfile Executable file → Normal file
View File

@ -1,8 +1,10 @@
#FROM golang:1.10.3 as builder
FROM gcr.io/open-match-public-images/openmatch-base:dev as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/examples/backendclient
COPY ./ ./
RUN go get -d -v
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o backendclient .
FROM open-match-base-build as builder
CMD ["./backendclient"]
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/examples/backendclient/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
FROM gcr.io/distroless/static
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/examples/backendclient/backendclient .
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/examples/backendclient/profiles profiles
ENTRYPOINT ["/backendclient"]

View File

@ -34,6 +34,7 @@ import (
backend "github.com/GoogleCloudPlatform/open-match/internal/pb"
"github.com/tidwall/gjson"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
)
func bytesToString(data []byte) string {
@ -125,7 +126,12 @@ func main() {
break
}
if err != nil {
log.Fatalf("Error reading stream for ListMatches(_) = _, %v", err)
stat, ok := status.FromError(err)
if ok {
log.Printf("Error reading stream for ListMatches() returned status: %s %s", stat.Code().String(), stat.Message())
} else {
log.Printf("Error reading stream for ListMatches() returned status: %s", err)
}
break
}
@ -154,7 +160,13 @@ func main() {
log.Printf("Waiting for matches...")
_, err = client.CreateAssignments(context.Background(), assign)
if err != nil {
log.Println(err)
stat, ok := status.FromError(err)
if ok {
log.Printf("Error reading stream for ListMatches() returned status: %s %s", stat.Code().String(), stat.Message())
} else {
log.Printf("Error reading stream for ListMatches() returned status: %s", err)
}
break
}
log.Println("Success! Not deleting assignments [demo mode].")

View File

@ -1,10 +1,9 @@
# Golang application builder steps
FROM gcr.io/open-match-public-images/openmatch-base:dev as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/examples/evaluators/golang/simple
COPY . .
RUN go get -d -v
FROM open-match-base-build as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/examples/evaluators/golang/simple/
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo .
#FROM scratch
#COPY --from=builder /go/src/github.com/GoogleCloudPlatform/mmfstub/mmfstub mmfstub
ENTRYPOINT ["./simple"]
FROM gcr.io/distroless/static
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/examples/evaluators/golang/simple/simple .
ENTRYPOINT ["/simple"]

0
examples/evaluators/golang/simple/cloudbuild.yaml Executable file → Normal file
View File

View File

@ -32,7 +32,9 @@ import (
"strings"
"time"
"github.com/GoogleCloudPlatform/open-match/config"
om_messages "github.com/GoogleCloudPlatform/open-match/internal/pb"
redishelpers "github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis"
"github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis/redispb"
"github.com/gobs/pretty"
"github.com/gomodule/redigo/redis"
@ -47,30 +49,18 @@ func main() {
// Read config
lgr.Println("Initializing config...")
cfg, err := readConfig("matchmaker_config", map[string]interface{}{
"REDIS_SERVICE_HOST": "redis",
"REDIS_SERVICE_PORT": "6379",
"auth": map[string]string{
// Read from k8s secret eventually
// Probably doesn't need a map, just here for reference
"password": "12fa",
},
})
cfg, err := config.Read()
if err != nil {
panic(nil)
}
// Connect to redis
// As per https://www.iana.org/assignments/uri-schemes/prov/redis
// redis://user:secret@localhost:6379/0?foo=bar&qux=baz // redis pool docs: https://godoc.org/github.com/gomodule/redigo/redis#Pool
redisURL := "redis://" + cfg.GetString("REDIS_SERVICE_HOST") + ":" + cfg.GetString("REDIS_SERVICE_PORT")
lgr.Println("Connecting to redis at", redisURL)
pool := redis.Pool{
MaxIdle: 3,
MaxActive: 0,
IdleTimeout: 60 * time.Second,
Dial: func() (redis.Conn, error) { return redis.DialURL(redisURL) },
pool, err := redishelpers.ConnectionPool(cfg)
if err != nil {
lgr.Fatal(err)
}
defer pool.Close()
redisConn := pool.Get()
defer redisConn.Close()
@ -82,7 +72,7 @@ func main() {
start := time.Now()
proposedMatchIds, overloadedPlayers, overloadedMatches, approvedMatches, err := stub(cfg, &pool)
proposedMatchIds, overloadedPlayers, overloadedMatches, approvedMatches, err := stub(cfg, pool)
overloadedPlayerList, overloadedMatchList, approvedMatchList := generateLists(overloadedPlayers, overloadedMatches, approvedMatches)
fmt.Println("overloadedPlayers")
@ -151,36 +141,6 @@ func chooseMatches(overloaded []int) ([]int, []int, error) {
return []int{}, overloaded, nil
}
func readConfig(filename string, defaults map[string]interface{}) (*viper.Viper, error) {
/*
Examples of redis-related env vars as written by k8s
REDIS_SENTINEL_PORT_6379_TCP=tcp://10.55.253.195:6379
REDIS_SENTINEL_PORT=tcp://10.55.253.195:6379
REDIS_SENTINEL_PORT_6379_TCP_ADDR=10.55.253.195
REDIS_SERVICE_PORT=6379
REDIS_SENTINEL_PORT_6379_TCP_PORT=6379
REDIS_SENTINEL_PORT_6379_TCP_PROTO=tcp
REDIS_SERVICE_HOST=10.55.253.195
*/
v := viper.New()
for key, value := range defaults {
v.SetDefault(key, value)
}
v.SetConfigName(filename)
v.SetConfigType("json")
v.AddConfigPath(".")
v.AutomaticEnv()
// Optional read from config if it exists
err := v.ReadInConfig()
if err != nil {
//lgr.Printf("error when reading config: %v\n", err)
//lgr.Println("continuing...")
err = nil
}
return v, err
}
func stub(cfg *viper.Viper, pool *redis.Pool) ([]string, map[string][]int, map[int][]int, map[int]bool, error) {
//Init Logger
lgr := log.New(os.Stdout, "MMFEvalStub: ", log.LstdFlags)

View File

@ -1 +0,0 @@
../../../../config/matchmaker_config.json

View File

@ -0,0 +1 @@
../../../../config/matchmaker_config.yaml

View File

@ -1,10 +1,9 @@
# Golang application builder steps
FROM gcr.io/open-match-public-images/openmatch-base:dev as builder
FROM open-match-base-build as builder
WORKDIR /go/src/github.com/GoogleCloudPlatform/open-match/examples/functions/golang/manual-simple
COPY . .
RUN go get -d -v
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o mmf .
#FROM scratch
#COPY --from=builder /go/src/github.com/GoogleCloudPlatform/mmfstub/mmfstub mmfstub
CMD ["./mmf"]
FROM gcr.io/distroless/static
COPY --from=builder /go/src/github.com/GoogleCloudPlatform/open-match/examples/functions/golang/manual-simple/mmf .
ENTRYPOINT ["/mmf"]

View File

@ -25,6 +25,7 @@ import (
"github.com/GoogleCloudPlatform/open-match/config"
messages "github.com/GoogleCloudPlatform/open-match/internal/pb"
"github.com/GoogleCloudPlatform/open-match/internal/set"
redishelpers "github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis"
"github.com/GoogleCloudPlatform/open-match/internal/statestorage/redis/ignorelist"
"github.com/gogo/protobuf/jsonpb"
"github.com/gomodule/redigo/redis"
@ -51,12 +52,17 @@ func main() {
// Read config file.
cfg := viper.New()
cfg, err := config.Read()
if err != nil {
panic(err)
}
// As per https://www.iana.org/assignments/uri-schemes/prov/redis
// redis://user:secret@localhost:6379/0?foo=bar&qux=baz
redisURL := "redis://" + os.Getenv("REDIS_SERVICE_HOST") + ":" + os.Getenv("REDIS_SERVICE_PORT")
fmt.Println("Connecting to Redis at", redisURL)
redisConn, err := redis.DialURL(redisURL)
pool, err := redishelpers.ConnectionPool(cfg)
if err != nil {
panic(err)
}
defer pool.Close()
redisConn := pool.Get()
if err != nil {
panic(err)
}
@ -64,7 +70,7 @@ func main() {
// decrement the number of running MMFs once finished
defer func() {
fmt.Println("DECR moncurrentMMFs")
fmt.Println("DECR concurrentMMFs")
_, err = redisConn.Do("DECR", "concurrentMMFs")
if err != nil {
fmt.Println(err)
@ -102,7 +108,7 @@ func main() {
// select players
const numPlayers = 8
// ZRANGE is 0-indexed
pools := gjson.Get(profile["properties"], cfg.GetString("jsonkeys.pools"))
pools := gjson.Get(profile["properties"], os.Getenv("JSONKEYS_POOLS"))
fmt.Println("=========Pools")
fmt.Printf("pool.String() = %+v\n", pools.String())
@ -204,7 +210,7 @@ func main() {
}
// Loop through each roster in the profile and fill in players.
rosters := gjson.Get(profile["properties"], cfg.GetString("jsonkeys.rosters"))
rosters := gjson.Get(profile["properties"], os.Getenv("JSONKEYS_ROSTERS"))
fmt.Println("=========Rosters")
fmt.Printf("rosters.String() = %+v\n", rosters.String())
@ -269,9 +275,9 @@ func main() {
// Not enough players, exit.
fmt.Println("Not enough players in the pool to fill all player slots in requested roster", rName)
fmt.Printf("%+v\n", roster.String())
fmt.Println("SET", errorKey, `{"error": "insufficient_players"}`)
redisConn.Do("SET", errorKey, `{"error": "insufficient_players"}`)
os.Exit(1)
fmt.Println("HSET", errorKey, "error", "insufficient_players")
redisConn.Do("HSET", errorKey, "error", "insufficient_players")
os.Exit(0)
}
}
@ -317,7 +323,7 @@ func main() {
// for backwards compatibility with backends that haven't been updated to take
// advantage of the new rosters field in the MatchObject protobuf message introduced
// in 0.2.0.
profile["properties"], err = sjson.Set(profile["properties"], cfg.GetString("jsonkeys.rosters"), proposedRosters.String())
profile["properties"], err = sjson.Set(profile["properties"], os.Getenv("JSONKEYS_ROSTERS"), proposedRosters.String())
profile["properties"] = strings.Replace(profile["properties"], "\\", "", -1)
profile["properties"] = strings.Replace(profile["properties"], "]\"", "]", -1)
profile["properties"] = strings.Replace(profile["properties"], "\"[", "[", -1)

View File

@ -1 +0,0 @@
../../../../config/matchmaker_config.json

View File

@ -0,0 +1 @@
../../../../config/matchmaker_config.yaml

View File

@ -11,9 +11,11 @@ RUN echo "extension=grpc.so" > /usr/local/etc/php/conf.d/30-grpc.ini
RUN pecl install protobuf
RUN echo "extension=protobuf.so" > /usr/local/etc/php/conf.d/30-protobuf.ini
WORKDIR /usr/src/open-match
COPY examples/functions/php/mmlogic-simple examples/functions/php/mmlogic-simple
COPY config config
RUN mkdir -p /usr/src/open-match/examples/functions/php/mmlogic-simple
COPY examples/functions/php/mmlogic-simple /usr/src/open-match/examples/functions/php/mmlogic-simple
# TODO: Remove embedding the config once loading configuration is normalized and this can respect the ConfigMap.
COPY config /usr/src/open-match/examples/functions/php/mmlogic-simple/config
WORKDIR /usr/src/open-match/examples/functions/php/mmlogic-simple
RUN composer install

View File

@ -10,12 +10,11 @@ function dump_pb_message($msg) {
print($msg->serializeToJsonString() . "\n");
}
# Load config file
$cfg = json_decode(file_get_contents('matchmaker_config.json'), true);
$debug = strtolower(trim(getenv('DEBUG'))) == 'true';
# Step 2 - Talk to Redis. This example uses the MM Logic API in OM to read/write to/from redis.
# Establish grpc channel and make the API client stub
$api_conn_info = sprintf('%s:%s', $cfg['api']['mmlogic']['hostname'], $cfg['api']['mmlogic']['port']);
$api_conn_info = sprintf('%s:%s', getenv('OM_MMLOGICAPI_SERVICE_HOST'), getenv('OM_MMLOGICAPI_SERVICE_PORT'));
$mmlogic_api = new Api\MmLogicClient($api_conn_info, [
'credentials' => Grpc\ChannelCredentials::createInsecure(),
@ -24,8 +23,8 @@ $mmlogic_api = new Api\MmLogicClient($api_conn_info, [
# Step 3 - Read the profile written to the Backend API.
# Get profile from redis
$match_object = new Messages\MatchObject([
'id' => getenv('MMF_PROFILE_ID'
)]);
'id' => getenv('MMF_PROFILE_ID')
]);
list($profile_pb, $status) = $mmlogic_api->GetProfile($match_object)->wait();
dump_pb_message($profile_pb);
@ -47,7 +46,7 @@ foreach ($profile_pb->getPools() as $empty_pool) {
$empty_pool->setStats(new Messages\Stats());
}
if ($cfg['debug']) {
if ($debug) {
$start = microtime(true);
}
@ -73,7 +72,7 @@ foreach ($profile_pb->getPools() as $empty_pool) {
}
}
}
if ($cfg['debug']) {
if ($debug) {
$end = microtime(true);
printf("\n'%s': count %06d | elapsed %0.3f\n", $empty_pool_name, count($player_pools[$empty_pool_name]), $end - $start);
}
@ -85,8 +84,7 @@ foreach ($profile_pb->getPools() as $empty_pool) {
$results = make_matches($profile_dict, $player_pools);
#################################################################
# DEBUG
if ($cfg['debug']) {
if (debug) {
print("======= match_properties\n");
var_export($results);
}
@ -101,7 +99,7 @@ $mo->setPools($profile_pb->getPools());
# Access the rosters in dict form within the properties json.
# It is stored at the key specified in the config file.
$rosters_dict = $results;
foreach (explode('.', $cfg['jsonkeys']['rosters']) as $partial_key) {
foreach (explode('.', getenv('JSONKEYS_ROSTERS')) as $partial_key) {
$rosters_dict = $rosters_dict[$partial_key] ?? [];
}
@ -112,8 +110,7 @@ foreach ($rosters_dict as $roster) {
$mo->getRosters() []= $r;
}
#DEBUG: writing to error key prevents evalutor run
if ($cfg['debug']) {
if ($debug) {
print("======== MMF results:\n");
dump_pb_message($mo);
}

View File

@ -1 +0,0 @@
../../../../config/matchmaker_config.json

View File

@ -1,5 +1,4 @@
# Golang application builder steps
FROM python:3.5.3 as builder
FROM python:3.5.3
WORKDIR /usr/src/open-match
COPY examples/functions/python3/mmlogic-simple examples/functions/python3/mmlogic-simple
COPY config config

View File

@ -1,18 +1,5 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: api/protobuf-spec/messages.proto
#Copyright 2018 Google LLC
#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
#
# https://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.
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
@ -32,64 +19,12 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='messages',
syntax='proto3',
serialized_options=_b('Z5github.com/GoogleCloudPlatform/open-match/internal/pb'),
serialized_pb=_b('\n api/protobuf-spec/messages.proto\x12\x08messages\"\\\n\x07Profile\x12\n\n\x02id\x18\x01 \x01(\t\x12\x12\n\nproperties\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12#\n\x05pools\x18\x04 \x03(\x0b\x32\x14.messages.PlayerPool\"\x84\x01\n\x0bMatchObject\x12\n\n\x02id\x18\x01 \x01(\t\x12\x12\n\nproperties\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12!\n\x07rosters\x18\x04 \x03(\x0b\x32\x10.messages.Roster\x12#\n\x05pools\x18\x05 \x03(\x0b\x32\x14.messages.PlayerPool\"9\n\x06Roster\x12\x0c\n\x04name\x18\x01 \x01(\t\x12!\n\x07players\x18\x02 \x03(\x0b\x32\x10.messages.Player\"e\n\x06\x46ilter\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\tattribute\x18\x02 \x01(\t\x12\x0c\n\x04maxv\x18\x03 \x01(\x03\x12\x0c\n\x04minv\x18\x04 \x01(\x03\x12\x1e\n\x05stats\x18\x05 \x01(\x0b\x32\x0f.messages.Stats\"\'\n\x05Stats\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\x12\x0f\n\x07\x65lapsed\x18\x02 \x01(\x01\"\x7f\n\nPlayerPool\x12\x0c\n\x04name\x18\x01 \x01(\t\x12!\n\x07\x66ilters\x18\x02 \x03(\x0b\x32\x10.messages.Filter\x12 \n\x06roster\x18\x03 \x01(\x0b\x32\x10.messages.Roster\x12\x1e\n\x05stats\x18\x04 \x01(\x0b\x32\x0f.messages.Stats\"\x90\x01\n\x06Player\x12\n\n\x02id\x18\x01 \x01(\t\x12\x12\n\nproperties\x18\x02 \x01(\t\x12\x0c\n\x04pool\x18\x03 \x01(\t\x12.\n\nattributes\x18\x04 \x03(\x0b\x32\x1a.messages.Player.Attribute\x1a(\n\tAttribute\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x03\"(\n\x06Result\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\t\n\x07IlInput\"\x17\n\tTimestamp\x12\n\n\x02ts\x18\x01 \x01(\x03\"+\n\x0e\x43onnectionInfo\x12\x19\n\x11\x63onnection_string\x18\x01 \x01(\t\"c\n\x0b\x41ssignments\x12!\n\x07rosters\x18\x01 \x03(\x0b\x32\x10.messages.Roster\x12\x31\n\x0f\x63onnection_info\x18\x02 \x01(\x0b\x32\x18.messages.ConnectionInfoB7Z5github.com/GoogleCloudPlatform/open-match/internal/pbb\x06proto3')
serialized_pb=_b('\n api/protobuf-spec/messages.proto\x12\x08messages\"\x94\x01\n\x0bMatchObject\x12\n\n\x02id\x18\x01 \x01(\t\x12\x12\n\nproperties\x18\x02 \x01(\t\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12!\n\x07rosters\x18\x04 \x03(\x0b\x32\x10.messages.Roster\x12#\n\x05pools\x18\x05 \x03(\x0b\x32\x14.messages.PlayerPool\x12\x0e\n\x06status\x18\x06 \x01(\t\"9\n\x06Roster\x12\x0c\n\x04name\x18\x01 \x01(\t\x12!\n\x07players\x18\x02 \x03(\x0b\x32\x10.messages.Player\"e\n\x06\x46ilter\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\tattribute\x18\x02 \x01(\t\x12\x0c\n\x04maxv\x18\x03 \x01(\x03\x12\x0c\n\x04minv\x18\x04 \x01(\x03\x12\x1e\n\x05stats\x18\x05 \x01(\x0b\x32\x0f.messages.Stats\"\'\n\x05Stats\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\x12\x0f\n\x07\x65lapsed\x18\x02 \x01(\x01\"\x7f\n\nPlayerPool\x12\x0c\n\x04name\x18\x01 \x01(\t\x12!\n\x07\x66ilters\x18\x02 \x03(\x0b\x32\x10.messages.Filter\x12 \n\x06roster\x18\x03 \x01(\x0b\x32\x10.messages.Roster\x12\x1e\n\x05stats\x18\x04 \x01(\x0b\x32\x0f.messages.Stats\"\xc3\x01\n\x06Player\x12\n\n\x02id\x18\x01 \x01(\t\x12\x12\n\nproperties\x18\x02 \x01(\t\x12\x0c\n\x04pool\x18\x03 \x01(\t\x12.\n\nattributes\x18\x04 \x03(\x0b\x32\x1a.messages.Player.Attribute\x12\x12\n\nassignment\x18\x05 \x01(\t\x12\x0e\n\x06status\x18\x06 \x01(\t\x12\r\n\x05\x65rror\x18\x07 \x01(\t\x1a(\n\tAttribute\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x03\"(\n\x06Result\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\r\n\x05\x65rror\x18\x02 \x01(\t\"\t\n\x07IlInput\"D\n\x0b\x41ssignments\x12!\n\x07rosters\x18\x01 \x03(\x0b\x32\x10.messages.Roster\x12\x12\n\nassignment\x18\n \x01(\t\"k\n\x07Request\x12\x12\n\nprofile_id\x18\x01 \x01(\t\x12\x13\n\x0bproposal_id\x18\x02 \x01(\t\x12\x12\n\nrequest_id\x18\x03 \x01(\t\x12\x10\n\x08\x65rror_id\x18\x04 \x01(\t\x12\x11\n\ttimestamp\x18\x05 \x01(\t\"[\n\tArguments\x12\"\n\x07request\x18\x01 \x01(\x0b\x32\x11.messages.Request\x12*\n\x0bmatchobject\x18\x02 \x01(\x0b\x32\x15.messages.MatchObjectB7Z5github.com/GoogleCloudPlatform/open-match/internal/pbb\x06proto3')
)
_PROFILE = _descriptor.Descriptor(
name='Profile',
full_name='messages.Profile',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='id', full_name='messages.Profile.id', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='properties', full_name='messages.Profile.properties', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='name', full_name='messages.Profile.name', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='pools', full_name='messages.Profile.pools', index=3,
number=4, type=11, cpp_type=10, label=3,
has_default_value=False, default_value=[],
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=46,
serialized_end=138,
)
_MATCHOBJECT = _descriptor.Descriptor(
name='MatchObject',
full_name='messages.MatchObject',
@ -132,6 +67,13 @@ _MATCHOBJECT = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='status', full_name='messages.MatchObject.status', index=5,
number=6, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@ -144,8 +86,8 @@ _MATCHOBJECT = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=141,
serialized_end=273,
serialized_start=47,
serialized_end=195,
)
@ -182,8 +124,8 @@ _ROSTER = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=275,
serialized_end=332,
serialized_start=197,
serialized_end=254,
)
@ -241,8 +183,8 @@ _FILTER = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=334,
serialized_end=435,
serialized_start=256,
serialized_end=357,
)
@ -279,8 +221,8 @@ _STATS = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=437,
serialized_end=476,
serialized_start=359,
serialized_end=398,
)
@ -331,8 +273,8 @@ _PLAYERPOOL = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=478,
serialized_end=605,
serialized_start=400,
serialized_end=527,
)
@ -369,8 +311,8 @@ _PLAYER_ATTRIBUTE = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=712,
serialized_end=752,
serialized_start=685,
serialized_end=725,
)
_PLAYER = _descriptor.Descriptor(
@ -408,6 +350,27 @@ _PLAYER = _descriptor.Descriptor(
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='assignment', full_name='messages.Player.assignment', index=4,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='status', full_name='messages.Player.status', index=5,
number=6, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='error', full_name='messages.Player.error', index=6,
number=7, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
@ -420,8 +383,8 @@ _PLAYER = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=608,
serialized_end=752,
serialized_start=530,
serialized_end=725,
)
@ -458,8 +421,8 @@ _RESULT = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=754,
serialized_end=794,
serialized_start=727,
serialized_end=767,
)
@ -482,70 +445,8 @@ _ILINPUT = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=796,
serialized_end=805,
)
_TIMESTAMP = _descriptor.Descriptor(
name='Timestamp',
full_name='messages.Timestamp',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='ts', full_name='messages.Timestamp.ts', index=0,
number=1, type=3, cpp_type=2, label=1,
has_default_value=False, default_value=0,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=807,
serialized_end=830,
)
_CONNECTIONINFO = _descriptor.Descriptor(
name='ConnectionInfo',
full_name='messages.ConnectionInfo',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='connection_string', full_name='messages.ConnectionInfo.connection_string', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=832,
serialized_end=875,
serialized_start=769,
serialized_end=778,
)
@ -564,7 +465,104 @@ _ASSIGNMENTS = _descriptor.Descriptor(
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='connection_info', full_name='messages.Assignments.connection_info', index=1,
name='assignment', full_name='messages.Assignments.assignment', index=1,
number=10, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=780,
serialized_end=848,
)
_REQUEST = _descriptor.Descriptor(
name='Request',
full_name='messages.Request',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='profile_id', full_name='messages.Request.profile_id', index=0,
number=1, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='proposal_id', full_name='messages.Request.proposal_id', index=1,
number=2, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='request_id', full_name='messages.Request.request_id', index=2,
number=3, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='error_id', full_name='messages.Request.error_id', index=3,
number=4, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='timestamp', full_name='messages.Request.timestamp', index=4,
number=5, type=9, cpp_type=9, label=1,
has_default_value=False, default_value=_b("").decode('utf-8'),
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
],
extensions=[
],
nested_types=[],
enum_types=[
],
serialized_options=None,
is_extendable=False,
syntax='proto3',
extension_ranges=[],
oneofs=[
],
serialized_start=850,
serialized_end=957,
)
_ARGUMENTS = _descriptor.Descriptor(
name='Arguments',
full_name='messages.Arguments',
filename=None,
file=DESCRIPTOR,
containing_type=None,
fields=[
_descriptor.FieldDescriptor(
name='request', full_name='messages.Arguments.request', index=0,
number=1, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
is_extension=False, extension_scope=None,
serialized_options=None, file=DESCRIPTOR),
_descriptor.FieldDescriptor(
name='matchobject', full_name='messages.Arguments.matchobject', index=1,
number=2, type=11, cpp_type=10, label=1,
has_default_value=False, default_value=None,
message_type=None, enum_type=None, containing_type=None,
@ -582,11 +580,10 @@ _ASSIGNMENTS = _descriptor.Descriptor(
extension_ranges=[],
oneofs=[
],
serialized_start=877,
serialized_end=976,
serialized_start=959,
serialized_end=1050,
)
_PROFILE.fields_by_name['pools'].message_type = _PLAYERPOOL
_MATCHOBJECT.fields_by_name['rosters'].message_type = _ROSTER
_MATCHOBJECT.fields_by_name['pools'].message_type = _PLAYERPOOL
_ROSTER.fields_by_name['players'].message_type = _PLAYER
@ -597,8 +594,8 @@ _PLAYERPOOL.fields_by_name['stats'].message_type = _STATS
_PLAYER_ATTRIBUTE.containing_type = _PLAYER
_PLAYER.fields_by_name['attributes'].message_type = _PLAYER_ATTRIBUTE
_ASSIGNMENTS.fields_by_name['rosters'].message_type = _ROSTER
_ASSIGNMENTS.fields_by_name['connection_info'].message_type = _CONNECTIONINFO
DESCRIPTOR.message_types_by_name['Profile'] = _PROFILE
_ARGUMENTS.fields_by_name['request'].message_type = _REQUEST
_ARGUMENTS.fields_by_name['matchobject'].message_type = _MATCHOBJECT
DESCRIPTOR.message_types_by_name['MatchObject'] = _MATCHOBJECT
DESCRIPTOR.message_types_by_name['Roster'] = _ROSTER
DESCRIPTOR.message_types_by_name['Filter'] = _FILTER
@ -607,18 +604,11 @@ DESCRIPTOR.message_types_by_name['PlayerPool'] = _PLAYERPOOL
DESCRIPTOR.message_types_by_name['Player'] = _PLAYER
DESCRIPTOR.message_types_by_name['Result'] = _RESULT
DESCRIPTOR.message_types_by_name['IlInput'] = _ILINPUT
DESCRIPTOR.message_types_by_name['Timestamp'] = _TIMESTAMP
DESCRIPTOR.message_types_by_name['ConnectionInfo'] = _CONNECTIONINFO
DESCRIPTOR.message_types_by_name['Assignments'] = _ASSIGNMENTS
DESCRIPTOR.message_types_by_name['Request'] = _REQUEST
DESCRIPTOR.message_types_by_name['Arguments'] = _ARGUMENTS
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
Profile = _reflection.GeneratedProtocolMessageType('Profile', (_message.Message,), dict(
DESCRIPTOR = _PROFILE,
__module__ = 'api.protobuf_spec.messages_pb2'
# @@protoc_insertion_point(class_scope:messages.Profile)
))
_sym_db.RegisterMessage(Profile)
MatchObject = _reflection.GeneratedProtocolMessageType('MatchObject', (_message.Message,), dict(
DESCRIPTOR = _MATCHOBJECT,
__module__ = 'api.protobuf_spec.messages_pb2'
@ -683,20 +673,6 @@ IlInput = _reflection.GeneratedProtocolMessageType('IlInput', (_message.Message,
))
_sym_db.RegisterMessage(IlInput)
Timestamp = _reflection.GeneratedProtocolMessageType('Timestamp', (_message.Message,), dict(
DESCRIPTOR = _TIMESTAMP,
__module__ = 'api.protobuf_spec.messages_pb2'
# @@protoc_insertion_point(class_scope:messages.Timestamp)
))
_sym_db.RegisterMessage(Timestamp)
ConnectionInfo = _reflection.GeneratedProtocolMessageType('ConnectionInfo', (_message.Message,), dict(
DESCRIPTOR = _CONNECTIONINFO,
__module__ = 'api.protobuf_spec.messages_pb2'
# @@protoc_insertion_point(class_scope:messages.ConnectionInfo)
))
_sym_db.RegisterMessage(ConnectionInfo)
Assignments = _reflection.GeneratedProtocolMessageType('Assignments', (_message.Message,), dict(
DESCRIPTOR = _ASSIGNMENTS,
__module__ = 'api.protobuf_spec.messages_pb2'
@ -704,6 +680,20 @@ Assignments = _reflection.GeneratedProtocolMessageType('Assignments', (_message.
))
_sym_db.RegisterMessage(Assignments)
Request = _reflection.GeneratedProtocolMessageType('Request', (_message.Message,), dict(
DESCRIPTOR = _REQUEST,
__module__ = 'api.protobuf_spec.messages_pb2'
# @@protoc_insertion_point(class_scope:messages.Request)
))
_sym_db.RegisterMessage(Request)
Arguments = _reflection.GeneratedProtocolMessageType('Arguments', (_message.Message,), dict(
DESCRIPTOR = _ARGUMENTS,
__module__ = 'api.protobuf_spec.messages_pb2'
# @@protoc_insertion_point(class_scope:messages.Arguments)
))
_sym_db.RegisterMessage(Arguments)
DESCRIPTOR._options = None
# @@protoc_insertion_point(module_scope)

View File

@ -1,16 +1,3 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
#Copyright 2018 Google LLC
#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
#
# https://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.
import grpc

View File

@ -1,17 +1,5 @@
# Generated by the protocol buffer compiler. DO NOT EDIT!
# source: api/protobuf-spec/mmlogic.proto
#Copyright 2018 Google LLC
#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
#
# https://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.
import sys
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
@ -32,7 +20,7 @@ DESCRIPTOR = _descriptor.FileDescriptor(
package='api',
syntax='proto3',
serialized_options=_b('Z5github.com/GoogleCloudPlatform/open-match/internal/pb'),
serialized_pb=_b('\n\x1f\x61pi/protobuf-spec/mmlogic.proto\x12\x03\x61pi\x1a api/protobuf-spec/messages.proto2\xf6\x02\n\x07MmLogic\x12<\n\nGetProfile\x12\x15.messages.MatchObject\x1a\x15.messages.MatchObject\"\x00\x12;\n\x0e\x43reateProposal\x12\x15.messages.MatchObject\x1a\x10.messages.Result\"\x00\x12\x33\n\x0bReturnError\x12\x10.messages.Result\x1a\x10.messages.Result\"\x00\x12?\n\rGetPlayerPool\x12\x14.messages.PlayerPool\x1a\x14.messages.PlayerPool\"\x00\x30\x01\x12=\n\x14GetAllIgnoredPlayers\x12\x11.messages.IlInput\x1a\x10.messages.Roster\"\x00\x12;\n\x12ListIgnoredPlayers\x12\x11.messages.IlInput\x1a\x10.messages.Roster\"\x00\x42\x37Z5github.com/GoogleCloudPlatform/open-match/internal/pbb\x06proto3')
serialized_pb=_b('\n\x1f\x61pi/protobuf-spec/mmlogic.proto\x12\x03\x61pi\x1a api/protobuf-spec/messages.proto2\xc1\x02\n\x07MmLogic\x12<\n\nGetProfile\x12\x15.messages.MatchObject\x1a\x15.messages.MatchObject\"\x00\x12;\n\x0e\x43reateProposal\x12\x15.messages.MatchObject\x1a\x10.messages.Result\"\x00\x12?\n\rGetPlayerPool\x12\x14.messages.PlayerPool\x1a\x14.messages.PlayerPool\"\x00\x30\x01\x12=\n\x14GetAllIgnoredPlayers\x12\x11.messages.IlInput\x1a\x10.messages.Roster\"\x00\x12;\n\x12ListIgnoredPlayers\x12\x11.messages.IlInput\x1a\x10.messages.Roster\"\x00\x42\x37Z5github.com/GoogleCloudPlatform/open-match/internal/pbb\x06proto3')
,
dependencies=[api_dot_protobuf__spec_dot_messages__pb2.DESCRIPTOR,])
@ -50,7 +38,7 @@ _MMLOGIC = _descriptor.ServiceDescriptor(
index=0,
serialized_options=None,
serialized_start=75,
serialized_end=449,
serialized_end=396,
methods=[
_descriptor.MethodDescriptor(
name='GetProfile',
@ -70,19 +58,10 @@ _MMLOGIC = _descriptor.ServiceDescriptor(
output_type=api_dot_protobuf__spec_dot_messages__pb2._RESULT,
serialized_options=None,
),
_descriptor.MethodDescriptor(
name='ReturnError',
full_name='api.MmLogic.ReturnError',
index=2,
containing_service=None,
input_type=api_dot_protobuf__spec_dot_messages__pb2._RESULT,
output_type=api_dot_protobuf__spec_dot_messages__pb2._RESULT,
serialized_options=None,
),
_descriptor.MethodDescriptor(
name='GetPlayerPool',
full_name='api.MmLogic.GetPlayerPool',
index=3,
index=2,
containing_service=None,
input_type=api_dot_protobuf__spec_dot_messages__pb2._PLAYERPOOL,
output_type=api_dot_protobuf__spec_dot_messages__pb2._PLAYERPOOL,
@ -91,7 +70,7 @@ _MMLOGIC = _descriptor.ServiceDescriptor(
_descriptor.MethodDescriptor(
name='GetAllIgnoredPlayers',
full_name='api.MmLogic.GetAllIgnoredPlayers',
index=4,
index=3,
containing_service=None,
input_type=api_dot_protobuf__spec_dot_messages__pb2._ILINPUT,
output_type=api_dot_protobuf__spec_dot_messages__pb2._ROSTER,
@ -100,7 +79,7 @@ _MMLOGIC = _descriptor.ServiceDescriptor(
_descriptor.MethodDescriptor(
name='ListIgnoredPlayers',
full_name='api.MmLogic.ListIgnoredPlayers',
index=5,
index=4,
containing_service=None,
input_type=api_dot_protobuf__spec_dot_messages__pb2._ILINPUT,
output_type=api_dot_protobuf__spec_dot_messages__pb2._ROSTER,

View File

@ -1,25 +1,14 @@
# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
#Copyright 2018 Google LLC
#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
#
# https://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.
import grpc
from api.protobuf_spec import messages_pb2 as api_dot_protobuf__spec_dot_messages__pb2
class MmLogicStub(object):
"""Profile and match object functions
If your matchmaking logic makes a match, it should CreateProposal. If it
cannot, it should ReturnError.
"""The MMLogic API provides utility functions for common MMF functionality, such
as retreiving profiles and players from state storage, writing results to state storage,
and exposing metrics and statistics.
Profile and match object functions
"""
def __init__(self, channel):
@ -38,11 +27,6 @@ class MmLogicStub(object):
request_serializer=api_dot_protobuf__spec_dot_messages__pb2.MatchObject.SerializeToString,
response_deserializer=api_dot_protobuf__spec_dot_messages__pb2.Result.FromString,
)
self.ReturnError = channel.unary_unary(
'/api.MmLogic/ReturnError',
request_serializer=api_dot_protobuf__spec_dot_messages__pb2.Result.SerializeToString,
response_deserializer=api_dot_protobuf__spec_dot_messages__pb2.Result.FromString,
)
self.GetPlayerPool = channel.unary_stream(
'/api.MmLogic/GetPlayerPool',
request_serializer=api_dot_protobuf__spec_dot_messages__pb2.PlayerPool.SerializeToString,
@ -61,9 +45,10 @@ class MmLogicStub(object):
class MmLogicServicer(object):
"""Profile and match object functions
If your matchmaking logic makes a match, it should CreateProposal. If it
cannot, it should ReturnError.
"""The MMLogic API provides utility functions for common MMF functionality, such
as retreiving profiles and players from state storage, writing results to state storage,
and exposing metrics and statistics.
Profile and match object functions
"""
def GetProfile(self, request, context):
@ -77,27 +62,49 @@ class MmLogicServicer(object):
raise NotImplementedError('Method not implemented!')
def CreateProposal(self, request, context):
"""CreateProposal does the following:
- adds all players in the Roster to the proposed player ignore list
"""CreateProposal is called by MMFs that wish to write their results to
a proposed MatchObject, that can be sent out the Backend API once it has
been approved (by default, by the evaluator process).
- adds all players in all Rosters to the proposed player ignore list
- writes the proposed match to the provided key
- adds that key to the list of proposals to be considered
INPUT:
* TO RETURN A MATCHOBJECT AFTER A SUCCESSFUL MMF RUN
To create a match MatchObject message with these fields populated:
- id, set to the value of the MMF_PROPOSAL_ID env var
- properties
- error. You must explicitly set this to an empty string if your MMF
- roster, with the playerIDs filled in the 'players' repeated field.
- [optional] pools, set to the output from the 'GetPlayerPools' call,
will populate the pools with stats about how many players the filters
matched and how long the filters took to run, which will be sent out
the backend api along with your match results.
was successful.
* TO RETURN AN ERROR
To report a failure or error, send a MatchObject message with these
these fields populated:
- id, set to the value of the MMF_ERROR_ID env var.
- error, set to a string value describing the error your MMF encountered.
- [optional] properties, anything you put here is returned to the
backend along with your error.
- [optional] rosters, anything you put here is returned to the
backend along with your error.
- [optional] pools, set to the output from the 'GetPlayerPools' call,
will populate the pools with stats about how many players the filters
matched and how long the filters took to run, which will be sent out
the backend api along with your match results.
OUTPUT: a Result message with a boolean success value and an error string
if an error was encountered
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def ReturnError(self, request, context):
# missing associated documentation comment in .proto file
pass
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
raise NotImplementedError('Method not implemented!')
def GetPlayerPool(self, request, context):
"""Player listing and filtering functions
RetrievePlayerPool gets the list of players for every Filter in the
PlayerPool, and then removes all players it finds in the ignore list. It
RetrievePlayerPool gets the list of players that match every Filter in the
PlayerPool, .excluding players in any configured ignore lists. It
combines the results, and returns the resulting player pool.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@ -114,8 +121,8 @@ class MmLogicServicer(object):
raise NotImplementedError('Method not implemented!')
def ListIgnoredPlayers(self, request, context):
"""RetrieveIgnoreList retrieves players from the ignore list specified in the
config file under 'ignoreLists.proposedPlayers.key'.
"""ListIgnoredPlayers retrieves players from the ignore list specified in the
config file under 'ignoreLists.proposed.name'.
"""
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
context.set_details('Method not implemented!')
@ -134,11 +141,6 @@ def add_MmLogicServicer_to_server(servicer, server):
request_deserializer=api_dot_protobuf__spec_dot_messages__pb2.MatchObject.FromString,
response_serializer=api_dot_protobuf__spec_dot_messages__pb2.Result.SerializeToString,
),
'ReturnError': grpc.unary_unary_rpc_method_handler(
servicer.ReturnError,
request_deserializer=api_dot_protobuf__spec_dot_messages__pb2.Result.FromString,
response_serializer=api_dot_protobuf__spec_dot_messages__pb2.Result.SerializeToString,
),
'GetPlayerPool': grpc.unary_stream_rpc_method_handler(
servicer.GetPlayerPool,
request_deserializer=api_dot_protobuf__spec_dot_messages__pb2.PlayerPool.FromString,

View File

@ -26,14 +26,9 @@ import pprint as pp
from timeit import default_timer as timer
# Load config file
cfg = ''
with open("matchmaker_config.json") as f:
cfg = json.loads(f.read())
# Step 2 - Talk to Redis. This example uses the MM Logic API in OM to read/write to/from redis.
# Establish grpc channel and make the API client stub
api_conn_info = "%s:%d" % (cfg['api']['mmlogic']['hostname'], cfg['api']['mmlogic']['port'])
api_conn_info = "%s:%d" % (os.environ["OM_MMLOGICAPI_SERVICE_HOST"],os.environ["OM_MMLOGICAPI_SERVICE_PORT"])
with grpc.insecure_channel(api_conn_info) as channel:
mmlogic_api = mmlogic_pb2_grpc.MmLogicStub(channel)
@ -54,7 +49,7 @@ with grpc.insecure_channel(api_conn_info) as channel:
print("Retrieving pool '%s'" % empty_pool.name, end='')
# DEBUG: Print how long the filtering takes
if cfg['debug']:
if os.environ["DEBUG"]:
start = timer()
# Pool filter results are streamed in chunks as they can be too large to send
@ -71,9 +66,13 @@ with grpc.insecure_channel(api_conn_info) as channel:
player_pools[empty_pool.name][player.id][attr.name] = attr.value
except Exception as err:
print("Error encountered: %s" % err)
if cfg['debug']:
if os.environ["DEBUG"]:
print("\n'%s': count %06d | elapsed %0.3f" % (empty_pool.name, len(player_pools[empty_pool.name]),timer() - start))
num_players_total = 0
for _, pool in player_pools.items():
num_players_total += len(pool)
#################################################################
# Step 5 - Run custom matchmaking logic to try to find a match
# This is in the file mmf.py
@ -81,7 +80,7 @@ with grpc.insecure_channel(api_conn_info) as channel:
#################################################################
# DEBUG
if cfg['debug']:
if os.environ["DEBUG"]:
print("======== match_properties")
pp.pprint(results)
@ -95,7 +94,7 @@ with grpc.insecure_channel(api_conn_info) as channel:
# Access the rosters in dict form within the properties json.
# It is stored at the key specified in the config file.
rosters_dict = results
for partial_key in cfg['jsonkeys']['rosters'].split('.'):
for partial_key in os.environ["JSONKEYS_ROSTERS"].split('.'):
rosters_dict = rosters_dict.get(partial_key, {})
# Unmarshal the rosters into the MatchObject
@ -103,13 +102,20 @@ with grpc.insecure_channel(api_conn_info) as channel:
mo.rosters.extend([Parse(json.dumps(roster), mmlogic.Roster(), ignore_unknown_fields=True)])
#DEBUG: writing to error key prevents evalutor run
if cfg['debug']:
if os.environ["DEBUG"]:
#mo.id = os.environ["MMF_ERROR_ID"]
#mo.error = "skip evaluator"
print("======== MMF results:")
pp.pprint(mo)
# Step 6 - Write the outcome of the matchmaking logic back to state storage.
# Return error when there are no players in the pools
if num_players_total == 0:
if cfg['debug']:
print("All player pools are empty, writing to error to skip the evaluator")
mo.id = os.environ["MMF_ERROR_ID"]
mo.error = "insufficient players"
# Step 6 - Write the outcome of the matchmaking logic back to state storage.
# Step 7 - Remove the selected players from consideration by other MMFs.
# CreateProposal does both of these for you, and some other items as well.
success = mmlogic_api.CreateProposal(mo)

View File

@ -1 +0,0 @@
../../../../config/matchmaker_config.json

View File

@ -31,9 +31,13 @@ def makeMatches(profile_dict, player_pools):
for roster in profile_dict['properties']['rosters']:
for player in roster['players']:
if 'pool' in player:
player['id'] = random.choice(list(player_pools[player['pool']]))
del player_pools[player['pool']][player['id']]
print("Selected player %s from pool %s (strategy: RANDOM)" % (player['id'], player['pool']))
player_pool = list(player_pools[player['pool']])
if len(player_pool) > 0:
player['id'] = random.choice(player_pool)
del player_pools[player['pool']][player['id']]
print("Selected player %s from pool %s (strategy: RANDOM)" % (player['id'], player['pool']))
else:
print("Player pool %s is empty (roster %s)" % (player['pool'], roster['name']))
else:
print(player)
return profile_dict

39
go.mod Normal file
View File

@ -0,0 +1,39 @@
module github.com/GoogleCloudPlatform/open-match
go 1.12
require (
github.com/TV4/logrus-stackdriver-formatter v0.1.0
github.com/cenkalti/backoff v2.1.1+incompatible
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b
github.com/gogo/protobuf v1.2.1
github.com/golang/protobuf v1.3.0
github.com/gomodule/redigo v1.7.0
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf // indirect
github.com/googleapis/gnostic v0.2.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc // indirect
github.com/json-iterator/go v1.1.6 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1
github.com/rs/xid v1.2.1
github.com/sirupsen/logrus v1.4.0
github.com/spf13/viper v1.3.2
github.com/tidwall/gjson v1.2.1
github.com/tidwall/match v1.0.1 // indirect
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 // indirect
github.com/tidwall/sjson v1.0.4
go.opencensus.io v0.19.1
golang.org/x/net v0.0.0-20190313082753-5c2c250b6a70
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
google.golang.org/grpc v1.19.0
gopkg.in/inf.v0 v0.9.1 // indirect
k8s.io/api v0.0.0-20190222213804-5cb15d344471
k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628
k8s.io/client-go v10.0.0+incompatible
k8s.io/klog v0.2.0 // indirect
sigs.k8s.io/yaml v1.1.0 // indirect
)

205
go.sum Normal file
View File

@ -0,0 +1,205 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/TV4/logrus-stackdriver-formatter v0.1.0 h1:nFea8RiX7ecTnWPM+9FIqwZYJdcGo58CHMGIVdYzMXg=
github.com/TV4/logrus-stackdriver-formatter v0.1.0/go.mod h1:wwS7hOiBvP6SBD0UXCa767+VhHkaXrfX0MzUojYcN0Q=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY=
github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b h1:/vQ+oYKu+JoyaMPDsv5FzwuL2wwWBgBbtj/YLCi4LuA=
github.com/gobs/pretty v0.0.0-20180724170744-09732c25a95b/go.mod h1:Xo4aNUOrJnVruqWQJBtW6+bTBDTniY8yZum5rF3b5jw=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0 h1:kbxbvI4Un1LUWKxufD+BiE6AEExYYgkQLQmLFqA1LFk=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/gomodule/redigo v1.7.0 h1:ZKld1VOtsGhAe37E7wMxEDgAlGM5dvFY+DiOhSkhP9Y=
github.com/gomodule/redigo v1.7.0/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/googleapis/gnostic v0.2.0 h1:l6N3VoaVzTncYYW+9yOz2LJJammFZGBO13sqgEhpy9g=
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc h1:f8eY6cV/x1x+HLjOp4r72s/31/V2aTUtg5oKRRPf8/Q=
github.com/gregjones/httpcache v0.0.0-20190212212710-3befbb6ad0cc/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 h1:D+CiwcpGTW6pL6bv6KI3KbyEyCKyS+1JWS2h8PNDnGA=
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f h1:BVwpUVJDADN2ufcGik7W992pyps0wZ888b/y9GXcLTU=
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1 h1:+kGqA4dNN5hn7WwvKdzHl0rdN5AEkbNZd0VjRltAiZg=
github.com/rafaeljusto/redigomock v0.0.0-20190202135759-257e089e14a1/go.mod h1:JaY6n2sDr+z2WTsXkOmNRUfDy6FN0L6Nk7x06ndm4tY=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.0 h1:yKenngtzGh+cUSSh6GWbxW2abRqhYUSR/t/6+2QqNvE=
github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/tidwall/gjson v1.2.1 h1:j0efZLrZUvNerEf6xqoi0NjWMK5YlLrR7Guo/dxY174=
github.com/tidwall/gjson v1.2.1/go.mod h1:c/nTNbUr0E0OrXEhq1pwa8iEgc2DOt4ZZqAt1HtCkPA=
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51 h1:BP2bjP495BBPaBcS5rmqviTfrOkN5rO5ceKAMRZCRFc=
github.com/tidwall/pretty v0.0.0-20180105212114-65a9db5fad51/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tidwall/sjson v1.0.4 h1:UcdIRXff12Lpnu3OLtZvnc03g4vH2suXDXhBwBqmzYg=
github.com/tidwall/sjson v1.0.4/go.mod h1:bURseu1nuBkFpIES5cz6zBtjmYeOQmEESshn7VpF15Y=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
go.opencensus.io v0.19.1 h1:gPYKQ/GAQYR2ksU+qXNmq3CrOZWT1kkryvW6O0v1acY=
go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190313082753-5c2c250b6a70 h1:0OwHPyvXNyZS9VW4XXoGkWOwhrMN52Y4n/gSxvJOgj0=
golang.org/x/net v0.0.0-20190313082753-5c2c250b6a70/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.3.0 h1:FBSsiFRMz3LBeXIomRnVzrQwSDj4ibvcRexLG0LZGQk=
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb h1:dQshZyyJ5W/Xk8myF4GKBak1pZW6EywJuQ8+44EQhGA=
google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg=
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20190222213804-5cb15d344471 h1:MzQGt8qWQCR+39kbYRd0uQqsvSidpYqJLFeWiJ9l4OE=
k8s.io/api v0.0.0-20190222213804-5cb15d344471/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628 h1:UYfHH+KEF88OTg+GojQUwFTNxbxwmoktLwutUzR0GPg=
k8s.io/apimachinery v0.0.0-20190221213512-86fb29eff628/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
k8s.io/apimachinery v0.0.0-20190313115320-c9defaaddf6f h1:6ojhffWUv9DZ8i4L2LIvSjbWH3fXfP6PmrTNwXHHMhM=
k8s.io/client-go v10.0.0+incompatible h1:F1IqCqw7oMBzDkqlcBymRq1450wD0eNqLE9jzUrIi34=
k8s.io/client-go v10.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
k8s.io/klog v0.2.0 h1:0ElL0OHzF3N+OhoJTL0uca20SxtYt4X4+bzHeqrB83c=
k8s.io/klog v0.2.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=

24
install/helm/README.md Normal file
View File

@ -0,0 +1,24 @@
Open Match Helm Chart
=====================
Open Match provides a Helm chart to quickly
```bash
# Install Helm and Tiller
# See https://github.com/helm/helm/releases for
cd /tmp && curl -Lo helm.tar.gz https://storage.googleapis.com/kubernetes-helm/helm-v2.13.0-linux-amd64.tar.gz && tar xvzf helm.tar.gz --strip-components 1 && mv helm $(PREFIX)/bin/helm && mv tiller $(PREFIX)/bin/tiller
# Install Helm to Kubernetes Cluster
kubectl create serviceaccount --namespace kube-system tiller
helm init --service-account tiller --force-upgrade
kubectl create clusterrolebinding tiller-cluster-rule --clusterrole=cluster-admin --serviceaccount=kube-system:tiller
# Run if RBAC is enabled.
kubectl patch deploy --namespace kube-system tiller-deploy -p '{"spec":{"template":{"spec":{"serviceAccount":"tiller"}}}}'
# Deploy Open Match
helm upgrade --install --wait --debug open-match \
install/helm/open-match \
--namespace=open-match \
--set openmatch.image.registry=$(REGISTRY) \
--set openmatch.image.tag=$(TAG)
```

View File

@ -0,0 +1,36 @@
# Copyright 2019 Google Inc. 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.
apiVersion: v1
appVersion: "0.4.0"
version: 0.4.0
name: open-match-example
description: Flexible, extensible, and scalable video game matchmaking.
keywords:
- kubernetes
- game-development
- multiplayer
- matchmaking
- go
- golang
home: https://github.com/GoogleCloudPlatform/open-match
sources:
- https://github.com/GoogleCloudPlatform/open-match
maintainers:
- name: open-match
email: open-match-discuss@googlegroups.com
url: https://groups.google.com/forum/#!forum/open-match-discuss
engine: gotpl
#icon: https://github.com/GoogleCloudPlatform/open-match/raw/master/docs/open-match.png
tillerVersion: ">2.10.0"

View File

@ -0,0 +1,14 @@
Open Match Example Helm Chart
=============================
This chart installs the Open Match example clientloadgen, frontendclient, backendclient, and example MMF and evaluator.
To deploy this chart run:
```bash
helm upgrade --install --wait --debug open-match-example
install/helm/open-match-example \
--namespace=open-match \
--set openmatch.image.registry=$(REGISTRY) \
--set openmatch.image.tag=$(TAG)
```

View File

@ -0,0 +1,3 @@
The Open Match examples have been installed in the namespace {{ .Release.Namespace }}.
You can watch the status by running 'kubectl --namespace {{ .Release.Namespace }} get pods,svc'

Some files were not shown because too many files have changed in this diff Show More