Kruise-Game init

Signed-off-by: ChrisLiu <chrisliu1995@163.com>
This commit is contained in:
ChrisLiu 2022-09-21 14:27:27 +08:00
parent 3aa9e5654b
commit c98d68f919
118 changed files with 11902 additions and 8 deletions

4
.dockerignore Normal file
View File

@ -0,0 +1,4 @@
# More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file
# Ignore build and test binaries.
bin/
testbin/

10
.gitignore vendored
View File

@ -1,16 +1,15 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin/
testbin/
.temp
bin
testbin/*
# Test binary, build with `go test -c`
*.test
test/e2e/generated/bindata.go
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
@ -24,6 +23,3 @@ test/e2e/generated/bindata.go
*.swp
*.swo
*~
.vscode
.DS_Store

26
Dockerfile Normal file
View File

@ -0,0 +1,26 @@
# Build the manager binary
FROM golang:1.18 as builder
WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download
# Copy the go source
COPY main.go main.go
COPY apis/ apis/
COPY pkg/ pkg/
# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go
# Use distroless as minimal base images to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM alpine:3.14
WORKDIR /
COPY --from=builder /workspace/manager .
ENTRYPOINT ["/manager"]

133
Makefile Normal file
View File

@ -0,0 +1,133 @@
# Image URL to use all building/pushing images targets
IMG ?= kruise-game-manager:test
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.24.1
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
GOBIN=$(shell go env GOPATH)/bin
else
GOBIN=$(shell go env GOBIN)
endif
# Setting SHELL to bash allows bash commands to be executed by recipes.
# This is a requirement for 'setup-envtest.sh' in the test target.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec
.PHONY: all
all: build
##@ General
# The help target prints out all targets with their descriptions organized
# beneath their categories. The categories are represented by '##@' and the
# target descriptions by '##'. The awk commands is responsible for reading the
# entire set of makefiles included in this invocation, looking for lines of the
# file as xyz: ## something, and then pretty-format the target and help. Then,
# if there's a line with ##@ something, that gets pretty-printed as a category.
# More info on the usage of ANSI control characters for terminal formatting:
# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters
# More info on the awk command:
# http://linuxcommand.org/lc3_adv_awk.php
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Development
.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases
.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...
.PHONY: vet
vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
##@ Build
.PHONY: build
build: generate fmt vet ## Build manager binary.
go build -o bin/manager main.go
.PHONY: run
run: manifests generate fmt vet ## Run a controller from your host.
go run ./main.go
.PHONY: docker-build
docker-build: ## Build docker images with the manager.
docker build -t ${IMG} .
.PHONY: docker-push
docker-push: ## Push docker images with the manager.
docker push ${IMG}
##@ Deployment
ifndef ignore-not-found
ignore-not-found = false
endif
.PHONY: install
install: manifests kustomize ## Install CRDs into the K8s cluster specified in ~/.kube/config.
$(KUSTOMIZE) build config/crd | kubectl apply -f -
.PHONY: uninstall
uninstall: manifests kustomize ## Uninstall CRDs from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/crd | kubectl delete --ignore-not-found=$(ignore-not-found) -f -
.PHONY: deploy
deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config.
cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG}
$(KUSTOMIZE) build config/default | kubectl apply -f -
.PHONY: undeploy
undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/config. Call with ignore-not-found=true to ignore resource not found errors during deletion.
$(KUSTOMIZE) build config/default | kubectl delete --ignore-not-found=$(ignore-not-found) -f -
##@ Build Dependencies
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
## Tool Binaries
KUSTOMIZE ?= $(LOCALBIN)/kustomize
CONTROLLER_GEN ?= $(LOCALBIN)/controller-gen
ENVTEST ?= $(LOCALBIN)/setup-envtest
## Tool Versions
KUSTOMIZE_VERSION ?= v4.5.5
CONTROLLER_TOOLS_VERSION ?= v0.9.0
KUSTOMIZE_INSTALL_SCRIPT ?= "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"
.PHONY: kustomize
kustomize: $(KUSTOMIZE) ## Download kustomize locally if necessary.
$(KUSTOMIZE): $(LOCALBIN)
curl -s $(KUSTOMIZE_INSTALL_SCRIPT) | bash -s -- $(subst v,,$(KUSTOMIZE_VERSION)) $(LOCALBIN)
.PHONY: controller-gen
controller-gen: $(CONTROLLER_GEN) ## Download controller-gen locally if necessary.
$(CONTROLLER_GEN): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-tools/cmd/controller-gen@$(CONTROLLER_TOOLS_VERSION)
.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(LOCALBIN)
GOBIN=$(LOCALBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest

25
PROJECT Normal file
View File

@ -0,0 +1,25 @@
domain: my.domain
layout:
- go.kubebuilder.io/v3
projectName: kruise-game
repo: github.com/openkruise/kruise-game
resources:
- api:
crdVersion: v1
namespaced: true
controller: true
domain: kruise.io
group: game
kind: GameServerSet
path: github.com/openkruise/kruise-game/apis/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: kruise.io
group: game
kind: GameServer
path: github.com/openkruise/kruise-game/apis/v1alpha1
version: v1alpha1
version: "3"

View File

@ -1 +1,48 @@
# kruise-game
# kruise-game
## Introduction
`Kruise-Game` is an open source project based on OpenKruise, to solve the problem of game server landing in Kubernetes.
<img width="250px" src="./docs/images/logo.jpg" alt="OpenKruiseGame logo"/>
## Why is Kruise-Game?
Game servers are stateful services, and there are differences in the operation and maintenance of each game server, which also increases with time. In Kubernetes, general workloads manages a batch of game servers according to pod templates, which cannot take into account the differences in game server status. Batch management and directional management are in conflict in k8s. **Kruise-Game** was born to resolve that. Kruise-Game contains two CRDs, GameServer and GameServerSet:
- `GameServer` is responsible for the management of game server status. Users can customize the game server status to reflect the differences between game servers;
- `GameServerSet` is responsible for batch management of game servers. Users can customize update/reduction strategies according to the status of game servers.
Features:
- Game server status management
- Mark game servers status without effecting to its lifecycle
- Flexible scaling/deletion mechanism
- Support scaling down by user-defined status & priority
- Support specifying game server to delete directly
- Flexible update mechanism
- Support hot update (in-place update)
- Support updating game server by user-defined priority
- Can control the range of the game servers to be updated
- Can control the pace of the entire update process
- Custom service quality
- Support probing game servers containers and mark game servers status automatically
## Quick Start
- [Installation](./docs/getting_started/installation.md)
- [Basic Usage](./docs/tutorials/basic_usage.md)
## License
Copyright 2022.
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.

19
apis/v1alpha1/doc.go Normal file
View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// +k8s:openapi-gen=true
// +groupName=game.kruise.io
package v1alpha1

View File

@ -0,0 +1,156 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
const (
GameServerStateKey = "game.kruise.io/gs-state"
GameServerOpsStateKey = "game.kruise.io/gs-opsState"
GameServerUpdatePriorityKey = "game.kruise.io/gs-update-priority"
GameServerDeletePriorityKey = "game.kruise.io/gs-delete-priority"
)
// GameServerSpec defines the desired state of GameServer
type GameServerSpec struct {
OpsState OpsState `json:"opsState,omitempty"`
UpdatePriority *intstr.IntOrString `json:"updatePriority,omitempty"`
DeletionPriority *intstr.IntOrString `json:"deletionPriority,omitempty"`
NetworkDisabled bool `json:"networkDisabled,omitempty"`
}
type GameServerState string
const (
Unknown GameServerState = "Unknown"
Creating GameServerState = "Creating"
Ready GameServerState = "Ready"
NotReady GameServerState = "NotReady"
Crash GameServerState = "Crash"
Updating GameServerState = "Updating"
Deleting GameServerState = "Deleting"
)
type OpsState string
const (
Maintaining OpsState = "Maintaining"
WaitToDelete OpsState = "WaitToBeDeleted"
None OpsState = "None"
)
type ServiceQuality struct {
corev1.Probe `json:",inline"`
Name string `json:"name"`
ContainerName string `json:"containerName,omitempty"`
ServiceQualityAction []ServiceQualityAction `json:"serviceQualityAction,omitempty"`
}
type ServiceQualityCondition struct {
Name string `json:"name"`
Status string `json:"status,omitempty"`
LastProbeTime metav1.Time `json:"lastProbeTime,omitempty"`
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
LastActionTransitionTime metav1.Time `json:"lastActionTransitionTime,omitempty"`
}
type ServiceQualityAction struct {
Permanent bool `json:"permanent,omitempty"` // default: true
State bool `json:"state"`
GameServerSpec `json:",inline"`
}
// GameServerStatus defines the observed state of GameServer
type GameServerStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
DesiredState GameServerState `json:"desiredState,omitempty"`
CurrentState GameServerState `json:"currentState,omitempty"`
NetworkStatus NetworkStatus `json:"networkStatus,omitempty"`
PodStatus corev1.PodStatus `json:"podStatus,omitempty"`
ServiceQualitiesCondition []ServiceQualityCondition `json:"serviceQualitiesConditions,omitempty"`
// Lifecycle defines the lifecycle hooks for Pods pre-delete, in-place update.
UpdatePriority *intstr.IntOrString `json:"updatePriority,omitempty"`
DeletionPriority *intstr.IntOrString `json:"deletionPriority,omitempty"`
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
}
type NetworkStatus struct {
NetworkType string `json:"networkType,omitempty"`
InternalAddresses []NetworkAddress `json:"internalAddresses,omitempty"`
ExternalAddresses []NetworkAddress `json:"externalAddresses,omitempty"`
DesiredNetworkState NetworkState `json:"desiredNetworkState,omitempty"`
CurrentNetworkState NetworkState `json:"currentNetworkState,omitempty"`
CreateTime metav1.Time `json:"createTime,omitempty"`
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
}
type NetworkState string
type NetworkAddress struct {
IP string `json:"ip"`
// TODO add IPv6
Ports []NetworkPort `json:"ports,omitempty"`
PortRange NetworkPortRange `json:"portRange,omitempty"`
EndPoint string `json:"endPoint,omitempty"`
}
type NetworkPort struct {
Name string `json:"name"`
Protocol corev1.Protocol `json:"protocol,omitempty"`
Port *intstr.IntOrString `json:"port,omitempty"`
}
type NetworkPortRange struct {
Protocol corev1.Protocol `json:"protocol,omitempty"`
PortRange string `json:"portRange,omitempty"`
}
//+genclient
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:printcolumn:name="STATE",type="string",JSONPath=".status.currentState",description="The current state of GameServer"
//+kubebuilder:printcolumn:name="OPSSTATE",type="string",JSONPath=".spec.opsState",description="The operations state of GameServer"
//+kubebuilder:printcolumn:name="DP",type="string",JSONPath=".status.deletionPriority",description="The current deletionPriority of GameServer"
//+kubebuilder:printcolumn:name="UP",type="string",JSONPath=".status.updatePriority",description="The current updatePriority of GameServer"
//+kubebuilder:resource:shortName=gs
// GameServer is the Schema for the gameservers API
type GameServer struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec GameServerSpec `json:"spec,omitempty"`
Status GameServerStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// GameServerList contains a list of GameServer
type GameServerList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []GameServer `json:"items"`
}
func init() {
SchemeBuilder.Register(&GameServer{}, &GameServerList{})
}

View File

@ -0,0 +1,170 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
appspub "github.com/openkruise/kruise-api/apps/pub"
kruiseV1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
apps "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
const (
GameServerOwnerGssKey = "game.kruise.io/owner-gss"
GameServerSetReserveIdsKey = "game.kruise.io/reserve-ids"
GameServerSetNotExistIdsKey = "game.kruise.io/not-exist-ids"
AstsHashKey = "game.kruise.io/asts-hash"
)
// GameServerSetSpec defines the desired state of GameServerSet
type GameServerSetSpec struct {
// replicas is the desired number of replicas of the given Template.
// These are replicas in the sense that they are instantiations of the
// same Template, but individual replicas also have a consistent identity.
//+kubebuilder:validation:Required
//+kubebuilder:validation:Minimum=0
Replicas *int32 `json:"replicas"`
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
GameServerTemplate GameServerTemplate `json:"gameServerTemplate,omitempty"`
ReserveGameServerIds []int `json:"reserveGameServerIds,omitempty"`
ServiceQualities []ServiceQuality `json:"serviceQualities,omitempty"`
UpdateStrategy UpdateStrategy `json:"updateStrategy,omitempty"`
ScaleStrategy ScaleStrategy `json:"scaleStrategy,omitempty"`
Network *Network `json:"network,omitempty"`
}
type GameServerTemplate struct {
// +kubebuilder:pruning:PreserveUnknownFields
// +kubebuilder:validation:Schemaless
corev1.PodTemplateSpec `json:",inline"`
VolumeClaimTemplates []corev1.PersistentVolumeClaim `json:"volumeClaimTemplates,omitempty"`
}
type Network struct {
NetworkType string `json:"networkType,omitempty"`
NetworkConf []NetworkConfParams `json:"networkConf,omitempty"`
}
type NetworkConfParams KVParams
type KVParams struct {
Name string `json:"name,omitempty"`
Value string `json:"value,omitempty"`
}
type UpdateStrategy struct {
// Type indicates the type of the StatefulSetUpdateStrategy.
// Default is RollingUpdate.
// +optional
Type apps.StatefulSetUpdateStrategyType `json:"type,omitempty"`
// RollingUpdate is used to communicate parameters when Type is RollingUpdateStatefulSetStrategyType.
// +optional
RollingUpdate *RollingUpdateStatefulSetStrategy `json:"rollingUpdate,omitempty"`
}
type RollingUpdateStatefulSetStrategy struct {
// Partition indicates the ordinal at which the StatefulSet should be partitioned by default.
// But if unorderedUpdate has been set:
// - Partition indicates the number of pods with non-updated revisions when rolling update.
// - It means controller will update $(replicas - partition) number of pod.
// Default value is 0.
// +optional
Partition *int32 `json:"partition,omitempty"`
// The maximum number of pods that can be unavailable during the update.
// Value can be an absolute number (ex: 5) or a percentage of desired pods (ex: 10%).
// Absolute number is calculated from percentage by rounding down.
// Also, maxUnavailable can just be allowed to work with Parallel podManagementPolicy.
// Defaults to 1.
// +optional
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
// PodUpdatePolicy indicates how pods should be updated
// Default value is "ReCreate"
// +optional
PodUpdatePolicy kruiseV1beta1.PodUpdateStrategyType `json:"podUpdatePolicy,omitempty"`
// Paused indicates that the StatefulSet is paused.
// Default value is false
// +optional
Paused bool `json:"paused,omitempty"`
// UnorderedUpdate contains strategies for non-ordered update.
// If it is not nil, pods will be updated with non-ordered sequence.
// Noted that UnorderedUpdate can only be allowed to work with Parallel podManagementPolicy
// +optional
// UnorderedUpdate *kruiseV1beta1.UnorderedUpdateStrategy `json:"unorderedUpdate,omitempty"`
// InPlaceUpdateStrategy contains strategies for in-place update.
// +optional
InPlaceUpdateStrategy *appspub.InPlaceUpdateStrategy `json:"inPlaceUpdateStrategy,omitempty"`
// MinReadySeconds indicates how long will the pod be considered ready after it's updated.
// MinReadySeconds works with both OrderedReady and Parallel podManagementPolicy.
// It affects the pod scale up speed when the podManagementPolicy is set to be OrderedReady.
// Combined with MaxUnavailable, it affects the pod update speed regardless of podManagementPolicy.
// Default value is 0, max is 300.
// +optional
MinReadySeconds *int32 `json:"minReadySeconds,omitempty"`
}
type ScaleStrategy struct {
kruiseV1beta1.StatefulSetScaleStrategy `json:",inline"`
}
// GameServerSetStatus defines the observed state of GameServerSet
type GameServerSetStatus struct {
// replicas from advancedStatefulSet
Replicas int32 `json:"replicas"`
ReadyReplicas int32 `json:"readyReplicas"`
AvailableReplicas int32 `json:"availableReplicas"`
CurrentReplicas int32 `json:"currentReplicas"`
UpdatedReplicas int32 `json:"updatedReplicas"`
UpdatedReadyReplicas int32 `json:"updatedReadyReplicas,omitempty"`
MaintainingReplicas *int32 `json:"maintainingReplicas,omitempty"`
WaitToBeDeletedReplicas *int32 `json:"waitToBeDeletedReplicas,omitempty"`
// LabelSelector is label selectors for query over pods that should match the replica count used by HPA.
LabelSelector string `json:"labelSelector,omitempty"`
}
//+genclient
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
//+kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.replicas,selectorpath=.status.labelSelector
//+kubebuilder:resource:shortName=gss
// GameServerSet is the Schema for the gameserversets API
type GameServerSet struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec GameServerSetSpec `json:"spec,omitempty"`
Status GameServerSetStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// GameServerSetList contains a list of GameServerSet
type GameServerSetList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []GameServerSet `json:"items"`
}
func init() {
SchemeBuilder.Register(&GameServerSet{}, &GameServerSetList{})
}

View File

@ -0,0 +1,43 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Package v1alpha1 contains API Schema definitions for the game.kruise.io v1alpha1 API group
//+kubebuilder:object:generate=true
//+groupName=game.kruise.io
package v1alpha1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "game.kruise.io", Version: "v1alpha1"}
SchemeGroupVersion = GroupVersion
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
// Resource is required by pkg/client/listers/...
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

View File

@ -0,0 +1,562 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1alpha1
import (
"github.com/openkruise/kruise-api/apps/pub"
"k8s.io/api/core/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServer) DeepCopyInto(out *GameServer) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServer.
func (in *GameServer) DeepCopy() *GameServer {
if in == nil {
return nil
}
out := new(GameServer)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *GameServer) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerList) DeepCopyInto(out *GameServerList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]GameServer, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerList.
func (in *GameServerList) DeepCopy() *GameServerList {
if in == nil {
return nil
}
out := new(GameServerList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *GameServerList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerSet) DeepCopyInto(out *GameServerSet) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerSet.
func (in *GameServerSet) DeepCopy() *GameServerSet {
if in == nil {
return nil
}
out := new(GameServerSet)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *GameServerSet) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerSetList) DeepCopyInto(out *GameServerSetList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]GameServerSet, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerSetList.
func (in *GameServerSetList) DeepCopy() *GameServerSetList {
if in == nil {
return nil
}
out := new(GameServerSetList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *GameServerSetList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerSetSpec) DeepCopyInto(out *GameServerSetSpec) {
*out = *in
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
*out = new(int32)
**out = **in
}
in.GameServerTemplate.DeepCopyInto(&out.GameServerTemplate)
if in.ReserveGameServerIds != nil {
in, out := &in.ReserveGameServerIds, &out.ReserveGameServerIds
*out = make([]int, len(*in))
copy(*out, *in)
}
if in.ServiceQualities != nil {
in, out := &in.ServiceQualities, &out.ServiceQualities
*out = make([]ServiceQuality, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.UpdateStrategy.DeepCopyInto(&out.UpdateStrategy)
in.ScaleStrategy.DeepCopyInto(&out.ScaleStrategy)
if in.Network != nil {
in, out := &in.Network, &out.Network
*out = new(Network)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerSetSpec.
func (in *GameServerSetSpec) DeepCopy() *GameServerSetSpec {
if in == nil {
return nil
}
out := new(GameServerSetSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerSetStatus) DeepCopyInto(out *GameServerSetStatus) {
*out = *in
if in.MaintainingReplicas != nil {
in, out := &in.MaintainingReplicas, &out.MaintainingReplicas
*out = new(int32)
**out = **in
}
if in.WaitToBeDeletedReplicas != nil {
in, out := &in.WaitToBeDeletedReplicas, &out.WaitToBeDeletedReplicas
*out = new(int32)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerSetStatus.
func (in *GameServerSetStatus) DeepCopy() *GameServerSetStatus {
if in == nil {
return nil
}
out := new(GameServerSetStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerSpec) DeepCopyInto(out *GameServerSpec) {
*out = *in
if in.UpdatePriority != nil {
in, out := &in.UpdatePriority, &out.UpdatePriority
*out = new(intstr.IntOrString)
**out = **in
}
if in.DeletionPriority != nil {
in, out := &in.DeletionPriority, &out.DeletionPriority
*out = new(intstr.IntOrString)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerSpec.
func (in *GameServerSpec) DeepCopy() *GameServerSpec {
if in == nil {
return nil
}
out := new(GameServerSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerStatus) DeepCopyInto(out *GameServerStatus) {
*out = *in
in.NetworkStatus.DeepCopyInto(&out.NetworkStatus)
in.PodStatus.DeepCopyInto(&out.PodStatus)
if in.ServiceQualitiesCondition != nil {
in, out := &in.ServiceQualitiesCondition, &out.ServiceQualitiesCondition
*out = make([]ServiceQualityCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.UpdatePriority != nil {
in, out := &in.UpdatePriority, &out.UpdatePriority
*out = new(intstr.IntOrString)
**out = **in
}
if in.DeletionPriority != nil {
in, out := &in.DeletionPriority, &out.DeletionPriority
*out = new(intstr.IntOrString)
**out = **in
}
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerStatus.
func (in *GameServerStatus) DeepCopy() *GameServerStatus {
if in == nil {
return nil
}
out := new(GameServerStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GameServerTemplate) DeepCopyInto(out *GameServerTemplate) {
*out = *in
in.PodTemplateSpec.DeepCopyInto(&out.PodTemplateSpec)
if in.VolumeClaimTemplates != nil {
in, out := &in.VolumeClaimTemplates, &out.VolumeClaimTemplates
*out = make([]v1.PersistentVolumeClaim, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GameServerTemplate.
func (in *GameServerTemplate) DeepCopy() *GameServerTemplate {
if in == nil {
return nil
}
out := new(GameServerTemplate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KVParams) DeepCopyInto(out *KVParams) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KVParams.
func (in *KVParams) DeepCopy() *KVParams {
if in == nil {
return nil
}
out := new(KVParams)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Network) DeepCopyInto(out *Network) {
*out = *in
if in.NetworkConf != nil {
in, out := &in.NetworkConf, &out.NetworkConf
*out = make([]NetworkConfParams, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Network.
func (in *Network) DeepCopy() *Network {
if in == nil {
return nil
}
out := new(Network)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkAddress) DeepCopyInto(out *NetworkAddress) {
*out = *in
if in.Ports != nil {
in, out := &in.Ports, &out.Ports
*out = make([]NetworkPort, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
out.PortRange = in.PortRange
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkAddress.
func (in *NetworkAddress) DeepCopy() *NetworkAddress {
if in == nil {
return nil
}
out := new(NetworkAddress)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkConfParams) DeepCopyInto(out *NetworkConfParams) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkConfParams.
func (in *NetworkConfParams) DeepCopy() *NetworkConfParams {
if in == nil {
return nil
}
out := new(NetworkConfParams)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkPort) DeepCopyInto(out *NetworkPort) {
*out = *in
if in.Port != nil {
in, out := &in.Port, &out.Port
*out = new(intstr.IntOrString)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPort.
func (in *NetworkPort) DeepCopy() *NetworkPort {
if in == nil {
return nil
}
out := new(NetworkPort)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkPortRange) DeepCopyInto(out *NetworkPortRange) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkPortRange.
func (in *NetworkPortRange) DeepCopy() *NetworkPortRange {
if in == nil {
return nil
}
out := new(NetworkPortRange)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NetworkStatus) DeepCopyInto(out *NetworkStatus) {
*out = *in
if in.InternalAddresses != nil {
in, out := &in.InternalAddresses, &out.InternalAddresses
*out = make([]NetworkAddress, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.ExternalAddresses != nil {
in, out := &in.ExternalAddresses, &out.ExternalAddresses
*out = make([]NetworkAddress, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.CreateTime.DeepCopyInto(&out.CreateTime)
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkStatus.
func (in *NetworkStatus) DeepCopy() *NetworkStatus {
if in == nil {
return nil
}
out := new(NetworkStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RollingUpdateStatefulSetStrategy) DeepCopyInto(out *RollingUpdateStatefulSetStrategy) {
*out = *in
if in.Partition != nil {
in, out := &in.Partition, &out.Partition
*out = new(int32)
**out = **in
}
if in.MaxUnavailable != nil {
in, out := &in.MaxUnavailable, &out.MaxUnavailable
*out = new(intstr.IntOrString)
**out = **in
}
if in.InPlaceUpdateStrategy != nil {
in, out := &in.InPlaceUpdateStrategy, &out.InPlaceUpdateStrategy
*out = new(pub.InPlaceUpdateStrategy)
**out = **in
}
if in.MinReadySeconds != nil {
in, out := &in.MinReadySeconds, &out.MinReadySeconds
*out = new(int32)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RollingUpdateStatefulSetStrategy.
func (in *RollingUpdateStatefulSetStrategy) DeepCopy() *RollingUpdateStatefulSetStrategy {
if in == nil {
return nil
}
out := new(RollingUpdateStatefulSetStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ScaleStrategy) DeepCopyInto(out *ScaleStrategy) {
*out = *in
in.StatefulSetScaleStrategy.DeepCopyInto(&out.StatefulSetScaleStrategy)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScaleStrategy.
func (in *ScaleStrategy) DeepCopy() *ScaleStrategy {
if in == nil {
return nil
}
out := new(ScaleStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceQuality) DeepCopyInto(out *ServiceQuality) {
*out = *in
in.Probe.DeepCopyInto(&out.Probe)
if in.ServiceQualityAction != nil {
in, out := &in.ServiceQualityAction, &out.ServiceQualityAction
*out = make([]ServiceQualityAction, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceQuality.
func (in *ServiceQuality) DeepCopy() *ServiceQuality {
if in == nil {
return nil
}
out := new(ServiceQuality)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceQualityAction) DeepCopyInto(out *ServiceQualityAction) {
*out = *in
in.GameServerSpec.DeepCopyInto(&out.GameServerSpec)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceQualityAction.
func (in *ServiceQualityAction) DeepCopy() *ServiceQualityAction {
if in == nil {
return nil
}
out := new(ServiceQualityAction)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ServiceQualityCondition) DeepCopyInto(out *ServiceQualityCondition) {
*out = *in
in.LastProbeTime.DeepCopyInto(&out.LastProbeTime)
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
in.LastActionTransitionTime.DeepCopyInto(&out.LastActionTransitionTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceQualityCondition.
func (in *ServiceQualityCondition) DeepCopy() *ServiceQualityCondition {
if in == nil {
return nil
}
out := new(ServiceQualityCondition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *UpdateStrategy) DeepCopyInto(out *UpdateStrategy) {
*out = *in
if in.RollingUpdate != nil {
in, out := &in.RollingUpdate, &out.RollingUpdate
*out = new(RollingUpdateStatefulSetStrategy)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateStrategy.
func (in *UpdateStrategy) DeepCopy() *UpdateStrategy {
if in == nil {
return nil
}
out := new(UpdateStrategy)
in.DeepCopyInto(out)
return out
}

View File

@ -0,0 +1,838 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: gameservers.game.kruise.io
spec:
group: game.kruise.io
names:
kind: GameServer
listKind: GameServerList
plural: gameservers
shortNames:
- gs
singular: gameserver
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: The current state of GameServer
jsonPath: .status.currentState
name: STATE
type: string
- description: The operations state of GameServer
jsonPath: .spec.opsState
name: OPSSTATE
type: string
- description: The current deletionPriority of GameServer
jsonPath: .status.deletionPriority
name: DP
type: string
- description: The current updatePriority of GameServer
jsonPath: .status.updatePriority
name: UP
type: string
name: v1alpha1
schema:
openAPIV3Schema:
description: GameServer is the Schema for the gameservers API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: GameServerSpec defines the desired state of GameServer
properties:
deletionPriority:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
networkDisabled:
type: boolean
opsState:
type: string
updatePriority:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
type: object
status:
description: GameServerStatus defines the observed state of GameServer
properties:
currentState:
type: string
deletionPriority:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
desiredState:
description: 'INSERT ADDITIONAL STATUS FIELD - define observed state
of cluster Important: Run "make" to regenerate code after modifying
this file'
type: string
lastTransitionTime:
format: date-time
type: string
networkStatus:
properties:
createTime:
format: date-time
type: string
currentNetworkState:
type: string
desiredNetworkState:
type: string
externalAddresses:
items:
properties:
endPoint:
type: string
ip:
type: string
portRange:
properties:
portRange:
type: string
protocol:
default: TCP
type: string
type: object
ports:
description: TODO add IPv6
items:
properties:
name:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
protocol:
default: TCP
type: string
required:
- name
type: object
type: array
required:
- ip
type: object
type: array
internalAddresses:
items:
properties:
endPoint:
type: string
ip:
type: string
portRange:
properties:
portRange:
type: string
protocol:
default: TCP
type: string
type: object
ports:
description: TODO add IPv6
items:
properties:
name:
type: string
port:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
protocol:
default: TCP
type: string
required:
- name
type: object
type: array
required:
- ip
type: object
type: array
lastTransitionTime:
format: date-time
type: string
networkType:
type: string
type: object
podStatus:
description: PodStatus represents information about the status of
a pod. Status may trail the actual state of a system, especially
if the node that hosts the pod cannot contact the control plane.
properties:
conditions:
description: 'Current service state of pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions'
items:
description: PodCondition contains details for the current condition
of this pod.
properties:
lastProbeTime:
description: Last time we probed the condition.
format: date-time
type: string
lastTransitionTime:
description: Last time the condition transitioned from one
status to another.
format: date-time
type: string
message:
description: Human-readable message indicating details about
last transition.
type: string
reason:
description: Unique, one-word, CamelCase reason for the
condition's last transition.
type: string
status:
description: 'Status is the status of the condition. Can
be True, False, Unknown. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions'
type: string
type:
description: 'Type is the type of the condition. More info:
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-conditions'
type: string
required:
- status
- type
type: object
type: array
containerStatuses:
description: 'The list has one entry per container in the manifest.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status'
items:
description: ContainerStatus contains details for the current
status of this container.
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'.
type: string
image:
description: 'The image the container is running. More info:
https://kubernetes.io/docs/concepts/containers/images.'
type: string
imageID:
description: ImageID of the container's image.
type: string
lastState:
description: Details about the container's last termination
condition.
properties:
running:
description: Details about a running container
properties:
startedAt:
description: Time at which the container was last
(re-)started
format: date-time
type: string
type: object
terminated:
description: Details about a terminated container
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'
type: string
exitCode:
description: Exit status from the last termination
of the container
format: int32
type: integer
finishedAt:
description: Time at which the container last terminated
format: date-time
type: string
message:
description: Message regarding the last termination
of the container
type: string
reason:
description: (brief) reason from the last termination
of the container
type: string
signal:
description: Signal from the last termination of
the container
format: int32
type: integer
startedAt:
description: Time at which previous execution of
the container started
format: date-time
type: string
required:
- exitCode
type: object
waiting:
description: Details about a waiting container
properties:
message:
description: Message regarding why the container
is not yet running.
type: string
reason:
description: (brief) reason the container is not
yet running.
type: string
type: object
type: object
name:
description: This must be a DNS_LABEL. Each container in
a pod must have a unique name. Cannot be updated.
type: string
ready:
description: Specifies whether the container has passed
its readiness probe.
type: boolean
restartCount:
description: The number of times the container has been
restarted.
format: int32
type: integer
started:
description: Specifies whether the container has passed
its startup probe. Initialized as false, becomes true
after startupProbe is considered successful. Resets to
false when the container is restarted, or if kubelet loses
state temporarily. Is always true when no startupProbe
is defined.
type: boolean
state:
description: Details about the container's current condition.
properties:
running:
description: Details about a running container
properties:
startedAt:
description: Time at which the container was last
(re-)started
format: date-time
type: string
type: object
terminated:
description: Details about a terminated container
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'
type: string
exitCode:
description: Exit status from the last termination
of the container
format: int32
type: integer
finishedAt:
description: Time at which the container last terminated
format: date-time
type: string
message:
description: Message regarding the last termination
of the container
type: string
reason:
description: (brief) reason from the last termination
of the container
type: string
signal:
description: Signal from the last termination of
the container
format: int32
type: integer
startedAt:
description: Time at which previous execution of
the container started
format: date-time
type: string
required:
- exitCode
type: object
waiting:
description: Details about a waiting container
properties:
message:
description: Message regarding why the container
is not yet running.
type: string
reason:
description: (brief) reason the container is not
yet running.
type: string
type: object
type: object
required:
- image
- imageID
- name
- ready
- restartCount
type: object
type: array
ephemeralContainerStatuses:
description: Status for any ephemeral containers that have run
in this pod. This field is beta-level and available on clusters
that haven't disabled the EphemeralContainers feature gate.
items:
description: ContainerStatus contains details for the current
status of this container.
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'.
type: string
image:
description: 'The image the container is running. More info:
https://kubernetes.io/docs/concepts/containers/images.'
type: string
imageID:
description: ImageID of the container's image.
type: string
lastState:
description: Details about the container's last termination
condition.
properties:
running:
description: Details about a running container
properties:
startedAt:
description: Time at which the container was last
(re-)started
format: date-time
type: string
type: object
terminated:
description: Details about a terminated container
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'
type: string
exitCode:
description: Exit status from the last termination
of the container
format: int32
type: integer
finishedAt:
description: Time at which the container last terminated
format: date-time
type: string
message:
description: Message regarding the last termination
of the container
type: string
reason:
description: (brief) reason from the last termination
of the container
type: string
signal:
description: Signal from the last termination of
the container
format: int32
type: integer
startedAt:
description: Time at which previous execution of
the container started
format: date-time
type: string
required:
- exitCode
type: object
waiting:
description: Details about a waiting container
properties:
message:
description: Message regarding why the container
is not yet running.
type: string
reason:
description: (brief) reason the container is not
yet running.
type: string
type: object
type: object
name:
description: This must be a DNS_LABEL. Each container in
a pod must have a unique name. Cannot be updated.
type: string
ready:
description: Specifies whether the container has passed
its readiness probe.
type: boolean
restartCount:
description: The number of times the container has been
restarted.
format: int32
type: integer
started:
description: Specifies whether the container has passed
its startup probe. Initialized as false, becomes true
after startupProbe is considered successful. Resets to
false when the container is restarted, or if kubelet loses
state temporarily. Is always true when no startupProbe
is defined.
type: boolean
state:
description: Details about the container's current condition.
properties:
running:
description: Details about a running container
properties:
startedAt:
description: Time at which the container was last
(re-)started
format: date-time
type: string
type: object
terminated:
description: Details about a terminated container
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'
type: string
exitCode:
description: Exit status from the last termination
of the container
format: int32
type: integer
finishedAt:
description: Time at which the container last terminated
format: date-time
type: string
message:
description: Message regarding the last termination
of the container
type: string
reason:
description: (brief) reason from the last termination
of the container
type: string
signal:
description: Signal from the last termination of
the container
format: int32
type: integer
startedAt:
description: Time at which previous execution of
the container started
format: date-time
type: string
required:
- exitCode
type: object
waiting:
description: Details about a waiting container
properties:
message:
description: Message regarding why the container
is not yet running.
type: string
reason:
description: (brief) reason the container is not
yet running.
type: string
type: object
type: object
required:
- image
- imageID
- name
- ready
- restartCount
type: object
type: array
hostIP:
description: IP address of the host to which the pod is assigned.
Empty if not yet scheduled.
type: string
initContainerStatuses:
description: 'The list has one entry per init container in the
manifest. The most recent successful init container will have
ready = true, the most recently started container will have
startTime set. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-and-container-status'
items:
description: ContainerStatus contains details for the current
status of this container.
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'.
type: string
image:
description: 'The image the container is running. More info:
https://kubernetes.io/docs/concepts/containers/images.'
type: string
imageID:
description: ImageID of the container's image.
type: string
lastState:
description: Details about the container's last termination
condition.
properties:
running:
description: Details about a running container
properties:
startedAt:
description: Time at which the container was last
(re-)started
format: date-time
type: string
type: object
terminated:
description: Details about a terminated container
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'
type: string
exitCode:
description: Exit status from the last termination
of the container
format: int32
type: integer
finishedAt:
description: Time at which the container last terminated
format: date-time
type: string
message:
description: Message regarding the last termination
of the container
type: string
reason:
description: (brief) reason from the last termination
of the container
type: string
signal:
description: Signal from the last termination of
the container
format: int32
type: integer
startedAt:
description: Time at which previous execution of
the container started
format: date-time
type: string
required:
- exitCode
type: object
waiting:
description: Details about a waiting container
properties:
message:
description: Message regarding why the container
is not yet running.
type: string
reason:
description: (brief) reason the container is not
yet running.
type: string
type: object
type: object
name:
description: This must be a DNS_LABEL. Each container in
a pod must have a unique name. Cannot be updated.
type: string
ready:
description: Specifies whether the container has passed
its readiness probe.
type: boolean
restartCount:
description: The number of times the container has been
restarted.
format: int32
type: integer
started:
description: Specifies whether the container has passed
its startup probe. Initialized as false, becomes true
after startupProbe is considered successful. Resets to
false when the container is restarted, or if kubelet loses
state temporarily. Is always true when no startupProbe
is defined.
type: boolean
state:
description: Details about the container's current condition.
properties:
running:
description: Details about a running container
properties:
startedAt:
description: Time at which the container was last
(re-)started
format: date-time
type: string
type: object
terminated:
description: Details about a terminated container
properties:
containerID:
description: Container's ID in the format '<type>://<container_id>'
type: string
exitCode:
description: Exit status from the last termination
of the container
format: int32
type: integer
finishedAt:
description: Time at which the container last terminated
format: date-time
type: string
message:
description: Message regarding the last termination
of the container
type: string
reason:
description: (brief) reason from the last termination
of the container
type: string
signal:
description: Signal from the last termination of
the container
format: int32
type: integer
startedAt:
description: Time at which previous execution of
the container started
format: date-time
type: string
required:
- exitCode
type: object
waiting:
description: Details about a waiting container
properties:
message:
description: Message regarding why the container
is not yet running.
type: string
reason:
description: (brief) reason the container is not
yet running.
type: string
type: object
type: object
required:
- image
- imageID
- name
- ready
- restartCount
type: object
type: array
message:
description: A human readable message indicating details about
why the pod is in this condition.
type: string
nominatedNodeName:
description: nominatedNodeName is set only when this pod preempts
other pods on the node, but it cannot be scheduled right away
as preemption victims receive their graceful termination periods.
This field does not guarantee that the pod will be scheduled
on this node. Scheduler may decide to place the pod elsewhere
if other nodes become available sooner. Scheduler may also decide
to give the resources on this node to a higher priority pod
that is created after preemption. As a result, this field may
be different than PodSpec.nodeName when the pod is scheduled.
type: string
phase:
description: "The phase of a Pod is a simple, high-level summary
of where the Pod is in its lifecycle. The conditions array,
the reason and message fields, and the individual container
status arrays contain more detail about the pod's status. There
are five possible phase values: \n Pending: The pod has been
accepted by the Kubernetes system, but one or more of the container
images has not been created. This includes time before being
scheduled as well as time spent downloading images over the
network, which could take a while. Running: The pod has been
bound to a node, and all of the containers have been created.
At least one container is still running, or is in the process
of starting or restarting. Succeeded: All containers in the
pod have terminated in success, and will not be restarted. Failed:
All containers in the pod have terminated, and at least one
container has terminated in failure. The container either exited
with non-zero status or was terminated by the system. Unknown:
For some reason the state of the pod could not be obtained,
typically due to an error in communicating with the host of
the pod. \n More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#pod-phase"
type: string
podIP:
description: IP address allocated to the pod. Routable at least
within the cluster. Empty if not yet allocated.
type: string
podIPs:
description: podIPs holds the IP addresses allocated to the pod.
If this field is specified, the 0th entry must match the podIP
field. Pods may be allocated at most 1 value for each of IPv4
and IPv6. This list is empty if no IPs have been allocated yet.
items:
description: 'IP address information for entries in the (plural)
PodIPs field. Each entry includes: IP: An IP address allocated
to the pod. Routable at least within the cluster.'
properties:
ip:
description: ip is an IP address (IPv4 or IPv6) assigned
to the pod
type: string
type: object
type: array
qosClass:
description: 'The Quality of Service (QOS) classification assigned
to the pod based on resource requirements See PodQOSClass type
for available QOS classes More info: https://git.k8s.io/community/contributors/design-proposals/node/resource-qos.md'
type: string
reason:
description: A brief CamelCase message indicating details about
why the pod is in this state. e.g. 'Evicted'
type: string
startTime:
description: RFC 3339 date and time at which the object was acknowledged
by the Kubelet. This is before the Kubelet pulled the container
image(s) for the pod.
format: date-time
type: string
type: object
serviceQualitiesConditions:
items:
properties:
lastActionTransitionTime:
format: date-time
type: string
lastProbeTime:
format: date-time
type: string
lastTransitionTime:
format: date-time
type: string
name:
type: string
status:
type: string
required:
- name
type: object
type: array
updatePriority:
anyOf:
- type: integer
- type: string
description: Lifecycle defines the lifecycle hooks for Pods pre-delete,
in-place update.
x-kubernetes-int-or-string: true
type: object
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -0,0 +1,665 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: gameserversets.game.kruise.io
spec:
group: game.kruise.io
names:
kind: GameServerSet
listKind: GameServerSetList
plural: gameserversets
shortNames:
- gss
singular: gameserverset
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: GameServerSet is the Schema for the gameserversets API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: GameServerSetSpec defines the desired state of GameServerSet
properties:
gameServerTemplate:
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
Important: Run "make" to regenerate code after modifying this file'
properties:
volumeClaimTemplates:
items:
description: PersistentVolumeClaim is a user's request for and
claim to a persistent volume
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of
this representation of an object. Servers should convert
recognized schemas to the latest internal value, and may
reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST
resource this object represents. Servers may infer this
from the endpoint the client submits requests to. Cannot
be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata'
type: object
spec:
description: 'spec defines the desired characteristics of
a volume requested by a pod author. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
properties:
accessModes:
description: 'accessModes contains the desired access
modes the volume should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
items:
type: string
type: array
dataSource:
description: 'dataSource field can be used to specify
either: * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot)
* An existing PVC (PersistentVolumeClaim) If the provisioner
or an external controller can support the specified
data source, it will create a new volume based on
the contents of the specified data source. If the
AnyVolumeDataSource feature gate is enabled, this
field will always have the same contents as the DataSourceRef
field.'
properties:
apiGroup:
description: APIGroup is the group for the resource
being referenced. If APIGroup is not specified,
the specified Kind must be in the core API group.
For any other third-party types, APIGroup is required.
type: string
kind:
description: Kind is the type of resource being
referenced
type: string
name:
description: Name is the name of resource being
referenced
type: string
required:
- kind
- name
type: object
dataSourceRef:
description: 'dataSourceRef specifies the object from
which to populate the volume with data, if a non-empty
volume is desired. This may be any local object from
a non-empty API group (non core object) or a PersistentVolumeClaim
object. When this field is specified, volume binding
will only succeed if the type of the specified object
matches some installed volume populator or dynamic
provisioner. This field will replace the functionality
of the DataSource field and as such if both fields
are non-empty, they must have the same value. For
backwards compatibility, both fields (DataSource and
DataSourceRef) will be set to the same value automatically
if one of them is empty and the other is non-empty.
There are two important differences between DataSource
and DataSourceRef: * While DataSource only allows
two specific types of objects, DataSourceRef allows
any non-core object, as well as PersistentVolumeClaim
objects. * While DataSource ignores disallowed values
(dropping them), DataSourceRef preserves all values,
and generates an error if a disallowed value is specified.
(Beta) Using this field requires the AnyVolumeDataSource
feature gate to be enabled.'
properties:
apiGroup:
description: APIGroup is the group for the resource
being referenced. If APIGroup is not specified,
the specified Kind must be in the core API group.
For any other third-party types, APIGroup is required.
type: string
kind:
description: Kind is the type of resource being
referenced
type: string
name:
description: Name is the name of resource being
referenced
type: string
required:
- kind
- name
type: object
resources:
description: 'resources represents the minimum resources
the volume should have. If RecoverVolumeExpansionFailure
feature is enabled users are allowed to specify resource
requirements that are lower than previous value but
must still be higher than capacity recorded in the
status field of the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources'
properties:
limits:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'Limits describes the maximum amount
of compute resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
type: object
requests:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: 'Requests describes the minimum amount
of compute resources required. If Requests is
omitted for a container, it defaults to Limits
if that is explicitly specified, otherwise to
an implementation-defined value. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
type: object
type: object
selector:
description: selector is a label query over volumes
to consider for binding.
properties:
matchExpressions:
description: matchExpressions is a list of label
selector requirements. The requirements are ANDed.
items:
description: A label selector requirement is a
selector that contains values, a key, and an
operator that relates the key and values.
properties:
key:
description: key is the label key that the
selector applies to.
type: string
operator:
description: operator represents a key's relationship
to a set of values. Valid operators are
In, NotIn, Exists and DoesNotExist.
type: string
values:
description: values is an array of string
values. If the operator is In or NotIn,
the values array must be non-empty. If the
operator is Exists or DoesNotExist, the
values array must be empty. This array is
replaced during a strategic merge patch.
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
description: matchLabels is a map of {key,value}
pairs. A single {key,value} in the matchLabels
map is equivalent to an element of matchExpressions,
whose key field is "key", the operator is "In",
and the values array contains only "value". The
requirements are ANDed.
type: object
type: object
storageClassName:
description: 'storageClassName is the name of the StorageClass
required by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1'
type: string
volumeMode:
description: volumeMode defines what type of volume
is required by the claim. Value of Filesystem is implied
when not included in claim spec.
type: string
volumeName:
description: volumeName is the binding reference to
the PersistentVolume backing this claim.
type: string
type: object
status:
description: 'status represents the current information/status
of a persistent volume claim. Read-only. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims'
properties:
accessModes:
description: 'accessModes contains the actual access
modes the volume backing the PVC has. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1'
items:
type: string
type: array
allocatedResources:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: allocatedResources is the storage resource
within AllocatedResources tracks the capacity allocated
to a PVC. It may be larger than the actual capacity
when a volume expansion operation is requested. For
storage quota, the larger value from allocatedResources
and PVC.spec.resources is used. If allocatedResources
is not set, PVC.spec.resources alone is used for quota
calculation. If a volume expansion capacity request
is lowered, allocatedResources is only lowered if
there are no expansion operations in progress and
if the actual volume capacity is equal or lower than
the requested capacity. This is an alpha field and
requires enabling RecoverVolumeExpansionFailure feature.
type: object
capacity:
additionalProperties:
anyOf:
- type: integer
- type: string
pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
x-kubernetes-int-or-string: true
description: capacity represents the actual resources
of the underlying volume.
type: object
conditions:
description: conditions is the current Condition of
persistent volume claim. If underlying persistent
volume is being resized then the Condition will be
set to 'ResizeStarted'.
items:
description: PersistentVolumeClaimCondition contails
details about state of pvc
properties:
lastProbeTime:
description: lastProbeTime is the time we probed
the condition.
format: date-time
type: string
lastTransitionTime:
description: lastTransitionTime is the time the
condition transitioned from one status to another.
format: date-time
type: string
message:
description: message is the human-readable message
indicating details about last transition.
type: string
reason:
description: reason is a unique, this should be
a short, machine understandable string that
gives the reason for condition's last transition.
If it reports "ResizeStarted" that means the
underlying persistent volume is being resized.
type: string
status:
type: string
type:
description: PersistentVolumeClaimConditionType
is a valid value of PersistentVolumeClaimCondition.Type
type: string
required:
- status
- type
type: object
type: array
phase:
description: phase represents the current phase of PersistentVolumeClaim.
type: string
resizeStatus:
description: resizeStatus stores status of resize operation.
ResizeStatus is not set by default but when expansion
is complete resizeStatus is set to empty string by
resize controller or kubelet. This is an alpha field
and requires enabling RecoverVolumeExpansionFailure
feature.
type: string
type: object
type: object
type: array
type: object
x-kubernetes-preserve-unknown-fields: true
network:
properties:
networkConf:
items:
properties:
name:
type: string
value:
type: string
type: object
type: array
networkType:
type: string
type: object
replicas:
description: replicas is the desired number of replicas of the given
Template. These are replicas in the sense that they are instantiations
of the same Template, but individual replicas also have a consistent
identity.
format: int32
minimum: 0
type: integer
reserveGameServerIds:
items:
type: integer
type: array
scaleStrategy:
properties:
maxUnavailable:
anyOf:
- type: integer
- type: string
description: 'The maximum number of pods that can be unavailable
during scaling. Value can be an absolute number (ex: 5) or a
percentage of desired pods (ex: 10%). Absolute number is calculated
from percentage by rounding down. It can just be allowed to
work with Parallel podManagementPolicy.'
x-kubernetes-int-or-string: true
type: object
serviceQualities:
items:
properties:
containerName:
type: string
exec:
description: Exec specifies the action to take.
properties:
command:
description: Command is the command line to execute inside
the container, the working directory for the command is
root ('/') in the container's filesystem. The command
is simply exec'd, it is not run inside a shell, so traditional
shell instructions ('|', etc) won't work. To use a shell,
you need to explicitly call out to that shell. Exit status
of 0 is treated as live/healthy and non-zero is unhealthy.
items:
type: string
type: array
type: object
failureThreshold:
description: Minimum consecutive failures for the probe to be
considered failed after having succeeded. Defaults to 3. Minimum
value is 1.
format: int32
type: integer
grpc:
description: GRPC specifies an action involving a GRPC port.
This is a beta field and requires enabling GRPCContainerProbe
feature gate.
properties:
port:
description: Port number of the gRPC service. Number must
be in the range 1 to 65535.
format: int32
type: integer
service:
description: "Service is the name of the service to place
in the gRPC HealthCheckRequest (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
\n If this is not specified, the default behavior is defined
by gRPC."
type: string
required:
- port
type: object
httpGet:
description: HTTPGet specifies the http request to perform.
properties:
host:
description: Host name to connect to, defaults to the pod
IP. You probably want to set "Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in the request. HTTP
allows repeated headers.
items:
description: HTTPHeader describes a custom header to be
used in HTTP probes
properties:
name:
description: The header field name
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
path:
description: Path to access on the HTTP server.
type: string
port:
anyOf:
- type: integer
- type: string
description: Name or number of the port to access on the
container. Number must be in the range 1 to 65535. Name
must be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: Scheme to use for connecting to the host. Defaults
to HTTP.
type: string
required:
- port
type: object
initialDelaySeconds:
description: 'Number of seconds after the container has started
before liveness probes are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
name:
type: string
periodSeconds:
description: How often (in seconds) to perform the probe. Default
to 10 seconds. Minimum value is 1.
format: int32
type: integer
serviceQualityAction:
items:
properties:
deletionPriority:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
networkDisabled:
type: boolean
opsState:
type: string
permanent:
type: boolean
state:
type: boolean
updatePriority:
anyOf:
- type: integer
- type: string
x-kubernetes-int-or-string: true
required:
- state
type: object
type: array
successThreshold:
description: Minimum consecutive successes for the probe to
be considered successful after having failed. Defaults to
1. Must be 1 for liveness and startup. Minimum value is 1.
format: int32
type: integer
tcpSocket:
description: TCPSocket specifies an action involving a TCP port.
properties:
host:
description: 'Optional: Host name to connect to, defaults
to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: Number or name of the port to access on the
container. Number must be in the range 1 to 65535. Name
must be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
terminationGracePeriodSeconds:
description: Optional duration in seconds the pod needs to terminate
gracefully upon probe failure. The grace period is the duration
in seconds after the processes running in the pod are sent
a termination signal and the time when the processes are forcibly
halted with a kill signal. Set this value longer than the
expected cleanup time for your process. If this value is nil,
the pod's terminationGracePeriodSeconds will be used. Otherwise,
this value overrides the value provided by the pod spec. Value
must be non-negative integer. The value zero indicates stop
immediately via the kill signal (no opportunity to shut down).
This is a beta field and requires enabling ProbeTerminationGracePeriod
feature gate. Minimum value is 1. spec.terminationGracePeriodSeconds
is used if unset.
format: int64
type: integer
timeoutSeconds:
description: 'Number of seconds after which the probe times
out. Defaults to 1 second. Minimum value is 1. More info:
https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes'
format: int32
type: integer
required:
- name
type: object
type: array
updateStrategy:
properties:
rollingUpdate:
description: RollingUpdate is used to communicate parameters when
Type is RollingUpdateStatefulSetStrategyType.
properties:
inPlaceUpdateStrategy:
description: UnorderedUpdate contains strategies for non-ordered
update. If it is not nil, pods will be updated with non-ordered
sequence. Noted that UnorderedUpdate can only be allowed
to work with Parallel podManagementPolicy UnorderedUpdate
*kruiseV1beta1.UnorderedUpdateStrategy `json:"unorderedUpdate,omitempty"`
InPlaceUpdateStrategy contains strategies for in-place update.
properties:
gracePeriodSeconds:
description: GracePeriodSeconds is the timespan between
set Pod status to not-ready and update images in Pod
spec when in-place update a Pod.
format: int32
type: integer
type: object
maxUnavailable:
anyOf:
- type: integer
- type: string
description: 'The maximum number of pods that can be unavailable
during the update. Value can be an absolute number (ex:
5) or a percentage of desired pods (ex: 10%). Absolute number
is calculated from percentage by rounding down. Also, maxUnavailable
can just be allowed to work with Parallel podManagementPolicy.
Defaults to 1.'
x-kubernetes-int-or-string: true
minReadySeconds:
description: MinReadySeconds indicates how long will the pod
be considered ready after it's updated. MinReadySeconds
works with both OrderedReady and Parallel podManagementPolicy.
It affects the pod scale up speed when the podManagementPolicy
is set to be OrderedReady. Combined with MaxUnavailable,
it affects the pod update speed regardless of podManagementPolicy.
Default value is 0, max is 300.
format: int32
type: integer
partition:
description: 'Partition indicates the ordinal at which the
StatefulSet should be partitioned by default. But if unorderedUpdate
has been set: - Partition indicates the number of pods with
non-updated revisions when rolling update. - It means controller
will update $(replicas - partition) number of pod. Default
value is 0.'
format: int32
type: integer
paused:
description: Paused indicates that the StatefulSet is paused.
Default value is false
type: boolean
podUpdatePolicy:
description: PodUpdatePolicy indicates how pods should be
updated Default value is "ReCreate"
type: string
type: object
type:
description: Type indicates the type of the StatefulSetUpdateStrategy.
Default is RollingUpdate.
type: string
type: object
required:
- replicas
type: object
status:
description: GameServerSetStatus defines the observed state of GameServerSet
properties:
availableReplicas:
format: int32
type: integer
currentReplicas:
format: int32
type: integer
labelSelector:
description: LabelSelector is label selectors for query over pods
that should match the replica count used by HPA.
type: string
maintainingReplicas:
format: int32
type: integer
readyReplicas:
format: int32
type: integer
replicas:
description: replicas from advancedStatefulSet
format: int32
type: integer
updatedReadyReplicas:
format: int32
type: integer
updatedReplicas:
format: int32
type: integer
waitToBeDeletedReplicas:
format: int32
type: integer
required:
- availableReplicas
- currentReplicas
- readyReplicas
- replicas
- updatedReplicas
type: object
type: object
served: true
storage: true
subresources:
scale:
labelSelectorPath: .status.labelSelector
specReplicasPath: .spec.replicas
statusReplicasPath: .status.replicas
status: {}

View File

@ -0,0 +1,23 @@
# This kustomization.yaml is not intended to be run by itself,
# since it depends on service name and namespace that are out of this kustomize package.
# It should be run by config/default
resources:
- bases/game.kruise.io_gameserversets.yaml
- bases/game.kruise.io_gameservers.yaml
#+kubebuilder:scaffold:crdkustomizeresource
patchesStrategicMerge:
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_gameserversets.yaml
#+kubebuilder:scaffold:crdkustomizewebhookpatch
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
# patches here are for enabling the CA injection for each CRD
#- patches/cainjection_in_gameserversets.yaml
#- patches/cainjection_in_gameservers.yaml
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
# the following config is for teaching kustomize how to do kustomization for CRDs.
configurations:
- kustomizeconfig.yaml

View File

@ -0,0 +1,19 @@
# This file is for teaching kustomize how to substitute name and namespace reference in CRD
nameReference:
- kind: Service
version: v1
fieldSpecs:
- kind: CustomResourceDefinition
version: v1
group: apiextensions.k8s.io
path: spec/conversion/webhook/clientConfig/service/name
namespace:
- kind: CustomResourceDefinition
version: v1
group: apiextensions.k8s.io
path: spec/conversion/webhook/clientConfig/service/namespace
create: false
varReference:
- path: metadata/annotations

View File

@ -0,0 +1,74 @@
# Adds namespace to all resources.
namespace: kruise-game-system
# Value of this field is prepended to the
# names of all resources, e.g. a deployment named
# "wordpress" becomes "alices-wordpress".
# Note that it should also match with the prefix (text before '-') of the namespace
# field above.
namePrefix: kruise-game-
# Labels to add to all resources and selectors.
#commonLabels:
# someName: someValue
bases:
- ../crd
- ../rbac
- ../manager
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
- ../webhook
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'. 'WEBHOOK' components are required.
#- ../certmanager
# [PROMETHEUS] To enable prometheus monitor, uncomment all sections with 'PROMETHEUS'.
# - ../prometheus
patchesStrategicMerge:
# Protect the /metrics endpoint by putting it behind auth.
# If you want your controller-manager to expose the /metrics
# endpoint w/o any authn/z, please comment the following line.
#- manager_auth_proxy_patch.yaml
# Mount the controller config file for loading manager configurations
# through a ComponentConfig type
#- manager_config_patch.yaml
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix including the one in
# crd/kustomization.yaml
#- manager_webhook_patch.yaml
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER'.
# Uncomment 'CERTMANAGER' sections in crd/kustomization.yaml to enable the CA injection in the admission webhooks.
# 'CERTMANAGER' needs to be enabled to use ca injection
#- webhookcainjection_patch.yaml
# the following config is for teaching kustomize how to do var substitution
vars:
# [CERTMANAGER] To enable cert-manager, uncomment all sections with 'CERTMANAGER' prefix.
#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
# objref:
# kind: Certificate
# group: cert-manager.io
# version: v1
# name: serving-cert # this name should match the one in certificate.yaml
# fieldref:
# fieldpath: metadata.namespace
#- name: CERTIFICATE_NAME
# objref:
# kind: Certificate
# group: cert-manager.io
# version: v1
# name: serving-cert # this name should match the one in certificate.yaml
#- name: SERVICE_NAMESPACE # namespace of the service
# objref:
# kind: Service
# version: v1
# name: webhook-service
# fieldref:
# fieldpath: metadata.namespace
#- name: SERVICE_NAME
# objref:
# kind: Service
# version: v1
# name: webhook-service

View File

@ -0,0 +1,39 @@
# This patch inject a sidecar container which is a HTTP proxy for the
# controller manager, it performs RBAC authorization against the Kubernetes API using SubjectAccessReviews.
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: kube-rbac-proxy
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
image: ringtail/kube-rbac-proxy:v0.12.0
args:
- "--secure-listen-address=0.0.0.0:8443"
- "--upstream=http://127.0.0.1:8080/"
- "--logtostderr=true"
- "--v=0"
ports:
- containerPort: 8443
protocol: TCP
name: https
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 5m
memory: 64Mi
- name: manager
args:
- "--health-probe-bind-address=:8081"
- "--metrics-bind-address=127.0.0.1:8080"
- "--leader-elect"

View File

@ -0,0 +1,23 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
spec:
template:
spec:
containers:
- name: manager
ports:
- containerPort: 9443
name: webhook-server
protocol: TCP
volumeMounts:
- mountPath: /tmp/k8s-webhook-server/serving-certs
name: cert
readOnly: true
volumes:
- name: cert
secret:
defaultMode: 420
secretName: webhook-server-cert

View File

@ -0,0 +1,8 @@
# This patch add annotation to admission webhook config and
# the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize.
apiVersion: admissionregistration.k8s.io/v1beta1
kind: MutatingWebhookConfiguration
metadata:
name: mutating-webhook-configuration
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)

View File

@ -0,0 +1,21 @@
apiVersion: controller-runtime.sigs.k8s.io/v1alpha1
kind: ControllerManagerConfig
health:
healthProbeBindAddress: :8081
metrics:
bindAddress: 127.0.0.1:8080
webhook:
port: 9443
leaderElection:
leaderElect: true
resourceName: c637bb1e.my.domain
# leaderElectionReleaseOnCancel defines if the leader should step down volume
# when the Manager ends. This requires the binary to immediately end when the
# Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
# speeds up voluntary leader transitions as the new leader don't have to wait
# LeaseDuration time first.
# In the default scaffold provided, the program ends immediately after
# the manager stops, so would be fine to enable this option. However,
# if you are doing or is intended to do any operation such as perform cleanups
# after the manager stops then its usage might be unsafe.
# leaderElectionReleaseOnCancel: true

View File

@ -0,0 +1,16 @@
resources:
- manager.yaml
generatorOptions:
disableNameSuffixHash: true
configMapGenerator:
- files:
- controller_manager_config.yaml
name: manager-config
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
images:
- name: controller
newName: kruise-game-manager
newTag: test

View File

@ -0,0 +1,70 @@
apiVersion: v1
kind: Namespace
metadata:
labels:
control-plane: controller-manager
name: system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: controller-manager
namespace: system
labels:
control-plane: controller-manager
spec:
selector:
matchLabels:
control-plane: controller-manager
replicas: 1
template:
metadata:
annotations:
kubectl.kubernetes.io/default-container: manager
labels:
control-plane: controller-manager
spec:
# securityContext:
# runAsNonRoot: true
# TODO(user): For common cases that do not require escalating privileges
# it is recommended to ensure that all your Pods/Containers are restrictive.
# More info: https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted
# Please uncomment the following code if your project does NOT have to work on old Kubernetes
# versions < 1.19 or on vendors versions which do NOT support this field by default (i.e. Openshift < 4.11 ).
# seccompProfile:
# type: RuntimeDefault
containers:
- command:
- /manager
args:
- --leader-elect=false
image: controller:latest
name: manager
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- "ALL"
livenessProbe:
httpGet:
path: /healthz
port: 8082
initialDelaySeconds: 5
periodSeconds: 5
readinessProbe:
httpGet:
path: /readyz
port: 8082
initialDelaySeconds: 5
periodSeconds: 5
# TODO(user): Configure the resources accordingly based on the project requirements.
# More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
resources:
limits:
cpu: 500m
memory: 1024Mi
requests:
cpu: 10m
memory: 64Mi
serviceAccountName: controller-manager
terminationGracePeriodSeconds: 10

View File

@ -0,0 +1,2 @@
resources:
- monitor.yaml

View File

@ -0,0 +1,20 @@
# Prometheus Monitor Service (Metrics)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
labels:
control-plane: controller-manager
name: controller-manager-metrics-monitor
namespace: system
spec:
endpoints:
- path: /metrics
port: https
scheme: https
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
tlsConfig:
insecureSkipVerify: true
selector:
matchLabels:
control-plane: controller-manager

View File

@ -0,0 +1,9 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: metrics-reader
rules:
- nonResourceURLs:
- "/metrics"
verbs:
- get

View File

@ -0,0 +1,17 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: proxy-role
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create

View File

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: proxy-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: proxy-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
labels:
control-plane: controller-manager
name: controller-manager-metrics-service
namespace: system
spec:
ports:
- name: https
port: 8443
protocol: TCP
targetPort: https
selector:
control-plane: controller-manager

View File

@ -0,0 +1,24 @@
# permissions for end users to edit gameservers.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gameserver-editor-role
rules:
- apiGroups:
- game.kruise.io
resources:
- gameservers
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- game.kruise.io
resources:
- gameservers/status
verbs:
- get

View File

@ -0,0 +1,20 @@
# permissions for end users to view gameservers.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gameserver-viewer-role
rules:
- apiGroups:
- game.kruise.io
resources:
- gameservers
verbs:
- get
- list
- watch
- apiGroups:
- game.kruise.io
resources:
- gameservers/status
verbs:
- get

View File

@ -0,0 +1,24 @@
# permissions for end users to edit gameserversets.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gameserverset-editor-role
rules:
- apiGroups:
- game.kruise.io
resources:
- gameserversets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- game.kruise.io
resources:
- gameserversets/status
verbs:
- get

View File

@ -0,0 +1,20 @@
# permissions for end users to view gameserversets.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: gameserverset-viewer-role
rules:
- apiGroups:
- game.kruise.io
resources:
- gameserversets
verbs:
- get
- list
- watch
- apiGroups:
- game.kruise.io
resources:
- gameserversets/status
verbs:
- get

View File

@ -0,0 +1,18 @@
resources:
# All RBAC will be applied under this service account in
# the deployment namespace. You may comment out this resource
# if your manager will use a service account that exists at
# runtime. Be sure to update RoleBinding and ClusterRoleBinding
# subjects if changing service account names.
- service_account.yaml
- role.yaml
- role_binding.yaml
- leader_election_role.yaml
- leader_election_role_binding.yaml
# Comment the following 4 lines if you want to disable
# the auth proxy (https://github.com/brancz/kube-rbac-proxy)
# which protects your /metrics endpoint.
- auth_proxy_service.yaml
- auth_proxy_role.yaml
- auth_proxy_role_binding.yaml
- auth_proxy_client_clusterrole.yaml

View File

@ -0,0 +1,37 @@
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: leader-election-role
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch

View File

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: leader-election-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: leader-election-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system

131
config/rbac/role.yaml Normal file
View File

@ -0,0 +1,131 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
verbs:
- create
- get
- list
- patch
- update
- watch
- apiGroups:
- admissionregistration.k8s.io
resources:
- validatingwebhookconfigurations
verbs:
- create
- get
- list
- patch
- update
- watch
- apiGroups:
- apiextensions.k8s.io
resources:
- customresourcedefinitions
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- apps.kruise.io
resources:
- statefulsets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps.kruise.io
resources:
- statefulsets/status
verbs:
- get
- patch
- update
- apiGroups:
- ""
resources:
- pods
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- pods/status
verbs:
- get
- patch
- update
- apiGroups:
- game.kruise.io
resources:
- gameservers
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- game.kruise.io
resources:
- gameservers/finalizers
verbs:
- update
- apiGroups:
- game.kruise.io
resources:
- gameservers/status
verbs:
- get
- patch
- update
- apiGroups:
- game.kruise.io
resources:
- gameserversets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- game.kruise.io
resources:
- gameserversets/finalizers
verbs:
- update
- apiGroups:
- game.kruise.io
resources:
- gameserversets/status
verbs:
- get
- patch
- update

View File

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: manager-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: manager-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system

View File

@ -0,0 +1,5 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: controller-manager
namespace: system

View File

@ -0,0 +1,2 @@
resources:
- service.yaml

View File

@ -0,0 +1,12 @@
---
apiVersion: v1
kind: Service
metadata:
name: webhook-service
namespace: kruise-game-system
spec:
ports:
- port: 443
targetPort: 9876
selector:
control-plane: controller-manager

View File

@ -0,0 +1,26 @@
# Installation
## Install manually
### 0. Edit Makefile, changing {IMG}
### 1. Build docker image with the kruise-game controller manager.
```shell
make docker-build
```
### 2. Push docker image with the kruise-game controller manager.
```shell
make docker-push
```
### 3. Deploy kruise-game controller manager to the K8s cluster.
```shell
make deploy
```
## Uninstall manually
```shell
make undeploy
```

View File

@ -0,0 +1,30 @@
# Introduction
## What is Kruise-Game?
Kruise-Game is an open source project based on OpenKruise, to solve the problem of game server landing in Kubernetes.
## Why is Kruise-Game?
Game servers are stateful services, and there are differences in the operation and maintenance of each game server, which also increases with time. In Kubernetes, general workloads manages a batch of game servers according to pod templates, which cannot take into account the differences in game server status. Batch management and directional management are in conflict in k8s. **Kruise-Game** was born to resolve that. Kruise-Game contains two CRDs, GameServer and GameServerSet:
- `GameServer` is responsible for the management of game server status. Users can customize the game server status to reflect the differences between game servers;
- `GameServerSet` is responsible for batch management of game servers. Users can customize update/reduction strategies according to the status of game servers.
## Features
- Game server status management
- Mark game servers status without effecting to its lifecycle
- Flexible scaling/deletion mechanism
- Support scaling down by user-defined status & priority
- Support specifying game server to delete directly
- Flexible update mechanism
- Support hot update (in-place update)
- Support updating game server by user-defined priority
- Can control the range of the game servers to be updated
- Can control the pace of the entire update process
- Custom service quality
- Support probing game servers containers and mark game servers status automatically
## What's Next
Here are some recommended next steps:
- Start to [Install kruise-game](./installation.md).
- Learn Kruise-Game's [Basic Usage](../tutorials/basic_usage.md).

BIN
docs/images/logo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View File

@ -0,0 +1,222 @@
# Basic Usage
## Requirements
- Installation of Kruise, Reference [Install OpenKruise](https://openkruise.io/zh/docs/installation/).
- Installation of Kruise-Game, Reference [Install Kruise-Game](../getting_started/installation.md)
## Deploy GameServerSet
This is an example of GameServerSet, which manages 3 game servers.
```yaml
apiVersion: game.kruise.io/v1alpha1
kind: GameServerSet
metadata:
name: minecraft
namespace: default
spec:
replicas: 3
updateStrategy:
rollingUpdate:
podUpdatePolicy: InPlaceIfPossible
gameServerTemplate:
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/minecraft-demo:1.12.2
name: minecraft
```
When the deployment is complete, the cluster will generate 1 GameServerset, 3 GameServers, and 3 Pods corresponding to GameServers
```bash
kubectl get gss
NAME AGE
minecraft 9s
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-1 Ready None 0 0
minecraft-2 Ready None 0 0
kubectl get pod
NAME READY STATUS RESTARTS AGE
minecraft-0 1/1 Running 0 10s
minecraft-1 1/1 Running 0 10s
minecraft-2 1/1 Running 0 10s
```
## Game servers scale up
Directly adjust the number of replicas to the desired number
```bash
kubectl scale gss minecraft --replicas=5
gameserverset.game.kruise.io/minecraft scaled
```
The number of game servers eventually became 5
```bash
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-1 Ready None 0 0
minecraft-2 Ready None 0 0
minecraft-3 Ready None 0 0
minecraft-4 Ready None 0 0
```
## Game servers scale down by deletion priority
Manually set the GameServer deletionPriority (you can set the deletionPriority automatically through the ServiceQuality function)
```yaml
kubectl edit gs minecraft-2
...
spec:
deletionPriority: 10 #initial value is 0turn it up to 10
opsState: None
updatePriority: 0
...
```
Scale down
```bash
kubectl scale gss minecraft --replicas=4
gameserverset.game.kruise.io/minecraft scale
```
The numbers of game servers eventually became 4. It can be found that the No.2 gs with the highest deletionPriority has been deleted.
```bash
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-1 Ready None 0 0
minecraft-2 Deleting None 10 0
minecraft-3 Ready None 0 0
minecraft-4 Ready None 0 0
# After a while
...
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-1 Ready None 0 0
minecraft-3 Ready None 0 0
minecraft-4 Ready None 0 0
```
## Game servers scale down by OpsState
Manually set the GameServer OpsState to `WaitToBeDeleted` (you can set the OpsState automatically through the ServiceQuality function)
```yaml
kubectl edit gs minecraft-3
...
spec:
deletionPriority: 0
opsState: WaitToBeDeleted #Initialization is None, will be changed to WaitToBeDeleted
updatePriority: 0
...
```
Scale down
```bash
kubectl scale gss minecraft --replicas=3
gameserverset.game.kruise.io/minecraft scaled
```
The numbers of game servers eventually became 3. It can be found that the No.3 gs with WaitToBeDeleted OpsState has been deleted.
```bash
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-1 Ready None 0 0
minecraft-3 Deleting None 10 0
minecraft-4 Ready None 0 0
# After a while
...
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-1 Ready None 0 0
minecraft-4 Ready None 0 0
```
## Specify game server offline
Specify the game server with serial No.1 to go offline
```yaml
kubectl edit gss minecraft
...
spec:
replicas: 2 #replicas is reduced by 1, adjusted to 2
reserveGameServerIds:
- 1 #specify serial No.1
...
```
The numbers of game servers eventually became 2. It can be found that the No.1 gs has been deleted.
```bash
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-1 Deleting None 0 0
minecraft-4 Ready None 0 0
# After a while
...
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 0
minecraft-4 Ready None 0 0
```
## Game servers update by update priority
Manually set the GameServer updatePriority (you can set the updatePriority automatically through the ServiceQuality function)
```yaml
kubectl edit gs minecraft-0
...
spec:
deletionPriority: 0
opsState: None
updatePriority: 10 #initial value is 0turn it up to 10
...
```
Update game servers' image
```yaml
kubectl edit gss minecraft
...
spec:
gameServerTemplate:
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/minecraft-demo:1.13.0 #update images tag to 1.13.0
name: minecraft
...
```
Pay attention to the update process, you can find that the GameServer with a larger updatePriority is updated first
```bash
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Updating None 0 10
minecraft-4 Ready None 0 0
# After a while
...
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 10
minecraft-4 Updating None 0 0
# After a while
...
kubectl get gs
NAME STATE OPSSTATE DP UP
minecraft-0 Ready None 0 10
minecraft-4 Ready None 0 0
```

89
go.mod Normal file
View File

@ -0,0 +1,89 @@
module github.com/openkruise/kruise-game
go 1.18
require (
github.com/davecgh/go-spew v1.1.1
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.18.1
github.com/openkruise/kruise-api v1.2.0
k8s.io/api v0.24.0
k8s.io/apimachinery v0.24.0
k8s.io/client-go v0.24.0
k8s.io/code-generator v0.24.0
k8s.io/klog/v2 v2.60.1
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9
sigs.k8s.io/controller-runtime v0.12.1
)
require (
cloud.google.com/go v0.81.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-logr/logr v1.2.0 // indirect
github.com/go-logr/zapr v1.2.0 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.5 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/spf13/pflag v1.0.5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.27.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/apiextensions-apiserver v0.24.0 // indirect
k8s.io/component-base v0.24.0 // indirect
k8s.io/gengo v0.0.0-20211129171323-c02415ce4185 // indirect
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
)

1017
go.sum Normal file

File diff suppressed because it is too large Load Diff

15
hack/boilerplate.go.txt Normal file
View File

@ -0,0 +1,15 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/

170
hack/gencerts.sh Normal file
View File

@ -0,0 +1,170 @@
#!/bin/bash
#
# 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
#
# 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.
#
# Generates a CA certificate, a server key, and a server certificate signed by the CA.
set -e
SCRIPT=`basename ${BASH_SOURCE[0]}`
function usage {
cat<< EOF
Usage: $SCRIPT
Options:
-h | --help Display help information.
-n | --namespace <namespace> The namespace where the Spark operator is installed.
-s | --service <service> The name of the webhook service.
-p | --in-pod Whether the script is running inside a pod or not.
EOF
}
function parse_arguments {
while [[ $# -gt 0 ]]
do
case "$1" in
-n|--namespace)
if [[ -n "$2" ]]; then
NAMESPACE="$2"
else
echo "-n or --namespace requires a value."
exit 1
fi
shift 2
continue
;;
-s|--service)
if [[ -n "$2" ]]; then
SERVICE="$2"
else
echo "-s or --service requires a value."
exit 1
fi
shift 2
continue
;;
-p|--in-pod)
export IN_POD=true
shift 1
continue
;;
-h|--help)
usage
exit 0
;;
--) # End of all options.
shift
break
;;
'') # End of all options.
break
;;
*)
echo "Unrecognized option: $1"
exit 1
;;
esac
done
}
# Set the namespace to "kruise-game-system" by default if not provided.
# Set the webhook service name to "kruise-game-webhook" by default if not provided.
IN_POD=false
SERVICE="kruise-game-webhook"
NAMESPACE="kruise-game-system"
parse_arguments "$@"
TMP_DIR="/tmp/kruise-pod-webhook-certs"
echo "Generating certs for the kruise-game pod admission webhook in ${TMP_DIR}."
mkdir -p ${TMP_DIR}
cat > ${TMP_DIR}/server.conf << EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
[req_distinguished_name]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
subjectAltName = DNS:kruise-game-webhook.kruise-game-system.svc
EOF
# Create a certificate authority.
touch ${TMP_DIR}/.rnd
export RANDFILE=${TMP_DIR}/.rnd
openssl genrsa -out ${TMP_DIR}/ca-key.pem 2048
openssl req -x509 -new -nodes -key ${TMP_DIR}/ca-key.pem -days 100000 -out ${TMP_DIR}/ca-cert.pem -subj "/CN=${SERVICE}_ca" -addext "subjectAltName = DNS:${SERVICE}_ca"
# Create a server certificate.
openssl genrsa -out ${TMP_DIR}/server-key.pem 2048
# Note the CN is the DNS name of the service of the webhook.
openssl req -new -key ${TMP_DIR}/server-key.pem -out ${TMP_DIR}/server.csr -subj "/CN=${SERVICE}.${NAMESPACE}.svc" -config ${TMP_DIR}/server.conf -addext "subjectAltName = DNS:kruise-game-webhook.kruise-game-system.svc"
openssl x509 -req -in ${TMP_DIR}/server.csr -CA ${TMP_DIR}/ca-cert.pem -CAkey ${TMP_DIR}/ca-key.pem -CAcreateserial -out ${TMP_DIR}/server-cert.pem -days 100000 -extensions v3_req -extfile ${TMP_DIR}/server.conf
if [[ "$IN_POD" == "true" ]]; then
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# Base64 encode secrets and then remove the trailing newline to avoid issues in the curl command
ca_cert=$(cat ${TMP_DIR}/ca-cert.pem | base64 | tr -d '\n')
ca_key=$(cat ${TMP_DIR}/ca-key.pem | base64 | tr -d '\n')
server_cert=$(cat ${TMP_DIR}/server-cert.pem | base64 | tr -d '\n')
server_key=$(cat ${TMP_DIR}/server-key.pem | base64 | tr -d '\n')
# Create the secret resource
echo "Creating a secret for the certificate and keys"
STATUS=$(curl -ik \
-o ${TMP_DIR}/output \
-w "%{http_code}" \
-X POST \
-H "Authorization: Bearer $TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"kind": "Secret",
"apiVersion": "v1",
"metadata": {
"name": "kruise-game-webhook-certs",
"namespace": "'"$NAMESPACE"'"
},
"data": {
"ca-cert.pem": "'"$ca_cert"'",
"ca-key.pem": "'"$ca_key"'",
"server-cert.pem": "'"$server_cert"'",
"server-key.pem": "'"$server_key"'"
}
}' \
https://kubernetes.default.svc/api/v1/namespaces/${NAMESPACE}/secrets)
cat ${TMP_DIR}/output
case "$STATUS" in
201)
printf "\nSuccess - secret created.\n"
;;
409)
printf "\nSuccess - secret already exists.\n"
;;
*)
printf "\nFailed creating secret.\n"
exit 1
;;
esac
else
kubectl create secret --namespace=${NAMESPACE} generic kruise-game-webhook-certs --from-file=${TMP_DIR}/ca-key.pem --from-file=${TMP_DIR}/ca-cert.pem --from-file=${TMP_DIR}/server-key.pem --from-file=${TMP_DIR}/server-cert.pem
fi
# Clean up after we're done.
printf "\nDeleting ${TMP_DIR}.\n"
rm -rf ${TMP_DIR}

25
hack/tools.go Normal file
View File

@ -0,0 +1,25 @@
//go:build tools
// +build tools
/*
Copyright 2022 The Kruise Authors.
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.
*/
// This package imports things required by build scripts, to force `go mod` to see them as dependencies
package hack
import (
_ "k8s.io/code-generator"
)

