diff --git a/cmd/e2e/build_e2e_test.go b/cmd/e2e/build_e2e_test.go index b1651949..3087177e 100644 --- a/cmd/e2e/build_e2e_test.go +++ b/cmd/e2e/build_e2e_test.go @@ -299,7 +299,7 @@ func createE2eBuild(buildname, buildID, img string) *mpsv1alpha1.GameServerBuild Spec: mpsv1alpha1.GameServerBuildSpec{ BuildID: buildID, TitleID: "1E03", - PortsToExpose: []mpsv1alpha1.PortToExpose{{ContainerName: containerName, PortName: portKey}}, + PortsToExpose: []int32{80}, BuildMetadata: []mpsv1alpha1.BuildMetadataItem{ {Key: "metadatakey1", Value: "metadatavalue1"}, {Key: "metadatakey2", Value: "metadatavalue2"}, diff --git a/cmd/e2e/gameserverapi_test.go b/cmd/e2e/gameserverapi_test.go index 8fd12303..798a687d 100644 --- a/cmd/e2e/gameserverapi_test.go +++ b/cmd/e2e/gameserverapi_test.go @@ -202,7 +202,7 @@ func createGameServerBuild(name, namespace, img string) mpsv1alpha1.GameServerBu Spec: mpsv1alpha1.GameServerBuildSpec{ BuildID: uuid.New().String(), TitleID: "1E03", - PortsToExpose: []mpsv1alpha1.PortToExpose{{ContainerName: "netcore-sample", PortName: "gameport"}}, + PortsToExpose: []int32{80}, BuildMetadata: []mpsv1alpha1.BuildMetadataItem{ {Key: "metadatakey1", Value: "metadatavalue1"}, {Key: "metadatakey2", Value: "metadatavalue2"}, diff --git a/cmd/e2e/utilities_test.go b/cmd/e2e/utilities_test.go index 815968ac..e3d56c8e 100644 --- a/cmd/e2e/utilities_test.go +++ b/cmd/e2e/utilities_test.go @@ -334,17 +334,15 @@ func verifyPodsInHostNetwork(ctx context.Context, kubeClient client.Client, gsb for _, container := range pod.Spec.Containers { containerName := container.Name for _, portToExpose := range gsb.Spec.PortsToExpose { - // get the ports that this container needs exposed, from the GameServerBuild definition - if containerName == portToExpose.ContainerName { - for _, containerPortMapping := range container.Ports { - // found a port - if containerPortMapping.Name == portToExpose.PortName { - // let's make sure that hostPort is the same as containerPort (work done by the controller) - if containerPortMapping.HostPort != containerPortMapping.ContainerPort { - return fmt.Errorf("hostPort != containerPort for hostNetwork pod %s container %s, port %s", pod.Name, containerName, portToExpose.PortName) - } + for _, containerPortMapping := range container.Ports { + // found a port + if containerPortMapping.ContainerPort == portToExpose { + // let's make sure that hostPort is the same as containerPort (work done by the controller) + if containerPortMapping.HostPort != containerPortMapping.ContainerPort { + return fmt.Errorf("hostPort != containerPort for hostNetwork pod %s container %s, port %d", pod.Name, containerName, portToExpose) } } + } } @@ -500,7 +498,7 @@ func createTestBuild(buildName, buildID, img string) *mpsv1alpha1.GameServerBuil Spec: mpsv1alpha1.GameServerBuildSpec{ BuildID: buildID, TitleID: "1E03", - PortsToExpose: []mpsv1alpha1.PortToExpose{{ContainerName: containerName, PortName: portKey}}, + PortsToExpose: []int32{80}, StandingBy: 2, Max: 4, Template: corev1.PodTemplateSpec{ diff --git a/cmd/initcontainer/main.go b/cmd/initcontainer/main.go index debd0d92..4b77d22a 100644 --- a/cmd/initcontainer/main.go +++ b/cmd/initcontainer/main.go @@ -58,14 +58,18 @@ func main() { getGameServerNameNamespaceFromEnv() logger = log.WithFields(log.Fields{"GameServerName": sessionHostId, "GameServerNamespace": crdNamespace}) + setLogLevel() + getRestEnvVariables() gamePorts, gamePortConfiguration, err := parsePorts() if err != nil { logger.Fatalf("Could not parse game ports %s", err) } + logger.Debugf("Parsed ports %v", gamePorts) buildMetadata := parseBuildMetadata() + logger.Debugf("Parsed build metadata %v", buildMetadata) config := &GsdkConfig{ HeartbeatEndpoint: fmt.Sprintf("%s:%s", nodeInternalIP, heartbeatEndpointPort), @@ -86,6 +90,7 @@ func main() { logger.Info("Marshalling to JSON") configJson, err := json.Marshal(config) + logger.Debugf("Marshalled JSON: %s", configJson) handleError(err) logger.Info("Getting and creating folder(s)") @@ -96,12 +101,15 @@ func main() { logger.Infof("Creating empty GSDK JSON file %s", gsdkConfigFilePath) f, err := os.Create(gsdkConfigFilePath) handleError(err) + logger.Debugf("Created empty GSDK JSON file %s", gsdkConfigFilePath) logger.Infof("Saving GSDK JSON to file %s", gsdkConfigFilePath) _, err = f.Write(configJson) handleError(err) + logger.Debugf("Saved GSDK JSON to file %s", gsdkConfigFilePath) } +// parseBuildMetadata parses the build metadata from the corresponding environment variable func parseBuildMetadata() map[string]string { buildMetadata := make(map[string]string) if os.Getenv("PF_GAMESERVER_BUILD_METADATA") != "" { @@ -118,6 +126,7 @@ func parseBuildMetadata() map[string]string { return buildMetadata } +// parsePorts parses the portName/containerPort/hostPort from the gamePortsString func parsePorts() (map[string]string, []GamePort, error) { // format is port.Name + "," + containerPort + "," + hostPort + "?" + ... // similar to how docker run -p works https://docs.docker.com/config/containers/container-networking/ @@ -148,6 +157,7 @@ func parsePorts() (map[string]string, []GamePort, error) { return gamePorts, gamePortConfiguration, nil } +// handleError panics if error != nil func handleError(e error) { if e != nil { logger.Fatalf("panic because error: %s", e) @@ -201,3 +211,16 @@ func getRestEnvVariables() { nodeInternalIP = os.Getenv("PF_NODE_INTERNAL_IP") checkEnvOrFatal("PF_NODE_INTERNAL_IP", nodeInternalIP) } + +// setLogLevel sets the log level based on the LOG_LEVEL environment variable +func setLogLevel() { + log.SetOutput(os.Stdout) + log.SetFormatter(&log.TextFormatter{}) + + logLevel, err := log.ParseLevel(os.Getenv("LOG_LEVEL")) + if err != nil { + logLevel = log.InfoLevel + } + + log.SetLevel(logLevel) +} diff --git a/pkg/operator/api/v1alpha1/gameserver_types.go b/pkg/operator/api/v1alpha1/gameserver_types.go index e26c6dc0..d6247661 100644 --- a/pkg/operator/api/v1alpha1/gameserver_types.go +++ b/pkg/operator/api/v1alpha1/gameserver_types.go @@ -59,8 +59,8 @@ type GameServerSpec struct { // Build is the BuildID for this GameServer BuildID string `json:"buildID,omitempty"` //+kubebuilder:validation:Required - // PortsToExpose is an array of tuples of container/port names that correspond to the ports that will be exposed on the VM - PortsToExpose []PortToExpose `json:"portsToExpose,omitempty"` + // PortsToExpose is an array of ports that will be exposed on the VM + PortsToExpose []int32 `json:"portsToExpose,omitempty"` // BuildMetadata is the metadata for the GameServerBuild this GameServer belongs to BuildMetadata []BuildMetadataItem `json:"buildMetadata,omitempty"` } diff --git a/pkg/operator/api/v1alpha1/gameserverbuild_types.go b/pkg/operator/api/v1alpha1/gameserverbuild_types.go index c581bcfb..0228fd39 100644 --- a/pkg/operator/api/v1alpha1/gameserverbuild_types.go +++ b/pkg/operator/api/v1alpha1/gameserverbuild_types.go @@ -57,8 +57,8 @@ type GameServerBuildSpec struct { BuildID string `json:"buildID,omitempty"` //+kubebuilder:validation:Required - // PortsToExpose is an array of tuples of container/port names that correspond to the ports that will be exposed on the VM - PortsToExpose []PortToExpose `json:"portsToExpose,omitempty"` + // PortsToExpose is an array of ports that will be exposed on the VM + PortsToExpose []int32 `json:"portsToExpose,omitempty"` //+kubebuilder:default=5 //+kubebuilder:validation:Minimum=0 @@ -108,12 +108,6 @@ type GameServerBuildList struct { Items []GameServerBuild `json:"items"` } -// PortToExpose is a tuple of container/port names that correspond to the ports that will be exposed on the VM -type PortToExpose struct { - ContainerName string `json:"containerName"` - PortName string `json:"portName"` -} - func init() { SchemeBuilder.Register(&GameServerBuild{}, &GameServerBuildList{}) } diff --git a/pkg/operator/api/v1alpha1/zz_generated.deepcopy.go b/pkg/operator/api/v1alpha1/zz_generated.deepcopy.go index 9533d2fc..d5eb38a0 100644 --- a/pkg/operator/api/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/operator/api/v1alpha1/zz_generated.deepcopy.go @@ -132,7 +132,7 @@ func (in *GameServerBuildSpec) DeepCopyInto(out *GameServerBuildSpec) { in.Template.DeepCopyInto(&out.Template) if in.PortsToExpose != nil { in, out := &in.PortsToExpose, &out.PortsToExpose - *out = make([]PortToExpose, len(*in)) + *out = make([]int32, len(*in)) copy(*out, *in) } if in.BuildMetadata != nil { @@ -304,7 +304,7 @@ func (in *GameServerSpec) DeepCopyInto(out *GameServerSpec) { in.Template.DeepCopyInto(&out.Template) if in.PortsToExpose != nil { in, out := &in.PortsToExpose, &out.PortsToExpose - *out = make([]PortToExpose, len(*in)) + *out = make([]int32, len(*in)) copy(*out, *in) } if in.BuildMetadata != nil { @@ -338,18 +338,3 @@ func (in *GameServerStatus) DeepCopy() *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 *PortToExpose) DeepCopyInto(out *PortToExpose) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PortToExpose. -func (in *PortToExpose) DeepCopy() *PortToExpose { - if in == nil { - return nil - } - out := new(PortToExpose) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/operator/config/crd/bases/mps.playfab.com_gameserverbuilds.yaml b/pkg/operator/config/crd/bases/mps.playfab.com_gameserverbuilds.yaml index f6d854ee..24b30907 100644 --- a/pkg/operator/config/crd/bases/mps.playfab.com_gameserverbuilds.yaml +++ b/pkg/operator/config/crd/bases/mps.playfab.com_gameserverbuilds.yaml @@ -78,20 +78,11 @@ spec: minimum: 0 type: integer portsToExpose: - description: PortsToExpose is an array of tuples of container/port - names that correspond to the ports that will be exposed on the VM + description: PortsToExpose is an array of ports that will be exposed + on the VM items: - description: PortToExpose is a tuple of container/port names that - correspond to the ports that will be exposed on the VM - properties: - containerName: - type: string - portName: - type: string - required: - - containerName - - portName - type: object + format: int32 + type: integer type: array standingBy: description: StandingBy is the requested number of standingBy servers diff --git a/pkg/operator/config/crd/bases/mps.playfab.com_gameservers.yaml b/pkg/operator/config/crd/bases/mps.playfab.com_gameservers.yaml index fd124307..44038f67 100644 --- a/pkg/operator/config/crd/bases/mps.playfab.com_gameservers.yaml +++ b/pkg/operator/config/crd/bases/mps.playfab.com_gameservers.yaml @@ -72,20 +72,11 @@ spec: type: object type: array portsToExpose: - description: PortsToExpose is an array of tuples of container/port - names that correspond to the ports that will be exposed on the VM + description: PortsToExpose is an array of ports that will be exposed + on the VM items: - description: PortToExpose is a tuple of container/port names that - correspond to the ports that will be exposed on the VM - properties: - containerName: - type: string - portName: - type: string - required: - - containerName - - portName - type: object + format: int32 + type: integer type: array template: description: Template describes the pod template specification of diff --git a/pkg/operator/config/manager/kustomization.yaml b/pkg/operator/config/manager/kustomization.yaml index f817c7e3..43d1a99e 100755 --- a/pkg/operator/config/manager/kustomization.yaml +++ b/pkg/operator/config/manager/kustomization.yaml @@ -11,4 +11,4 @@ kind: Kustomization images: - name: controller newName: thundernetes-operator - newTag: dcc9988 + newTag: 104c3bb diff --git a/pkg/operator/controllers/gameserver_controller.go b/pkg/operator/controllers/gameserver_controller.go index 4f41a3d0..5bd40f07 100644 --- a/pkg/operator/controllers/gameserver_controller.go +++ b/pkg/operator/controllers/gameserver_controller.go @@ -232,7 +232,8 @@ func (r *GameServerReconciler) unassignPorts(gs *mpsv1alpha1.GameServer) error { for i := 0; i < len(gs.Spec.Template.Spec.Containers); i++ { container := gs.Spec.Template.Spec.Containers[i] for j := 0; j < len(container.Ports); j++ { - if sliceContainsPortToExpose(gs.Spec.PortsToExpose, container.Name, container.Ports[j].Name) { + // if the hostPort is > 0, this means that it has been assigned by the controller + if container.Ports[j].HostPort > 0 { hostPorts = append(hostPorts, container.Ports[j].HostPort) } } diff --git a/pkg/operator/controllers/utilities.go b/pkg/operator/controllers/utilities.go index a813f06c..d7c04480 100644 --- a/pkg/operator/controllers/utilities.go +++ b/pkg/operator/controllers/utilities.go @@ -113,7 +113,8 @@ func NewGameServerForGameServerBuild(gsb *mpsv1alpha1.GameServerBuild, portRegis Labels: map[string]string{LabelBuildID: gsb.Spec.BuildID, LabelBuildName: gsb.Name}, }, Spec: mpsv1alpha1.GameServerSpec{ - Template: gsb.Spec.Template, + // we're doing a DeepCopy since we modify the hostPort + Template: *gsb.Spec.Template.DeepCopy(), BuildID: gsb.Spec.BuildID, TitleID: gsb.Spec.TitleID, PortsToExpose: gsb.Spec.PortsToExpose, @@ -122,10 +123,10 @@ func NewGameServerForGameServerBuild(gsb *mpsv1alpha1.GameServerBuild, portRegis // we don't create any status since we have the .Status subresource enabled } // assigning host ports for all the containers in the Template.Spec - for i := 0; i < len(gsb.Spec.Template.Spec.Containers); i++ { - container := gsb.Spec.Template.Spec.Containers[i] + for i := 0; i < len(gs.Spec.Template.Spec.Containers); i++ { + container := gs.Spec.Template.Spec.Containers[i] for i := 0; i < len(container.Ports); i++ { - if sliceContainsPortToExpose(gsb.Spec.PortsToExpose, container.Name, container.Ports[i].Name) { + if sliceContainsPortToExpose(gsb.Spec.PortsToExpose, container.Ports[i].ContainerPort) { port, err := portRegistry.GetNewPort() if err != nil { return nil, err @@ -133,7 +134,7 @@ func NewGameServerForGameServerBuild(gsb *mpsv1alpha1.GameServerBuild, portRegis container.Ports[i].HostPort = port // if the user has specified that they want to use the host's network, we override the container port - if gsb.Spec.Template.Spec.HostNetwork { + if gs.Spec.Template.Spec.HostNetwork { container.Ports[i].ContainerPort = port } } @@ -284,9 +285,9 @@ func getInitContainerEnvVariables(gs *mpsv1alpha1.GameServer) []corev1.EnvVar { // get game ports for _, container := range gs.Spec.Template.Spec.Containers { for _, port := range container.Ports { - containerPort := strconv.Itoa(int(port.ContainerPort)) - hostPort := strconv.Itoa(int(port.HostPort)) - if sliceContainsPortToExpose(gs.Spec.PortsToExpose, container.Name, port.Name) { + if port.HostPort > 0 { // hostPort has been set, this means that this port is in the portsToExpose array + containerPort := strconv.Itoa(int(port.ContainerPort)) + hostPort := strconv.Itoa(int(port.HostPort)) b.WriteString(port.Name + "," + containerPort + "," + hostPort + "?") } } @@ -337,10 +338,10 @@ func getGameServerEnvVariables(gs *mpsv1alpha1.GameServer) []corev1.EnvVar { return envList } -// sliceContainsPortToExpose returns true if the specific containerName/tuple value is contained in the slice -func sliceContainsPortToExpose(slice []mpsv1alpha1.PortToExpose, containerName, portName string) bool { - for _, item := range slice { - if item.ContainerName == containerName && item.PortName == portName { +// sliceContainsPortToExpose returns true if the port is contained in the portsToExpose slice +func sliceContainsPortToExpose(portsToExpose []int32, port int32) bool { + for _, item := range portsToExpose { + if item == port { return true } } diff --git a/pkg/operator/controllers/utilities_test.go b/pkg/operator/controllers/utilities_test.go index fdc4c3bc..43c9d47c 100644 --- a/pkg/operator/controllers/utilities_test.go +++ b/pkg/operator/controllers/utilities_test.go @@ -43,23 +43,12 @@ var _ = Describe("Utilities tests", func() { Expect(containsString([]string{"foo"}, "bar")).To(BeFalse()) }) It("should find if containerName/portName tuple is contained in the PortToExpose slice", func() { - p := []mpsv1alpha1.PortToExpose{ - { - ContainerName: "container1", - PortName: "port1", - }, - { - ContainerName: "container1", - PortName: "port2", - }, - { - ContainerName: "container2", - PortName: "port1", - }, + p := []int32{ + 5, 10, 15, } - Expect(sliceContainsPortToExpose(p, "container1", "port1")).To(BeTrue()) - Expect(sliceContainsPortToExpose(p, "container1", "port2")).To(BeTrue()) - Expect(sliceContainsPortToExpose(p, "container2", "port2")).To(BeFalse()) + Expect(sliceContainsPortToExpose(p, 5)).To(BeTrue()) + Expect(sliceContainsPortToExpose(p, 10)).To(BeTrue()) + Expect(sliceContainsPortToExpose(p, 16)).To(BeFalse()) }) It("should return env variables for GameServer", func() { gs := &mpsv1alpha1.GameServer{ @@ -86,15 +75,8 @@ var _ = Describe("Utilities tests", func() { Spec: mpsv1alpha1.GameServerSpec{ TitleID: "test-title", BuildID: "test-build", - PortsToExpose: []mpsv1alpha1.PortToExpose{ - { - ContainerName: "container1", - PortName: "port1", - }, - { - ContainerName: "container1", - PortName: "port2", - }, + PortsToExpose: []int32{ + 80, 443, }, Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ diff --git a/samples/netcore/Program.cs b/samples/netcore/Program.cs index 29d5b9ad..ee4fbe6a 100644 --- a/samples/netcore/Program.cs +++ b/samples/netcore/Program.cs @@ -27,8 +27,7 @@ static void Main(string[] args) var portInfo = gameServerConnectionInfo.GamePortsConfiguration.Where(x=>x.Name == httpPortKey); if(portInfo.Count() == 0) { - Console.WriteLine("No port info found for " + httpPortKey); - return; + throw new Exception("No port info found for " + httpPortKey); } httpPort = portInfo.Single().ServerListeningPort;