From 5346b7c43554153be0e5f09b97133d11f8dacd6e Mon Sep 17 00:00:00 2001 From: Rafael Aranda Soto Date: Thu, 14 Oct 2021 18:15:33 -0500 Subject: [PATCH 1/6] allocator draft --- tools/allocator/main.go | 85 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 tools/allocator/main.go diff --git a/tools/allocator/main.go b/tools/allocator/main.go new file mode 100644 index 00000000..d30ac771 --- /dev/null +++ b/tools/allocator/main.go @@ -0,0 +1,85 @@ +package main; + +import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "strings" +); + +func main () { + args := os.Args; + + if len(args) <= 1 { + fmt.Println("Usage of the allocator tool"); + fmt.Println("\tallocate #Initialize a server with the given paramaters"); + fmt.Println("\tlist # Returns the available Game Servers on Standby status"); + } else if strings.Compare(args[1], "allocate") == 0 { + fmt.Println("Beginning the allocate process"); + + cmd := exec.Command("kubectl","get","svc","-n","thundernetes-system","thundernetes-controller-manager", + "-o","jsonpath='{.status.loadBalancer.ingress[0].ip}'"); + var ip string; + reqBody, err := json.Marshal(map[string] string { + "buildID": "85ffe8da-c82f-4035-86c5-9d2b5f42d6f6", + "sessionID": "ac1b7082-d811-47a7-89ae-fe1a9c48a6da", + }); + + + if err != nil { + log.Fatal(err); + } + + output, err := cmd.CombinedOutput(); + + if err != nil { + log.Fatal(string(output)); + } + + + if len(output) < 3 { // basically if we don't have a valid IP + ip = "http://127.0.0.1:5000/api/v1/allocate"; + } else { + ip = string(output); + } + + resp, err := http.Post(ip, "application/json", bytes.NewBuffer(reqBody)); + + if err != nil { + Fatal.Println(err); + } + + defer resp.Body.Close(); + + body, err := ioutil.ReadAll(resp.Body); + + if err != nil { + log.Println(err); + } + + log.Println(string(body)); + + } else if strings.Compare(args[1], "list") == 0 { + fmt.Println("Listing the available game servers"); + cmd := exec.Command("kubectl", "get", "gs"); + output, err := cmd.CombinedOutput(); + + if err != nil { + fmt.Println(string(output)); + log.Fatal("Error while fetching the servers: ", err); + fmt.Println("Please, make sure you have your cluster configured properly"); + } + + fmt.Println(string(output)); + } else { + fmt.Println("Sorry, but the commad "+args[1]+" is not recognized"); + } + + fmt.Println("\nThanks for using the thundernetes allocator tool"); + +} \ No newline at end of file From 5ec7738c72d2d89b2ffa6eb49db00ac8fff740b4 Mon Sep 17 00:00:00 2001 From: Rafael Aranda Soto Date: Fri, 15 Oct 2021 16:59:53 -0500 Subject: [PATCH 2/6] adding tls initialization --- tools/allocator/main.go | 107 +++++++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 23 deletions(-) diff --git a/tools/allocator/main.go b/tools/allocator/main.go index d30ac771..11695355 100644 --- a/tools/allocator/main.go +++ b/tools/allocator/main.go @@ -2,6 +2,7 @@ package main; import ( "bytes" + "crypto/tls" "encoding/json" "fmt" "io/ioutil" @@ -12,28 +13,33 @@ import ( "strings" ); +type AllocationResult struct { + IPV4Address string `json:"IPv4Address"`; + SessionID string `json:"SessionID"`; +}; + +var ( + ip string; + certFile string; + keyFile string; +); + func main () { args := os.Args; - - if len(args) <= 1 { - fmt.Println("Usage of the allocator tool"); - fmt.Println("\tallocate #Initialize a server with the given paramaters"); - fmt.Println("\tlist # Returns the available Game Servers on Standby status"); + + if len(args) == 1 { + fmt.Println("Usage of the allocator tool (is highly recommended to have"+ + " kubectl on your $PATH)"); + fmt.Println("\t- allocate [tls-public] [tls-private]"+ + " # Initialize a server with the given paramaters (if tls certs"+ + " are not on the TLS_PUBLIC / TLS_PRIVATE env variables, please"+ + " provide them via argument)"); + fmt.Println("\t- list # Returns the available Game Servers"); } else if strings.Compare(args[1], "allocate") == 0 { fmt.Println("Beginning the allocate process"); cmd := exec.Command("kubectl","get","svc","-n","thundernetes-system","thundernetes-controller-manager", "-o","jsonpath='{.status.loadBalancer.ingress[0].ip}'"); - var ip string; - reqBody, err := json.Marshal(map[string] string { - "buildID": "85ffe8da-c82f-4035-86c5-9d2b5f42d6f6", - "sessionID": "ac1b7082-d811-47a7-89ae-fe1a9c48a6da", - }); - - - if err != nil { - log.Fatal(err); - } output, err := cmd.CombinedOutput(); @@ -41,28 +47,34 @@ func main () { log.Fatal(string(output)); } - if len(output) < 3 { // basically if we don't have a valid IP ip = "http://127.0.0.1:5000/api/v1/allocate"; } else { ip = string(output); } - resp, err := http.Post(ip, "application/json", bytes.NewBuffer(reqBody)); + // get certificates to authenticate to operator API server + if len(args) < 5 { + certFile = os.Getenv("TLS_PUBLIC"); + keyFile = os.Getenv("TLS_PRIVATE"); + } else { + certFile = args[4]; + keyFile = args[5]; + } + + cert, err := tls.LoadX509KeyPair(certFile, keyFile); if err != nil { - Fatal.Println(err); + log.Panic(err); } - defer resp.Body.Close(); - - body, err := ioutil.ReadAll(resp.Body); + ar, err := allocate(ip, args[2], args[3], cert); if err != nil { - log.Println(err); + log.Panic(err); } - log.Println(string(body)); + log.Println("IP address: "+ ar.IPV4Address+". Session ID: "+ar.SessionID); } else if strings.Compare(args[1], "list") == 0 { fmt.Println("Listing the available game servers"); @@ -82,4 +94,53 @@ func main () { fmt.Println("\nThanks for using the thundernetes allocator tool"); +} + +func allocate(ip string, buildID string, sessionID string, cert tls.Certificate) (*AllocationResult, error) { + tlsConfig := &tls.Config{ + InsecureSkipVerify: true, + Certificates: []tls.Certificate{cert}, + } + + transport := &http.Transport{TLSClientConfig: tlsConfig}; + client := &http.Client{Transport: transport}; + + postBody, _ := json.Marshal(map[string]interface{}{ + "buildID": buildID, + "sessionID": sessionID, + "sessionCookie": "randomCookie", + "initialPlayers": []string{"player1", "player2"}, + }); + + postBodyBytes := bytes.NewBuffer(postBody); + resp, err := client.Post(ip+":5000/api/v1/allocate", "application/json", postBodyBytes); + + //Handle Error + if err != nil { + return nil, err; + } + + defer resp.Body.Close(); + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%d", resp.StatusCode); + } + + //Read the response body + body, err := ioutil.ReadAll(resp.Body); + if err != nil { + return nil, err; + } + + ar := &AllocationResult{}; + json.Unmarshal(body, ar); + + if ar.IPV4Address == "" { + return nil, fmt.Errorf("invalid IPV4Address %s", ar.IPV4Address); + } + + if ar.SessionID != sessionID { + return nil, fmt.Errorf("invalid SessionID %s", ar.SessionID); + } + + return ar, nil; } \ No newline at end of file From 6c41527c96733440d583c4205585642502f3d078 Mon Sep 17 00:00:00 2001 From: Rafael Aranda Soto Date: Fri, 15 Oct 2021 17:59:36 -0500 Subject: [PATCH 3/6] general cleanup --- tools/allocator/go.mod | 3 ++ tools/allocator/main.go | 103 +++++++++++++++++++++------------------- 2 files changed, 56 insertions(+), 50 deletions(-) create mode 100644 tools/allocator/go.mod diff --git a/tools/allocator/go.mod b/tools/allocator/go.mod new file mode 100644 index 00000000..dd82b241 --- /dev/null +++ b/tools/allocator/go.mod @@ -0,0 +1,3 @@ +module github.com/playfab/thundernetes/tools/allocator + +go 1.16 diff --git a/tools/allocator/main.go b/tools/allocator/main.go index 11695355..d7578068 100644 --- a/tools/allocator/main.go +++ b/tools/allocator/main.go @@ -1,4 +1,4 @@ -package main; +package main import ( "bytes" @@ -14,85 +14,88 @@ import ( ); type AllocationResult struct { - IPV4Address string `json:"IPv4Address"`; - SessionID string `json:"SessionID"`; + IPV4Address string `json:"IPv4Address"` + SessionID string `json:"SessionID"` }; var ( - ip string; - certFile string; - keyFile string; + ip string + certFile string + keyFile string ); func main () { - args := os.Args; + args := os.Args if len(args) == 1 { - fmt.Println("Usage of the allocator tool (is highly recommended to have"+ - " kubectl on your $PATH)"); + fmt.Println("Usage of the allocator tool (is required to have"+ + " kubectl on your $PATH)") fmt.Println("\t- allocate [tls-public] [tls-private]"+ " # Initialize a server with the given paramaters (if tls certs"+ " are not on the TLS_PUBLIC / TLS_PRIVATE env variables, please"+ - " provide them via argument)"); - fmt.Println("\t- list # Returns the available Game Servers"); + " provide them via argument)") + fmt.Println("\t- list # Returns the available Game Servers") } else if strings.Compare(args[1], "allocate") == 0 { - fmt.Println("Beginning the allocate process"); + fmt.Println("Beginning the allocate process") cmd := exec.Command("kubectl","get","svc","-n","thundernetes-system","thundernetes-controller-manager", - "-o","jsonpath='{.status.loadBalancer.ingress[0].ip}'"); + "-o","jsonpath='{.status.loadBalancer.ingress[0].ip}'") - output, err := cmd.CombinedOutput(); + output, err := cmd.CombinedOutput() if err != nil { - log.Fatal(string(output)); + log.Println("Is required to have kubectl on your $PATH") + log.Fatal(string(output)) + } if len(output) < 3 { // basically if we don't have a valid IP - ip = "http://127.0.0.1:5000/api/v1/allocate"; + ip = "https://127.0.0.1" } else { - ip = string(output); + ip = string(output) } // get certificates to authenticate to operator API server if len(args) < 5 { - certFile = os.Getenv("TLS_PUBLIC"); - keyFile = os.Getenv("TLS_PRIVATE"); + certFile = os.Getenv("TLS_PUBLIC") + keyFile = os.Getenv("TLS_PRIVATE") } else { - certFile = args[4]; - keyFile = args[5]; + certFile = args[4] + keyFile = args[5] } - cert, err := tls.LoadX509KeyPair(certFile, keyFile); + cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { - log.Panic(err); + log.Panic(err) } - ar, err := allocate(ip, args[2], args[3], cert); + ar, err := allocate(ip, args[2], args[3], cert) if err != nil { - log.Panic(err); + log.Panic(err) } log.Println("IP address: "+ ar.IPV4Address+". Session ID: "+ar.SessionID); } else if strings.Compare(args[1], "list") == 0 { - fmt.Println("Listing the available game servers"); - cmd := exec.Command("kubectl", "get", "gs"); - output, err := cmd.CombinedOutput(); + fmt.Println("Listing the available game servers") + cmd := exec.Command("kubectl", "get", "gs") + output, err := cmd.CombinedOutput() if err != nil { - fmt.Println(string(output)); - log.Fatal("Error while fetching the servers: ", err); - fmt.Println("Please, make sure you have your cluster configured properly"); + fmt.Println(string(output)) + log.Fatal("Error while fetching the servers: ", err) + log.Println("Is required to have kubectl on your $PATH") + fmt.Println("Please, make sure you have your cluster configured properly") } - fmt.Println(string(output)); + fmt.Println(string(output)) } else { - fmt.Println("Sorry, but the commad "+args[1]+" is not recognized"); + fmt.Println("Sorry, but the commad "+args[1]+" is not recognized") } - fmt.Println("\nThanks for using the thundernetes allocator tool"); + fmt.Println("\nThanks for using the thundernetes allocator tool") } @@ -102,45 +105,45 @@ func allocate(ip string, buildID string, sessionID string, cert tls.Certificate) Certificates: []tls.Certificate{cert}, } - transport := &http.Transport{TLSClientConfig: tlsConfig}; - client := &http.Client{Transport: transport}; + transport := &http.Transport{TLSClientConfig: tlsConfig} + client := &http.Client{Transport: transport} postBody, _ := json.Marshal(map[string]interface{}{ "buildID": buildID, "sessionID": sessionID, - "sessionCookie": "randomCookie", + "sessionCookie": "coolRandomCookie", "initialPlayers": []string{"player1", "player2"}, - }); + }) - postBodyBytes := bytes.NewBuffer(postBody); - resp, err := client.Post(ip+":5000/api/v1/allocate", "application/json", postBodyBytes); + postBodyBytes := bytes.NewBuffer(postBody) + resp, err := client.Post(ip+":5000/api/v1/allocate", "application/json", postBodyBytes) //Handle Error if err != nil { - return nil, err; + return nil, err } - defer resp.Body.Close(); + defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("%d", resp.StatusCode); + return nil, fmt.Errorf("%d", resp.StatusCode) } //Read the response body - body, err := ioutil.ReadAll(resp.Body); + body, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, err; + return nil, err } - ar := &AllocationResult{}; - json.Unmarshal(body, ar); + ar := &AllocationResult{} + json.Unmarshal(body, ar) if ar.IPV4Address == "" { - return nil, fmt.Errorf("invalid IPV4Address %s", ar.IPV4Address); + return nil, fmt.Errorf("invalid IPV4Address %s", ar.IPV4Address) } if ar.SessionID != sessionID { - return nil, fmt.Errorf("invalid SessionID %s", ar.SessionID); + return nil, fmt.Errorf("invalid SessionID %s", ar.SessionID) } - return ar, nil; + return ar, nil } \ No newline at end of file From 41b4726bd395ee97d062b65907e1dea896217ddd Mon Sep 17 00:00:00 2001 From: Rafael Aranda Soto Date: Fri, 15 Oct 2021 19:02:27 -0500 Subject: [PATCH 4/6] adding support for tls certs and no tls certs provided by user --- tools/allocator/main.go | 110 ++++++++++++++++++++++++++++++++-------- 1 file changed, 88 insertions(+), 22 deletions(-) diff --git a/tools/allocator/main.go b/tools/allocator/main.go index d7578068..73cde7d0 100644 --- a/tools/allocator/main.go +++ b/tools/allocator/main.go @@ -22,6 +22,8 @@ var ( ip string certFile string keyFile string + tlsSet bool + ar *AllocationResult ); func main () { @@ -49,31 +51,50 @@ func main () { } - if len(output) < 3 { // basically if we don't have a valid IP - ip = "https://127.0.0.1" - } else { - ip = string(output) + if len(args) < 5 { // if no more arguments are provided + if certFile == "" || keyFile == "" { // If the env vars are not set + tlsSet = false + } else { // the env vars are set + tlsSet = true + } + } else { // all the arguments are provided + tlsSet = true } - // get certificates to authenticate to operator API server - if len(args) < 5 { - certFile = os.Getenv("TLS_PUBLIC") - keyFile = os.Getenv("TLS_PRIVATE") - } else { - certFile = args[4] - keyFile = args[5] - } - - cert, err := tls.LoadX509KeyPair(certFile, keyFile) + if len(output) < 3 { // basically if we don't have a valid IP + if tlsSet == true { + ip = "https://127.0.0.1" + cert, err := tls.LoadX509KeyPair(certFile, keyFile) + ar, err = allocateTls(ip, args[2], args[3], cert) + + if err != nil { + log.Panic(err) + } + } else { + ip = "http://127.0.0.1" + ar, err = allocateNoTls(ip, args[2], args[3]) + + if err != nil { + log.Panic(err) + } + } + } else { // if we retrieve the ip correctly + ip = string(output) - if err != nil { - log.Panic(err) - } + if tlsSet == true { + cert, err := tls.LoadX509KeyPair(certFile, keyFile) + ar, err = allocateTls(ip, args[2], args[3], cert) - ar, err := allocate(ip, args[2], args[3], cert) + if err != nil { + log.Panic(err) + } + } else { + ar, err = allocateNoTls(ip, args[2], args[3]) - if err != nil { - log.Panic(err) + if err != nil { + log.Panic(err) + } + } } log.Println("IP address: "+ ar.IPV4Address+". Session ID: "+ar.SessionID); @@ -86,7 +107,7 @@ func main () { if err != nil { fmt.Println(string(output)) log.Fatal("Error while fetching the servers: ", err) - log.Println("Is required to have kubectl on your $PATH") + log.Println("It is required to have kubectl on your $PATH") fmt.Println("Please, make sure you have your cluster configured properly") } @@ -99,7 +120,7 @@ func main () { } -func allocate(ip string, buildID string, sessionID string, cert tls.Certificate) (*AllocationResult, error) { +func allocateTls(ip string, buildID string, sessionID string, cert tls.Certificate) (*AllocationResult, error) { tlsConfig := &tls.Config{ InsecureSkipVerify: true, Certificates: []tls.Certificate{cert}, @@ -145,5 +166,50 @@ func allocate(ip string, buildID string, sessionID string, cert tls.Certificate) return nil, fmt.Errorf("invalid SessionID %s", ar.SessionID) } + return ar, nil +} + +func allocateNoTls(ip string, buildID string, sessionID string) (*AllocationResult, error) { + + transport := &http.Transport{} + client := &http.Client{Transport: transport} + + postBody, _ := json.Marshal(map[string]interface{}{ + "buildID": buildID, + "sessionID": sessionID, + "sessionCookie": "coolRandomCookie", + "initialPlayers": []string{"player1", "player2"}, + }) + + postBodyBytes := bytes.NewBuffer(postBody) + resp, err := client.Post(ip+":5000/api/v1/allocate", "application/json", postBodyBytes) + + //Handle Error + if err != nil { + return nil, err + } + + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("%d", resp.StatusCode) + } + + //Read the response body + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + ar := &AllocationResult{} + json.Unmarshal(body, ar) + + if ar.IPV4Address == "" { + return nil, fmt.Errorf("invalid IPV4Address %s", ar.IPV4Address) + } + + if ar.SessionID != sessionID { + return nil, fmt.Errorf("invalid SessionID %s", ar.SessionID) + } + return ar, nil } \ No newline at end of file From 2166a0909f22dcd93bb2b8263b525d6cc3b91ee9 Mon Sep 17 00:00:00 2001 From: Rafael Aranda Soto Date: Fri, 15 Oct 2021 19:24:10 -0500 Subject: [PATCH 5/6] adding README --- tools/allocator/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tools/allocator/README.md diff --git a/tools/allocator/README.md b/tools/allocator/README.md new file mode 100644 index 00000000..86a7669e --- /dev/null +++ b/tools/allocator/README.md @@ -0,0 +1,9 @@ +# Thundernetes allocator tool + +Thanks for using the allocator tool for thundernetes. To use it: +- `kubectl` is required to be in $PATH. for more information, please refer to the following [guide](https://kubernetes.io/docs/tasks/tools/#kubectl) +- Compile the main.go file (optional to provide a meaningful name like allocator, thunderallocator or something similar). +- Once you the executable, you can: + - run the executable with no argument for some help and details + - `list` which will provide the available servers. + - `allocate [tls-public] [tls-private]` where the tls certificates are optional, but build and session ID are mandatory. Please note that providing the certs as env variables is also supported; if so, please name them TLS_PUBLIC for the cert file and TLS_PRIVATE for the key file. \ No newline at end of file From 5d97c31a9305f2639cbaf9f1d6fcc608a3aa4337 Mon Sep 17 00:00:00 2001 From: Rafael Aranda Soto Date: Fri, 15 Oct 2021 19:31:42 -0500 Subject: [PATCH 6/6] readme typos --- tools/allocator/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/allocator/README.md b/tools/allocator/README.md index 86a7669e..0a5b6113 100644 --- a/tools/allocator/README.md +++ b/tools/allocator/README.md @@ -2,8 +2,8 @@ Thanks for using the allocator tool for thundernetes. To use it: - `kubectl` is required to be in $PATH. for more information, please refer to the following [guide](https://kubernetes.io/docs/tasks/tools/#kubectl) -- Compile the main.go file (optional to provide a meaningful name like allocator, thunderallocator or something similar). -- Once you the executable, you can: - - run the executable with no argument for some help and details +- Compile the main.go file with `go build main.go` (optional to provide a meaningful name like allocator, thunderallocator or something similar). +- Once you have the executable ready, you can run it to: + - Provide no argument for some help and details. - `list` which will provide the available servers. - `allocate [tls-public] [tls-private]` where the tls certificates are optional, but build and session ID are mandatory. Please note that providing the certs as env variables is also supported; if so, please name them TLS_PUBLIC for the cert file and TLS_PRIVATE for the key file. \ No newline at end of file