150
main.go Normal file
View File

@ -0,0 +1,150 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"flag"
kruiseV1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
controller "github.com/openkruise/kruise-game/pkg/controllers"
"github.com/openkruise/kruise-game/pkg/webhook"
"os"
"time"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
_ "k8s.io/client-go/plugin/pkg/client/auth"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
gamekruiseiov1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
utilclient "github.com/openkruise/kruise-game/pkg/util/client"
//+kubebuilder:scaffold:imports
)
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
)
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(gamekruiseiov1alpha1.AddToScheme(scheme))
utilruntime.Must(kruiseV1beta1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
}
func main() {
var metricsAddr string
var enableLeaderElection bool
var probeAddr string
var namespace string
var syncPeriodStr string
flag.StringVar(&metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.")
flag.StringVar(&probeAddr, "health-probe-bind-address", ":8082", "The address the probe endpoint binds to.")
flag.BoolVar(&enableLeaderElection, "leader-elect", false,
"Enable leader election for controller manager. "+
"Enabling this will ensure there is only one active controller manager.")
flag.StringVar(&namespace, "namespace", "",
"Namespace if specified restricts the manager's cache to watch objects in the desired namespace. Defaults to all namespaces.")
flag.StringVar(&syncPeriodStr, "sync-period", "", "Determines the minimum frequency at which watched resources are reconciled.")
opts := zap.Options{
Development: true,
}
opts.BindFlags(flag.CommandLine)
flag.Parse()
ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
// syncPeriod parsed
var syncPeriod *time.Duration
if syncPeriodStr != "" {
d, err := time.ParseDuration(syncPeriodStr)
if err != nil {
setupLog.Error(err, "invalid sync period flag")
} else {
syncPeriod = &d
}
}
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Port: 9443,
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "game-kruise-manager",
// LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily
// when the Manager ends. This requires the binary to immediately end when the
// Manager is stopped, otherwise, this setting is unsafe. Setting this significantly
// speeds up voluntary leader transitions as the new leader don't have to wait
// LeaseDuration time first.
//
// In the default scaffold provided, the program ends immediately after
// the manager stops, so would be fine to enable this option. However,
// if you are doing or is intended to do any operation such as perform cleanups
// after the manager stops then its usage might be unsafe.
// LeaderElectionReleaseOnCancel: true,
Namespace: namespace,
SyncPeriod: syncPeriod,
NewClient: utilclient.NewClient,
})
if err != nil {
setupLog.Error(err, "unable to start kruise-game-manager")
os.Exit(1)
}
// create webhook server
wss := webhook.NewWebhookServer(mgr)
// validate webhook server
if err := wss.SetupWithManager(mgr).Initialize(mgr.GetConfig()); err != nil {
setupLog.Error(err, "unable to set up webhook server")
os.Exit(1)
}
//+kubebuilder:scaffold:builder
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up health check")
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
setupLog.Error(err, "unable to set up ready check")
os.Exit(1)
}
go func() {
setupLog.Info("setup controllers")
if err = controller.SetupWithManager(mgr); err != nil {
setupLog.Error(err, "unable to setup controllers")
os.Exit(1)
}
}()
setupLog.Info("starting kruise-game-manager")
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
setupLog.Error(err, "problem running manager")
os.Exit(1)
}
}

