// This file is part of MinIO Console Server // Copyright (c) 2021 MinIO, Inc. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . package operatorintegration import ( "bytes" b64 "encoding/base64" "encoding/json" "fmt" "io" "io/ioutil" "log" "net/http" "os" "os/exec" "strconv" "strings" "testing" "time" "github.com/go-openapi/loads" "github.com/minio/console/models" "github.com/minio/console/operatorapi" "github.com/minio/console/operatorapi/operations" "github.com/stretchr/testify/assert" ) var ( token string jwt string ) func inspectHTTPResponse(httpResponse *http.Response) string { /* Helper function to inspect the content of a HTTP response. */ b, err := io.ReadAll(httpResponse.Body) if err != nil { log.Fatalln(err) } return "Http Response: " + string(b) } func decodeBase64(value string) string { /* Helper function to decode in base64 */ result, err := b64.StdEncoding.DecodeString(value) if err != nil { log.Fatal("error:", err) } return string(result) } func printLoggingMessage(message string, functionName string) { /* Helper function to have standard output across the tests. */ finalString := "......................." + functionName + "(): " + message fmt.Println(finalString) } func printStartFunc(functionName string) { /* Common function for all tests to tell that test has started */ fmt.Println("") printLoggingMessage("started", functionName) } func printEndFunc(functionName string) { /* Helper function for all tests to tell that test has ended, is completed */ printLoggingMessage("completed", functionName) fmt.Println("") } func initConsoleServer() (*operatorapi.Server, error) { // os.Setenv("CONSOLE_MINIO_SERVER", "localhost:9000") swaggerSpec, err := loads.Embedded(operatorapi.SwaggerJSON, operatorapi.FlatSwaggerJSON) if err != nil { return nil, err } noLog := func(string, ...interface{}) { // nothing to log } // Initialize MinIO loggers operatorapi.LogInfo = noLog operatorapi.LogError = noLog api := operations.NewOperatorAPI(swaggerSpec) api.Logger = noLog server := operatorapi.NewServer(api) // register all APIs server.ConfigureAPI() consolePort, _ := strconv.Atoi("9090") server.Host = "0.0.0.0" server.Port = consolePort operatorapi.Port = "9090" operatorapi.Hostname = "0.0.0.0" return server, nil } func TestMain(m *testing.M) { printStartFunc("TestMain") // start console server go func() { fmt.Println("start server") srv, err := initConsoleServer() fmt.Println("Server has been started at this point") if err != nil { fmt.Println("There is an error in console server: ", err) log.Println(err) log.Println("init fail") return } fmt.Println("Start serving with Serve() function") srv.Serve() fmt.Println("After Serve() function") }() fmt.Println("sleeping") time.Sleep(2 * time.Second) fmt.Println("after 2 seconds sleep") fmt.Println("creating the client") // SA_TOKEN=$(kubectl -n minio-operator get secret console-sa-secret -o jsonpath="{.data.token}" | base64 --decode) fmt.Println("Where we have the secret already: ") app2 := "kubectl" argu0 := "--namespace" argu1 := "minio-operator" argu2 := "get" argu3 := "secret" argu4 := "console-sa-secret" argu5 := "-o" argu6 := "jsonpath=\"{.data.token}\"" fmt.Println("Prior executing second command to get the token") cmd2 := exec.Command(app2, argu0, argu1, argu2, argu3, argu4, argu5, argu6) fmt.Println("after executing second command to get the token") var out2 bytes.Buffer var stderr2 bytes.Buffer cmd2.Stdout = &out2 cmd2.Stderr = &stderr2 err2 := cmd2.Run() if err2 != nil { fmt.Println(fmt.Sprint(err2) + ": -> " + stderr2.String()) return } secret2 := out2.String() jwt := decodeBase64(secret2[1 : len(secret2)-1]) if jwt == "" { fmt.Println("jwt cannot be empty string") os.Exit(-1) } response, err := LoginOperator() if err != nil { log.Println(err) return } if response != nil { for _, cookie := range response.Cookies() { if cookie.Name == "token" { token = cookie.Value break } } } if token == "" { log.Println("authentication token not found in cookies response") return } code := m.Run() printEndFunc("TestMain") os.Exit(code) } func ListTenants() (*http.Response, error) { /* Helper function to list buckets HTTP Verb: GET URL: http://localhost:9090/api/v1/tenants */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/tenants", nil) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestListTenants(t *testing.T) { // Tenants can be listed via API: https://github.com/miniohq/engineering/issues/591 printStartFunc("TestListTenants") assert := assert.New(t) resp, err := ListTenants() assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, "Status Code is incorrect") } bodyBytes, _ := ioutil.ReadAll(resp.Body) result := models.ListTenantsResponse{} err = json.Unmarshal(bodyBytes, &result) if err != nil { log.Println(err) assert.Nil(err) } TenantName := &result.Tenants[0].Name // The array has to be empty, no index accessible fmt.Println(*TenantName) assert.Equal("storage-kms-encrypted", *TenantName, *TenantName) printEndFunc("TestListTenants") } func CreateTenant(tenantName string, namespace string, accessKey string, secretKey string, accessKeys []string, idp map[string]interface{}, tls map[string]interface{}, prometheusConfiguration map[string]interface{}, logSearchConfiguration map[string]interface{}, erasureCodingParity int, pools []map[string]interface{}, exposeConsole bool, exposeMinIO bool, image string, serviceName string, enablePrometheus bool, enableConsole bool, enableTLS bool, secretKeys []string) (*http.Response, error) { /* Helper function to create a tenant HTTP Verb: POST API: /api/v1/tenants */ requestDataAdd := map[string]interface{}{ "name": tenantName, "namespace": namespace, "access_key": accessKey, "secret_key": secretKey, "access_keys": accessKeys, "secret_keys": secretKeys, "enable_tls": enableTLS, "enable_console": enableConsole, "enable_prometheus": enablePrometheus, "service_name": serviceName, "image": image, "expose_minio": exposeMinIO, "expose_console": exposeConsole, "pools": pools, "erasureCodingParity": erasureCodingParity, "logSearchConfiguration": logSearchConfiguration, "prometheusConfiguration": prometheusConfiguration, "tls": tls, "idp": idp, } requestDataJSON, _ := json.Marshal(requestDataAdd) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( "POST", "http://localhost:9090/api/v1/tenants", requestDataBody, ) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func DeleteTenant(nameSpace, tenant string) (*http.Response, error) { /* URL: /namespaces/{namespace}/tenants/{tenant}: HTTP Verb: DELETE Summary: Delete tenant and underlying pvcs */ request, err := http.NewRequest( "DELETE", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant, nil, ) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestCreateTenant(t *testing.T) { printStartFunc("TestCreateTenant") // Variables assert := assert.New(t) erasureCodingParity := 2 tenantName := "new-tenant" namespace := "default" accessKey := "" secretKey := "" var accessKeys []string var secretKeys []string var minio []string var caCertificates []string var consoleCAcertificates []string enableTLS := true enableConsole := true enablePrometheus := true serviceName := "" image := "" exposeMinIO := true exposeConsole := true values := make([]string, 1) values[0] = "new-tenant" values2 := make([]string, 1) values2[0] = "pool-0" keys := make([]map[string]interface{}, 1) keys[0] = map[string]interface{}{ "access_key": "IGLksSXdiU3fjcRI", "secret_key": "EqeCPZ1xBYdnygizxxRWnkH09N2350nO", } pools := make([]map[string]interface{}, 1) matchExpressions := make([]map[string]interface{}, 2) matchExpressions[0] = map[string]interface{}{ "key": "v1.min.io/tenant", "operator": "In", "values": values, } matchExpressions[1] = map[string]interface{}{ "key": "v1.min.io/pool", "operator": "In", "values": values2, } requiredDuringSchedulingIgnoredDuringExecution := make([]map[string]interface{}, 1) requiredDuringSchedulingIgnoredDuringExecution[0] = map[string]interface{}{ "labelSelector": map[string]interface{}{ "matchExpressions": matchExpressions, }, "topologyKey": "kubernetes.io/hostname", } pools0 := map[string]interface{}{ "name": "pool-0", "servers": 4, "volumes_per_server": 1, "volume_configuration": map[string]interface{}{ "size": 26843545600, "storage_class_name": "standard", }, "securityContext": nil, "affinity": map[string]interface{}{ "podAntiAffinity": map[string]interface{}{ "requiredDuringSchedulingIgnoredDuringExecution": requiredDuringSchedulingIgnoredDuringExecution, }, }, "resources": map[string]interface{}{ "requests": map[string]interface{}{ "cpu": 2, "memory": 2, }, }, } logSearchConfiguration := map[string]interface{}{ "image": "", "postgres_image": "", "postgres_init_image": "", } prometheusConfiguration := map[string]interface{}{ "image": "", "sidecar_image": "", "init_image": "", } tls := map[string]interface{}{ "minio": minio, "ca_certificates": caCertificates, "console_ca_certificates": consoleCAcertificates, } idp := map[string]interface{}{ "keys": keys, } pools[0] = pools0 // 1. Create Tenant resp, err := CreateTenant( tenantName, namespace, accessKey, secretKey, accessKeys, idp, tls, prometheusConfiguration, logSearchConfiguration, erasureCodingParity, pools, exposeConsole, exposeMinIO, image, serviceName, enablePrometheus, enableConsole, enableTLS, secretKeys, ) assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, "Status Code is incorrect") } printEndFunc("TestCreateTenant") } func TestDeleteTenant(t *testing.T) { printStartFunc("TestCreateTenant") // Variables assert := assert.New(t) erasureCodingParity := 2 tenantName := "new-tenant-3" namespace := "new-namespace-3" // 0. Create the namespace resp, err := CreateNamespace(namespace) assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 201, resp.StatusCode, inspectHTTPResponse(resp)) } accessKey := "" secretKey := "" var accessKeys []string var secretKeys []string var minio []string var caCertificates []string var consoleCAcertificates []string enableTLS := true enableConsole := true enablePrometheus := true serviceName := "" image := "" exposeMinIO := true exposeConsole := true values := make([]string, 1) values[0] = "new-tenant" values2 := make([]string, 1) values2[0] = "pool-0" keys := make([]map[string]interface{}, 1) keys[0] = map[string]interface{}{ "access_key": "IGLksSXdiU3fjcRI", "secret_key": "EqeCPZ1xBYdnygizxxRWnkH09N2350nO", } pools := make([]map[string]interface{}, 1) matchExpressions := make([]map[string]interface{}, 2) matchExpressions[0] = map[string]interface{}{ "key": "v1.min.io/tenant", "operator": "In", "values": values, } matchExpressions[1] = map[string]interface{}{ "key": "v1.min.io/pool", "operator": "In", "values": values2, } requiredDuringSchedulingIgnoredDuringExecution := make([]map[string]interface{}, 1) requiredDuringSchedulingIgnoredDuringExecution[0] = map[string]interface{}{ "labelSelector": map[string]interface{}{ "matchExpressions": matchExpressions, }, "topologyKey": "kubernetes.io/hostname", } pools0 := map[string]interface{}{ "name": "pool-0", "servers": 4, "volumes_per_server": 1, "volume_configuration": map[string]interface{}{ "size": 26843545600, "storage_class_name": "standard", }, "securityContext": nil, "affinity": map[string]interface{}{ "podAntiAffinity": map[string]interface{}{ "requiredDuringSchedulingIgnoredDuringExecution": requiredDuringSchedulingIgnoredDuringExecution, }, }, "resources": map[string]interface{}{ "requests": map[string]interface{}{ "cpu": 2, "memory": 2, }, }, } logSearchConfiguration := map[string]interface{}{ "image": "", "postgres_image": "", "postgres_init_image": "", } prometheusConfiguration := map[string]interface{}{ "image": "", "sidecar_image": "", "init_image": "", } tls := map[string]interface{}{ "minio": minio, "ca_certificates": caCertificates, "console_ca_certificates": consoleCAcertificates, } idp := map[string]interface{}{ "keys": keys, } pools[0] = pools0 // 1. Create Tenant resp, err = CreateTenant( tenantName, namespace, accessKey, secretKey, accessKeys, idp, tls, prometheusConfiguration, logSearchConfiguration, erasureCodingParity, pools, exposeConsole, exposeMinIO, image, serviceName, enablePrometheus, enableConsole, enableTLS, secretKeys, ) assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, "Status Code is incorrect") } // 2. Delete tenant resp, err = DeleteTenant(namespace, tenantName) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 204, resp.StatusCode, inspectHTTPResponse(resp), ) } printEndFunc("TestCreateTenant") } func ListTenantsByNameSpace(namespace string) (*http.Response, error) { /* Helper function to list buckets HTTP Verb: GET URL: http://localhost:9090/api/v1/namespaces/{namespace}/tenants */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/namespaces/"+namespace+"/tenants", nil) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestListTenantsByNameSpace(t *testing.T) { assert := assert.New(t) namespace := "default" resp, err := ListTenantsByNameSpace(namespace) assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, "Status Code is incorrect") } bodyBytes, _ := ioutil.ReadAll(resp.Body) result := models.ListTenantsResponse{} err = json.Unmarshal(bodyBytes, &result) if err != nil { log.Println(err) assert.Nil(err) } if len(result.Tenants) == 0 { assert.Fail("FAIL: There are no tenants in the array") } TenantName := &result.Tenants[0].Name fmt.Println(*TenantName) assert.Equal("new-tenant", *TenantName, *TenantName) } func ListNodeLabels() (*http.Response, error) { /* Helper function to list buckets HTTP Verb: GET URL: http://localhost:9090/api/v1/nodes/labels */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/nodes/labels", nil) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestListNodeLabels(t *testing.T) { assert := assert.New(t) resp, err := ListNodeLabels() assert.Nil(err) if err != nil { log.Println(err) return } finalResponse := inspectHTTPResponse(resp) if resp != nil { assert.Equal( 200, resp.StatusCode, finalResponse) } // "beta.kubernetes.io/arch" is a label of our nodes and is expected assert.True( strings.Contains(finalResponse, "beta.kubernetes.io/arch"), finalResponse) } func GetPodEvents(nameSpace string, tenant string, podName string) (*http.Response, error) { /* Helper function to get events for pod URL: /namespaces/{namespace}/tenants/{tenant}/pods/{podName}/events HTTP Verb: GET */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant+"/pods/"+podName+"/events", nil) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestGetPodEvents(t *testing.T) { assert := assert.New(t) namespace := "tenant-lite" tenant := "storage-lite" podName := "storage-lite-pool-0-0" resp, err := GetPodEvents(namespace, tenant, podName) assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, "Status Code is incorrect") } } func GetPodDescribe(nameSpace string, tenant string, podName string) (*http.Response, error) { /* Helper function to get events for pod URL: /namespaces/{namespace}/tenants/{tenant}/pods/{podName}/events HTTP Verb: GET */ fmt.Println(nameSpace) fmt.Println(tenant) fmt.Println(podName) request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant+"/pods/"+podName+"/describe", nil) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestGetPodDescribe(t *testing.T) { assert := assert.New(t) namespace := "tenant-lite" tenant := "storage-lite" podName := "storage-lite-pool-0-0" resp, err := GetPodDescribe(namespace, tenant, podName) assert.Nil(err) if err != nil { log.Println(err) return } finalResponse := inspectHTTPResponse(resp) if resp != nil { assert.Equal( 200, resp.StatusCode, finalResponse) } /*if resp != nil { assert.Equal( 200, resp.StatusCode, "Status Code is incorrect") }*/ } func GetCSR(nameSpace string, tenant string) (*http.Response, error) { /* Helper function to get events for pod URL: /namespaces/{namespace}/tenants/{tenant}/csr HTTP Verb: GET */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant+"/csr/", nil) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestGetCSR(t *testing.T) { assert := assert.New(t) namespace := "tenant-lite" tenant := "storage-lite" resp, err := GetCSR(namespace, tenant) assert.Nil(err) if err != nil { log.Println(err) return } finalResponse := inspectHTTPResponse(resp) if resp != nil { assert.Equal( 200, resp.StatusCode, finalResponse) } assert.Equal(strings.Contains(finalResponse, "Automatically approved by MinIO Operator"), true, finalResponse) } func TestGetMultipleCSRs(t *testing.T) { /* We can have multiple CSRs per tenant, the idea is to support them in our API and test them here, making sure we can retrieve them all, as an example I found this tenant: storage-kms-encrypted -client -tenant-kms-encrypted-csr storage-kms-encrypted -kes -tenant-kms-encrypted-csr storage-kms-encrypted -tenant-kms-encrypted-csr Notice the nomenclature of it: -<*>--csr where * is anything either nothing or something, anything. */ assert := assert.New(t) namespace := "tenant-kms-encrypted" tenant := "storage-kms-encrypted" resp, err := GetCSR(namespace, tenant) assert.Nil(err) if err != nil { log.Println(err) return } finalResponse := inspectHTTPResponse(resp) if resp != nil { assert.Equal( 200, resp.StatusCode, finalResponse) } var expectedMessages [3]string expectedMessages[0] = "storage-kms-encrypted-tenant-kms-encrypted-csr" expectedMessages[1] = "storage-kms-encrypted-kes-tenant-kms-encrypted-csr" expectedMessages[2] = "Automatically approved by MinIO Operator" for _, element := range expectedMessages { assert.Equal(strings.Contains(finalResponse, element), true) } } func ListPVCsForTenant(nameSpace string, tenant string) (*http.Response, error) { /* URL: /namespaces/{namespace}/tenants/{tenant}/pvcs HTTP Verb: GET */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant+"/pvcs/", nil) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestListPVCsForTenant(t *testing.T) { /* Function to list and verify the Tenant's Persistent Volume Claims */ assert := assert.New(t) namespace := "tenant-lite" tenant := "storage-lite" resp, err := ListPVCsForTenant(namespace, tenant) bodyResponse := resp.Body assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, "failed") } bodyBytes, _ := ioutil.ReadAll(bodyResponse) listObjs := models.ListPVCsResponse{} err = json.Unmarshal(bodyBytes, &listObjs) if err != nil { log.Println(err) assert.Nil(err) } var pvcArray [4]string pvcArray[0] = "data0-storage-lite-pool-0-0" pvcArray[1] = "data0-storage-lite-pool-0-1" pvcArray[2] = "data0-storage-lite-pool-0-2" pvcArray[3] = "data0-storage-lite-pool-0-3" for i := 0; i < len(pvcArray); i++ { assert.Equal(strings.Contains(listObjs.Pvcs[i].Name, pvcArray[i]), true) } } func CreateNamespace(nameSpace string) (*http.Response, error) { /* Description: Creates a new Namespace with given information URL: /namespace HTTP Verb: POST */ requestDataAdd := map[string]interface{}{ "name": nameSpace, } requestDataJSON, _ := json.Marshal(requestDataAdd) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( "POST", "http://localhost:9090/api/v1/namespace/", requestDataBody, ) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestCreateNamespace(t *testing.T) { /* Function to Create a Namespace only once. */ assert := assert.New(t) namespace := "new-namespace-thujun2208pm" tests := []struct { name string nameSpace string expectedStatus int }{ { name: "Create Namespace for the first time", expectedStatus: 201, nameSpace: namespace, }, { name: "Create repeated namespace for second time", expectedStatus: 500, nameSpace: namespace, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, err := CreateNamespace(tt.nameSpace) assert.Nil(err) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( tt.expectedStatus, resp.StatusCode, "failed") } else { assert.Fail("resp cannot be nil") } }) } } func LoginOperator() (*http.Response, error) { /* Description: Login to Operator Console. URL: /login/operator Params in the Body: jwt */ requestData := map[string]string{ "jwt": jwt, } fmt.Println("requestData: ", requestData) requestDataJSON, _ := json.Marshal(requestData) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest("POST", "http://localhost:9090/api/v1/login/operator", requestDataBody) if err != nil { log.Println(err) } request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func LogoutOperator() (*http.Response, error) { /* Description: Logout from Operator. URL: /logout */ request, err := http.NewRequest( "POST", "http://localhost:9090/api/v1/logout", nil, ) request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") if err != nil { log.Println(err) } request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestLogout(t *testing.T) { // Vars assert := assert.New(t) // 1. Logout response, err := LogoutOperator() if err != nil { log.Println(err) return } if response != nil { assert.Equal( 200, response.StatusCode, inspectHTTPResponse(response), ) } // 2. Login to recover token response, err = LoginOperator() if err != nil { log.Println(err) return } if response != nil { for _, cookie := range response.Cookies() { if cookie.Name == "token" { token = cookie.Value break } } } // Verify token if token == "" { assert.Fail("authentication token not found in cookies response") } } func EnableTenantLogging(namespace, tenant string) (*http.Response, error) { /* Description: Enable Tenant Logging HTTP Verb: POST */ request, err := http.NewRequest( "POST", "http://localhost:9090/api/v1/namespaces/"+namespace+"/tenants/"+tenant+"/enable-logging", nil, ) request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") if err != nil { log.Println(err) } request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func DisableTenantLogging(namespace, tenant string) (*http.Response, error) { /* Description: Disable Tenant Logging */ request, err := http.NewRequest( "POST", "http://localhost:9090/api/v1/namespaces/"+namespace+"/tenants/"+tenant+"/disable-logging", nil, ) request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") if err != nil { log.Println(err) } request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestEnableTenantLogging(t *testing.T) { // Vars assert := assert.New(t) namespace := "tenant-lite" tenant := "storage-lite" // Enable tenant logging resp, err := EnableTenantLogging(namespace, tenant) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, inspectHTTPResponse(resp), ) } } func TestDisableTenantLogging(t *testing.T) { // Vars assert := assert.New(t) namespace := "tenant-lite" tenant := "storage-lite" // Disable tenant logging resp, err := DisableTenantLogging(namespace, tenant) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, inspectHTTPResponse(resp), ) } } func GetTenantLogs(nameSpace, tenant string) (*http.Response, error) { /* URL: /namespaces/{namespace}/tenants/{tenant}/log summary: Get Tenant Logs HTTP Verb:GET */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant+"/log", nil, ) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func SetTenantLogs(labels, annotations, nodeSelector, dbLabels, dbAnnotations, dbNodeSelector []string, nameSpace, tenant, dbServiceAccountName, logMemRequest, logDBMemRequest, diskCapacityGB, serviceAccountName string) (*http.Response, error) { /* URL: /namespaces/{namespace}/tenants/{tenant}/log summary: Set Tenant Logs HTTP Verb: PUT */ requestDataAdd := map[string]interface{}{ "labels": labels, "annotations": annotations, "dbAnnotations": dbAnnotations, "dbLabels": dbLabels, "dbNodeSelector": dbNodeSelector, "diskCapacityGB": diskCapacityGB, "nodeSelector": nodeSelector, "serviceAccountName": serviceAccountName, "dbServiceAccountName": dbServiceAccountName, "logMemRequest": logMemRequest, "logDBMemRequest": logDBMemRequest, } requestDataJSON, _ := json.Marshal(requestDataAdd) requestDataBody := bytes.NewReader(requestDataJSON) request, err := http.NewRequest( "PUT", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant+"/log", requestDataBody, ) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestGetTenantLogs(t *testing.T) { // Vars assert := assert.New(t) namespace := "tenant-lite" tenant := "storage-lite" // Get Log Settings resp, err := GetTenantLogs(namespace, tenant) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, inspectHTTPResponse(resp), ) } } func TestSetTenantLogs(t *testing.T) { // Vars assert := assert.New(t) nameSpace := "tenant-lite" tenant := "storage-lite" var nodeSelector []string var labels []string var annotations []string var dbAnnotations []string var dbNodeSelector []string var dbLabels []string diskCapacityGB := "2" dbServiceAccountName := "" logMemRequest := "0Gi" logDBMemRequest := "0Gi" serviceAccountName := "" // Set Tenant Logs resp, err := SetTenantLogs( labels, annotations, nodeSelector, dbLabels, dbAnnotations, dbNodeSelector, nameSpace, tenant, dbServiceAccountName, logMemRequest, logDBMemRequest, diskCapacityGB, serviceAccountName, ) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, inspectHTTPResponse(resp), ) } } func TenantDetails(nameSpace, tenant string) (*http.Response, error) { /* url: /namespaces/{namespace}/tenants/{tenant} summary: Tenant Details operationId: TenantDetails HTTP Verb: GET */ request, err := http.NewRequest( "GET", "http://localhost:9090/api/v1/namespaces/"+nameSpace+"/tenants/"+tenant, nil, ) if err != nil { log.Println(err) } request.Header.Add("Cookie", fmt.Sprintf("token=%s", token)) request.Header.Add("Content-Type", "application/json") client := &http.Client{ Timeout: 2 * time.Second, } response, err := client.Do(request) return response, err } func TestTenantDetails(t *testing.T) { // Vars assert := assert.New(t) nameSpace := "tenant-lite" tenant := "storage-lite" resp, err := TenantDetails(nameSpace, tenant) if err != nil { log.Println(err) return } if resp != nil { assert.Equal( 200, resp.StatusCode, inspectHTTPResponse(resp), ) } }