View File

@ -0,0 +1,120 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package versioned
import (
"fmt"
"net/http"
gamev1alpha1 "github.com/openkruise/kruise-game/pkg/client/clientset/versioned/typed/apis/v1alpha1"
discovery "k8s.io/client-go/discovery"
rest "k8s.io/client-go/rest"
flowcontrol "k8s.io/client-go/util/flowcontrol"
)
type Interface interface {
Discovery() discovery.DiscoveryInterface
GameV1alpha1() gamev1alpha1.GameV1alpha1Interface
}
// Clientset contains the clients for groups. Each group has exactly one
// version included in a Clientset.
type Clientset struct {
*discovery.DiscoveryClient
gameV1alpha1 *gamev1alpha1.GameV1alpha1Client
}
// GameV1alpha1 retrieves the GameV1alpha1Client
func (c *Clientset) GameV1alpha1() gamev1alpha1.GameV1alpha1Interface {
return c.gameV1alpha1
}
// Discovery retrieves the DiscoveryClient
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
if c == nil {
return nil
}
return c.DiscoveryClient
}
// NewForConfig creates a new Clientset for the given config.
// If config's RateLimiter is not set and QPS and Burst are acceptable,
// NewForConfig will generate a rate-limiter in configShallowCopy.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c).
func NewForConfig(c *rest.Config) (*Clientset, error) {
configShallowCopy := *c
if configShallowCopy.UserAgent == "" {
configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent()
}
// share the transport between all clients
httpClient, err := rest.HTTPClientFor(&configShallowCopy)
if err != nil {
return nil, err
}
return NewForConfigAndClient(&configShallowCopy, httpClient)
}
// NewForConfigAndClient creates a new Clientset for the given config and http client.
// Note the http client provided takes precedence over the configured transport values.
// If config's RateLimiter is not set and QPS and Burst are acceptable,
// NewForConfigAndClient will generate a rate-limiter in configShallowCopy.
func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) {
configShallowCopy := *c
if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 {
if configShallowCopy.Burst <= 0 {
return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0")
}
configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst)
}
var cs Clientset
var err error
cs.gameV1alpha1, err = gamev1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient)
if err != nil {
return nil, err
}
cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient)
if err != nil {
return nil, err
}
return &cs, nil
}
// NewForConfigOrDie creates a new Clientset for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *Clientset {
cs, err := NewForConfig(c)
if err != nil {
panic(err)
}
return cs
}
// New creates a new Clientset for the given RESTClient.
func New(c rest.Interface) *Clientset {
var cs Clientset
cs.gameV1alpha1 = gamev1alpha1.New(c)
cs.DiscoveryClient = discovery.NewDiscoveryClient(c)
return &cs
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated clientset.
package versioned

View File

@ -0,0 +1,84 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
clientset "github.com/openkruise/kruise-game/pkg/client/clientset/versioned"
gamev1alpha1 "github.com/openkruise/kruise-game/pkg/client/clientset/versioned/typed/apis/v1alpha1"
fakegamev1alpha1 "github.com/openkruise/kruise-game/pkg/client/clientset/versioned/typed/apis/v1alpha1/fake"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/discovery"
fakediscovery "k8s.io/client-go/discovery/fake"
"k8s.io/client-go/testing"
)
// NewSimpleClientset returns a clientset that will respond with the provided objects.
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
// without applying any validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests.
func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
for _, obj := range objects {
if err := o.Add(obj); err != nil {
panic(err)
}
}
cs := &Clientset{tracker: o}
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
cs.AddReactor("*", "*", testing.ObjectReaction(o))
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
gvr := action.GetResource()
ns := action.GetNamespace()
watch, err := o.Watch(gvr, ns)
if err != nil {
return false, nil, err
}
return true, watch, nil
})
return cs
}
// Clientset implements clientset.Interface. Meant to be embedded into a
// struct to get a default implementation. This makes faking out just the method
// you want to test easier.
type Clientset struct {
testing.Fake
discovery *fakediscovery.FakeDiscovery
tracker testing.ObjectTracker
}
func (c *Clientset) Discovery() discovery.DiscoveryInterface {
return c.discovery
}
func (c *Clientset) Tracker() testing.ObjectTracker {
return c.tracker
}
var (
_ clientset.Interface = &Clientset{}
_ testing.FakeClient = &Clientset{}
)
// GameV1alpha1 retrieves the GameV1alpha1Client
func (c *Clientset) GameV1alpha1() gamev1alpha1.GameV1alpha1Interface {
return &fakegamev1alpha1.FakeGameV1alpha1{Fake: &c.Fake}
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated fake clientset.
package fake

View File

@ -0,0 +1,55 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
gamev1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
var scheme = runtime.NewScheme()
var codecs = serializer.NewCodecFactory(scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
gamev1alpha1.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:
//
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
//
// kclientset, _ := kubernetes.NewForConfig(c)
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
//
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.
var AddToScheme = localSchemeBuilder.AddToScheme
func init() {
v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"})
utilruntime.Must(AddToScheme(scheme))
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package contains the scheme of the automatically generated clientset.
package scheme

View File

@ -0,0 +1,55 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package scheme
import (
gamev1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
serializer "k8s.io/apimachinery/pkg/runtime/serializer"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
var Scheme = runtime.NewScheme()
var Codecs = serializer.NewCodecFactory(Scheme)
var ParameterCodec = runtime.NewParameterCodec(Scheme)
var localSchemeBuilder = runtime.SchemeBuilder{
gamev1alpha1.AddToScheme,
}
// AddToScheme adds all types of this clientset into the given scheme. This allows composition
// of clientsets, like in:
//
// import (
// "k8s.io/client-go/kubernetes"
// clientsetscheme "k8s.io/client-go/kubernetes/scheme"
// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme"
// )
//
// kclientset, _ := kubernetes.NewForConfig(c)
// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme)
//
// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types
// correctly.
var AddToScheme = localSchemeBuilder.AddToScheme
func init() {
v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"})
utilruntime.Must(AddToScheme(Scheme))
}

View File

@ -0,0 +1,111 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"net/http"
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
"github.com/openkruise/kruise-game/pkg/client/clientset/versioned/scheme"
rest "k8s.io/client-go/rest"
)
type GameV1alpha1Interface interface {
RESTClient() rest.Interface
GameServersGetter
GameServerSetsGetter
}
// GameV1alpha1Client is used to interact with features provided by the game.kruise.io group.
type GameV1alpha1Client struct {
restClient rest.Interface
}
func (c *GameV1alpha1Client) GameServers(namespace string) GameServerInterface {
return newGameServers(c, namespace)
}
func (c *GameV1alpha1Client) GameServerSets(namespace string) GameServerSetInterface {
return newGameServerSets(c, namespace)
}
// NewForConfig creates a new GameV1alpha1Client for the given config.
// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient),
// where httpClient was generated with rest.HTTPClientFor(c).
func NewForConfig(c *rest.Config) (*GameV1alpha1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
httpClient, err := rest.HTTPClientFor(&config)
if err != nil {
return nil, err
}
return NewForConfigAndClient(&config, httpClient)
}
// NewForConfigAndClient creates a new GameV1alpha1Client for the given config and http client.
// Note the http client provided takes precedence over the configured transport values.
func NewForConfigAndClient(c *rest.Config, h *http.Client) (*GameV1alpha1Client, error) {
config := *c
if err := setConfigDefaults(&config); err != nil {
return nil, err
}
client, err := rest.RESTClientForConfigAndClient(&config, h)
if err != nil {
return nil, err
}
return &GameV1alpha1Client{client}, nil
}
// NewForConfigOrDie creates a new GameV1alpha1Client for the given config and
// panics if there is an error in the config.
func NewForConfigOrDie(c *rest.Config) *GameV1alpha1Client {
client, err := NewForConfig(c)
if err != nil {
panic(err)
}
return client
}
// New creates a new GameV1alpha1Client for the given RESTClient.
func New(c rest.Interface) *GameV1alpha1Client {
return &GameV1alpha1Client{c}
}
func setConfigDefaults(config *rest.Config) error {
gv := v1alpha1.SchemeGroupVersion
config.GroupVersion = &gv
config.APIPath = "/apis"
config.NegotiatedSerializer = scheme.Codecs.WithoutConversion()
if config.UserAgent == "" {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
return nil
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *GameV1alpha1Client) RESTClient() rest.Interface {
if c == nil {
return nil
}
return c.restClient
}

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v1alpha1

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// Package fake has the automatically generated clients.
package fake

View File

@ -0,0 +1,43 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
v1alpha1 "github.com/openkruise/kruise-game/pkg/client/clientset/versioned/typed/apis/v1alpha1"
rest "k8s.io/client-go/rest"
testing "k8s.io/client-go/testing"
)
type FakeGameV1alpha1 struct {
*testing.Fake
}
func (c *FakeGameV1alpha1) GameServers(namespace string) v1alpha1.GameServerInterface {
return &FakeGameServers{c, namespace}
}
func (c *FakeGameV1alpha1) GameServerSets(namespace string) v1alpha1.GameServerSetInterface {
return &FakeGameServerSets{c, namespace}
}
// RESTClient returns a RESTClient that is used to communicate
// with API server by this client implementation.
func (c *FakeGameV1alpha1) RESTClient() rest.Interface {
var ret *rest.RESTClient
return ret
}

View File

@ -0,0 +1,141 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeGameServers implements GameServerInterface
type FakeGameServers struct {
Fake *FakeGameV1alpha1
ns string
}
var gameserversResource = schema.GroupVersionResource{Group: "game.kruise.io", Version: "v1alpha1", Resource: "gameservers"}
var gameserversKind = schema.GroupVersionKind{Group: "game.kruise.io", Version: "v1alpha1", Kind: "GameServer"}
// Get takes name of the gameServer, and returns the corresponding gameServer object, and an error if there is any.
func (c *FakeGameServers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.GameServer, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(gameserversResource, c.ns, name), &v1alpha1.GameServer{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServer), err
}
// List takes label and field selectors, and returns the list of GameServers that match those selectors.
func (c *FakeGameServers) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.GameServerList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(gameserversResource, gameserversKind, c.ns, opts), &v1alpha1.GameServerList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.GameServerList{ListMeta: obj.(*v1alpha1.GameServerList).ListMeta}
for _, item := range obj.(*v1alpha1.GameServerList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested gameServers.
func (c *FakeGameServers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(gameserversResource, c.ns, opts))
}
// Create takes the representation of a gameServer and creates it. Returns the server's representation of the gameServer, and an error, if there is any.
func (c *FakeGameServers) Create(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.CreateOptions) (result *v1alpha1.GameServer, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(gameserversResource, c.ns, gameServer), &v1alpha1.GameServer{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServer), err
}
// Update takes the representation of a gameServer and updates it. Returns the server's representation of the gameServer, and an error, if there is any.
func (c *FakeGameServers) Update(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.UpdateOptions) (result *v1alpha1.GameServer, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(gameserversResource, c.ns, gameServer), &v1alpha1.GameServer{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServer), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeGameServers) UpdateStatus(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.UpdateOptions) (*v1alpha1.GameServer, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(gameserversResource, "status", c.ns, gameServer), &v1alpha1.GameServer{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServer), err
}
// Delete takes name of the gameServer and deletes it. Returns an error if one occurs.
func (c *FakeGameServers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteActionWithOptions(gameserversResource, c.ns, name, opts), &v1alpha1.GameServer{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeGameServers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(gameserversResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha1.GameServerList{})
return err
}
// Patch applies the patch and returns the patched gameServer.
func (c *FakeGameServers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.GameServer, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(gameserversResource, c.ns, name, pt, data, subresources...), &v1alpha1.GameServer{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServer), err
}

View File

@ -0,0 +1,141 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake
import (
"context"
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
labels "k8s.io/apimachinery/pkg/labels"
schema "k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
testing "k8s.io/client-go/testing"
)
// FakeGameServerSets implements GameServerSetInterface
type FakeGameServerSets struct {
Fake *FakeGameV1alpha1
ns string
}
var gameserversetsResource = schema.GroupVersionResource{Group: "game.kruise.io", Version: "v1alpha1", Resource: "gameserversets"}
var gameserversetsKind = schema.GroupVersionKind{Group: "game.kruise.io", Version: "v1alpha1", Kind: "GameServerSet"}
// Get takes name of the gameServerSet, and returns the corresponding gameServerSet object, and an error if there is any.
func (c *FakeGameServerSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.GameServerSet, err error) {
obj, err := c.Fake.
Invokes(testing.NewGetAction(gameserversetsResource, c.ns, name), &v1alpha1.GameServerSet{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServerSet), err
}
// List takes label and field selectors, and returns the list of GameServerSets that match those selectors.
func (c *FakeGameServerSets) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.GameServerSetList, err error) {
obj, err := c.Fake.
Invokes(testing.NewListAction(gameserversetsResource, gameserversetsKind, c.ns, opts), &v1alpha1.GameServerSetList{})
if obj == nil {
return nil, err
}
label, _, _ := testing.ExtractFromListOptions(opts)
if label == nil {
label = labels.Everything()
}
list := &v1alpha1.GameServerSetList{ListMeta: obj.(*v1alpha1.GameServerSetList).ListMeta}
for _, item := range obj.(*v1alpha1.GameServerSetList).Items {
if label.Matches(labels.Set(item.Labels)) {
list.Items = append(list.Items, item)
}
}
return list, err
}
// Watch returns a watch.Interface that watches the requested gameServerSets.
func (c *FakeGameServerSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
return c.Fake.
InvokesWatch(testing.NewWatchAction(gameserversetsResource, c.ns, opts))
}
// Create takes the representation of a gameServerSet and creates it. Returns the server's representation of the gameServerSet, and an error, if there is any.
func (c *FakeGameServerSets) Create(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.CreateOptions) (result *v1alpha1.GameServerSet, err error) {
obj, err := c.Fake.
Invokes(testing.NewCreateAction(gameserversetsResource, c.ns, gameServerSet), &v1alpha1.GameServerSet{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServerSet), err
}
// Update takes the representation of a gameServerSet and updates it. Returns the server's representation of the gameServerSet, and an error, if there is any.
func (c *FakeGameServerSets) Update(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.UpdateOptions) (result *v1alpha1.GameServerSet, err error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateAction(gameserversetsResource, c.ns, gameServerSet), &v1alpha1.GameServerSet{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServerSet), err
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *FakeGameServerSets) UpdateStatus(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.UpdateOptions) (*v1alpha1.GameServerSet, error) {
obj, err := c.Fake.
Invokes(testing.NewUpdateSubresourceAction(gameserversetsResource, "status", c.ns, gameServerSet), &v1alpha1.GameServerSet{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServerSet), err
}
// Delete takes name of the gameServerSet and deletes it. Returns an error if one occurs.
func (c *FakeGameServerSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
_, err := c.Fake.
Invokes(testing.NewDeleteActionWithOptions(gameserversetsResource, c.ns, name, opts), &v1alpha1.GameServerSet{})
return err
}
// DeleteCollection deletes a collection of objects.
func (c *FakeGameServerSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
action := testing.NewDeleteCollectionAction(gameserversetsResource, c.ns, listOpts)
_, err := c.Fake.Invokes(action, &v1alpha1.GameServerSetList{})
return err
}
// Patch applies the patch and returns the patched gameServerSet.
func (c *FakeGameServerSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.GameServerSet, err error) {
obj, err := c.Fake.
Invokes(testing.NewPatchSubresourceAction(gameserversetsResource, c.ns, name, pt, data, subresources...), &v1alpha1.GameServerSet{})
if obj == nil {
return nil, err
}
return obj.(*v1alpha1.GameServerSet), err
}

View File

@ -0,0 +1,194 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
"time"
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
scheme "github.com/openkruise/kruise-game/pkg/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// GameServersGetter has a method to return a GameServerInterface.
// A group's client should implement this interface.
type GameServersGetter interface {
GameServers(namespace string) GameServerInterface
}
// GameServerInterface has methods to work with GameServer resources.
type GameServerInterface interface {
Create(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.CreateOptions) (*v1alpha1.GameServer, error)
Update(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.UpdateOptions) (*v1alpha1.GameServer, error)
UpdateStatus(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.UpdateOptions) (*v1alpha1.GameServer, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.GameServer, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.GameServerList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.GameServer, err error)
GameServerExpansion
}
// gameServers implements GameServerInterface
type gameServers struct {
client rest.Interface
ns string
}
// newGameServers returns a GameServers
func newGameServers(c *GameV1alpha1Client, namespace string) *gameServers {
return &gameServers{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the gameServer, and returns the corresponding gameServer object, and an error if there is any.
func (c *gameServers) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.GameServer, err error) {
result = &v1alpha1.GameServer{}
err = c.client.Get().
Namespace(c.ns).
Resource("gameservers").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of GameServers that match those selectors.
func (c *gameServers) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.GameServerList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha1.GameServerList{}
err = c.client.Get().
Namespace(c.ns).
Resource("gameservers").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested gameServers.
func (c *gameServers) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("gameservers").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a gameServer and creates it. Returns the server's representation of the gameServer, and an error, if there is any.
func (c *gameServers) Create(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.CreateOptions) (result *v1alpha1.GameServer, err error) {
result = &v1alpha1.GameServer{}
err = c.client.Post().
Namespace(c.ns).
Resource("gameservers").
VersionedParams(&opts, scheme.ParameterCodec).
Body(gameServer).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a gameServer and updates it. Returns the server's representation of the gameServer, and an error, if there is any.
func (c *gameServers) Update(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.UpdateOptions) (result *v1alpha1.GameServer, err error) {
result = &v1alpha1.GameServer{}
err = c.client.Put().
Namespace(c.ns).
Resource("gameservers").
Name(gameServer.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(gameServer).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *gameServers) UpdateStatus(ctx context.Context, gameServer *v1alpha1.GameServer, opts v1.UpdateOptions) (result *v1alpha1.GameServer, err error) {
result = &v1alpha1.GameServer{}
err = c.client.Put().
Namespace(c.ns).
Resource("gameservers").
Name(gameServer.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(gameServer).
Do(ctx).
Into(result)
return
}
// Delete takes name of the gameServer and deletes it. Returns an error if one occurs.
func (c *gameServers) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("gameservers").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *gameServers) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("gameservers").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched gameServer.
func (c *gameServers) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.GameServer, err error) {
result = &v1alpha1.GameServer{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("gameservers").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -0,0 +1,194 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
"time"
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
scheme "github.com/openkruise/kruise-game/pkg/client/clientset/versioned/scheme"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
)
// GameServerSetsGetter has a method to return a GameServerSetInterface.
// A group's client should implement this interface.
type GameServerSetsGetter interface {
GameServerSets(namespace string) GameServerSetInterface
}
// GameServerSetInterface has methods to work with GameServerSet resources.
type GameServerSetInterface interface {
Create(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.CreateOptions) (*v1alpha1.GameServerSet, error)
Update(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.UpdateOptions) (*v1alpha1.GameServerSet, error)
UpdateStatus(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.UpdateOptions) (*v1alpha1.GameServerSet, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.GameServerSet, error)
List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.GameServerSetList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.GameServerSet, err error)
GameServerSetExpansion
}
// gameServerSets implements GameServerSetInterface
type gameServerSets struct {
client rest.Interface
ns string
}
// newGameServerSets returns a GameServerSets
func newGameServerSets(c *GameV1alpha1Client, namespace string) *gameServerSets {
return &gameServerSets{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the gameServerSet, and returns the corresponding gameServerSet object, and an error if there is any.
func (c *gameServerSets) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.GameServerSet, err error) {
result = &v1alpha1.GameServerSet{}
err = c.client.Get().
Namespace(c.ns).
Resource("gameserversets").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of GameServerSets that match those selectors.
func (c *gameServerSets) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.GameServerSetList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1alpha1.GameServerSetList{}
err = c.client.Get().
Namespace(c.ns).
Resource("gameserversets").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested gameServerSets.
func (c *gameServerSets) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("gameserversets").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a gameServerSet and creates it. Returns the server's representation of the gameServerSet, and an error, if there is any.
func (c *gameServerSets) Create(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.CreateOptions) (result *v1alpha1.GameServerSet, err error) {
result = &v1alpha1.GameServerSet{}
err = c.client.Post().
Namespace(c.ns).
Resource("gameserversets").
VersionedParams(&opts, scheme.ParameterCodec).
Body(gameServerSet).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a gameServerSet and updates it. Returns the server's representation of the gameServerSet, and an error, if there is any.
func (c *gameServerSets) Update(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.UpdateOptions) (result *v1alpha1.GameServerSet, err error) {
result = &v1alpha1.GameServerSet{}
err = c.client.Put().
Namespace(c.ns).
Resource("gameserversets").
Name(gameServerSet.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(gameServerSet).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *gameServerSets) UpdateStatus(ctx context.Context, gameServerSet *v1alpha1.GameServerSet, opts v1.UpdateOptions) (result *v1alpha1.GameServerSet, err error) {
result = &v1alpha1.GameServerSet{}
err = c.client.Put().
Namespace(c.ns).
Resource("gameserversets").
Name(gameServerSet.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(gameServerSet).
Do(ctx).
Into(result)
return
}
// Delete takes name of the gameServerSet and deletes it. Returns an error if one occurs.
func (c *gameServerSets) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("gameserversets").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *gameServerSets) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("gameserversets").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched gameServerSet.
func (c *gameServerSets) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.GameServerSet, err error) {
result = &v1alpha1.GameServerSet{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("gameserversets").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}

View File

@ -0,0 +1,22 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1alpha1
type GameServerExpansion interface{}
type GameServerSetExpansion interface{}

View File

@ -0,0 +1,64 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
kruiseclientset "github.com/openkruise/kruise-game/pkg/client/clientset/versioned"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/discovery"
kubeclientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
)
// GenericClientset defines a generic client
type GenericClientset struct {
DiscoveryClient discovery.DiscoveryInterface
KubeClient kubeclientset.Interface
KruiseGameClient kruiseclientset.Interface
}
// newForConfig creates a new Clientset for the given config.
func newForConfig(c *rest.Config) (*GenericClientset, error) {
cWithProtobuf := rest.CopyConfig(c)
cWithProtobuf.ContentType = runtime.ContentTypeProtobuf
discoveryClient, err := discovery.NewDiscoveryClientForConfig(cWithProtobuf)
if err != nil {
return nil, err
}
kubeClient, err := kubeclientset.NewForConfig(cWithProtobuf)
if err != nil {
return nil, err
}
kruiseClient, err := kruiseclientset.NewForConfig(c)
if err != nil {
return nil, err
}
return &GenericClientset{
DiscoveryClient: discoveryClient,
KubeClient: kubeClient,
KruiseGameClient: kruiseClient,
}, nil
}
// newForConfig creates a new Clientset for the given config.
func newForConfigOrDie(c *rest.Config) *GenericClientset {
gc, err := newForConfig(c)
if err != nil {
panic(err)
}
return gc
}

View File

@ -0,0 +1,45 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package apis
import (
v1alpha1 "github.com/openkruise/kruise-game/pkg/client/informers/externalversions/apis/v1alpha1"
internalinterfaces "github.com/openkruise/kruise-game/pkg/client/informers/externalversions/internalinterfaces"
)
// Interface provides access to each of this group's versions.
type Interface interface {
// V1alpha1 provides access to shared informers for resources in V1alpha1.
V1alpha1() v1alpha1.Interface
}
type group struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// V1alpha1 returns a new v1alpha1.Interface.
func (g *group) V1alpha1() v1alpha1.Interface {
return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions)
}

View File

@ -0,0 +1,89 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
time "time"
apisv1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
versioned "github.com/openkruise/kruise-game/pkg/client/clientset/versioned"
internalinterfaces "github.com/openkruise/kruise-game/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "github.com/openkruise/kruise-game/pkg/client/listers/apis/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// GameServerInformer provides access to a shared informer and lister for
// GameServers.
type GameServerInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha1.GameServerLister
}
type gameServerInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewGameServerInformer constructs a new informer for GameServer type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewGameServerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredGameServerInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredGameServerInformer constructs a new informer for GameServer type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredGameServerInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.GameV1alpha1().GameServers(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.GameV1alpha1().GameServers(namespace).Watch(context.TODO(), options)
},
},
&apisv1alpha1.GameServer{},
resyncPeriod,
indexers,
)
}
func (f *gameServerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredGameServerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *gameServerInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&apisv1alpha1.GameServer{}, f.defaultInformer)
}
func (f *gameServerInformer) Lister() v1alpha1.GameServerLister {
return v1alpha1.NewGameServerLister(f.Informer().GetIndexer())
}

View File

@ -0,0 +1,89 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
"context"
time "time"
apisv1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
versioned "github.com/openkruise/kruise-game/pkg/client/clientset/versioned"
internalinterfaces "github.com/openkruise/kruise-game/pkg/client/informers/externalversions/internalinterfaces"
v1alpha1 "github.com/openkruise/kruise-game/pkg/client/listers/apis/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// GameServerSetInformer provides access to a shared informer and lister for
// GameServerSets.
type GameServerSetInformer interface {
Informer() cache.SharedIndexInformer
Lister() v1alpha1.GameServerSetLister
}
type gameServerSetInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewGameServerSetInformer constructs a new informer for GameServerSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewGameServerSetInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredGameServerSetInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredGameServerSetInformer constructs a new informer for GameServerSet type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredGameServerSetInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.GameV1alpha1().GameServerSets(namespace).List(context.TODO(), options)
},
WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.GameV1alpha1().GameServerSets(namespace).Watch(context.TODO(), options)
},
},
&apisv1alpha1.GameServerSet{},
resyncPeriod,
indexers,
)
}
func (f *gameServerSetInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredGameServerSetInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *gameServerSetInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&apisv1alpha1.GameServerSet{}, f.defaultInformer)
}
func (f *gameServerSetInformer) Lister() v1alpha1.GameServerSetLister {
return v1alpha1.NewGameServerSetLister(f.Informer().GetIndexer())
}

View File

@ -0,0 +1,51 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1alpha1
import (
internalinterfaces "github.com/openkruise/kruise-game/pkg/client/informers/externalversions/internalinterfaces"
)
// Interface provides access to all the informers in this group version.
type Interface interface {
// GameServers returns a GameServerInformer.
GameServers() GameServerInformer
// GameServerSets returns a GameServerSetInformer.
GameServerSets() GameServerSetInformer
}
type version struct {
factory internalinterfaces.SharedInformerFactory
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
}
// New returns a new Interface.
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}
// GameServers returns a GameServerInformer.
func (v *version) GameServers() GameServerInformer {
return &gameServerInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// GameServerSets returns a GameServerSetInformer.
func (v *version) GameServerSets() GameServerSetInformer {
return &gameServerSetInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}

View File

@ -0,0 +1,179 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package externalversions
import (
reflect "reflect"
sync "sync"
time "time"
versioned "github.com/openkruise/kruise-game/pkg/client/clientset/versioned"
apis "github.com/openkruise/kruise-game/pkg/client/informers/externalversions/apis"
internalinterfaces "github.com/openkruise/kruise-game/pkg/client/informers/externalversions/internalinterfaces"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache"
)
// SharedInformerOption defines the functional option type for SharedInformerFactory.
type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory
type sharedInformerFactory struct {
client versioned.Interface
namespace string
tweakListOptions internalinterfaces.TweakListOptionsFunc
lock sync.Mutex
defaultResync time.Duration
customResync map[reflect.Type]time.Duration
informers map[reflect.Type]cache.SharedIndexInformer
// startedInformers is used for tracking which informers have been started.
// This allows Start() to be called multiple times safely.
startedInformers map[reflect.Type]bool
}
// WithCustomResyncConfig sets a custom resync period for the specified informer types.
func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption {
return func(factory *sharedInformerFactory) *sharedInformerFactory {
for k, v := range resyncConfig {
factory.customResync[reflect.TypeOf(k)] = v
}
return factory
}
}
// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory.
func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption {
return func(factory *sharedInformerFactory) *sharedInformerFactory {
factory.tweakListOptions = tweakListOptions
return factory
}
}
// WithNamespace limits the SharedInformerFactory to the specified namespace.
func WithNamespace(namespace string) SharedInformerOption {
return func(factory *sharedInformerFactory) *sharedInformerFactory {
factory.namespace = namespace
return factory
}
}
// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces.
func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory {
return NewSharedInformerFactoryWithOptions(client, defaultResync)
}
// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory.
// Listers obtained via this SharedInformerFactory will be subject to the same filters
// as specified here.
// Deprecated: Please use NewSharedInformerFactoryWithOptions instead
func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory {
return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions))
}
// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options.
func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory {
factory := &sharedInformerFactory{
client: client,
namespace: v1.NamespaceAll,
defaultResync: defaultResync,
informers: make(map[reflect.Type]cache.SharedIndexInformer),
startedInformers: make(map[reflect.Type]bool),
customResync: make(map[reflect.Type]time.Duration),
}
// Apply all options
for _, opt := range options {
factory = opt(factory)
}
return factory
}
// Start initializes all requested informers.
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
f.lock.Lock()
defer f.lock.Unlock()
for informerType, informer := range f.informers {
if !f.startedInformers[informerType] {
go informer.Run(stopCh)
f.startedInformers[informerType] = true
}
}
}
// WaitForCacheSync waits for all started informers' cache were synced.
func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool {
informers := func() map[reflect.Type]cache.SharedIndexInformer {
f.lock.Lock()
defer f.lock.Unlock()
informers := map[reflect.Type]cache.SharedIndexInformer{}
for informerType, informer := range f.informers {
if f.startedInformers[informerType] {
informers[informerType] = informer
}
}
return informers
}()
res := map[reflect.Type]bool{}
for informType, informer := range informers {
res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced)
}
return res
}
// InternalInformerFor returns the SharedIndexInformer for obj using an internal
// client.
func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
f.lock.Lock()
defer f.lock.Unlock()
informerType := reflect.TypeOf(obj)
informer, exists := f.informers[informerType]
if exists {
return informer
}
resyncPeriod, exists := f.customResync[informerType]
if !exists {
resyncPeriod = f.defaultResync
}
informer = newFunc(f.client, resyncPeriod)
f.informers[informerType] = informer
return informer
}
// SharedInformerFactory provides shared informers for resources in all known
// API group versions.
type SharedInformerFactory interface {
internalinterfaces.SharedInformerFactory
ForResource(resource schema.GroupVersionResource) (GenericInformer, error)
WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool
Game() apis.Interface
}
func (f *sharedInformerFactory) Game() apis.Interface {
return apis.New(f, f.namespace, f.tweakListOptions)
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package externalversions
import (
"fmt"
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
schema "k8s.io/apimachinery/pkg/runtime/schema"
cache "k8s.io/client-go/tools/cache"
)
// GenericInformer is type of SharedIndexInformer which will locate and delegate to other
// sharedInformers based on type
type GenericInformer interface {
Informer() cache.SharedIndexInformer
Lister() cache.GenericLister
}
type genericInformer struct {
informer cache.SharedIndexInformer
resource schema.GroupResource
}
// Informer returns the SharedIndexInformer.
func (f *genericInformer) Informer() cache.SharedIndexInformer {
return f.informer
}
// Lister returns the GenericLister.
func (f *genericInformer) Lister() cache.GenericLister {
return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource)
}
// ForResource gives generic access to a shared informer of the matching type
// TODO extend this to unknown resources with a client pool
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
switch resource {
// Group=game.kruise.io, Version=v1alpha1
case v1alpha1.SchemeGroupVersion.WithResource("gameservers"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Game().V1alpha1().GameServers().Informer()}, nil
case v1alpha1.SchemeGroupVersion.WithResource("gameserversets"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Game().V1alpha1().GameServerSets().Informer()}, nil
}
return nil, fmt.Errorf("no informer found for %v", resource)
}

View File

@ -0,0 +1,39 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by informer-gen. DO NOT EDIT.
package internalinterfaces
import (
time "time"
versioned "github.com/openkruise/kruise-game/pkg/client/clientset/versioned"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
cache "k8s.io/client-go/tools/cache"
)
// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer.
type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer
// SharedInformerFactory a small interface to allow for adding an informer without an import cycle
type SharedInformerFactory interface {
Start(stopCh <-chan struct{})
InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer
}
// TweakListOptionsFunc is a function that transforms a v1.ListOptions.
type TweakListOptionsFunc func(*v1.ListOptions)

View File

@ -0,0 +1,34 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
// GameServerListerExpansion allows custom methods to be added to
// GameServerLister.
type GameServerListerExpansion interface{}
// GameServerNamespaceListerExpansion allows custom methods to be added to
// GameServerNamespaceLister.
type GameServerNamespaceListerExpansion interface{}
// GameServerSetListerExpansion allows custom methods to be added to
// GameServerSetLister.
type GameServerSetListerExpansion interface{}
// GameServerSetNamespaceListerExpansion allows custom methods to be added to
// GameServerSetNamespaceLister.
type GameServerSetNamespaceListerExpansion interface{}

View File

@ -0,0 +1,98 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// GameServerLister helps list GameServers.
// All objects returned here must be treated as read-only.
type GameServerLister interface {
// List lists all GameServers in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.GameServer, err error)
// GameServers returns an object that can list and get GameServers.
GameServers(namespace string) GameServerNamespaceLister
GameServerListerExpansion
}
// gameServerLister implements the GameServerLister interface.
type gameServerLister struct {
indexer cache.Indexer
}
// NewGameServerLister returns a new GameServerLister.
func NewGameServerLister(indexer cache.Indexer) GameServerLister {
return &gameServerLister{indexer: indexer}
}
// List lists all GameServers in the indexer.
func (s *gameServerLister) List(selector labels.Selector) (ret []*v1alpha1.GameServer, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.GameServer))
})
return ret, err
}
// GameServers returns an object that can list and get GameServers.
func (s *gameServerLister) GameServers(namespace string) GameServerNamespaceLister {
return gameServerNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// GameServerNamespaceLister helps list and get GameServers.
// All objects returned here must be treated as read-only.
type GameServerNamespaceLister interface {
// List lists all GameServers in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.GameServer, err error)
// Get retrieves the GameServer from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v1alpha1.GameServer, error)
GameServerNamespaceListerExpansion
}
// gameServerNamespaceLister implements the GameServerNamespaceLister
// interface.
type gameServerNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all GameServers in the indexer for a given namespace.
func (s gameServerNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.GameServer, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.GameServer))
})
return ret, err
}
// Get retrieves the GameServer from the indexer for a given namespace and name.
func (s gameServerNamespaceLister) Get(name string) (*v1alpha1.GameServer, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1alpha1.Resource("gameserver"), name)
}
return obj.(*v1alpha1.GameServer), nil
}

View File

@ -0,0 +1,98 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1alpha1
import (
v1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/tools/cache"
)
// GameServerSetLister helps list GameServerSets.
// All objects returned here must be treated as read-only.
type GameServerSetLister interface {
// List lists all GameServerSets in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.GameServerSet, err error)
// GameServerSets returns an object that can list and get GameServerSets.
GameServerSets(namespace string) GameServerSetNamespaceLister
GameServerSetListerExpansion
}
// gameServerSetLister implements the GameServerSetLister interface.
type gameServerSetLister struct {
indexer cache.Indexer
}
// NewGameServerSetLister returns a new GameServerSetLister.
func NewGameServerSetLister(indexer cache.Indexer) GameServerSetLister {
return &gameServerSetLister{indexer: indexer}
}
// List lists all GameServerSets in the indexer.
func (s *gameServerSetLister) List(selector labels.Selector) (ret []*v1alpha1.GameServerSet, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.GameServerSet))
})
return ret, err
}
// GameServerSets returns an object that can list and get GameServerSets.
func (s *gameServerSetLister) GameServerSets(namespace string) GameServerSetNamespaceLister {
return gameServerSetNamespaceLister{indexer: s.indexer, namespace: namespace}
}
// GameServerSetNamespaceLister helps list and get GameServerSets.
// All objects returned here must be treated as read-only.
type GameServerSetNamespaceLister interface {
// List lists all GameServerSets in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*v1alpha1.GameServerSet, err error)
// Get retrieves the GameServerSet from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*v1alpha1.GameServerSet, error)
GameServerSetNamespaceListerExpansion
}
// gameServerSetNamespaceLister implements the GameServerSetNamespaceLister
// interface.
type gameServerSetNamespaceLister struct {
indexer cache.Indexer
namespace string
}
// List lists all GameServerSets in the indexer for a given namespace.
func (s gameServerSetNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.GameServerSet, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
ret = append(ret, m.(*v1alpha1.GameServerSet))
})
return ret, err
}
// Get retrieves the GameServerSet from the indexer for a given namespace and name.
func (s gameServerSetNamespaceLister) Get(name string) (*v1alpha1.GameServerSet, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)
if err != nil {
return nil, err
}
if !exists {
return nil, errors.NewNotFound(v1alpha1.Resource("gameserverset"), name)
}
return obj.(*v1alpha1.GameServerSet), nil
}

56
pkg/client/registry.go Normal file
View File

@ -0,0 +1,56 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"fmt"
"k8s.io/client-go/rest"
)
var (
cfg *rest.Config
defaultGenericClient *GenericClientset
)
// NewRegistry creates clientset by client-go
func NewRegistry(c *rest.Config) error {
var err error
defaultGenericClient, err = newForConfig(c)
if err != nil {
return err
}
cfgCopy := *c
cfg = &cfgCopy
return nil
}
// GetGenericClient returns default clientset
func GetGenericClient() *GenericClientset {
return defaultGenericClient
}
// GetGenericClientWithName returns clientset with given name as user-agent
func GetGenericClientWithName(name string) *GenericClientset {
if cfg == nil {
return nil
}
newCfg := *cfg
newCfg.UserAgent = fmt.Sprintf("%s/%s", cfg.UserAgent, name)
return newForConfigOrDie(&newCfg)
}

View File

@ -0,0 +1,18 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package versioned

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated clientset.
package versioned

View File

@ -0,0 +1,18 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake

View File

@ -0,0 +1,19 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated fake clientset.
package fake

View File

@ -0,0 +1,18 @@
/*
Copyright 2022 The Kruise Authors.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake

View File

@ -0,0 +1,19 @@
/*
Copyright 2022.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package contains the scheme of the automatically generated clientset.
package scheme

View File

@ -0,0 +1,18 @@
/*
Copyright 2022.
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.
*/
// Code generated by client-gen. DO NOT EDIT.
package scheme

View File

@ -0,0 +1,45 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package controller
import (
"github.com/openkruise/kruise-game/pkg/controllers/gameserver"
"github.com/openkruise/kruise-game/pkg/controllers/gameserverset"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/manager"
)
var controllerAddFuncs []func(manager.Manager) error
func init() {
controllerAddFuncs = append(controllerAddFuncs, gameserver.Add)
controllerAddFuncs = append(controllerAddFuncs, gameserverset.Add)
}
func SetupWithManager(m manager.Manager) error {
for _, f := range controllerAddFuncs {
if err := f(m); err != nil {
if kindMatchErr, ok := err.(*meta.NoKindMatchError); ok {
klog.Infof("CRD %v is not installed, its controller will perform noops!", kindMatchErr.GroupKind)
continue
}
return err
}
}
return nil
}

View File

@ -0,0 +1,251 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gameserver
import (
"context"
gamekruiseiov1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
utildiscovery "github.com/openkruise/kruise-game/pkg/util/discovery"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)
var (
controllerKind = gamekruiseiov1alpha1.SchemeGroupVersion.WithKind("GameServer")
// leave it to batch size
concurrentReconciles = 10
)
func Add(mgr manager.Manager) error {
if !utildiscovery.DiscoverGVK(controllerKind) {
return nil
}
return add(mgr, newReconciler(mgr))
}
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
recorder := mgr.GetEventRecorderFor("gameserver-controller")
return &GameServerReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
recorder: recorder,
}
}
func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Create a new controller
klog.Info("Starting GameServer Controller")
c, err := controller.New("gameserver-controller", mgr, controller.Options{Reconciler: r, MaxConcurrentReconciles: concurrentReconciles})
if err != nil {
klog.Error(err)
return err
}
if err = c.Watch(&source.Kind{Type: &gamekruiseiov1alpha1.GameServer{}}, &handler.EnqueueRequestForOwner{
OwnerType: &corev1.Pod{},
IsController: true,
}); err != nil {
klog.Error(err)
return err
}
if err = watchPod(c); err != nil {
klog.Error(err)
return err
}
return nil
}
// GameServerReconciler reconciles a GameServer object
type GameServerReconciler struct {
client.Client
Scheme *runtime.Scheme
recorder record.EventRecorder
}
func watchPod(c controller.Controller) error {
if err := c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.Funcs{
CreateFunc: func(createEvent event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) {
pod := createEvent.Object.(*corev1.Pod)
if _, exist := pod.GetLabels()[gamekruiseiov1alpha1.GameServerOwnerGssKey]; exist {
limitingInterface.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: pod.GetName(),
Namespace: pod.GetNamespace(),
}})
}
},
UpdateFunc: func(updateEvent event.UpdateEvent, limitingInterface workqueue.RateLimitingInterface) {
newPod := updateEvent.ObjectNew.(*corev1.Pod)
if _, exist := newPod.GetLabels()[gamekruiseiov1alpha1.GameServerOwnerGssKey]; exist {
limitingInterface.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: newPod.GetName(),
Namespace: newPod.GetNamespace(),
}})
}
},
DeleteFunc: func(deleteEvent event.DeleteEvent, limitingInterface workqueue.RateLimitingInterface) {
pod := deleteEvent.Object.(*corev1.Pod)
if _, exist := pod.GetLabels()[gamekruiseiov1alpha1.GameServerOwnerGssKey]; exist {
limitingInterface.Add(reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: deleteEvent.Object.GetNamespace(),
Name: deleteEvent.Object.GetName(),
},
})
}
},
}); err != nil {
return err
}
return nil
}
//+kubebuilder:rbac:groups=game.kruise.io,resources=gameservers,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=game.kruise.io,resources=gameservers/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=game.kruise.io,resources=gameservers/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the GameServer object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.1/pkg/reconcile
func (r *GameServerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
namespacedName := req.NamespacedName
// get pod
pod := &corev1.Pod{}
err := r.Get(ctx, namespacedName, pod)
if err != nil {
if errors.IsNotFound(err) {
return reconcile.Result{}, nil
}
klog.Errorf("failed to find pod %s in %s, because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
// get GameServer
gs := &gamekruiseiov1alpha1.GameServer{}
err = r.Get(ctx, namespacedName, gs)
if err != nil {
if errors.IsNotFound(err) {
err := r.initGameServer(pod)
if err != nil && !errors.IsAlreadyExists(err) && !errors.IsNotFound(err) {
klog.Errorf("failed to create GameServer %s in %s, because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
return reconcile.Result{}, nil
}
klog.Errorf("failed to find GameServer %s in %s, because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
gsm := NewGameServerManager(gs, pod, r.Client)
gss, err := r.getGameServerSet(pod)
if err != nil {
if errors.IsNotFound(err) {
return ctrl.Result{}, nil
}
klog.Errorf("failed to get GameServerSet for GameServer %s in %s, because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
podUpdated, err := gsm.SyncToPod()
if err != nil || podUpdated {
return reconcile.Result{Requeue: podUpdated}, err
}
err = gsm.SyncToGs(gss.Spec.ServiceQualities)
if err != nil {
return reconcile.Result{}, err
}
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *GameServerReconciler) SetupWithManager(mgr ctrl.Manager) (c controller.Controller, err error) {
c, err = ctrl.NewControllerManagedBy(mgr).
For(&gamekruiseiov1alpha1.GameServer{}).Build(r)
return c, err
}
func (r *GameServerReconciler) getGameServerSet(pod *corev1.Pod) (*gamekruiseiov1alpha1.GameServerSet, error) {
gssName := pod.GetLabels()[gamekruiseiov1alpha1.GameServerOwnerGssKey]
gss := &gamekruiseiov1alpha1.GameServerSet{}
err := r.Client.Get(context.Background(), types.NamespacedName{
Namespace: pod.GetNamespace(),
Name: gssName,
}, gss)
return gss, err
}
func (r *GameServerReconciler) initGameServer(pod *corev1.Pod) error {
gs := &gamekruiseiov1alpha1.GameServer{}
gs.Name = pod.GetName()
gs.Namespace = pod.GetNamespace()
// set owner reference
ors := make([]metav1.OwnerReference, 0)
or := metav1.OwnerReference{
APIVersion: pod.APIVersion,
Kind: pod.Kind,
Name: pod.GetName(),
UID: pod.GetUID(),
Controller: pointer.BoolPtr(true),
BlockOwnerDeletion: pointer.BoolPtr(true),
}
ors = append(ors, or)
gs.OwnerReferences = ors
// set NetWork
gs.Spec.NetworkDisabled = false
// set OpsState
gs.Spec.OpsState = gamekruiseiov1alpha1.None
// set UpdatePriority
updatePriority := intstr.FromInt(0)
gs.Spec.UpdatePriority = &updatePriority
// set deletionPriority
deletionPriority := intstr.FromInt(0)
gs.Spec.DeletionPriority = &deletionPriority
return r.Client.Create(context.Background(), gs)
}

View File

@ -0,0 +1,214 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gameserver
import (
"context"
kruisePub "github.com/openkruise/kruise-api/apps/pub"
gameKruiseV1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
"github.com/openkruise/kruise-game/pkg/util"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
)
type Control interface {
SyncToPod() (bool, error)
SyncToGs(qualities []gameKruiseV1alpha1.ServiceQuality) error
}
type GameServerManager struct {
gameServer *gameKruiseV1alpha1.GameServer
pod *corev1.Pod
client client.Client
}
func (manager GameServerManager) SyncToPod() (bool, error) {
// compare GameServer Spec With Pod
pod := manager.pod
gs := manager.gameServer
podLabels := pod.GetLabels()
podDeletePriority := podLabels[gameKruiseV1alpha1.GameServerDeletePriorityKey]
podUpdatePriority := podLabels[gameKruiseV1alpha1.GameServerUpdatePriorityKey]
podGsOpsState := podLabels[gameKruiseV1alpha1.GameServerOpsStateKey]
podGsState := podLabels[gameKruiseV1alpha1.GameServerStateKey]
updated := false
newLabels := make(map[string]string)
if gs.Spec.DeletionPriority.String() != podDeletePriority {
newLabels[gameKruiseV1alpha1.GameServerDeletePriorityKey] = gs.Spec.DeletionPriority.String()
updated = true
}
if gs.Spec.UpdatePriority.String() != podUpdatePriority {
newLabels[gameKruiseV1alpha1.GameServerUpdatePriorityKey] = gs.Spec.UpdatePriority.String()
updated = true
}
if string(gs.Spec.OpsState) != podGsOpsState {
newLabels[gameKruiseV1alpha1.GameServerOpsStateKey] = string(gs.Spec.OpsState)
updated = true
}
var gsState gameKruiseV1alpha1.GameServerState
switch pod.Status.Phase {
case corev1.PodRunning:
// GameServer Updating
lifecycleState, exist := pod.GetLabels()[kruisePub.LifecycleStateKey]
if exist && (lifecycleState == string(kruisePub.LifecycleStateUpdating) || lifecycleState == string(kruisePub.LifecycleStatePreparingUpdate)) {
gsState = gameKruiseV1alpha1.Updating
break
}
// GameServer Deleting
if !pod.DeletionTimestamp.IsZero() {
gsState = gameKruiseV1alpha1.Deleting
break
}
// GameServer Ready / NotReady
for _, con := range pod.Status.Conditions {
if con.Type == corev1.PodReady {
if con.Status == corev1.ConditionTrue {
gsState = gameKruiseV1alpha1.Ready
} else {
gsState = gameKruiseV1alpha1.NotReady
}
break
}
}
case corev1.PodFailed:
gsState = gameKruiseV1alpha1.Crash
case corev1.PodPending:
gsState = gameKruiseV1alpha1.Creating
default:
gsState = gameKruiseV1alpha1.Unknown
}
if string(gsState) != podGsState {
newLabels[gameKruiseV1alpha1.GameServerStateKey] = string(gsState)
updated = true
}
if updated {
patchPod := map[string]interface{}{"metadata": map[string]map[string]string{"labels": newLabels}}
patchPodBytes, err := json.Marshal(patchPod)
if err != nil {
return updated, err
}
err = manager.client.Patch(context.TODO(), pod, client.RawPatch(types.StrategicMergePatchType, patchPodBytes))
if err != nil && !errors.IsNotFound(err) {
klog.Errorf("failed to patch Pod %s in %s,because of %s.", pod.GetName(), pod.GetNamespace(), err.Error())
return updated, err
}
}
return updated, nil
}
func (manager GameServerManager) SyncToGs(qualities []gameKruiseV1alpha1.ServiceQuality) error {
gs := manager.gameServer
pod := manager.pod
podLabels := pod.GetLabels()
podDeletePriority := intstr.FromString(podLabels[gameKruiseV1alpha1.GameServerDeletePriorityKey])
podUpdatePriority := intstr.FromString(podLabels[gameKruiseV1alpha1.GameServerUpdatePriorityKey])
podGsState := gameKruiseV1alpha1.GameServerState(podLabels[gameKruiseV1alpha1.GameServerStateKey])
gsConditions := gs.Status.ServiceQualitiesCondition
podConditions := pod.Status.Conditions
var sqNames []string
for _, sq := range qualities {
sqNames = append(sqNames, sq.Name)
}
var toExec map[string]string
var newGsConditions []gameKruiseV1alpha1.ServiceQualityCondition
for _, pc := range podConditions {
if util.IsStringInList(string(pc.Type), sqNames) {
toExecAction := true
lastActionTransitionTime := metav1.Now()
for _, gsc := range gsConditions {
if gsc.Name == string(pc.Type) && gsc.Status == string(pc.Status) {
toExecAction = false
lastActionTransitionTime = gsc.LastActionTransitionTime
break
}
}
serviceQualityCondition := gameKruiseV1alpha1.ServiceQualityCondition{
Name: string(pc.Type),
Status: string(pc.Status),
LastProbeTime: pc.LastProbeTime,
LastTransitionTime: pc.LastTransitionTime,
LastActionTransitionTime: lastActionTransitionTime,
}
newGsConditions = append(newGsConditions, serviceQualityCondition)
if toExecAction {
toExec[string(pc.Type)] = string(pc.Status)
}
}
}
if toExec != nil {
var spec gameKruiseV1alpha1.GameServerSpec
for _, sq := range qualities {
for name := range toExec {
if sq.Name == name {
// TODO exec action
}
}
}
patchSpec := map[string]interface{}{"spec": spec}
jsonPatchSpec, err := json.Marshal(patchSpec)
if err != nil {
return err
}
err = manager.client.Patch(context.TODO(), gs, client.RawPatch(types.MergePatchType, jsonPatchSpec))
if err != nil && !errors.IsNotFound(err) {
klog.Errorf("failed to patch GameServer spec %s in %s,because of %s.", gs.GetName(), gs.GetNamespace(), err.Error())
return err
}
}
status := gameKruiseV1alpha1.GameServerStatus{
PodStatus: pod.Status,
CurrentState: podGsState,
DesiredState: gameKruiseV1alpha1.Ready,
UpdatePriority: &podUpdatePriority,
DeletionPriority: &podDeletePriority,
ServiceQualitiesCondition: newGsConditions,
LastTransitionTime: metav1.Now(),
}
patchStatus := map[string]interface{}{"status": status}
jsonPatchStatus, err := json.Marshal(patchStatus)
if err != nil {
return err
}
err = manager.client.Status().Patch(context.TODO(), gs, client.RawPatch(types.MergePatchType, jsonPatchStatus))
if err != nil && !errors.IsNotFound(err) {
klog.Errorf("failed to patch GameServer Status %s in %s,because of %s.", gs.GetName(), gs.GetNamespace(), err.Error())
return err
}
return nil
}
func NewGameServerManager(gs *gameKruiseV1alpha1.GameServer, pod *corev1.Pod, c client.Client) Control {
return &GameServerManager{
gameServer: gs,
pod: pod,
client: c,
}
}

View File

@ -0,0 +1,286 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gameserverset
import (
"context"
kruiseV1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
gamekruiseiov1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
"github.com/openkruise/kruise-game/pkg/util"
utildiscovery "github.com/openkruise/kruise-game/pkg/util/discovery"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
)
var (
controllerKind = gamekruiseiov1alpha1.SchemeGroupVersion.WithKind("GameServerSet")
// leave it to batch size
concurrentReconciles = 10
)
func Add(mgr manager.Manager) error {
if !utildiscovery.DiscoverGVK(controllerKind) {
return nil
}
return add(mgr, newReconciler(mgr))
}
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
recorder := mgr.GetEventRecorderFor("gameserverset-controller")
return &GameServerSetReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
recorder: recorder,
}
}
func add(mgr manager.Manager, r reconcile.Reconciler) error {
// Create a new controller
klog.Info("Starting GameServerSet Controller")
c, err := controller.New("gameserverset-controller", mgr, controller.Options{Reconciler: r, MaxConcurrentReconciles: concurrentReconciles})
if err != nil {
klog.Error(err)
return err
}
if err = c.Watch(&source.Kind{Type: &gamekruiseiov1alpha1.GameServerSet{}}, &handler.EnqueueRequestForObject{}); err != nil {
klog.Error(err)
return err
}
if err = watchPod(c); err != nil {
klog.Error(err)
return err
}
if err = watchWorkloads(c); err != nil {
klog.Error(err)
return err
}
return nil
}
// watch pod
func watchPod(c controller.Controller) (err error) {
if err := c.Watch(&source.Kind{Type: &corev1.Pod{}}, &handler.Funcs{
CreateFunc: func(createEvent event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) {
pod := createEvent.Object.(*corev1.Pod)
if gssName, exist := pod.GetLabels()[gamekruiseiov1alpha1.GameServerOwnerGssKey]; exist {
limitingInterface.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: gssName,
Namespace: pod.GetNamespace(),
}})
}
},
UpdateFunc: func(updateEvent event.UpdateEvent, limitingInterface workqueue.RateLimitingInterface) {
pod := updateEvent.ObjectNew.(*corev1.Pod)
if gssName, exist := pod.GetLabels()[gamekruiseiov1alpha1.GameServerOwnerGssKey]; exist {
limitingInterface.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: gssName,
Namespace: pod.GetNamespace(),
}})
}
},
DeleteFunc: func(deleteEvent event.DeleteEvent, limitingInterface workqueue.RateLimitingInterface) {
pod := deleteEvent.Object.(*corev1.Pod)
if gssName, exist := pod.GetLabels()[gamekruiseiov1alpha1.GameServerOwnerGssKey]; exist {
limitingInterface.Add(reconcile.Request{NamespacedName: types.NamespacedName{
Name: gssName,
Namespace: pod.GetNamespace(),
}})
}
},
}); err != nil {
return err
}
return nil
}
// watch workloads
func watchWorkloads(c controller.Controller) (err error) {
if err := c.Watch(&source.Kind{Type: &kruiseV1beta1.StatefulSet{}}, &handler.EnqueueRequestForOwner{
IsController: true,
OwnerType: &gamekruiseiov1alpha1.GameServerSet{},
}); err != nil {
return err
}
return nil
}
// GameServerSetReconciler reconciles a GameServerSet object
type GameServerSetReconciler struct {
client.Client
Scheme *runtime.Scheme
recorder record.EventRecorder
}
//+kubebuilder:rbac:groups=game.kruise.io,resources=gameserversets,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=game.kruise.io,resources=gameserversets/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=game.kruise.io,resources=gameserversets/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// TODO(user): Modify the Reconcile function to compare the state specified by
// the GameServerSet object against the actual cluster state, and then
// perform operations to make the cluster state reflect the state specified by
// the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.12.1/pkg/reconcile
func (r *GameServerSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
_ = log.FromContext(ctx)
namespacedName := req.NamespacedName
// get GameServerSet
gss := &gamekruiseiov1alpha1.GameServerSet{}
err := r.Get(ctx, namespacedName, gss)
if err != nil {
if errors.IsNotFound(err) {
return reconcile.Result{}, nil
}
klog.Errorf("Failed to find GameServerSet %s in %s,because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
// get advanced statefulset
asts := &kruiseV1beta1.StatefulSet{}
err = r.Get(ctx, namespacedName, asts)
if err != nil {
if errors.IsNotFound(err) {
err = r.initAsts(gss)
if err != nil {
klog.Errorf("failed to create advanced statefulset %s in %s,because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
return reconcile.Result{}, nil
}
klog.Errorf("failed to find advanced statefulset %s in %s,because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
// get actual Pod list
podList := &corev1.PodList{}
err = r.List(ctx, podList, &client.ListOptions{
Namespace: gss.GetNamespace(),
LabelSelector: labels.SelectorFromSet(map[string]string{
gamekruiseiov1alpha1.GameServerOwnerGssKey: gss.GetName(),
})})
if err != nil {
klog.Errorf("failed to list GameServers of GameServerSet %s in %s.", gss.GetName(), gss.GetNamespace())
return reconcile.Result{}, err
}
gsm := NewGameServerSetManager(gss, asts, podList.Items, r.Client)
// scale game servers
if gsm.IsNeedToScale() {
err = gsm.GameServerScale()
if err != nil {
klog.Errorf("GameServerSet %s failed to scale GameServers in %s,because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
return reconcile.Result{}, nil
}
// update workload
if gsm.IsNeedToUpdateWorkload() {
err = gsm.UpdateWorkload()
if err != nil {
klog.Errorf("GameServerSet %s failed to synchronize workload in %s,because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
return reconcile.Result{}, nil
}
// TODO sync PodProbeMarker
err = gsm.SyncPodProbeMarker()
if err != nil {
klog.Errorf("GameServerSet %s failed to synchronize PodProbeMarker in %s,because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
// sync GameServerSet Status
err = gsm.SyncStatus()
if err != nil {
klog.Errorf("GameServerSet %s failed to synchronize its status in %s,because of %s.", namespacedName.Name, namespacedName.Namespace, err.Error())
return reconcile.Result{}, err
}
return ctrl.Result{}, nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *GameServerSetReconciler) SetupWithManager(mgr ctrl.Manager) (c controller.Controller, err error) {
c, err = ctrl.NewControllerManagedBy(mgr).
For(&gamekruiseiov1alpha1.GameServerSet{}).Build(r)
return c, err
}
func (r *GameServerSetReconciler) initAsts(gss *gamekruiseiov1alpha1.GameServerSet) error {
asts := &kruiseV1beta1.StatefulSet{}
asts.Namespace = gss.GetNamespace()
asts.Name = gss.GetName()
// set owner reference
ors := make([]metav1.OwnerReference, 0)
or := metav1.OwnerReference{
APIVersion: gss.APIVersion,
Kind: gss.Kind,
Name: gss.GetName(),
UID: gss.GetUID(),
Controller: pointer.BoolPtr(true),
BlockOwnerDeletion: pointer.BoolPtr(true),
}
ors = append(ors, or)
asts.SetOwnerReferences(ors)
// set label
astsLabels := make(map[string]string)
astsLabels[gamekruiseiov1alpha1.AstsHashKey] = util.GetAstsHash(gss)
asts.SetLabels(astsLabels)
// set label selector
asts.Spec.Selector = &metav1.LabelSelector{
MatchLabels: map[string]string{gamekruiseiov1alpha1.GameServerOwnerGssKey: gss.GetName()},
}
// set replicas
asts.Spec.Replicas = gss.Spec.Replicas
asts = util.GetNewAstsFromGss(gss, asts)
return r.Client.Create(context.Background(), asts)
}

View File

@ -0,0 +1,246 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gameserverset
import (
"context"
kruiseV1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
gameKruiseV1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
"github.com/openkruise/kruise-game/pkg/util"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sort"
)
type Control interface {
GameServerScale() error
UpdateWorkload() error
SyncStatus() error
IsNeedToScale() bool
IsNeedToUpdateWorkload() bool
SyncPodProbeMarker() error
}
type GameServerSetManager struct {
gameServerSet *gameKruiseV1alpha1.GameServerSet
asts *kruiseV1beta1.StatefulSet
podList []corev1.Pod
client client.Client
}
func NewGameServerSetManager(gss *gameKruiseV1alpha1.GameServerSet, asts *kruiseV1beta1.StatefulSet, gsList []corev1.Pod, c client.Client) Control {
return &GameServerSetManager{
gameServerSet: gss,
asts: asts,
podList: gsList,
client: c,
}
}
func (manager *GameServerSetManager) IsNeedToScale() bool {
gss := manager.gameServerSet
asts := manager.asts
gsList := manager.podList
currentReplicas := len(gsList)
workloadReplicas := int(*asts.Spec.Replicas)
expectedReplicas := int(*gss.Spec.Replicas)
// workload is reconciling its replicas, don't interrupt
if currentReplicas != workloadReplicas {
return false
}
// no need to scale
return !(expectedReplicas == currentReplicas && util.IsSliceEqual(util.StringToIntSlice(gss.GetAnnotations()[gameKruiseV1alpha1.GameServerSetReserveIdsKey], ","), gss.Spec.ReserveGameServerIds))
}
func (manager *GameServerSetManager) GameServerScale() error {
gss := manager.gameServerSet
asts := manager.asts
gsList := manager.podList
c := manager.client
ctx := context.Background()
currentReplicas := len(gsList)
expectedReplicas := int(*gss.Spec.Replicas)
as := gss.GetAnnotations()
reserveIds := util.StringToIntSlice(as[gameKruiseV1alpha1.GameServerSetReserveIdsKey], ",")
notExistIds := util.StringToIntSlice(as[gameKruiseV1alpha1.GameServerSetNotExistIdsKey], ",")
gssReserveIds := gss.Spec.ReserveGameServerIds
klog.Infof("GameServers %s/%s already has %d replicas, expect to have %d replicas.", gss.GetNamespace(), gss.GetName(), currentReplicas, expectedReplicas)
newNotExistIds := computeToScaleGs(gssReserveIds, reserveIds, notExistIds, expectedReplicas, gsList)
asts.Spec.ReserveOrdinals = append(gssReserveIds, newNotExistIds...)
asts.Spec.Replicas = gss.Spec.Replicas
asts.Spec.ScaleStrategy = &kruiseV1beta1.StatefulSetScaleStrategy{
MaxUnavailable: gss.Spec.ScaleStrategy.MaxUnavailable,
}
err := c.Update(ctx, asts)
if err != nil {
klog.Errorf("failed to update workload replicas %s in %s,because of %s.", gss.GetName(), gss.GetNamespace(), err.Error())
return err
}
gssAnnotations := make(map[string]string)
gssAnnotations[gameKruiseV1alpha1.GameServerSetReserveIdsKey] = util.IntSliceToString(gssReserveIds, ",")
gssAnnotations[gameKruiseV1alpha1.GameServerSetNotExistIdsKey] = util.IntSliceToString(newNotExistIds, ",")
patchGss := map[string]interface{}{"metadata": map[string]map[string]string{"annotations": gssAnnotations}}
patchGssBytes, _ := json.Marshal(patchGss)
err = c.Patch(ctx, gss, client.RawPatch(types.MergePatchType, patchGssBytes))
if err != nil {
klog.Errorf("failed to patch GameServerSet %s in %s,because of %s.", gss.GetName(), gss.GetNamespace(), err.Error())
return err
}
return nil
}
func computeToScaleGs(gssReserveIds, reserveIds, notExistIds []int, expectedReplicas int, pods []corev1.Pod) []int {
workloadManageIds := util.GetIndexListFromPodList(pods)
var toAdd []int
var toDelete []int
// 1. compute reserved GameServerIds, firstly
// 1.a. to delete those new reserved GameServers already in workloadManageIds
toDelete = util.GetSliceInAandInB(util.GetSliceInANotInB(gssReserveIds, reserveIds), workloadManageIds)
// 1.b. to add those remove-reserved GameServers already in workloadManageIds
existLastIndex := -1
if len(workloadManageIds) != 0 {
sort.Ints(workloadManageIds)
existLastIndex = workloadManageIds[len(workloadManageIds)-1]
}
for _, id := range util.GetSliceInANotInB(reserveIds, gssReserveIds) {
if existLastIndex > id {
toAdd = append(toAdd, id)
}
}
// 2. compute remain GameServerIds, secondly
numToAdd := expectedReplicas - len(pods) + len(toDelete) - len(toAdd)
if numToAdd < 0 {
// 2.a to delete GameServers according to DeleteSequence
sortedGs := util.DeleteSequenceGs(pods)
sort.Sort(sortedGs)
toDelete = append(toDelete, util.GetIndexListFromPodList(sortedGs[:-numToAdd])...)
} else {
// 2.b to add GameServers, firstly add those in add notExistIds, secondly add those in future sequence
numNotExist := len(notExistIds)
if numNotExist < numToAdd {
toAdd = append(toAdd, notExistIds...)
times := 0
for i := existLastIndex + 1; times < numToAdd-numNotExist; i++ {
if !util.IsNumInList(i, gssReserveIds) {
toAdd = append(toAdd, i)
times++
}
}
} else {
toAdd = append(toAdd, notExistIds[:numToAdd]...)
}
}
newManageIds := append(workloadManageIds, util.GetSliceInANotInB(toAdd, workloadManageIds)...)
newManageIds = util.GetSliceInANotInB(newManageIds, toDelete)
var newNotExistIds []int
if len(newManageIds) != 0 {
sort.Ints(newManageIds)
for i := 0; i < newManageIds[len(newManageIds)-1]; i++ {
if !util.IsNumInList(i, newManageIds) && !util.IsNumInList(i, gssReserveIds) {
newNotExistIds = append(newNotExistIds, i)
}
}
}
return newNotExistIds
}
func (manager *GameServerSetManager) IsNeedToUpdateWorkload() bool {
return manager.asts.GetLabels()[gameKruiseV1alpha1.AstsHashKey] != util.GetAstsHash(manager.gameServerSet)
}
func (manager *GameServerSetManager) UpdateWorkload() error {
gss := manager.gameServerSet
asts := manager.asts
// sync with Advanced StatefulSet
asts = util.GetNewAstsFromGss(gss, asts)
astsLabels := asts.GetLabels()
astsLabels[gameKruiseV1alpha1.AstsHashKey] = util.GetAstsHash(manager.gameServerSet)
asts.SetLabels(astsLabels)
return manager.client.Update(context.Background(), asts)
}
func (manager *GameServerSetManager) SyncPodProbeMarker() error {
return nil
}
func (manager *GameServerSetManager) SyncStatus() error {
gss := manager.gameServerSet
asts := manager.asts
c := manager.client
ctx := context.Background()
podList := manager.podList
maintainingGs := 0
waitToBeDeletedGs := 0
for _, pod := range podList {
podLabels := pod.GetLabels()
opsState := podLabels[gameKruiseV1alpha1.GameServerOpsStateKey]
// ops state
switch opsState {
case string(gameKruiseV1alpha1.WaitToDelete):
waitToBeDeletedGs++
case string(gameKruiseV1alpha1.Maintaining):
maintainingGs++
}
}
status := gameKruiseV1alpha1.GameServerSetStatus{
Replicas: *gss.Spec.Replicas,
CurrentReplicas: int32(len(podList)),
AvailableReplicas: asts.Status.AvailableReplicas,
ReadyReplicas: asts.Status.ReadyReplicas,
UpdatedReplicas: asts.Status.UpdatedReplicas,
UpdatedReadyReplicas: asts.Status.UpdatedReadyReplicas,
MaintainingReplicas: pointer.Int32Ptr(int32(maintainingGs)),
WaitToBeDeletedReplicas: pointer.Int32Ptr(int32(waitToBeDeletedGs)),
LabelSelector: asts.Status.LabelSelector,
}
patchStatus := map[string]interface{}{"status": status}
jsonPatch, err := json.Marshal(patchStatus)
if err != nil {
return err
}
return c.Status().Patch(ctx, gss, client.RawPatch(types.MergePatchType, jsonPatch))
}

View File

@ -0,0 +1,167 @@
/*
Copyright 2022 The Kruise Authors.
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"context"
"flag"
"strings"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
)
var (
disableNoDeepCopy bool
)
func init() {
flag.BoolVar(&disableNoDeepCopy, "disable-no-deepcopy", false, "If you are going to disable NoDeepCopy List in some controllers and webhooks.")
}
// NewClient creates the default caching client with disable deepcopy list from cache.
func NewClient(cache cache.Cache, config *rest.Config, options client.Options, uncachedObjects ...client.Object) (client.Client, error) {
c, err := client.New(config, options)
if err != nil {
return nil, err
}
uncachedGVKs := map[schema.GroupVersionKind]struct{}{}
for _, obj := range uncachedObjects {
gvk, err := apiutil.GVKForObject(obj, c.Scheme())
if err != nil {
return nil, err
}
uncachedGVKs[gvk] = struct{}{}
}
return &delegatingClient{
scheme: c.Scheme(),
mapper: c.RESTMapper(),
Reader: &delegatingReader{
CacheReader: cache,
ClientReader: c,
noDeepCopyLister: &noDeepCopyLister{cache: cache, scheme: c.Scheme()},
scheme: c.Scheme(),
uncachedGVKs: uncachedGVKs,
},
Writer: c,
StatusClient: c,
}, nil
}
type delegatingClient struct {
client.Reader
client.Writer
client.StatusClient
scheme *runtime.Scheme
mapper meta.RESTMapper
}
// Scheme returns the scheme this client is using.
func (d *delegatingClient) Scheme() *runtime.Scheme {
return d.scheme
}
// RESTMapper returns the rest mapper this client is using.
func (d *delegatingClient) RESTMapper() meta.RESTMapper {
return d.mapper
}
// delegatingReader forms a Reader that will cause Get and List requests for
// unstructured types to use the ClientReader while requests for any other type
// of object with use the CacheReader. This avoids accidentally caching the
// entire cluster in the common case of loading arbitrary unstructured objects
// (e.g. from OwnerReferences).
type delegatingReader struct {
CacheReader client.Reader
ClientReader client.Reader
noDeepCopyLister *noDeepCopyLister
uncachedGVKs map[schema.GroupVersionKind]struct{}
scheme *runtime.Scheme
cacheUnstructured bool
}
func (d *delegatingReader) shouldBypassCache(obj runtime.Object) (bool, error) {
gvk, err := apiutil.GVKForObject(obj, d.scheme)
if err != nil {
return false, err
}
// TODO: this is producing unsafe guesses that don't actually work,
// but it matches ~99% of the cases out there.
if meta.IsListType(obj) {
gvk.Kind = strings.TrimSuffix(gvk.Kind, "List")
}
if _, isUncached := d.uncachedGVKs[gvk]; isUncached {
return true, nil
}
if !d.cacheUnstructured {
_, isUnstructured := obj.(*unstructured.Unstructured)
_, isUnstructuredList := obj.(*unstructured.UnstructuredList)
return isUnstructured || isUnstructuredList, nil
}
return false, nil
}
// Get retrieves an obj for a given object key from the Kubernetes Cluster.
func (d *delegatingReader) Get(ctx context.Context, key client.ObjectKey, obj client.Object) error {
if isUncached, err := d.shouldBypassCache(obj); err != nil {
return err
} else if isUncached {
return d.ClientReader.Get(ctx, key, obj)
}
return d.CacheReader.Get(ctx, key, obj)
}
// List retrieves list of objects for a given namespace and list options.
func (d *delegatingReader) List(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
if isUncached, err := d.shouldBypassCache(list); err != nil {
return err
} else if isUncached {
return d.ClientReader.List(ctx, list, opts...)
}
if !disableNoDeepCopy && isDisableDeepCopy(opts) {
return d.noDeepCopyLister.List(ctx, list, opts...)
}
return d.CacheReader.List(ctx, list, opts...)
}
var DisableDeepCopy = disableDeepCopy{}
type disableDeepCopy struct{}
func (_ disableDeepCopy) ApplyToList(_ *client.ListOptions) {
}
func isDisableDeepCopy(opts []client.ListOption) bool {
for _, opt := range opts {
if opt == DisableDeepCopy {
return true
}
}
return false
}

View File

@ -0,0 +1,198 @@
/*
Copyright 2022 The Kruise Authors.
Copyright 2018 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package client
import (
"context"
"fmt"
"reflect"
"strings"
"time"
apimeta "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/selection"
toolscache "k8s.io/client-go/tools/cache"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
)
type noDeepCopyLister struct {
cache cache.Cache
scheme *runtime.Scheme
}
func (r *noDeepCopyLister) List(ctx context.Context, out client.ObjectList, opts ...client.ListOption) error {
startTime := time.Now()
gvk, _, err := r.objectTypeForListObject(out)
if err != nil {
return err
}
indexer, err := r.getIndexerByGVK(ctx, *gvk)
if err != nil {
return err
}
listOpts := client.ListOptions{}
listOpts.ApplyOptions(opts)
var objs []interface{}
switch {
case listOpts.FieldSelector != nil:
field, val, requiresExact := requiresExactMatch(listOpts.FieldSelector)
if !requiresExact {
return fmt.Errorf("non-exact field matches are not supported by the cache")
}
// list all objects by the field selector. If this is namespaced and we have one, ask for the
// namespaced index key. Otherwise, ask for the non-namespaced variant by using the fake "all namespaces"
// namespace.
objs, err = indexer.ByIndex(FieldIndexName(field), KeyToNamespacedKey(listOpts.Namespace, val))
case listOpts.Namespace != "":
objs, err = indexer.ByIndex(toolscache.NamespaceIndex, listOpts.Namespace)
default:
objs = indexer.List()
}
if err != nil {
return err
}
var labelSel labels.Selector
if listOpts.LabelSelector != nil {
labelSel = listOpts.LabelSelector
}
limitSet := listOpts.Limit > 0
runtimeObjs := make([]runtime.Object, 0, len(objs))
for _, item := range objs {
// if the Limit option is set and the number of items
// listed exceeds this limit, then stop reading.
if limitSet && int64(len(runtimeObjs)) >= listOpts.Limit {
break
}
obj, isObj := item.(runtime.Object)
if !isObj {
return fmt.Errorf("cache contained %T, which is not an Object", obj)
}
meta, err := apimeta.Accessor(obj)
if err != nil {
return err
}
if labelSel != nil {
lbls := labels.Set(meta.GetLabels())
if !labelSel.Matches(lbls) {
continue
}
}
runtimeObjs = append(runtimeObjs, obj)
}
defer func() {
klog.V(6).Infof("Listed %v %v objects %v without DeepCopy, cost %v", gvk.GroupVersion(), gvk.Kind, len(runtimeObjs), time.Since(startTime))
}()
return apimeta.SetList(out, runtimeObjs)
}
func (r *noDeepCopyLister) getIndexerByGVK(ctx context.Context, gvk schema.GroupVersionKind) (toolscache.Indexer, error) {
informer, err := r.cache.GetInformerForKind(ctx, gvk)
if err != nil {
return nil, err
}
sharedInformer, ok := informer.(toolscache.SharedIndexInformer)
if !ok {
return nil, fmt.Errorf("informer %T from cache is not a SharedIndexInformer", informer)
}
return sharedInformer.GetIndexer(), nil
}
// objectTypeForListObject tries to find the runtime.Object and associated GVK
// for a single object corresponding to the passed-in list type. We need them
// because they are used as cache map key.
func (r *noDeepCopyLister) objectTypeForListObject(list client.ObjectList) (*schema.GroupVersionKind, runtime.Object, error) {
gvk, err := apiutil.GVKForObject(list, r.scheme)
if err != nil {
return nil, nil, err
}
if !strings.HasSuffix(gvk.Kind, "List") {
return nil, nil, fmt.Errorf("non-list type %T (kind %q) passed as output", list, gvk)
}
// we need the non-list GVK, so chop off the "List" from the end of the kind
gvk.Kind = gvk.Kind[:len(gvk.Kind)-4]
_, isUnstructured := list.(*unstructured.UnstructuredList)
var cacheTypeObj runtime.Object
if isUnstructured {
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(gvk)
cacheTypeObj = u
} else {
itemsPtr, err := apimeta.GetItemsPtr(list)
if err != nil {
return nil, nil, err
}
// http://knowyourmeme.com/memes/this-is-fine
elemType := reflect.Indirect(reflect.ValueOf(itemsPtr)).Type().Elem()
if elemType.Kind() != reflect.Ptr {
elemType = reflect.PtrTo(elemType)
}
cacheTypeValue := reflect.Zero(elemType)
var ok bool
cacheTypeObj, ok = cacheTypeValue.Interface().(runtime.Object)
if !ok {
return nil, nil, fmt.Errorf("cannot get cache for %T, its element %T is not a runtime.Object", list, cacheTypeValue.Interface())
}
}
return &gvk, cacheTypeObj, nil
}
// requiresExactMatch checks if the given field selector is of the form `k=v` or `k==v`.
func requiresExactMatch(sel fields.Selector) (field, val string, required bool) {
reqs := sel.Requirements()
if len(reqs) != 1 {
return "", "", false
}
req := reqs[0]
if req.Operator != selection.Equals && req.Operator != selection.DoubleEquals {
return "", "", false
}
return req.Field, req.Value, true
}
// FieldIndexName constructs the name of the index over the given field,
// for use with an indexer.
func FieldIndexName(field string) string {
return "field:" + field
}
// noNamespaceNamespace is used as the "namespace" when we want to list across all namespaces.
const allNamespacesNamespace = "__all_namespaces"
// KeyToNamespacedKey prefixes the given index key with a namespace
// for use in field selector indexes.
func KeyToNamespacedKey(ns string, baseKey string) string {
if ns != "" {
return ns + "/" + baseKey
}
return allNamespacesNamespace + "/" + baseKey
}

View File

@ -0,0 +1,97 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package discovery
import (
"fmt"
"k8s.io/klog/v2"
"time"
"github.com/openkruise/kruise-game/pkg/client"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
)
var (
internalScheme = runtime.NewScheme()
errKindNotFound = fmt.Errorf("kind not found in group version resources")
backOff = wait.Backoff{
Steps: 4,
Duration: 500 * time.Millisecond,
Factor: 5.0,
Jitter: 0.1,
}
)
func init() {
_ = AddToScheme(internalScheme)
}
func DiscoverGVK(gvk schema.GroupVersionKind) bool {
genericClient := client.GetGenericClient()
if genericClient == nil {
return true
}
discoveryClient := genericClient.DiscoveryClient
startTime := time.Now()
err := retry.OnError(backOff, func(err error) bool { return true }, func() error {
resourceList, err := discoveryClient.ServerResourcesForGroupVersion(gvk.GroupVersion().String())
if err != nil {
return err
}
for _, r := range resourceList.APIResources {
if r.Kind == gvk.Kind {
return nil
}
}
return errKindNotFound
})
if err != nil {
if err == errKindNotFound {
klog.Warningf("Not found kind %s in group version %s, waiting time %s", gvk.Kind, gvk.GroupVersion().String(), time.Since(startTime))
return false
}
// This might be caused by abnormal apiserver or etcd, ignore it
klog.Errorf("Failed to find resources in group version %s: %v, waiting time %s", gvk.GroupVersion().String(), err, time.Since(startTime))
}
return true
}
func DiscoverObject(obj runtime.Object) bool {
gvk, err := apiutil.GVKForObject(obj, internalScheme)
if err != nil {
klog.Warningf("Not recognized object %T in scheme: %v", obj, err)
return false
}
return DiscoverGVK(gvk)
}
// AddToSchemes may be used to add all resources defined in the project to a Scheme
var AddToSchemes runtime.SchemeBuilder
// AddToScheme adds all Resources to the Scheme
func AddToScheme(s *runtime.Scheme) error {
return AddToSchemes.AddToScheme(s)
}

164
pkg/util/gameserver.go Normal file
View File

@ -0,0 +1,164 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
appspub "github.com/openkruise/kruise-api/apps/pub"
kruiseV1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
gameKruiseV1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
apps "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"strconv"
"strings"
)
type DeleteSequenceGs []corev1.Pod
func (dg DeleteSequenceGs) Len() int {
return len(dg)
}
func (dg DeleteSequenceGs) Swap(i, j int) {
dg[i], dg[j] = dg[j], dg[i]
}
func (dg DeleteSequenceGs) Less(i, j int) bool {
iLabels := dg[i].GetLabels()
jLabels := dg[j].GetLabels()
iOpsState := iLabels[gameKruiseV1alpha1.GameServerOpsStateKey]
jOpsState := jLabels[gameKruiseV1alpha1.GameServerOpsStateKey]
iDeletionPriority := iLabels[gameKruiseV1alpha1.GameServerDeletePriorityKey]
jDeletionPriority := jLabels[gameKruiseV1alpha1.GameServerDeletePriorityKey]
// OpsState
if iOpsState != jOpsState {
return opsStateDeletePrority(iOpsState) > opsStateDeletePrority(jOpsState)
}
// Deletion Priority
if iDeletionPriority != jDeletionPriority {
iDeletionPriorityInt, _ := strconv.Atoi(iDeletionPriority)
jDeletionPriorityInt, _ := strconv.Atoi(jDeletionPriority)
return iDeletionPriorityInt > jDeletionPriorityInt
}
// Index Number
return GetIndexFromGsName(dg[i].GetName()) > GetIndexFromGsName(dg[j].GetName())
}
func opsStateDeletePrority(opsState string) int {
switch opsState {
case string(gameKruiseV1alpha1.WaitToDelete):
return 1
case string(gameKruiseV1alpha1.None):
return 0
case string(gameKruiseV1alpha1.Maintaining):
return -1
}
return 0
}
func GetIndexFromGsName(gsName string) int {
temp := strings.Split(gsName, "-")
index, _ := strconv.Atoi(temp[len(temp)-1])
return index
}
func GetIndexListFromPodList(podList []corev1.Pod) []int {
var indexList []int
for i := 0; i < len(podList); i++ {
indexList = append(indexList, GetIndexFromGsName(podList[i].GetName()))
}
return indexList
}
func GetIndexListFromGsList(gsList []gameKruiseV1alpha1.GameServer) []int {
var indexList []int
for i := 0; i < len(gsList); i++ {
indexList = append(indexList, GetIndexFromGsName(gsList[i].GetName()))
}
return indexList
}
func GetNewAstsFromGss(gss *gameKruiseV1alpha1.GameServerSet, asts *kruiseV1beta1.StatefulSet) *kruiseV1beta1.StatefulSet {
// default: set ParallelPodManagement
asts.Spec.PodManagementPolicy = apps.ParallelPodManagement
// set pod labels
podLabels := gss.Spec.GameServerTemplate.GetLabels()
if podLabels == nil {
podLabels = make(map[string]string)
}
podLabels[gameKruiseV1alpha1.GameServerOwnerGssKey] = gss.GetName()
asts.Spec.Template.SetLabels(podLabels)
// set pod annotations
podAnnotations := gss.Spec.GameServerTemplate.GetAnnotations()
asts.Spec.Template.SetAnnotations(podAnnotations)
// set template spec
asts.Spec.Template.Spec = gss.Spec.GameServerTemplate.Spec
// default: add InPlaceUpdateReady condition
readinessGates := gss.Spec.GameServerTemplate.Spec.ReadinessGates
readinessGates = append(readinessGates, corev1.PodReadinessGate{ConditionType: appspub.InPlaceUpdateReady})
asts.Spec.Template.Spec.ReadinessGates = readinessGates
// set VolumeClaimTemplates
asts.Spec.VolumeClaimTemplates = gss.Spec.GameServerTemplate.VolumeClaimTemplates
// set ScaleStrategy
asts.Spec.ScaleStrategy = &kruiseV1beta1.StatefulSetScaleStrategy{
MaxUnavailable: gss.Spec.ScaleStrategy.MaxUnavailable,
}
// set UpdateStrategy
asts.Spec.UpdateStrategy.Type = gss.Spec.UpdateStrategy.Type
var rollingUpdateStatefulSetStrategy *kruiseV1beta1.RollingUpdateStatefulSetStrategy
if gss.Spec.UpdateStrategy.RollingUpdate != nil {
asts.Spec.UpdateStrategy.Type = apps.RollingUpdateStatefulSetStrategyType
rollingUpdateStatefulSetStrategy = &kruiseV1beta1.RollingUpdateStatefulSetStrategy{
Partition: gss.Spec.UpdateStrategy.RollingUpdate.Partition,
MaxUnavailable: gss.Spec.UpdateStrategy.RollingUpdate.MaxUnavailable,
PodUpdatePolicy: gss.Spec.UpdateStrategy.RollingUpdate.PodUpdatePolicy,
Paused: gss.Spec.UpdateStrategy.RollingUpdate.Paused,
InPlaceUpdateStrategy: gss.Spec.UpdateStrategy.RollingUpdate.InPlaceUpdateStrategy,
MinReadySeconds: gss.Spec.UpdateStrategy.RollingUpdate.MinReadySeconds,
UnorderedUpdate: &kruiseV1beta1.UnorderedUpdateStrategy{
PriorityStrategy: &appspub.UpdatePriorityStrategy{
OrderPriority: []appspub.UpdatePriorityOrderTerm{
{
OrderedKey: gameKruiseV1alpha1.GameServerUpdatePriorityKey,
},
},
},
},
}
}
asts.Spec.UpdateStrategy.RollingUpdate = rollingUpdateStatefulSetStrategy
return asts
}
type astsToUpdate struct {
UpdateStrategy gameKruiseV1alpha1.UpdateStrategy
Template gameKruiseV1alpha1.GameServerTemplate
}
func GetAstsHash(gss *gameKruiseV1alpha1.GameServerSet) string {
return GetHash(astsToUpdate{
UpdateStrategy: gss.Spec.UpdateStrategy,
Template: gss.Spec.GameServerTemplate,
})
}

110
pkg/util/gameserver_test.go Normal file
View File

@ -0,0 +1,110 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
gameKruiseV1alpha1 "github.com/openkruise/kruise-game/apis/v1alpha1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sort"
"testing"
)
func TestGetIndexFromGsName(t *testing.T) {
tests := []struct {
name string
result int
}{
{
name: "xxx-23-3",
result: 3,
},
{
name: "www_3-12",
result: 12,
},
}
for _, test := range tests {
actual := GetIndexFromGsName(test.name)
expect := test.result
if expect != actual {
t.Errorf("expect %v but got %v", expect, actual)
}
}
}
func TestDeleteSequenceGs(t *testing.T) {
tests := []struct {
before []corev1.Pod
after []int
}{
{
before: []corev1.Pod{
{
ObjectMeta: metav1.ObjectMeta{
Name: "xxx-0",
Labels: map[string]string{
gameKruiseV1alpha1.GameServerOpsStateKey: string(gameKruiseV1alpha1.None),
gameKruiseV1alpha1.GameServerDeletePriorityKey: "10",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "xxx-1",
Labels: map[string]string{
gameKruiseV1alpha1.GameServerOpsStateKey: string(gameKruiseV1alpha1.Maintaining),
gameKruiseV1alpha1.GameServerDeletePriorityKey: "0",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "xxx-2",
Labels: map[string]string{
gameKruiseV1alpha1.GameServerOpsStateKey: string(gameKruiseV1alpha1.WaitToDelete),
gameKruiseV1alpha1.GameServerDeletePriorityKey: "0",
},
},
},
{
ObjectMeta: metav1.ObjectMeta{
Name: "xxx-3",
Labels: map[string]string{
gameKruiseV1alpha1.GameServerOpsStateKey: string(gameKruiseV1alpha1.None),
gameKruiseV1alpha1.GameServerDeletePriorityKey: "0",
},
},
},
},
after: []int{2, 0, 3, 1},
},
}
for _, test := range tests {
after := DeleteSequenceGs(test.before)
sort.Sort(after)
expect := test.after
actual := GetIndexListFromPodList(after)
for i := 0; i < len(actual); i++ {
if expect[i] != actual[i] {
t.Errorf("expect %v but got %v", expect, actual)
}
}
}
}

44
pkg/util/hash.go Normal file
View File

@ -0,0 +1,44 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"fmt"
"github.com/davecgh/go-spew/spew"
"hash"
"hash/fnv"
)
func GetHash(objectToWrite interface{}) string {
hf := fnv.New32()
DeepHashObject(hf, objectToWrite)
return fmt.Sprint(hf.Sum32())
}
// DeepHashObject writes specified object to hash using the spew library
// which follows pointers and prints actual values of the nested objects
// ensuring the hash does not change when a pointer changes.
func DeepHashObject(hasher hash.Hash, objectToWrite interface{}) {
hasher.Reset()
printer := spew.ConfigState{
Indent: " ",
SortKeys: true,
DisableMethods: true,
SpewKeys: true,
}
printer.Fprintf(hasher, "%#v", objectToWrite)
}

62
pkg/util/hash_test.go Normal file
View File

@ -0,0 +1,62 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
corev1 "k8s.io/api/core/v1"
"testing"
)
func TestGetHash(t *testing.T) {
tests := []struct {
objectA interface{}
objectB interface{}
result bool
}{
{
objectA: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "containerA",
Image: "nginx:latest",
},
},
},
},
objectB: corev1.PodTemplateSpec{
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "containerB",
Image: "nginx:latest",
},
},
},
},
result: false,
},
}
for _, test := range tests {
actual := GetHash(test.objectA) == GetHash(test.objectB)
expect := test.result
if expect != actual {
t.Errorf("expect %v but got %v", expect, actual)
}
}
}

141
pkg/util/slice.go Normal file
View File

@ -0,0 +1,141 @@
/*
Copyright 2022 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package util
import (
"fmt"
"sort"
"strconv"
"strings"
)
func IsNumInList(num int, list []int) bool {
for _, n := range list {
if num == n {
return true
}
}
return false
}
func IsStringInList(str string, list []string) bool {
for _, s := range list {
if s == str {
return true
}
}
return false
}
func GetSliceInANotInB(a, b []int) []int {
var ret []int
for _, aa := range a {
if !IsNumInList(aa, b) {
ret = append(ret, aa)
}
}
return ret
}
func GetSliceInAandInB(a, b []int) []int {
var ret []int
for _, aa := range a {
if IsNumInList(aa, b) {
ret = append(ret, aa)
}
}
return ret
}
func IntSliceToString(number []int, delimiter string) string {
return strings.Trim(strings.Replace(fmt.Sprint(number), " ", delimiter, -1), "[]")
}
func StringToIntSlice(str string, delimiter string) []int {
if str == "" {
return nil
}
strList := strings.Split(str, delimiter)
if len(strList) == 0 {
return nil
}
var retSlice []int
for _, item := range strList {
if item == "" {
continue
}
val, err := strconv.Atoi(item)
if err != nil {
continue
}
retSlice = append(retSlice, val)
}
return retSlice
}
func IsSliceEqual(a, b []int) bool {
if (a == nil) != (b == nil) {
return false
}
if len(a) != len(b) {
return false
}
sort.Ints(a)
sort.Ints(b)
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func RemoveRepeat(nums []int) []int {
var result []int
tempMap := map[int]byte{}
for _, num := range nums {
beforeLen := len(tempMap)
tempMap[num] = 0
if len(tempMap) == beforeLen {
continue
}
result = append(result, num)
}
return result
}
func IsRepeat(nums []int) bool {
tempMap := map[int]byte{}
for _, num := range nums {
beforeLen := len(tempMap)
tempMap[num] = 0
if len(tempMap) == beforeLen {
return true
}
}
return false
}
func IsHasNegativeNum(nums []int) bool {
for _, num := range nums {
if num < 0 {
return true
}
}
return false
}

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